From 593f96a08cc2ba5016951168cb8829a32c53fa2a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 11 Sep 2016 14:53:23 -0300 Subject: [PATCH] Add support for non-square matrix uniforms in desktop GLSL. The notation is columns x rows, e.g. a mat4x2 has 4 columns and 2 rows. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed the memory layout of matrices sent to shaders via Shader:send. Note that this is a breaking fix and will probably cause matrices designed to work with older versions of LÖVE to be transposed in shaders compared to what they were previously, if Shader:send or sendMatrix was used to put them in the shader. --HG-- branch : minor --- src/modules/graphics/opengl/Shader.cpp | 84 +++++++++++++++++---- src/modules/graphics/opengl/Shader.h | 15 +++- src/modules/graphics/opengl/wrap_Shader.cpp | 35 +++++---- 3 files changed, 105 insertions(+), 29 deletions(-) diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index f96e3758b..cfa52c9ac 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -200,7 +200,11 @@ void Shader::mapActiveUniforms() u.name = std::string(cname, (size_t) namelen); u.location = glGetUniformLocation(program, u.name.c_str()); u.baseType = getUniformBaseType(gltype); - u.components = getUniformTypeSize(gltype); + + if (u.baseType == UNIFORM_MATRIX) + u.matrix = getMatrixSize(gltype); + else + u.components = getUniformTypeComponents(gltype); // Initialize all samplers to 0. Both GLSL and GLSL ES are supposed to // do this themselves, but some Android devices (galaxy tab 3 and 4) @@ -517,19 +521,27 @@ void Shader::sendMatrices(const UniformInfo *info, const float *m, int count) int location = info->location; - switch (info->components) - { - case 4: - glUniformMatrix4fv(location, count, GL_FALSE, m); - break; - case 3: - glUniformMatrix3fv(location, count, GL_FALSE, m); - break; - case 2: - default: + int columns = info->matrix.columns; + int rows = info->matrix.rows; + + if (columns == 2 && rows == 2) glUniformMatrix2fv(location, count, GL_FALSE, m); - break; - } + else if (columns == 3 && rows == 3) + glUniformMatrix3fv(location, count, GL_FALSE, m); + else if (columns == 4 && rows == 4) + glUniformMatrix4fv(location, count, GL_FALSE, m); + else if (columns == 2 && rows == 3) + glUniformMatrix2x3fv(location, count, GL_FALSE, m); + else if (columns == 2 && rows == 4) + glUniformMatrix2x4fv(location, count, GL_FALSE, m); + else if (columns == 3 && rows == 2) + glUniformMatrix3x2fv(location, count, GL_FALSE, m); + else if (columns == 3 && rows == 4) + glUniformMatrix3x4fv(location, count, GL_FALSE, m); + else if (columns == 4 && rows == 2) + glUniformMatrix4x2fv(location, count, GL_FALSE, m); + else if (columns == 4 && rows == 3) + glUniformMatrix4x3fv(location, count, GL_FALSE, m); } void Shader::sendTexture(const UniformInfo *info, Texture *texture) @@ -819,7 +831,7 @@ bool Shader::isSupported() return GLAD_ES_VERSION_2_0 || (getGLSLVersion() >= "1.2"); } -int Shader::getUniformTypeSize(GLenum type) const +int Shader::getUniformTypeComponents(GLenum type) const { switch (type) { @@ -850,6 +862,50 @@ int Shader::getUniformTypeSize(GLenum type) const } } +Shader::MatrixSize Shader::getMatrixSize(GLenum type) const +{ + MatrixSize m; + + switch (type) + { + case GL_FLOAT_MAT2: + m.columns = m.rows = 2; + break; + case GL_FLOAT_MAT3: + m.columns = m.rows = 3; + break; + case GL_FLOAT_MAT4: + m.columns = m.rows = 4; + break; + case GL_FLOAT_MAT2x3: + m.columns = 2; + m.rows = 3; + break; + case GL_FLOAT_MAT2x4: + m.columns = 2; + m.rows = 4; + break; + case GL_FLOAT_MAT3x2: + m.columns = 3; + m.rows = 2; + break; + case GL_FLOAT_MAT3x4: + m.columns = 3; + m.rows = 4; + break; + case GL_FLOAT_MAT4x2: + m.columns = 4; + m.rows = 2; + break; + case GL_FLOAT_MAT4x3: + m.columns = 4; + m.rows = 3; + break; + } + + return m; +} + Shader::UniformType Shader::getUniformBaseType(GLenum type) const { switch (type) diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 59fbf535f..61915061f 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -88,11 +88,21 @@ public: std::string pixel; }; + struct MatrixSize + { + short columns; + short rows; + }; + struct UniformInfo { int location; int count; - int components; + union + { + int components; + MatrixSize matrix; + }; UniformType baseType; std::string name; }; @@ -195,7 +205,8 @@ private: // Map active uniform names to their locations. void mapActiveUniforms(); - int getUniformTypeSize(GLenum type) const; + int getUniformTypeComponents(GLenum type) const; + MatrixSize getMatrixSize(GLenum type) const; UniformType getUniformBaseType(GLenum type) const; GLuint compileCode(ShaderStage stage, const std::string &code); diff --git a/src/modules/graphics/opengl/wrap_Shader.cpp b/src/modules/graphics/opengl/wrap_Shader.cpp index 8943490a8..fce37b3a4 100644 --- a/src/modules/graphics/opengl/wrap_Shader.cpp +++ b/src/modules/graphics/opengl/wrap_Shader.cpp @@ -151,8 +151,9 @@ int w_Shader_sendBooleans(lua_State *L, int startidx, Shader *shader, const Shad int w_Shader_sendMatrices(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info) { int count = _getCount(L, startidx, info); - int dimension = info->components; - int elements = dimension * dimension; + int columns = info->matrix.columns; + int rows = info->matrix.rows; + int elements = columns * rows; float *values = shader->getScratchBuffer(elements * count); @@ -166,28 +167,36 @@ int w_Shader_sendMatrices(lua_State *L, int startidx, Shader *shader, const Shad if (table_of_tables) { - int n = 0; + int n = i * elements; - for (int j = 1; j <= dimension; j++) + for (int row = 0; row < rows; row++) { - lua_rawgeti(L, startidx + i, j); + lua_rawgeti(L, startidx + i, row + 1); - for (int k = 1; k <= dimension; k++) + for (int column = 0; column < columns; column++) { - lua_rawgeti(L, -k, k); - values[i * elements + n] = (float) luaL_checknumber(L, -1); - n++; + // The table has the matrix elements laid out in row-major + // order, but we need to store them column-major in memory. + lua_rawgeti(L, -(column + 1), column + 1); + values[n + (column * rows + row)] = (float) luaL_checknumber(L, -1); } - lua_pop(L, dimension + 1); + lua_pop(L, columns + 1); } } else { - for (int k = 1; k <= elements; k++) + int n = i * elements; + + for (int column = 0; column < columns; column++) { - lua_rawgeti(L, startidx + i, k); - values[i * elements + (k - 1)] = (float) luaL_checknumber(L, -1); + for (int row = 0; row < rows; row++) + { + // The table has the matrix elements laid out in row-major + // order, but we need to store them column-major in memory. + lua_rawgeti(L, startidx + i, row * columns + column + 1); + values[n + (column * rows + row)] = (float) luaL_checknumber(L, -1); + } } lua_pop(L, elements);