Skip to content

Instantly share code, notes, and snippets.

@RobertHue
Last active April 3, 2018 07:04
Show Gist options
  • Save RobertHue/57e465f5edfd9ab6f57ef954ccaffd17 to your computer and use it in GitHub Desktop.
Save RobertHue/57e465f5edfd9ab6f57ef954ccaffd17 to your computer and use it in GitHub Desktop.
OpenGL - glsl Shader loader class
#ifndef SHADER_H
#define SHADER_H
#include <GL/glew.h>
#include <iostream> // std::cout std::cin
#include <fstream> // std::ifstream
#include <string> // std::string
#include <sstream> // std::stringstream
///////////////////////////////////////////////////////////////////////////////////////////////////
/// @class used to compile a vertex and fragment shader and
/// link them to a program which will get loaded onto the GPU
class Shader
{
public:
/// @brief creates, loads and activates a shader program to run on GPU
Shader(const std::string& filePathVertexShader, const std::string& filePathFragmentShader);
/// @brief destroys the shader program
~Shader();
private:
/// @brief reads the file give by its path filePath
/// @return a copy of the content of the file
std::string readFile(const std::string& filePath);
/// @brief compiles a shader of give type with give GLSL source code as string
/// @param type GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
/// @param source a reference to the GLSL source code as std::string
/// @return hShader if succeeded, otherwhise 0
GLuint compileShader(GLuint type, const std::string& source);
/// @brief compiles and links a GLSL-Shader-Pair
/// @note to activate the shader created by this use glUseProgram(hProgram);
void createShader(const std::string& vertexShader, const std::string& fragmentShader);
private:
GLuint hProgram;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////// public implementations:
inline
Shader::Shader(const std::string& filePathVertexShader, const std::string& filePathFragmentShader)
{
// read compile link and load a GLSL shader as a program
std::string vertexShader = readFile(filePathVertexShader);
std::string fragmentShader = readFile(filePathFragmentShader);
createShader(vertexShader, fragmentShader);
glUseProgram(hProgram);
}
inline
Shader::~Shader()
{
if (hProgram != 0)
{
glDeleteProgram(hProgram);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////// private implementations:
inline
std::string Shader::readFile(const std::string& filePath) {
std::ifstream fs(filePath, std::ios::in);
if (!fs.is_open()) {
std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl;
return "";
}
std::stringstream buffer;
std::string line;
while (std::getline(fs, line)) {
// debug:
// std::cout << line << "\n";
buffer << line << "\n";
}
fs.close();
return buffer.str();
}
inline
GLuint Shader::compileShader(GLuint type, const std::string& source)
{
// creates an empty shader obj, ready to accept source-code and be compiled
GLuint hShader = glCreateShader(type);
// hands the shader source code to the shader object so that it can keep a copy of it
const char* src = source.c_str();
glShaderSource(hShader, 1, &src, nullptr);
// compiles whatever source code is contained in the shader object
glCompileShader(hShader);
// Error Handling: Check whether the shader has been compiled
GLint result;
glGetShaderiv(hShader, GL_COMPILE_STATUS, &result); // assigns result with compile operation status
if (result == GL_FALSE)
{
int length;
glGetShaderiv(hShader, GL_INFO_LOG_LENGTH, &length); // assigns length with length of information log
char* infoLog = (char*)alloca(length * sizeof(char)); // allocate on stack frame of caller
glGetShaderInfoLog(hShader, length, &length, infoLog); // returns the information log for a shader object
std::cout << "Failed to compile shader!"
<< (type == GL_VERTEX_SHADER ? "vertex" : "fragment")
<< std::endl;
std::cout << infoLog << std::endl;
glDeleteShader(hShader);
return static_cast<GLuint>(0);
}
return hShader;
}
inline
void Shader::createShader(const std::string& vertexShader, const std::string& fragmentShader) {
// compile the two shaders given as string reference
GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShader);
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragmentShader);
if (vs == 0 || fs == 0) { return; }
// create a container for the program-object to which you can attach shader objects
hProgram = glCreateProgram();
// attaches the shader objects to the program object
glAttachShader(hProgram, vs);
glAttachShader(hProgram, fs);
// links all the shader objects, that are attached to a program object, together
glLinkProgram(hProgram);
// Error Handling: Check whether program has been linked successfully
GLint result;
glGetShaderiv(hProgram, GL_COMPILE_STATUS, &result); // assigns result with compile operation status
if (result == GL_FALSE)
{
int length;
glGetShaderiv(hProgram, GL_INFO_LOG_LENGTH, &length); // assigns length with length of information log
char* infoLog = (char*)alloca(length * sizeof(char)); // allocate on stack frame of caller
glGetShaderInfoLog(hProgram, length, &length, infoLog); // returns the information log for a shader object
std::cout << "Failed to link vertex and fragment shader!"
<< std::endl;
std::cout << infoLog << std::endl;
glDeleteProgram(hProgram);
return;
}
glValidateProgram(hProgram);
// deletes intermediate objects
glDeleteShader(vs);
glDeleteShader(fs);
// activate the program into the state machine of opengl
// glUseProgram(hProgram);
}
#endif /* SHADER_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment