Compile and Link OpenGL Shader Language - GLSL
This is a header-only mini-library to compile simple OpenGL shaders and link them into shader programs. You can also find a working example of its use HERE.
Why?
Let’s read some GLSL files, compile them, then Link them into a program the old fashioned way. Code taken from learnopengl.com.
// I'll spare you the wall of text. Just go to the learnopengl.com link above and you'll see how arduous it is.
That’s more than I want to write and it only covers two shaders. Let’s use this library!
GLProgram simple{
{
GLShader{GL_VERTEX_SHADER, "path/to/vert.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/frag.glsl"}
}
};
Whoa! That was easy! Now for the technical stuff.
Prerequisites
- GLEW
- C++11
Use
// Construct a linked OpenGL Shader Program with an implicitly converted std::vector< GLShader >
GLProgram simple{
{
GLShader{GL_VERTEX_SHADER, "path/to/vert.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/frag.glsl"}
}
};
// Instruct OpenGL server to use the compiled program by calling glUseProgram()
// First checks whether it contains a valid shader program
simple.use();
// Return the Program as GLuint for use in OpenGL functions
// First checks whether it contains a valid shader program
GLint someAttributeInShader = glGetAttribLocation(simple.program(), "someAttributeInShader");
Declarations
class GLShader{
public:
GLuint type;
std::string fileName = "";
GLuint compiled;
GLShader();
GLShader(const GLuint& t, const std::string& fn);
// Rule of 5's
GLShader(const GLShader& rhs);
GLShader& operator=(const GLShader& rhs);
GLShader(const GLShader&& o);
GLShader& operator=(const GLShader&& o);
~GLShader();
};
class GLProgram{
public:
GLuint prg;
GLProgram();
GLProgram(const std::vector< GLShader >& sh);
// Rule of 5's
GLProgram(const GLProgram& rhs);
GLProgram& operator=(const GLProgram& rhs);
GLProgram(const GLProgram&& o);
GLProgram& operator=(const GLProgram&& o);
~GLProgram();
GLuint program();
void use();
};
Instantiations
// Arguments are GLenum shaderType and an std::string filename. Filename extension does not matter.
// Shaders are compiled upon instantiation
GLShader myVertexShader{GL_VERTEX_SHADER, "path/to/vert.glsl"};
GLShader myFragmentShader{GL_FRAGMENT_SHADER, "path/to/frag.glsl"};
std::vector< GLShader > myShaders = {myVertexShader, myFragmentShader};
// Create program with an std::vector< GLShader >
// You can supply an std::vector of any size
// The program is linked upon instantiation
GLProgram myFirstProgram{myShaders};
// Create program with implicitly converted std::vector< GLShader >
// You can supply a list of any size
GLProgram mySecondProgram{
{
GLShader{GL_VERTEX_SHADER, "path/to/vert.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/frag.glsl"}
}
};
Management
// Easy program management with map
#include <map>
#include <string>
GLProgram simple{
{
GLShader{GL_VERTEX_SHADER, "path/to/vert.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/frag.glsl"}
}
};
GLProgram complex{
{
GLShader{GL_VERTEX_SHADER, "path/to/vert.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/frag.glsl"},
GLShader{GL_GEOMETRY_SHADER, "path/to/geometry.glsl"}
}
};
std::map< std::string, GLProgram > myPrograms = {
{"simple", simple},
{"complex", complex}
}
// Showing another way to instantiate
std::map< std::string, GLProgram > myOtherPrograms = {
{"simple",
GLProgram{
{
GLShader{GL_VERTEX_SHADER, "path/to/vertex.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/fragment.glsl"},
}
}
}
};
myPrograms["simple"].use();
GLint someAttributeInShader = glGetAttribLocation(myPrograms["simple"].program(), "someAttributeInShader");
myPrograms["complex"].use();
GLint someOtherAttributeInShader = glGetAttribLocation(myPrograms["complex"].program(), "someOtherAttributeInShader");</string></map>
Copying and Moving
#include <map>
#include <string>
GLShader myVertexShader;
GLShader tempVertex{GL_VERTEX_SHADER, "path/to/vert.glsl"};
// Copy Assignment
myVertexShader = tempVertex;
// Move Assignment
myVertexShader = GLShader{GL_VERTEX_SHADER, "path/to/vert.glsl"};
GLProgram simple{
{
GLShader{GL_VERTEX_SHADER, "path/to/vert.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/frag.glsl"}
}
};
GLProgram complex{
{
GLShader{GL_VERTEX_SHADER, "path/to/vert.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/frag.glsl"},
GLShader{GL_GEOMETRY_SHADER, "path/to/geometry.glsl"}
}
};
std::map< std::string, GLProgram > myPrograms = {
{"simple", simple},
{"complex", complex}
}
// Showing another way to instantiate
std::map< std::string, GLProgram > myOtherPrograms = {
{"simple",
GLProgram{
{
GLShader{GL_VERTEX_SHADER, "path/to/vertex.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/fragment.glsl"},
}
}
},
{"complex",
GLProgram{
{
GLShader{GL_VERTEX_SHADER, "path/to/vertex.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/fragment.glsl"},
GLShader{GL_GEOMETRY_SHADER, "path/to/geometry.glsl"}
}
}
}
};
// Copy Assignment
myPrograms["simple"] = myOtherPrograms["simple"];
// Move Assignment
myProgram["complex"] = GLProgram{
{
GLShader{GL_VERTEX_SHADER, "path/to/vertex.glsl"},
GLShader{GL_FRAGMENT_SHADER, "path/to/fragment.glsl"},
GLShader{GL_GEOMETRY_SHADER, "path/to/geometry.glsl"}
}
};</string></map>