diff --git a/include/blt/gfx/shader.h b/include/blt/gfx/shader.h index de77028..07baf03 100644 --- a/include/blt/gfx/shader.h +++ b/include/blt/gfx/shader.h @@ -77,18 +77,22 @@ namespace blt::gfx struct IntDefaultedToMinusOne { GLint i = -1; + + inline explicit operator bool() const + { + return i != -1; + } + + inline operator int() const + { + return i; + } }; + std::unordered_map uniformVars; GLuint programID = 0; - inline GLint getUniformLocation(const std::string& name) - { - if (uniformVars[name].i != -1) - return uniformVars[name].i; - int loc = glGetUniformLocation(programID, name.c_str()); - uniformVars[name].i = loc; - return loc; - } + IntDefaultedToMinusOne getUniformLocation(const std::string& name); public: inline const shader_base_t& bind() const @@ -103,51 +107,25 @@ namespace blt::gfx return *this; } - inline shader_base_t& setBool(const std::string& name, bool value) - { - glUniform1i(getUniformLocation(name), (int) value); - return *this; - } + shader_base_t& setBool(const std::string& name, bool value); - inline void setInt(const std::string& name, int value) - { - glUniform1i(getUniformLocation(name), value); - } + shader_base_t& setInt(const std::string& name, int value); - inline void setFloat(const std::string& name, float value) - { - glUniform1f(getUniformLocation(name), value); - } + shader_base_t& setFloat(const std::string& name, float value); - inline void setMatrix(const std::string& name, blt::mat4x4& matrix) - { - glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, matrix.ptr()); - } + shader_base_t& setMatrix(const std::string& name, blt::mat4x4& matrix); - inline void setVec3(const std::string& name, const blt::vec3& vec) - { - glUniform3f(getUniformLocation(name), vec.x(), vec.y(), vec.z()); - } + shader_base_t& setVec2(const std::string& name, const blt::vec2& vec); - inline void setVec4(const std::string& name, const blt::vec4& vec) - { - glUniform4f(getUniformLocation(name), vec.x(), vec.y(), vec.z(), vec.w()); - } + shader_base_t& setVec3(const std::string& name, const blt::vec3& vec); - inline void setVec2(const std::string& name, float x, float y) - { - glUniform2f(getUniformLocation(name), x, y); - } + shader_base_t& setVec4(const std::string& name, const blt::vec4& vec); - inline void setVec3(const std::string& name, float x, float y, float z) - { - glUniform3f(getUniformLocation(name), x, y, z); - } + shader_base_t& setVec2(const std::string& name, float x, float y); - inline void setVec4(const std::string& name, float x, float y, float z, float w) - { - glUniform4f(getUniformLocation(name), x, y, z, w); - } + shader_base_t& setVec3(const std::string& name, float x, float y, float z); + + shader_base_t& setVec4(const std::string& name, float x, float y, float z, float w); }; /** diff --git a/src/blt/gfx/shader.cpp b/src/blt/gfx/shader.cpp index bfd3126..adb23fc 100644 --- a/src/blt/gfx/shader.cpp +++ b/src/blt/gfx/shader.cpp @@ -22,11 +22,14 @@ namespace blt::gfx { - static std::string removeEmptyFirstLines(const std::string& string){ + static std::string removeEmptyFirstLines(const std::string& string) + { auto lines = blt::string::split(string, "\n"); std::string new_source_string; - for (const auto& line : lines) { - if (!line.empty() && !blt::string::contains(line, "\"")) { + for (const auto& line : lines) + { + if (!line.empty() && !blt::string::contains(line, "\"")) + { new_source_string += line; new_source_string += "\n"; } @@ -34,7 +37,8 @@ namespace blt::gfx return new_source_string; } - unsigned int shader_t::createShader(const std::string& source, int type) { + unsigned int shader_t::createShader(const std::string& source, int type) + { const char* shader_code = source.c_str(); // creates a Shader unsigned int shaderID = glCreateShader(type); @@ -49,7 +53,8 @@ namespace blt::gfx // the TODO: maybe find a way of lexing the output to give suggestions about fixing the error? default error messages can be unhelpful at times. GLint success; glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success); - if (!success) { + if (!success) + { int log_length = 0; glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &log_length); @@ -68,15 +73,18 @@ namespace blt::gfx return shaderID; } - shader_t::shader_t(const std::string& vertex, const std::string& fragment, bool load_as_string) { + shader_t::shader_t(const std::string& vertex, const std::string& fragment, bool load_as_string) + { // load shader sources std::string vertex_source = vertex; std::string fragment_source = fragment; - if (!load_as_string){ + if (!load_as_string) + { // BLT provides a recursive file loader for glsl shaders. It's pretty much just a recursive function looking for include statements. vertex_source = blt::fs::loadShaderFile(vertex); fragment_source = blt::fs::loadShaderFile(fragment); - } else { + } else + { vertex_source = removeEmptyFirstLines(vertex_source); fragment_source = removeEmptyFirstLines(fragment_source); } @@ -95,7 +103,8 @@ namespace blt::gfx GLint success; glGetProgramiv(programID, GL_LINK_STATUS, &success); - if (!success) { + if (!success) + { int log_length = 0; glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &log_length); @@ -118,12 +127,14 @@ namespace blt::gfx glUseProgram(0); } - void shader_t::bindAttribute(int attribute, const std::string &name) const { + void shader_t::bindAttribute(int attribute, const std::string& name) const + { bind(); glBindAttribLocation(programID, attribute, name.c_str()); } - void shader_t::setUniformBlockLocation(const std::string &name, int location) const { + void shader_t::setUniformBlockLocation(const std::string& name, int location) const + { bind(); auto blockID = glGetUniformBlockIndex(programID, name.c_str()); if (blockID != GL_INVALID_INDEX) @@ -132,7 +143,8 @@ namespace blt::gfx BLT_WARN("Unable to find uniform buffer '%s'. Did you forget to declare it?", name.c_str()); } - shader_t::~shader_t() { + shader_t::~shader_t() + { glUseProgram(0); // shader was moved if (programID <= 0) @@ -149,7 +161,8 @@ namespace blt::gfx glDeleteProgram(programID); } - shader_t::shader_t(shader_t&& move) noexcept { + shader_t::shader_t(shader_t&& move) noexcept + { // the move constructor doesn't need to construct a new shader but it does need to ensure all old variables are moved over programID = move.programID; vertexShaderID = move.vertexShaderID; @@ -207,4 +220,104 @@ namespace blt::gfx { glDeleteBuffers(1, &uboID); } + + shader_base_t& shader_base_t::setBool(const std::string& name, bool value) + { + if (auto i = getUniformLocation(name)) + glUniform1i(i.i, (int) value); + else + BLT_WARN("Unable to find boolean uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setInt(const std::string& name, int value) + { + if (auto i = getUniformLocation(name)) + glUniform1i(i.i, value); + else + BLT_WARN("Unable to find integer uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setFloat(const std::string& name, float value) + { + if (auto i = getUniformLocation(name)) + glUniform1f(i.i, value); + else + BLT_WARN("Unable to find float uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setMatrix(const std::string& name, mat4x4& matrix) + { + if (auto i = getUniformLocation(name)) + glUniformMatrix4fv(i.i, 1, GL_FALSE, matrix.ptr()); + else + BLT_WARN("Unable to find matrix uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setVec2(const std::string& name, const vec2& vec) + { + if (auto i = getUniformLocation(name)) + glUniform2f(i.i, vec.x(), vec.y()); + else + BLT_WARN("Unable to find vec3 uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setVec3(const std::string& name, const vec3& vec) + { + if (auto i = getUniformLocation(name)) + glUniform3f(i.i, vec.x(), vec.y(), vec.z()); + else + BLT_WARN("Unable to find vec3 uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setVec4(const std::string& name, const vec4& vec) + { + if (auto i = getUniformLocation(name)) + glUniform4f(i.i, vec.x(), vec.y(), vec.z(), vec.w()); + else + BLT_WARN("Unable to find vec4 uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setVec2(const std::string& name, float x, float y) + { + if (auto i = getUniformLocation(name)) + glUniform2f(i.i, x, y); + else + BLT_WARN("Unable to find vec2 uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setVec3(const std::string& name, float x, float y, float z) + { + if (auto i = getUniformLocation(name)) + glUniform3f(i.i, x, y, z); + else + BLT_WARN("Unable to find vec3 uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t& shader_base_t::setVec4(const std::string& name, float x, float y, float z, float w) + { + if (auto i = getUniformLocation(name)) + glUniform4f(i.i, x, y, z, w); + else + BLT_WARN("Unable to find vec4 uniform variable %s", name.c_str()); + return *this; + } + + shader_base_t::IntDefaultedToMinusOne shader_base_t::getUniformLocation(const std::string& name) + { + if (uniformVars[name]) + return uniformVars[name]; + int loc = glGetUniformLocation(programID, name.c_str()); + auto& v = uniformVars[name]; + v.i = loc; + return v; + } }