diff --git a/inferno/src/inferno/application.cpp b/inferno/src/inferno/application.cpp index 2b91670..73047b0 100644 --- a/inferno/src/inferno/application.cpp +++ b/inferno/src/inferno/application.cpp @@ -89,8 +89,9 @@ namespace Inferno { // ----------------------------------------- - m_shaderSimple = std::make_shared("assets/glsl/simple.vert", "assets/glsl/simple.frag"); - m_shaderTexture = std::make_shared("assets/glsl/texture.vert", "assets/glsl/texture.frag"); + ShaderManager shaderManager; + m_shaderSimple = shaderManager.load("assets/glsl/simple"); + m_shaderTexture = shaderManager.load("assets/glsl/texture"); m_shaderTexture->setInt("u_texture", m_texture->id()); } diff --git a/inferno/src/inferno/render/shader.cpp b/inferno/src/inferno/render/shader.cpp index a816865..6473058 100644 --- a/inferno/src/inferno/render/shader.cpp +++ b/inferno/src/inferno/render/shader.cpp @@ -11,12 +11,12 @@ namespace Inferno { - Shader::Shader(const std::string& vertexSource, const std::string& fragmentSource) : - m_program(0) + Shader::Shader(const std::string& name) + : m_id(0) { // Get file contents - std::string vertexSrc = File::read(vertexSource); - std::string fragmentSrc = File::read(fragmentSource); + std::string vertexSrc = File::read(name + ".vert"); + std::string fragmentSrc = File::read(name + ".frag"); // Compile shaders uint32_t vertexID = compileShader(GL_VERTEX_SHADER, vertexSrc.c_str()); @@ -24,7 +24,7 @@ namespace Inferno { // Link shaders if (vertexID > 0 && fragmentID > 0) { - m_program = linkShader(vertexID, fragmentID); + m_id = linkShader(vertexID, fragmentID); } // Clear resources else if (vertexID > 0) glDeleteShader(vertexID); @@ -33,75 +33,70 @@ namespace Inferno { Shader::~Shader() { - if (m_program > 0) { - glDeleteProgram(m_program); - m_program = 0; + if (m_id > 0) { + glDeleteProgram(m_id); + m_id = 0; } } -// ----------------------------------------- + int32_t Shader::findUniform(const std::string& name) const + { + int32_t location = glGetUniformLocation(m_id, name.c_str()); + ASSERT(location != -1, "Shader could not find uniform '{}'", name.c_str()); + return location; + } void Shader::setInt(const std::string &name, int value) { // Set unifrom int - GLint location = glGetUniformLocation(m_program, name.c_str()); - glUniform1i(location, value); + glUniform1i(findUniform(name), value); } void Shader::setFloat(const std::string &name, float value) const { // Set uniform float - GLint location = glGetUniformLocation(m_program, name.c_str()); - glUniform1f(location, value); + glUniform1f(findUniform(name), value); } void Shader::setFloat(const std::string &name, float v1, float v2, float v3, float v4) const { // Set uniform vec4 data - GLint location = glGetUniformLocation(m_program, name.c_str()); - glUniform4f(location, v1, v2, v3, v4); + glUniform4f(findUniform(name), v1, v2, v3, v4); } void Shader::setFloat(const std::string &name, glm::vec2 value) const { // Set uniform vec2 data - GLint location = glGetUniformLocation(m_program, name.c_str()); - glUniform2f(location, value.x, value.y); + glUniform2f(findUniform(name), value.x, value.y); } void Shader::setFloat(const std::string &name, glm::vec3 value) const { // Set uniform vec3 data - GLint location = glGetUniformLocation(m_program, name.c_str()); - glUniform3f(location, value.x, value.y, value.z); + glUniform3f(findUniform(name), value.x, value.y, value.z); } void Shader::setFloat(const std::string &name, glm::vec4 value) const { // Set uniform vec4 data - GLint location = glGetUniformLocation(m_program, name.c_str()); - glUniform4f(location, value.x, value.y, value.z, value.w); + glUniform4f(findUniform(name), value.x, value.y, value.z, value.w); } void Shader::setFloat(const std::string &name, glm::mat3 matrix) const { // Set uniform mat3 data - GLint location = glGetUniformLocation(m_program, name.c_str()); - glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(matrix)); + glUniformMatrix3fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix)); } void Shader::setFloat(const std::string &name, glm::mat4 matrix) const { // Set uniform mat4 data - GLint location = glGetUniformLocation(m_program, name.c_str()); - glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix)); + glUniformMatrix4fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix)); } -// ----------------------------------------- - void Shader::bind() const { - glUseProgram(m_program); + glUseProgram(m_id); } void Shader::unbind() const @@ -109,8 +104,6 @@ namespace Inferno { glUseProgram(0); } -// ----------------------------------------- - uint32_t Shader::compileShader(int32_t type, const char* source) const { // Create new shader @@ -190,4 +183,71 @@ namespace Inferno { return success; } +// ----------------------------------------- + + void ShaderManager::add(const std::string& name, const std::shared_ptr& shader) + { + // Construct (key, value) pair and insert it into the unordered_map + m_shaderList.emplace(name, shader); + } + + std::shared_ptr ShaderManager::load(const std::string& name) + { + if (exists(name)) { + return get(name); + } + + std::shared_ptr shader = std::make_shared(name); + add(name, shader); + return get(name); + } + + std::shared_ptr ShaderManager::load(const std::string& vertexSource, + const std::string& fragmentSource) + { + std::string name = computeName(vertexSource, fragmentSource); + return load(name); + } + + std::shared_ptr ShaderManager::get(const std::string& name) + { + return exists(name) ? m_shaderList.at(name) : nullptr; + } + + bool ShaderManager::exists(const std::string& name) + { + return m_shaderList.find(name) != m_shaderList.end(); + } + + void ShaderManager::remove(const std::string& name) + { + if (exists(name)) { + m_shaderList.erase(name); + } + } + + void ShaderManager::remove(const std::shared_ptr& shader) + { + if (exists(shader->name())) { + m_shaderList.erase(shader->name()); + } + } + + std::string ShaderManager::computeName(const std::string& vertexSource, + const std::string& fragmentSource) + { + auto vertexPos = vertexSource.find_last_of('.'); + auto fragmentPos = fragmentSource.find_last_of('.'); + + ASSERT(vertexPos != std::string::npos, "Shader did not have file extension: '{}'", vertexSource); + ASSERT(fragmentPos != std::string::npos, "Shader did not have file extension: '{}'", fragmentSource); + + auto vertexName = vertexSource.substr(0, vertexPos); + auto fragmentName = vertexSource.substr(0, fragmentPos); + + ASSERT(vertexName == fragmentName, "Shader names did not match: {} {}", vertexSource, fragmentSource); + + return vertexName; + } + } diff --git a/inferno/src/inferno/render/shader.h b/inferno/src/inferno/render/shader.h index c5a7962..abdb150 100644 --- a/inferno/src/inferno/render/shader.h +++ b/inferno/src/inferno/render/shader.h @@ -2,39 +2,35 @@ #define SHADER_H #include // std::int32_t, std::uint32_t +#include #include // std::string #include +#include namespace Inferno { class Shader { public: - Shader(const std::string &vertexSource, const std::string &fragmentSource); + Shader(const std::string& name); ~Shader(); -// ----------------------------------------- + int32_t findUniform(const std::string& name) const; - // Set uniform data void setInt(const std::string& name, int value); - void setFloat(const std::string &name, float value) const; - void setFloat(const std::string &name, float v1, float v2, float v3, float v4) const; - void setFloat(const std::string &name, glm::vec2 value) const; - void setFloat(const std::string &name, glm::vec3 value) const; - void setFloat(const std::string &name, glm::vec4 value) const; - void setFloat(const std::string &name, glm::mat3 matrix) const; - void setFloat(const std::string &name, glm::mat4 matrix) const; - -// ----------------------------------------- + void setFloat(const std::string& name, float value) const; + void setFloat(const std::string& name, float v1, float v2, float v3, float v4) const; + void setFloat(const std::string& name, glm::vec2 value) const; + void setFloat(const std::string& name, glm::vec3 value) const; + void setFloat(const std::string& name, glm::vec4 value) const; + void setFloat(const std::string& name, glm::mat3 matrix) const; + void setFloat(const std::string& name, glm::mat4 matrix) const; void bind() const; void unbind() const; -// ----------------------------------------- - - inline uint32_t getProgram() const { return m_program; } - -// ----------------------------------------- + inline std::string name() const { return m_name; } + inline uint32_t program() const { return m_id; } protected: uint32_t compileShader(int32_t type, const char* shaderSource) const; @@ -42,9 +38,32 @@ namespace Inferno { int32_t checkStatus(uint32_t check, bool isProgram = false) const; private: - uint32_t m_program; + std::string m_name; + uint32_t m_id; }; +// ----------------------------------------- + + class ShaderManager { + public: + void add(const std::string& name, const std::shared_ptr& shader); + std::shared_ptr load(const std::string& name); + std::shared_ptr load(const std::string& vertexSource, + const std::string& fragmentSource); + std::shared_ptr get(const std::string& name); + bool exists(const std::string& name); + + void remove(const std::string& name); + void remove(const std::shared_ptr& shader); + + protected: + std::string computeName(const std::string& vertexSource, + const std::string& fragmentSource); + + private: + std::unordered_map> m_shaderList; + }; + }