string mixin only works once per block?

TheFlyingFiddle theflyingfiddle at gmail.com
Fri Apr 11 20:15:18 PDT 2014


On Friday, 11 April 2014 at 18:46:12 UTC, Vlad Levenfeld wrote:
> Corrections and suggestions welcome!

I would not recommend using string attributes since it's easy to 
misspell them, it would be better to use a struct tag or simply 
make a uniform type since the compiler will help you out if you 
miss something.

//Struct tag

struct Uniform { }
@Uniform GLint start_color;

instead of

@("uniform") GLint start_color;

// Even better using uniform as a type

struct Uniform(T)
{
    T value;
    GLint location;
}

Uniform!vec4 start_color;


For a next step i would recommend that you do some validation as 
part of the linking process. After you have found the location of 
the uniform simply use the opengl query functions to get the type 
of the uniform and do type-checking agains the client uniform 
type.

If you want to take it even further you could automate the opengl 
setup step. (Templates are freeking awesome)

//U == Uniform Type V == vertex type (used for validation).
struct ShaderProgram(U,V)
{
    GLint[U.tupleof.length] uniformLocations; //Locations of all 
the uniforms in the same order as they appear in the U struct.
    U uniforms; //All the uniforms that exists in the shader.
    GLint glName; //gl id

    this(string geometrySource,
         string vertSource,
         string fragSource)
    {
       //Compile shaders link program.
       //Find uniforms locations by looking at fileds in U and do 
some validation
       //on these.
       //Find all vertex input attributes and do validation 
against fields in V
    }

    void use()
    {
       //Call glUseProgram(glName);

       //Go through all the fields in
       //uniformValues and set them with
       //glUniform*
       //Locations are stored in locations array.
    }

    //More methods for validation or other convinience things.
}


An example useage of this system. (I assume some sort of particle 
system)

struct Particle
{
    vec2 velocity;
    vec2 position;
    float spawnTime;
}


struct ParticleUniforms
{
    mat4 projection;
    Color startColor;
    Color endColor;

    vec2 startSize;
    vec2 endSize;

    float particleLifeTime;
    float currentTime;
}


ShaderProgram!(Particle, ParticleUniforms) program;
void setup()
{
    //Initialize the program with the given shaders
    //If we get passed this line we can be sure that the
    //program is actually functional!
    program = ShaderProgram!(Particle, ParticleUniforms)
              (gShader, vShader, fShader);


    //Set initial values for all the uniforms in the program.
    program.uniforms.startColor = Color.red;
    program.uniforms.endColor   = Color.green;
    etc...
}

void render(Time time)
{
    //Update interesting uniforms
    program.uniform.currentTime += time.delta;

    program.use(); //glUseProgram

    //Now we have a program that is usable and ensured to be valid.
    //(If it works like intended is subject to the shaders ^^)
}

I am currently using something similar to this and it has made 
compability debugging virtually nonexistant. It also leaves the 
amount of boilerplate to a minimum. (It can be extended even 
further to validate correct setup of various buffers, vertex 
array objects and most other opengl related stuff)

One last thing: The following will make debugging opengl easier.

struct gl
{
     static auto ref opDispatch(string name, Args...)(Args args)
     {
          enum glName = "gl" ~ name[0].toUpper.to!string ~ name[1 
.. $];
          debug scope(exit) checkGLError(name, args)
	 mixin("return " ~ glName ~ "(args);");
     }
}

Now instead of calling opengl methods like this:

glUniform*
glBindTexture*
etc

Call them like this.

gl.uniform*
gl.bindTexture*
etc

This will automagically add a glGetError() after every call in 
debugmode.
No more adding glGetError manually!

I feel i went of topic. I hope this was usefull to you.


More information about the Digitalmars-d-learn mailing list