Buffer Objects in jME

YES! That’s the point. Same object on the user side, different bindings on the opengl side.

Come on… read carefully what I wrote.
you don’t use the same method on the material…so you know what to do

But you shouldn’t allow it, because different shaders with different layouts can read incorrect data.

But I can’t place this information to “MatParam”, so I can’t reach to it in other places.

You mean you write data differently in the Byte buffer depending on the layout?

then let’s add this information.

yes, my method “computeData()” writes to a buffer data depending on a layout of BO.

ok, I can do it, but I definetly don’t understand why you are against additional classes? :slight_smile:

@nehon I have updated the PR. My last version of this is:

This is nice. I like it a lot better. I’ll review the PR, but one first remark:
As said before

Don’t you feel there is a redundancy here?

IMO the setValue should declare the field so you don’t have to do it when you create the BufferObject.
Make it a setField mehtod. The method will look up for an existing filed with this name, or create it if it doesn’t exists.
Have a static Map in BufferObject (or maybe in buffer utils) that maps Class and VarType
Pseudo code

 static final Map<Class,VarType> typeMap = new HashMap<>();
    static {
        typeMap.put(ColorRGBA.class, VarType.Vector4);
        //...
        //...
    }

    public void setField(String fieldName, Object value){

        VarType type = typeMap.get(value.getClass());
        if(type == null){
            throw new IllegalArgumentException("Invalid field type: " + value.getClass());
        }

        BufferObjectField field = fields.get(fieldName);
        if(field != null){
            if(field.getType() != type){
                throw new IllegalArgumentException("fields " + fieldName + " should be of type "+ field.getType());
            }
        } else {
            field = new BufferObjectField(fieldName, type);
            fields.put(fieldName, field);
            // add it to your array structure (I recommend using a SafeArrayList instead of an array and iterate over it using getArray()
            // It will allow you to easily add elements and still have a fast array iteration.
        }

        field.setValue(value);

    }

this way you example becomes:

ssbo = new BufferObject(3);
ssbo.setValue("light_1", ColorRGBA.Red);
ssbo.setValue("light_2", ColorRGBA.Green);
1 Like

it’s ok, but what about collections? I can’t detect a target type by a collection.

The wiki for the users should then explain it like this:

public static final String BO_LIGHT_1 = "light_1";
public static final String BO_LIGHT_2 = "light_2";
ssbo = new BufferObject(3);
ssbo.setValue(BO_LIGHT_1, ColorRGBA.Red);
ssbo.setValue(BO_LIGHT_2, ColorRGBA.Green);

To avoid typos, which can happen with strings - doesn’t happen with @javasabr idea - there it could throw an exception or log an error if user tries to use a String name which wasn’t previously defined.

Mhh… why not?
the collection will be mapped to a XXXArray VarType anyway. And you can find the XXX type using the Class of the first element of the collection.

If the user really needs the control over this you can still add a declareField(String name, VarType type) method in the BufferObject. So the general case woul dbe easy, but if ever the user want to do more complex things he can use this method

List<Vector3f> vecs = new ArrayList<>();
ssbo = new BufferObject(3);
ssbo.declareFiel("my_collection", VarType.Vector3Array);
ssbo.setField("my_collection", vecs);
ssbo.setField("light_1", ColorRGBA.Red);
ssbo.setField("light_2", ColorRGBA.Green);

But IMO it’s still possible to automate this.

1 Like

Yes… though it’s most usually java best practice. But yeah.
IMO it’s more convenient to have a “get or create” method.

I still need to know declaration of a buffer in shader, where can I find it? :slight_smile:

ho you still have the

material.setShaderStorageBufferObject("buffername", ssbo);

this would map to a "m_buffername’’ buffer in the shader, as you did.

I talk about declarations like this:

layout (std140, binding = 4) buffer m_TestSSBO
{
  int index;
  vec4 colors[3];
};

I need to know how to write data to a byte buffer.

Well this is unchanged compared to what you do right now… I don’t get what the issue is.

EDIT: you still have the fields in the BufferObject. It’s just they are not declared when you instantitate the bufferObject but when ever they are added.

I need to know an order of these fields to send data correctly, if I have the order:

field_1
field_2

in my shader, but I set these fields in my code using another order, I will have wrong data.

1 Like

Well… order of creation is the order in the data layout :
Either make it really clear in the javadoc. and you can make the method name setOrDeclareField(“flied_1”, value); so that’s more explicit what it really does.
Either add a way to order them.
Or both.
IMO it’s more convenient than having to declare them beforehand.

EDIT: you can even have a debug method in BufferObject getShaderDeclaration() that would output the proper declaration in the console…

when you have to declare a structure in a constructor of your BO object, you can prevent some mistakes with working with the BO, for example, “forgot to declare some fields, incorrect order and etc”. I just try to make safer API :slight_smile: JS is more compact language than Java, but not safer. :wink:

1 Like

Well I’m not gonna go through the whole “do we take the user by the hand or are we focusing on being efficient” discussion.
Here your point is: Let’s be super verbose every time for every users that knows exactly how it works because they read the doc, to save the user that uses this API without knowing how it works because he didn’t read the doc.

Also if you have this code:

ssbo = new BufferObject(3);
ssbo.setField("field", ColorRGBA.Red);
ssbo.setField("anotherField", ColorRGBA.Green);
ssbo.setField("fieldfield", ColorRGBA.Green);
ssbo.setField("yetAnotherField", ColorRGBA.Green);

Is the order that much un-intuitive?
As said if ever the user is lost, have method that output this in the console

layout (std140, binding = 4) buffer m_<paramName>
{
  vec4 field;
  vec4 anotherField;
  vec4 fieldfield;
  vec4 yetAnotherField;
};
1 Like

@nehon I have updated the PR again. My last version of this is:

@nehon also, I have updated implementation of data layout, I tested with arrays/vec2-3-4-arrays/matrix3-4-arrays and other, it worked ok :slight_smile: