diff options
Diffstat (limited to 'source/Material.cpp')
-rw-r--r-- | source/Material.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/source/Material.cpp b/source/Material.cpp new file mode 100644 index 0000000..138434c --- /dev/null +++ b/source/Material.cpp @@ -0,0 +1,169 @@ +#include "Material.hpp" + +#include <cstdlib> +#include <cstring> + +Material::Material(Shader* shader) + : mShader(shader) { +} + +namespace ProjectBrussel_UNITY_ID { +template <class TUniform> +TUniform& ObtainUniform(std::vector<TUniform>& uniforms, GLint location) { + for (auto& uniform : uniforms) { + if (uniform.location == location) { + return uniform; + } + } + + auto& uniform = uniforms.emplace_back(); + uniform.location = location; + return uniform; +} +} // namespace ProjectBrussel_UNITY_ID + +void Material::SetFloat(const char* name, float value) { + GLint location = glGetUniformLocation(mShader->GetProgram(), name); + auto& uniform = ProjectBrussel_UNITY_ID::ObtainUniform(mBoundScalars, location); + uniform.floatValue = value; + uniform.actualType = GL_FLOAT; +} + +void Material::SetInt(const char* name, int32_t value) { + GLint location = glGetUniformLocation(mShader->GetProgram(), name); + auto& uniform = ProjectBrussel_UNITY_ID::ObtainUniform(mBoundScalars, location); + uniform.intValue = value; + uniform.actualType = GL_INT; +} + +void Material::SetUInt(const char* name, uint32_t value) { + GLint location = glGetUniformLocation(mShader->GetProgram(), name); + auto& uniform = ProjectBrussel_UNITY_ID::ObtainUniform(mBoundScalars, location); + uniform.uintValue = value; + uniform.actualType = GL_UNSIGNED_INT; +} + +template <int length> +void Material::SetVector(const char* name, const glm::vec<length, float>& vec) { + static_assert(length >= 1 && length <= 4); + + GLint location = glGetUniformLocation(mShader->GetProgram(), name); + auto& uniform = ProjectBrussel_UNITY_ID::ObtainUniform(mBoundVectors, location); + uniform.actualLength = length; + std::memset(uniform.value, 0, sizeof(uniform.value)); + std::memcpy(uniform.value, &vec[0], length * sizeof(float)); +} + +template void Material::SetVector<1>(const char*, const glm::vec<1, float>&); +template void Material::SetVector<2>(const char*, const glm::vec<2, float>&); +template void Material::SetVector<3>(const char*, const glm::vec<3, float>&); +template void Material::SetVector<4>(const char*, const glm::vec<4, float>&); + +template <int width, int height> +void Material::SetMatrix(const char* name, const glm::mat<width, height, float>& mat) { + static_assert(width >= 1 && width <= 4); + static_assert(height >= 1 && height <= 4); + + GLint location = glGetUniformLocation(mShader->GetProgram(), name); + auto& uniform = ProjectBrussel_UNITY_ID::ObtainUniform(mBoundMatrices, location); + uniform.actualWidth = width; + uniform.actualHeight = height; + std::memset(uniform.value, 0, sizeof(uniform.value)); + std::memcpy(uniform.value, &mat[0][0], width * height * sizeof(float)); +} + +template void Material::SetMatrix<2, 2>(const char*, const glm::mat<2, 2, float>&); +template void Material::SetMatrix<3, 3>(const char*, const glm::mat<3, 3, float>&); +template void Material::SetMatrix<4, 4>(const char*, const glm::mat<4, 4, float>&); + +template void Material::SetMatrix<2, 3>(const char*, const glm::mat<2, 3, float>&); +template void Material::SetMatrix<3, 2>(const char*, const glm::mat<3, 2, float>&); + +template void Material::SetMatrix<2, 4>(const char*, const glm::mat<2, 4, float>&); +template void Material::SetMatrix<4, 2>(const char*, const glm::mat<4, 2, float>&); + +template void Material::SetMatrix<3, 4>(const char*, const glm::mat<3, 4, float>&); +template void Material::SetMatrix<4, 3>(const char*, const glm::mat<4, 3, float>&); + +void Material::SetTexture(const char* name, Texture* texture) { + GLint location = glGetUniformLocation(mShader->GetProgram(), name); + + for (auto& uniform : mBoundTextures) { + if (uniform.location == location) { + uniform.value.Attach(texture); + return; + } + } + + auto& uniform = mBoundTextures.emplace_back(); + uniform.value.Attach(texture); + uniform.location = location; +} + +std::span<const Material::VectorUniform> Material::GetVectors() const { + return mBoundVectors; +} + +std::span<const Material::MatrixUniform> Material::GetMatrices() const { + return mBoundMatrices; +} + +std::span<const Material::TextureUniform> Material::GetTextures() const { + return mBoundTextures; +} + +const Shader& Material::GetShader() const { + return *mShader; +} + +static constexpr int IdentifyMatrixSize(int width, int height) { + return width * 10 + height; +} + +void Material::UseUniforms() const { + for (auto& uniform : mBoundScalars) { + switch (uniform.actualType) { + case GL_FLOAT: glUniform1f(uniform.location, uniform.intValue); break; + case GL_INT: glUniform1i(uniform.location, uniform.intValue); break; + case GL_UNSIGNED_INT: glUniform1ui(uniform.location, uniform.intValue); break; + default: break; + } + } + + for (auto& uniform : mBoundVectors) { + switch (uniform.actualLength) { + case 1: glUniform1fv(uniform.location, 1, &uniform.value[0]); break; + case 2: glUniform2fv(uniform.location, 1, &uniform.value[0]); break; + case 3: glUniform3fv(uniform.location, 1, &uniform.value[0]); break; + case 4: glUniform4fv(uniform.location, 1, &uniform.value[0]); break; + default: break; + } + } + + for (auto& uniform : mBoundMatrices) { + switch (IdentifyMatrixSize(uniform.actualWidth, uniform.actualHeight)) { + case IdentifyMatrixSize(2, 2): glUniformMatrix2fv(uniform.location, 1, GL_FALSE, uniform.value); break; + case IdentifyMatrixSize(3, 3): glUniformMatrix3fv(uniform.location, 1, GL_FALSE, uniform.value); break; + case IdentifyMatrixSize(4, 4): glUniformMatrix4fv(uniform.location, 1, GL_FALSE, uniform.value); break; + + case IdentifyMatrixSize(2, 3): glUniformMatrix2x3fv(uniform.location, 1, GL_FALSE, uniform.value); break; + case IdentifyMatrixSize(3, 2): glUniformMatrix3x2fv(uniform.location, 1, GL_FALSE, uniform.value); break; + + case IdentifyMatrixSize(2, 4): glUniformMatrix2x4fv(uniform.location, 1, GL_FALSE, uniform.value); break; + case IdentifyMatrixSize(4, 2): glUniformMatrix4x2fv(uniform.location, 1, GL_FALSE, uniform.value); break; + + case IdentifyMatrixSize(3, 4): glUniformMatrix3x4fv(uniform.location, 1, GL_FALSE, uniform.value); break; + case IdentifyMatrixSize(4, 3): glUniformMatrix4x3fv(uniform.location, 1, GL_FALSE, uniform.value); break; + + default: break; + } + } + + int i = 0; + for (auto& uniform : mBoundTextures) { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, uniform.value->GetHandle()); + glUniform1i(uniform.location, i); + ++i; + } +} |