#32 - Shader Class C++
Date: 2018-10-27 12:00 - C++
Simple OpenGL Shader Wrapper class.
// Shader.h
#pragma once
#include "../OpenGL.h"
#include <list>
#include <map>
#include <string>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
namespace YourNamespace {
namespace Rendering {
class Shader {
public:
static void unuse();
private:
GLuint _program;
std::list<GLuint> _shaders;
std::map<std::string, GLuint> _attributes;
std::map<std::string, GLuint> _uniforms;
public:
Shader();
bool compiled() const { return _program != 0; }
void loadFromText(GLenum type, const std::string& source);
void loadFromFile(GLenum type, const std::string& filename);
virtual void createLinkProgram();
bool setAttribLocation(const std::string& attribute, GLuint location);
GLuint getAttibLocation(const std::string& attribute);
GLuint getUniformLocation(const std::string& uniform);
void uniform(unsigned int location, const glm::mat4& matrix) {
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
}
void uniform(unsigned int location, const glm::vec2& value) {
glUniform2f(location, value.x, value.y);
}
void uniform(unsigned int location, const glm::vec3& value) {
glUniform3f(location, value.x, value.y, value.z);
}
void uniform(unsigned int location, const glm::vec4& value) {
glUniform4f(location, value.x, value.y, value.z, value.w);
}
void uniform(unsigned int location, int value) {
glUniform1i(location, value);
}
void uniform(unsigned int location, float value) {
glUniform1f(location, value);
}
void uniform(unsigned int location, float v1, float v2) {
glUniform2f(location, v1, v2);
}
void uniform(unsigned int location, float v1, float v2, float v3) {
glUniform3f(location, v1, v2, v3);
}
void uniform(unsigned int location, float v1, float v2, float v3, float v4) {
glUniform4f(location, v1, v2, v3, v4);
}
void uniform(const std::string& uniform, const glm::mat4& matrix) {
glUniformMatrix4fv(getUniformLocation(uniform), 1, GL_FALSE, glm::value_ptr(matrix));
}
void uniform(const std::string& uniform, const glm::vec2& value) {
glUniform2f(getUniformLocation(uniform), value.x, value.y);
}
void uniform(const std::string& uniform, const glm::vec3& value) {
glUniform3f(getUniformLocation(uniform), value.x, value.y, value.z);
}
void uniform(const std::string& uniform, const glm::vec4& value) {
glUniform4f(getUniformLocation(uniform), value.x, value.y, value.z, value.w);
}
void uniform(const std::string& uniform, int value) {
glUniform1i(getUniformLocation(uniform), value);
}
void uniform(const std::string& uniform, float value) {
glUniform1f(getUniformLocation(uniform), value);
}
void uniform(const std::string& uniform, float v1, float v2) {
glUniform2f(getUniformLocation(uniform), v1, v2);
}
void uniform(const std::string& uniform, float v1, float v2, float v3) {
glUniform3f(getUniformLocation(uniform), v1, v2, v3);
}
void uniform(const std::string& uniform, float v1, float v2, float v3, float v4) {
glUniform4f(getUniformLocation(uniform), v1, v2, v3, v4);
}
void use() {
glUseProgram(_program);
}
virtual ~Shader();
};
}
}
// Shader.cpp
#include "Shader.h"
#include <iostream>
#include <fstream>
#include "../Logging/Logger.h"
#define CHECK_IF_COMPILED if(_program != 0) throw "Shader already created.";
using namespace YourNamespace::Rendering;
void Shader::unuse() {
glUseProgram(0);
}
Shader::Shader() : _program(0), _shaders() {
}
void Shader::loadFromText(GLenum type, const std::string& source) {
CHECK_IF_COMPILED
GLuint shader = glCreateShader(type);
const char * ptmp = source.c_str();
glShaderSource(shader, 1, &ptmp, NULL);
GLint status;
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog = new GLchar[infoLogLength];
glGetShaderInfoLog(shader, infoLogLength, NULL, infoLog);
std::string error = "Compile log: " + std::string(infoLog);
delete[] infoLog;
throw error;
}
_shaders.push_front(shader);
}
void Shader::loadFromFile(GLenum type, const std::string& filename) {
CHECK_IF_COMPILED
std::ifstream fp;
fp.open(filename.c_str(), std::ios_base::in);
if (fp) {
std::string line, buffer;
while (getline(fp, line)) {
buffer.append(line);
buffer.append("\r\n");
}
fp.close();
loadFromText(type, buffer);
}
else
throw ("Missing shader file: " + std::string(filename));
}
void Shader::createLinkProgram() {
CHECK_IF_COMPILED
_program = glCreateProgram();
for (std::list<GLuint>::iterator shader = _shaders.begin(); shader != _shaders.end(); ++shader) {
glAttachShader(_program, *shader);
}
std::map<std::string, GLuint>::iterator it = _attributes.begin();
for (;it != _attributes.end(); it++) {
const char * ptmp = it->first.c_str();
glBindAttribLocation(_program, it->second, ptmp);
}
GLint status;
glLinkProgram(_program);
glGetProgramiv(_program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog = new GLchar[infoLogLength];
glGetProgramInfoLog(_program, infoLogLength, NULL, infoLog);
std::string error = "Link log: " + std::string(infoLog);
delete[] infoLog;
throw error;
}
for (std::list<GLuint>::iterator shader = _shaders.begin(); shader != _shaders.end(); ++shader)
glDeleteShader(*shader);
_shaders.clear();
}
bool Shader::setAttribLocation(const std::string& attribute, GLuint location) {
CHECK_IF_COMPILED
_attributes[attribute] = location;
return true;
}
GLuint Shader::getAttibLocation(const std::string& attribute) {
GLuint location = -1;
try {
location = _attributes.at(attribute);
}
catch (const std::out_of_range& oor) {
static_cast<void>(oor);
location = glGetAttribLocation(_program, attribute.c_str());
_attributes[attribute] = location;
if (location == -1) {
throw ("Attribute not found: " + std::string(attribute));
}
}
return location;
}
GLuint Shader::getUniformLocation(const std::string& uniform) {
std::map<std::string, GLuint>::iterator it = _uniforms.find(uniform);
if (it != _uniforms.end())
return (*it).second;
GLuint location = glGetUniformLocation(_program, uniform.c_str());
_uniforms[uniform] = location;
if (location == -1) {
throw ("Uniform not found: " + std::string(uniform));
}
return location;
}
Shader::~Shader() {
glUseProgram(NULL);
glDeleteProgram(_program);
}