diff options
Diffstat (limited to 'src/render/Shader.cpp')
| -rw-r--r-- | src/render/Shader.cpp | 180 |
1 files changed, 170 insertions, 10 deletions
diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp index 7201d1c0..60a27092 100644 --- a/src/render/Shader.cpp +++ b/src/render/Shader.cpp @@ -1,44 +1,204 @@ #include "Shader.hpp" #include "render/OpenGL.hpp" +#define EPSILON(x, y) (std::abs((x) - (y)) < 1e-5f) + +static bool compareFloat(auto a, auto b) { + if (a.size() != b.size()) + return false; + + for (size_t i = 0; i < a.size(); ++i) + if (std::fabs(a[i] - b[i]) > 1e-5f) + return false; + + return true; +} + +SShader::SShader() { + uniformLocations.fill(-1); +} + SShader::~SShader() { destroy(); } void SShader::createVao() { + GLuint shaderVao = 0, shaderVbo = 0, shaderVboUv = 0; + glGenVertexArrays(1, &shaderVao); glBindVertexArray(shaderVao); - if (posAttrib != -1) { - glGenBuffers(1, &shaderVboPos); - glBindBuffer(GL_ARRAY_BUFFER, shaderVboPos); + if (uniformLocations[SHADER_POS_ATTRIB] != -1) { + glGenBuffers(1, &shaderVbo); + glBindBuffer(GL_ARRAY_BUFFER, shaderVbo); glBufferData(GL_ARRAY_BUFFER, sizeof(fullVerts), fullVerts, GL_STATIC_DRAW); - glEnableVertexAttribArray(posAttrib); - glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); + glEnableVertexAttribArray(uniformLocations[SHADER_POS_ATTRIB]); + glVertexAttribPointer(uniformLocations[SHADER_POS_ATTRIB], 2, GL_FLOAT, GL_FALSE, 0, nullptr); } // UV VBO (dynamic, may be updated per frame) - if (texAttrib != -1) { + if (uniformLocations[SHADER_TEX_ATTRIB] != -1) { glGenBuffers(1, &shaderVboUv); glBindBuffer(GL_ARRAY_BUFFER, shaderVboUv); glBufferData(GL_ARRAY_BUFFER, sizeof(fullVerts), fullVerts, GL_DYNAMIC_DRAW); // Initial dummy UVs - glEnableVertexAttribArray(texAttrib); - glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); + glEnableVertexAttribArray(uniformLocations[SHADER_TEX_ATTRIB]); + glVertexAttribPointer(uniformLocations[SHADER_TEX_ATTRIB], 2, GL_FLOAT, GL_FALSE, 0, nullptr); } glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); + + uniformLocations[SHADER_SHADER_VAO] = shaderVao; + uniformLocations[SHADER_SHADER_VBO_POS] = shaderVbo; + uniformLocations[SHADER_SHADER_VBO_UV] = shaderVboUv; + + RASSERT(uniformLocations[SHADER_SHADER_VAO] >= 0, "SHADER_SHADER_VAO could not be created"); + RASSERT(uniformLocations[SHADER_SHADER_VBO_POS] >= 0, "SHADER_SHADER_VBO_POS could not be created"); + RASSERT(uniformLocations[SHADER_SHADER_VBO_UV] >= 0, "SHADER_SHADER_VBO_UV could not be created"); +} + +void SShader::setUniformInt(eShaderUniform location, GLint v0) { + if (uniformLocations.at(location) == -1) + return; + + auto& cached = uniformStatus.at(location); + + if (cached.index() != 0 && std::get<GLint>(cached) == v0) + return; + + cached = v0; + glUniform1i(uniformLocations[location], v0); +} + +void SShader::setUniformFloat(eShaderUniform location, GLfloat v0) { + if (uniformLocations.at(location) == -1) + return; + + auto& cached = uniformStatus.at(location); + + if (cached.index() != 0) { + auto val = std::get<GLfloat>(cached); + if (EPSILON(val, v0)) + return; + } + + cached = v0; + glUniform1f(uniformLocations[location], v0); +} + +void SShader::setUniformFloat2(eShaderUniform location, GLfloat v0, GLfloat v1) { + if (uniformLocations.at(location) == -1) + return; + + auto& cached = uniformStatus.at(location); + + if (cached.index() != 0) { + auto val = std::get<std::array<GLfloat, 2>>(cached); + if (EPSILON(val[0], v0) && EPSILON(val[1], v1)) + return; + } + + cached = std::array<GLfloat, 2>{v0, v1}; + glUniform2f(uniformLocations[location], v0, v1); +} + +void SShader::setUniformFloat3(eShaderUniform location, GLfloat v0, GLfloat v1, GLfloat v2) { + if (uniformLocations.at(location) == -1) + return; + + auto& cached = uniformStatus.at(location); + + if (cached.index() != 0) { + auto val = std::get<std::array<GLfloat, 3>>(cached); + if (EPSILON(val[0], v0) && EPSILON(val[1], v1) && EPSILON(val[2], v2)) + return; + } + + cached = std::array<GLfloat, 3>{v0, v1, v2}; + glUniform3f(uniformLocations[location], v0, v1, v2); +} + +void SShader::setUniformFloat4(eShaderUniform location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { + if (uniformLocations.at(location) == -1) + return; + + auto& cached = uniformStatus.at(location); + + if (cached.index() != 0) { + auto val = std::get<std::array<GLfloat, 4>>(cached); + if (EPSILON(val[0], v0) && EPSILON(val[1], v1) && EPSILON(val[2], v2) && EPSILON(val[3], v3)) + return; + } + + cached = std::array<GLfloat, 4>{v0, v1, v2, v3}; + glUniform4f(uniformLocations[location], v0, v1, v2, v3); +} + +void SShader::setUniformMatrix3fv(eShaderUniform location, GLsizei count, GLboolean transpose, std::array<GLfloat, 9> value) { + if (uniformLocations.at(location) == -1) + return; + + auto& cached = uniformStatus.at(location); + + if (cached.index() != 0) { + auto val = std::get<SUniformMatrix3Data>(cached); + if (val.count == count && val.transpose == transpose && compareFloat(val.value, value)) + return; + } + + cached = SUniformMatrix3Data{.count = count, .transpose = transpose, .value = value}; + glUniformMatrix3fv(uniformLocations[location], count, transpose, value.data()); +} + +void SShader::setUniformMatrix4x2fv(eShaderUniform location, GLsizei count, GLboolean transpose, std::array<GLfloat, 8> value) { + if (uniformLocations.at(location) == -1) + return; + + auto& cached = uniformStatus.at(location); + + if (cached.index() != 0) { + auto val = std::get<SUniformMatrix4Data>(cached); + if (val.count == count && val.transpose == transpose && compareFloat(val.value, value)) + return; + } + + cached = SUniformMatrix4Data{.count = count, .transpose = transpose, .value = value}; + glUniformMatrix4x2fv(uniformLocations[location], count, transpose, value.data()); +} + +void SShader::setUniform4fv(eShaderUniform location, GLsizei count, std::vector<float> value) { + if (uniformLocations.at(location) == -1) + return; + + auto& cached = uniformStatus.at(location); + + if (cached.index() != 0) { + auto val = std::get<SUniform4Data>(cached); + if (val.count == count && compareFloat(val.value, value)) + return; + } + + cached = SUniform4Data{.count = count, .value = value}; + glUniform4fv(uniformLocations[location], count, value.data()); } void SShader::destroy() { + uniformStatus.fill(std::monostate()); + if (program == 0) return; + GLuint shaderVao, shaderVbo, shaderVboUv; + + shaderVao = uniformLocations[SHADER_SHADER_VAO] == -1 ? 0 : uniformLocations[SHADER_SHADER_VAO]; + shaderVbo = uniformLocations[SHADER_SHADER_VBO_POS] == -1 ? 0 : uniformLocations[SHADER_SHADER_VBO_POS]; + shaderVboUv = uniformLocations[SHADER_SHADER_VBO_UV] == -1 ? 0 : uniformLocations[SHADER_SHADER_VBO_UV]; + if (shaderVao) glDeleteVertexArrays(1, &shaderVao); - if (shaderVboPos) - glDeleteBuffers(1, &shaderVboPos); + if (shaderVbo) + glDeleteBuffers(1, &shaderVbo); if (shaderVboUv) glDeleteBuffers(1, &shaderVboUv); |
