Created
December 9, 2018 21:58
-
-
Save htmlboss/1279c87e4e79c1b2fcee3ddb0e23a4e5 to your computer and use it in GitHub Desktop.
OpenGL shader wrapper in C++17. It also scans and caches active shader uniforms in getUniforms() for fast lookups when rendering.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "GPUProgram.hpp" | |
#include "Shader.hpp" | |
#include <glm/gtc/type_ptr.hpp> | |
#include <iostream> | |
#include <array> | |
/***********************************************************************************/ | |
GPUProgram::GPUProgram(const std::string_view programName, const std::initializer_list<Shader>& shaders) : m_programName{ programName }, | |
m_ID{ glCreateProgram() } { | |
for (const auto& shader : shaders) { | |
glAttachShader(m_ID, shader.m_ID); | |
} | |
if (linkAndValidate()) { | |
getUniforms(); | |
} | |
// Cleanup | |
for (auto shader : shaders) { | |
glDetachShader(m_ID, shader.m_ID); | |
shader.Delete(); | |
} | |
} | |
/***********************************************************************************/ | |
GPUProgram::~GPUProgram() { | |
Delete(); | |
} | |
/***********************************************************************************/ | |
void GPUProgram::Delete() { | |
if (m_ID != 0) { | |
glDeleteProgram(m_ID); | |
m_ID = 0; | |
} | |
} | |
/***********************************************************************************/ | |
GPUProgram& GPUProgram::SetUniform(const std::string& uniformName, const int value) { | |
glProgramUniform1i(m_ID, m_uniforms.at(uniformName), value); | |
return *this; | |
} | |
/***********************************************************************************/ | |
GPUProgram& GPUProgram::SetUniform(const std::string& uniformName, const float value) { | |
glProgramUniform1f(m_ID, m_uniforms.at(uniformName), value); | |
return *this; | |
} | |
/***********************************************************************************/ | |
GPUProgram& GPUProgram::SetUniform(const std::string& uniformName, const glm::ivec2& value) { | |
glProgramUniform2iv(m_ID, m_uniforms.at(uniformName), 1, glm::value_ptr(value)); | |
return *this; | |
} | |
/***********************************************************************************/ | |
GPUProgram& GPUProgram::SetUniform(const std::string& uniformName, const glm::vec2& value) { | |
glProgramUniform2fv(m_ID, m_uniforms.at(uniformName), 1, glm::value_ptr(value)); | |
return *this; | |
} | |
/***********************************************************************************/ | |
GPUProgram& GPUProgram::SetUniform(const std::string& uniformName, const glm::vec3& value) { | |
glProgramUniform3fv(m_ID, m_uniforms.at(uniformName), 1, glm::value_ptr(value)); | |
return *this; | |
} | |
/***********************************************************************************/ | |
GPUProgram& GPUProgram::SetUniform(const std::string& uniformName, const glm::vec4& value) { | |
glProgramUniform4fv(m_ID, m_uniforms.at(uniformName), 1, glm::value_ptr(value)); | |
return *this; | |
} | |
/***********************************************************************************/ | |
GPUProgram& GPUProgram::SetUniform(const std::string& uniformName, const glm::mat3x3& value) { | |
glProgramUniformMatrix3fv(m_ID, m_uniforms.at(uniformName), 1, GL_FALSE, glm::value_ptr(value)); | |
return *this; | |
} | |
/***********************************************************************************/ | |
GPUProgram& GPUProgram::SetUniform(const std::string& uniformName, const glm::mat4x4& value) { | |
glProgramUniformMatrix4fv(m_ID, m_uniforms.at(uniformName), 1, GL_FALSE, glm::value_ptr(value)); | |
return *this; | |
} | |
/***********************************************************************************/ | |
bool GPUProgram::linkAndValidate() const { | |
int success{ -1 }; | |
std::array<char, 1024> infoLog; | |
glLinkProgram(m_ID); | |
glGetProgramiv(m_ID, GL_LINK_STATUS, &success); | |
if (!success) { | |
glGetProgramInfoLog(m_ID, infoLog.size(), nullptr, infoLog.data()); | |
std::cerr << m_programName << " linking error: " << infoLog.data() << std::endl; | |
return false; | |
} | |
glValidateProgram(m_ID); | |
glGetProgramiv(m_ID, GL_VALIDATE_STATUS, &success); | |
if (!success) { | |
glGetProgramInfoLog(m_ID, infoLog.size(), nullptr, infoLog.data()); | |
std::cerr << m_programName << " validation error: " << infoLog.data() << std::endl; | |
return false; | |
} | |
return true; | |
} | |
/***********************************************************************************/ | |
void GPUProgram::getUniforms() { | |
int total{ -1 }; | |
glGetProgramiv(m_ID, GL_ACTIVE_UNIFORMS, &total); | |
for (auto i = 0; i < total; ++i) { | |
int name_len{ -1 }, num{ -1 }; | |
GLenum type{ GL_ZERO }; | |
char name[100]; | |
glGetActiveUniform(m_ID, static_cast<GLuint>(i), sizeof(name) - 1, &name_len, &num, &type, name); | |
name[name_len] = 0; | |
const std::string nameStr{ name }; | |
m_uniforms.try_emplace(nameStr, glGetUniformLocation(m_ID, name)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <glad/glad.h> | |
#include <glm/mat4x4.hpp> | |
#include <string> | |
#include <unordered_map> | |
/***********************************************************************************/ | |
// Forward declarations | |
class Shader; | |
/***********************************************************************************/ | |
class GPUProgram { | |
public: | |
GPUProgram(const std::string_view programName, const std::initializer_list<Shader>& shaders); | |
~GPUProgram(); | |
GPUProgram(const GPUProgram&) = delete; | |
GPUProgram(GPUProgram&&) = default; | |
GPUProgram& operator=(const GPUProgram&) = delete; | |
GPUProgram& operator=(GPUProgram&&) = default; | |
void Delete(); | |
auto GetName() const { return m_programName; } | |
GPUProgram& SetUniform(const std::string& uniformName, const int value); | |
GPUProgram& SetUniform(const std::string& uniformName, const float value); | |
GPUProgram& SetUniform(const std::string& uniformName, const glm::ivec2& value); | |
GPUProgram& SetUniform(const std::string& uniformName, const glm::vec2& value); | |
GPUProgram& SetUniform(const std::string& uniformName, const glm::vec3& value); | |
GPUProgram& SetUniform(const std::string& uniformName, const glm::vec4& value); | |
GPUProgram& SetUniform(const std::string& uniformName, const glm::mat3x3& value); | |
GPUProgram& SetUniform(const std::string& uniformName, const glm::mat4x4& value); | |
private: | |
// | |
[[nodiscard]] bool linkAndValidate() const; | |
// | |
void getUniforms(); | |
std::string m_programName; | |
GLuint m_ID{ 0 }; | |
std::unordered_map<std::string, GLint> m_uniforms; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Shader.hpp" | |
#include <iostream> | |
#include <array> | |
/***********************************************************************************/ | |
Shader::Shader(const std::string_view shaderCode, const Type type) { | |
m_ID = glCreateShader(type); | |
compile(shaderCode.data()); | |
} | |
/***********************************************************************************/ | |
Shader::~Shader() { | |
Delete(); | |
} | |
/***********************************************************************************/ | |
void Shader::Delete() { | |
if (m_ID != 0) { | |
glDeleteShader(m_ID); | |
m_ID = 0; | |
} | |
} | |
/***********************************************************************************/ | |
void Shader::compile(const GLchar* shaderCode) const { | |
GLint success; | |
std::array<GLchar, 1024> infoLog; | |
glShaderSource(m_ID, 1, &shaderCode, nullptr); | |
glCompileShader(m_ID); | |
glGetShaderiv(m_ID, GL_COMPILE_STATUS, &success); | |
if (!success) { | |
glGetShaderInfoLog(m_ID, infoLog.size(), nullptr, infoLog.data()); | |
std::cerr << "Shader Error: " << infoLog.data() << std::endl; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <glad/glad.h> | |
#include <string_view> | |
/***********************************************************************************/ | |
// Forward declarations | |
class GPUProgram; | |
/***********************************************************************************/ | |
class Shader { | |
friend class GPUProgram; | |
public: | |
enum Type : decltype(GL_VERTEX_SHADER) { | |
VERTEX = GL_VERTEX_SHADER, | |
GEOMETRY = GL_GEOMETRY_SHADER, | |
FRAGMENT = GL_FRAGMENT_SHADER, | |
COMPUTE = GL_COMPUTE_SHADER, | |
TESS_CONTROL = GL_TESS_CONTROL_SHADER, | |
TESS_EVAL = GL_TESS_EVALUATION_SHADER | |
}; | |
Shader(const std::string_view shaderCode, const Type type); | |
~Shader(); | |
Shader(const Shader&) = default; | |
Shader(Shader&&) = default; | |
Shader& operator=(const Shader&) = default; | |
Shader& operator=(Shader&&) = default; | |
void Delete(); | |
private: | |
// Compiles a shader file and checks for errors | |
void compile(const GLchar* shaderCode) const; | |
GLuint m_ID{ 0 }; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment