Skip to content

Instantly share code, notes, and snippets.

@htmlboss
Created December 9, 2018 21:58
Show Gist options
  • Save htmlboss/1279c87e4e79c1b2fcee3ddb0e23a4e5 to your computer and use it in GitHub Desktop.
Save htmlboss/1279c87e4e79c1b2fcee3ddb0e23a4e5 to your computer and use it in GitHub Desktop.

Revisions

  1. htmlboss created this gist Dec 9, 2018.
    138 changes: 138 additions & 0 deletions GPUProgram.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,138 @@
    #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));
    }
    }
    49 changes: 49 additions & 0 deletions GPUProgram.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,49 @@
    #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;
    };
    39 changes: 39 additions & 0 deletions Shader.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,39 @@
    #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;
    }
    }
    39 changes: 39 additions & 0 deletions Shader.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,39 @@
    #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 };
    };