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