Zyansheep
Zyansheep

Reputation: 188

For OpenGL Shaders, how would you write a Uniform Function in C++ that accepts all types?

So say I have a Shader class and I want to have a Uniform function that sends the data I pass to the loaded Shader program

class Shader{
   unsigned int programid;
   template<typename Type>
   void Uniform(unsigned int location, Type object){
       //Some logic that passes the type data to the uniform using glUniform[?]()
   }
}

How would I write the Uniform function (using templates in C++) to accept any type (primitive OR object) and pass it to the Shader?

Examples:

GLSL: uniform float Amount; C++: shader.Uniform(somefloat);

GLSL: uniform vec3 Position;

C++:

template<typename Type, size_t Size>
Vector{ Type data[Size]; }

Vector<float, 3> position = {0.0f, 1.0f, 1.0f}
shader.Uniform(position);

GLSL:

struct Light
{
  vec3 position;
  vec4 rotation;
  float luminosity;
  bool status;
};

uniform Light object;

C++:

struct Light {
  Vector<float, 3> position;
  Vector<float, 4> rotation;
  float luminosity;
  bool status;
}
Light object = {{1.0f,0.0f,0.0f},{0.0f,0.0f,0.0f},0.75f,true};
shader.Uniform(object);

Upvotes: 0

Views: 1319

Answers (1)

Hugh Fisher
Hugh Fisher

Reputation: 2516

First, C++ and GLSL are statically typed languages, not dynamically typed like JavaScript or Python. So there is no actual way to write a C++ function that accepts any type. What your C++ template function does is, essentially, a text substitution. Every time the C++ compiler sees the template used, eg "Vector", it takes the original template declaration and makes a new copy with "Type" and "Size" replaced by "float" and "3" respectively. And the compiler generates a unique mangled name to prevent linker errors something like __Vector_TypeFOO_SizeBAR...

(For sake of completeness, yes it's possible to implement your own dynamic typing in C/C++ with unions and/or pointer casts. But since you can't do either of those in GLSL, it doesn't help answer the question.)

So, since GLSL doesn't have templates to do the text replacement, you'll have to implement it yourself. Load the source of your shader from file or whatever. Before you pass it to glCompileShader, use your favourite string processing library to insert actual strings into placeholder text.

Eg in your shader you could write something like:

<TYPE><SIZE> position;

and your main program would do something like

src = loadShaderCode("example.template");
src.replace("<TYPE>", "vec");
src.replace("<SIZE>", "3");
shader = compileShader(src, ...);

Hope this helps.

Upvotes: 2

Related Questions