cginternals / globjects

C++ library strictly wrapping OpenGL objects.
https://globjects.org
MIT License
538 stars 59 forks source link

Setting uniforms requires compile time information about their type #286

Closed mrzzzrm closed 9 years ago

mrzzzrm commented 9 years ago

As far as I can tell it isn't possible to set the value of a globjects::Program's uniform using the globjects API if only the uniform's GLenum type / its memory location/size are available.

Imo globjects::Program should fully expose https://www.opengl.org/wiki/GLAPI/glProgramUniform / https://www.opengl.org/sdk/docs/man/html/glUniform.xhtml with optional convenience methods setUniform(location, type, ptr) and setUniform(name, type, ptr).

What do you think? I'd be happy to do the hacking, just wanted to ask for feedback first.

scheibel commented 9 years ago

As for now, globjects::Program implements the following functions:

template<typename T>
void setUniform(const std::string & name, const T & value);
template<typename T>
void setUniform(gl::GLint location, const T & value);
template<typename T>
Uniform<T> * getUniform(const std::string & name);
template<typename T>
const Uniform<T> * getUniform(const std::string & name) const;
template<typename T>
Uniform<T> * getUniform(gl::GLint location);
template<typename T>
const Uniform<T> * getUniform(gl::GLint location) const;

and further to fulfil your requirements. Or did I miss anything?

mrzzzrm commented 9 years ago

What I want to do is set a uniform from a raw data pointer (and a runtime type (like GL_FLOAT_VEC2), but that could be queried from the program object). Now I just realised that even the glUniform*v() functions require you to code the uniform type into the function name. Bummer... Alright, change my question to: Would you accept the convenience functions setUniform(location, type, ptr) and setUniform(name, type, ptr) and respective equivalents for array uniforms in globjects or is that out of the scope of the lib? These functions would really just be massive switch(type) blocks that would call the appropriate, already available setUniform function.

scheibel commented 9 years ago

This interface would imply, that the provided type behind ptr has to be converted to the given type from type. This is something we hasn't done before and I'm not sure if we ever will. What is the point of a rendering system to store uniform values in another type as expected in the shader and why would a rendering system doesn't provide the necessary conversion by itself (so that this part has to be taken by globjects)?

What I have looked up (in glbinding) is, that the OpenGL API indeed has enum values for the common uniform types:

GL_FLOAT_VEC2                                                 = 0x8B50,
GL_FLOAT_VEC2_ARB                                             = 0x8B50,
GL_FLOAT_VEC3                                                 = 0x8B51,
GL_FLOAT_VEC3_ARB                                             = 0x8B51,
GL_FLOAT_VEC4                                                 = 0x8B52,
GL_FLOAT_VEC4_ARB                                             = 0x8B52,
GL_INT_VEC2                                                   = 0x8B53,
GL_INT_VEC2_ARB                                               = 0x8B53,
GL_INT_VEC3                                                   = 0x8B54,
GL_INT_VEC3_ARB                                               = 0x8B54,
GL_INT_VEC4                                                   = 0x8B55,
GL_INT_VEC4_ARB                                               = 0x8B55,
GL_BOOL                                                       = 0x8B56,
GL_BOOL_ARB                                                   = 0x8B56,
GL_BOOL_VEC2                                                  = 0x8B57,
GL_BOOL_VEC2_ARB                                              = 0x8B57,
GL_BOOL_VEC3                                                  = 0x8B58,
GL_BOOL_VEC3_ARB                                              = 0x8B58,
GL_BOOL_VEC4                                                  = 0x8B59,
GL_BOOL_VEC4_ARB                                              = 0x8B59,
GL_FLOAT_MAT2                                                 = 0x8B5A,
GL_FLOAT_MAT2_ARB                                             = 0x8B5A,
GL_FLOAT_MAT3                                                 = 0x8B5B,
GL_FLOAT_MAT3_ARB                                             = 0x8B5B,
GL_FLOAT_MAT4                                                 = 0x8B5C,
GL_FLOAT_MAT4_ARB                                             = 0x8B5C,
GL_SAMPLER_1D                                                 = 0x8B5D,
GL_SAMPLER_1D_ARB                                             = 0x8B5D,
GL_SAMPLER_2D                                                 = 0x8B5E,
GL_SAMPLER_2D_ARB                                             = 0x8B5E,
GL_SAMPLER_3D                                                 = 0x8B5F,
GL_SAMPLER_3D_ARB                                             = 0x8B5F,
GL_SAMPLER_CUBE                                               = 0x8B60,
GL_SAMPLER_CUBE_ARB                                           = 0x8B60,
GL_SAMPLER_1D_SHADOW                                          = 0x8B61,
GL_SAMPLER_1D_SHADOW_ARB                                      = 0x8B61,
GL_SAMPLER_2D_SHADOW                                          = 0x8B62,
GL_SAMPLER_2D_SHADOW_ARB                                      = 0x8B62,
GL_SAMPLER_2D_RECT                                            = 0x8B63,
GL_SAMPLER_2D_RECT_ARB                                        = 0x8B63,
GL_SAMPLER_2D_RECT_SHADOW                                     = 0x8B64,
GL_SAMPLER_2D_RECT_SHADOW_ARB                                 = 0x8B64,
GL_FLOAT_MAT2x3                                               = 0x8B65,
GL_FLOAT_MAT2x4                                               = 0x8B66,
GL_FLOAT_MAT3x2                                               = 0x8B67,
GL_FLOAT_MAT3x4                                               = 0x8B68,
GL_FLOAT_MAT4x2                                               = 0x8B69,
GL_FLOAT_MAT4x3                                               = 0x8B6A,

Nethertheless, your proposed interface would require to rely on C semantics where globjects tries to use semantics-rich (and thus, typed) objects and classes. If you don't want to use those object semantics you are free to call straight glbinding OpenGL calls everywhere in your code. To ease the automatic uniform update upon program relinking, I think we can add the possibility of a callback or observer interface so you get called when non-tracked uniforms has to be updated.

Alternatively, maybe you can explain an explicit use case where we can better understand the intention.

mrzzzrm commented 9 years ago

Think of loading arbitrary shaders into an editor that than exposes its uniforms in UI elements generated at runtime (like, single line text edit for float, 4x4 for matrix, ...) and than passing them to the running shader. At some point you're gonna have that massive switch block over the enum you quoted. But if you don't think globjects should be that place, that's okay, feel free to close this ;)

scheibel commented 9 years ago

Thank you for your use-case.

If I had to implement such editor, I would parse the shader for the uniforms and their types (e.g., using https://www.opengl.org/wiki/Program_Introspection#Uniforms_and_blocks). The information about the types would then be used to generate an appropriate UI. If the values in the UI gets updated, I would have the information about the type of the uniform to call the correct method on the program object. The information about the type is a must-have somewhere in the code, since either the UI is highly specialized for the uniform values, or the new value has to be parsed, validated, and converted into the target format.

So I would also tend to closing this issue.

sbusch42 commented 9 years ago

If you think in C-terms, then yes, you would use such a switch block. But in C++ this could also be solved in a type-safe manner by using templates. For example, have a GuiElement that can be specialized for the specific types, and then you can use the approriate types Uniform classes from globjects. Or, you could use the already existing property system in libzeug for the gui :)

mrzzzrm commented 9 years ago

You can do fancy, fancy things with this C++, indeed ;) Thanks for your comments, both of you!