#include "Material.hpp" #include #include Material::Material(Shader* shader) : mShader(shader) { } namespace ProjectBrussel_UNITY_ID { template TUniform& ObtainUniform(std::vector& 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 void Material::SetVector(const char* name, const glm::vec& 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 void Material::SetMatrix(const char* name, const glm::mat& 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 Material::GetVectors() const { return mBoundVectors; } std::span Material::GetMatrices() const { return mBoundMatrices; } std::span 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; } }