aboutsummaryrefslogtreecommitdiff
path: root/source/Material.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Material.cpp')
-rw-r--r--source/Material.cpp169
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;
+ }
+}