A Simple C++ OpenGL Shader Loader

Update: There’s a re-worked and improved version of this shader loading code here: https://r3dux.org/2015/01/a-simple-c-opengl-shader-loader-improved/ – you should probably use that instead of this.


I’ve been doing a bunch of OpenGL programming recently and wanted to create my own shader classes to make setting up shaders as easy as possible – so I did ;-) To create vertex and fragment shaders and tie them into a shader program you can just import the Shader.hpp and ShaderProgram.hpp classes and use code like the following:

// Set up vertex shader
Shader vertexShader(GL_VERTEX_SHADER);
vertexShader.loadFromFile("MyVertexShader.vert");
vertexShader.compile();
 
// Set up fragment shader
Shader fragmentShader(GL_FRAGMENT_SHADER);
fragmentShader.loadFromFile("MyFragmentShader.frag");
fragmentShader.compile();
 
// Set up shader program
shaderProgram = new ShaderProgram();
shaderProgram->attachShader(vertexShader);
shaderProgram->attachShader(fragmentShader);
shaderProgram->linkProgram();

There’s also a loadFromString(some-string-containing-GLSL-source-code) method, if that’s your preference.

The ShaderProgram class uses a string/int map as a key/value pair, so to add attributes or uniforms you just specify their name and they’ll have a location assigned to them:

// Add the shader attributes
shaderProgram->addAttribute("vVertex");
// ...
 
// Add the shader uniforms
shaderProgram->addUniform("pMatrix");
// ...

The ShaderProgram class then uses two methods called attribute and uniform to return the bound locations (you could argue that I should have called these methods getAttribute and getUniform – but I felt that just attribute and uniform were cleaner in use. Feel free to mod if you feel strongly about it). When binding vertex attribute pointers you can use code like this:

// Set up a vertex buffer object to hold the vertex position data
GLuint vertexBufferId;
glGenBuffers(1, &vertexBufferId);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
glBufferData(GL_ARRAY_BUFFER, model.getVertexDataSizeBytes(), model.getVertexData(), GL_STATIC_DRAW);
 
// Set up the vertex attribute pointer for the vVertex attribute
glVertexAttribPointer(
    shaderProgram->attribute("vVertex"),  // Attribute location
    VERTEX_COMPONENTS,                    // Number of elements per vertex, here (x,y,z), so 3
    GL_FLOAT,                             // Data type of each element
    GL_FALSE,                             // Normalised?
    0,                                    // Stride
    0                                     // Offset
);

Finally, when drawing your geometry you can get just enable the shader program, provide the location and data for bound uniforms, and then disable it like this (I’m using the GL Mathematics library for matrices – you can use anything you fancy):

shaderProgram->use();
 
    // Provide uniform data
    glUniformMatrix4fv( shaderProgram->uniform("mMatrix"), 1, GL_FALSE, glm::value_ptr(mMatrix) );
    // ...
 
    // Draw stuff
 
shaderProgram->disable();

That’s pretty much it – nice and simple. I haven’t done anything with geometry shaders yet so I’ve no idea if there’s anything else you’ll need, but if so it likely won’t be too tricky a job to implement it yourself. Anyways, you can look at the source code for the classes themselves below, and I’ll put the two classes in a zip file here: ShaderHelperClasses.zip.

As a final note, you can’t create anything shader-y without having a valid OpenGL rendering context (i.e. a window to draw stuff to) or the code will segfault – that’s just how it works. The easiest way around this if you want to keep a global ShaderProgram object around is to create it as a pointer (i.e. ShaderProgram *shaderProgram;) and then initialise it later on when you’ve got the window open with shaderProgram = new ShaderProgram(); like I’ve done above.

Cheers! =D

Source code after the jump…

How To: Syntax highlight GLSL shaders in Gedit

GLSL shaders share a lot in common with the C language, and Gedit can syntax highlight C/C++ and a host of other languages – so why not GLSL shaders? Here’s a simple way to make it happen…

1.) Gedit uses gtksourceview for its syntax highlighting rules – so find out where that’s located on your distro with the following:

locate gtksourceview | grep /c.lang

Once you’ve got the location of the c.lang file, navigate there in the bash (on Ubuntu it’s in /usr/share/gtksourceview-2.0/language-specs).

2.) Make a copy of the c.lang file in case you accidentally stuff it up (optional, but better safe than sorry):

sudo cp c.lang c.lang.ORIG

3.) Open the file with your text editor of choice and modify the c.lang file to add in additional file extensions which should be syntax highlighted as per the c.lang definitions:

gksudo gedit ./c.lang

A couple of lines into the file (after the comments at the top) you’ll see the following:

<property name="globs">*.c;</property>

Assuming you’re ending your vertex shaders with .vp and your fragment shaders with .fp (if you’re using .vert and .frag or such just substitute appropriately), change the line to read:

<property name="globs">*.c;*.vp;*.fp</property>

Save it, close gedit, and open a .vp or .fp file with Gedit – syntax highlighty goodness is rightfully yours. Of course, this is normal C highlighting, not true GLSL highlighting – but it’s a good start.

If you wanted to add things like vec3, uniform etc. then you can find the following sections in the c.lang file and add ’em in yourself:

<context id="keywords" style-ref="keyword" class="keyword">
<context id="types" style-ref="type" class="type">

Cheers!

C++/OpenGL/GLSL Texture Manipulation

Just learning some GLSL and playing about with vertex and fragment shaders – not a bad first start, but it’s going to take a significant amount of time and effort to get to really writing some descent shaders – it’s just very, very different from fixed-pipeline stuff… What you’re looking at is a texture where I’ve drawn some stuff on it in bright red, and then in the fragment shader anything found in the texture to be bright red gets discarded, effectively leaving in empty, like a cut-out =D

All in, the project’s around 500 lines of source, with the shaders being merely:

Vertex Shader

#version 110 // Olde...
 
varying vec2 vTexCoord; // varying is now deprecated.. will re-write soon
 
void main(void)
{
   vTexCoord = gl_MultiTexCoord0; 
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; // 3D vertex -> 2D window position transformation
}

Fragment Shader

sampler2D myTexture;    // Apparently this should not be a uniform variable as you shouldn't loop through uniform variables for performance reasons...
varying vec2 vTexCoord; // Pass through from our vertex shader. Should be type "in" in more recent versions of GLSL
 
void main (void) 
{  
   vec4 color = texture2D(myTexture, vTexCoord); 
 
   if (color.r > 0.9 && (color.g < 0.15 && color.b < 0.15))
      discard; 
 
   gl_FragColor = color;
}

The Linux Code::Blocks project will all source & image can be found below, but you’ll need to have or install libGL, libGLEW, libglfw, libIL, libILU, libILUT for it to work right out of the box. The linkage details are all in the Code::Blocks project file (and also in the .depend file if you don’t use C::B) so you can see what you need if there’s anything missing.

Download: GLSL-Texture-Manipulation-Test.zip

Update: Ha! Hadn’t thought of this before, but I guess what I’m really doing is Chroma-Keying (or Colour-Keying, whatever you prefer)… And you can do the same thing in SDL/OpenGL without using any shaders like this.