diff --git a/src/common/Matrix.cpp b/src/common/Matrix.cpp index 003decb82..61b2b44e2 100644 --- a/src/common/Matrix.cpp +++ b/src/common/Matrix.cpp @@ -85,7 +85,7 @@ Matrix4 Matrix4::operator * (const Matrix4 &m) const void Matrix4::operator *= (const Matrix4 &m) { Matrix4 t = (*this) * m; - memcpy((void *)this->e, (void *)t.e, sizeof(float)*16); + memcpy(this->e, t.e, sizeof(float)*16); } const float *Matrix4::getElements() const @@ -191,5 +191,101 @@ Matrix4 Matrix4::ortho(float left, float right, float bottom, float top) return m; } +/** + * | e0 e3 e6 | + * | e1 e4 e7 | + * | e2 e5 e8 | + **/ +Matrix3::Matrix3() +{ + setIdentity(); +} + +Matrix3::Matrix3(const Matrix4 &mat4) +{ + const float *mat4elems = mat4.getElements(); + + // Column 0. + e[0] = mat4elems[0]; + e[1] = mat4elems[1]; + e[2] = mat4elems[2]; + + // Column 1. + e[3] = mat4elems[4]; + e[4] = mat4elems[5]; + e[5] = mat4elems[6]; + + // Column 2. + e[6] = mat4elems[8]; + e[7] = mat4elems[9]; + e[8] = mat4elems[10]; +} + +Matrix3::~Matrix3() +{ +} + +void Matrix3::setIdentity() +{ + memset(e, 0, sizeof(float) * 9); + e[8] = e[4] = e[0] = 1.0f; +} + +Matrix3 Matrix3::operator * (const love::Matrix3 &m) const +{ + Matrix3 t; + + t.e[0] = (e[0]*m.e[0]) + (e[3]*m.e[1]) + (e[6]*m.e[2]); + t.e[3] = (e[0]*m.e[3]) + (e[3]*m.e[4]) + (e[6]*m.e[5]); + t.e[6] = (e[0]*m.e[6]) + (e[3]*m.e[7]) + (e[6]*m.e[8]); + + t.e[1] = (e[1]*m.e[0]) + (e[4]*m.e[1]) + (e[7]*m.e[2]); + t.e[4] = (e[1]*m.e[3]) + (e[4]*m.e[4]) + (e[7]*m.e[5]); + t.e[7] = (e[1]*m.e[6]) + (e[4]*m.e[7]) + (e[7]*m.e[8]); + + t.e[2] = (e[2]*m.e[0]) + (e[5]*m.e[1]) + (e[8]*m.e[2]); + t.e[5] = (e[2]*m.e[3]) + (e[5]*m.e[4]) + (e[8]*m.e[5]); + t.e[8] = (e[2]*m.e[6]) + (e[5]*m.e[7]) + (e[8]*m.e[8]); + + return t; +} + +void Matrix3::operator *= (const Matrix3 &m) +{ + Matrix3 t = (*this) * m; + memcpy(e, t.e, sizeof(float) * 9); +} + +const float *Matrix3::getElements() const +{ + return e; +} + +Matrix3 Matrix3::transposedInverse() const +{ + // e0 e3 e6 + // e1 e4 e7 + // e2 e5 e8 + + float det = e[0] * (e[4]*e[8] - e[7]*e[5]) + - e[1] * (e[3]*e[8] - e[5]*e[6]) + + e[2] * (e[3]*e[7] - e[4]*e[6]); + + float invdet = 1.0f / det; + + Matrix3 m; + + m.e[0] = invdet * (e[4]*e[8] - e[7]*e[5]); + m.e[3] = -invdet * (e[1]*e[8] - e[2]*e[7]); + m.e[6] = invdet * (e[1]*e[5] - e[2]*e[4]); + m.e[1] = -invdet * (e[3]*e[8] - e[5]*e[6]); + m.e[4] = invdet * (e[0]*e[8] - e[2]*e[6]); + m.e[7] = -invdet * (e[0]*e[5] - e[3]*e[2]); + m.e[2] = invdet * (e[3]*e[7] - e[6]*e[4]); + m.e[5] = -invdet * (e[0]*e[7] - e[6]*e[1]); + m.e[8] = invdet * (e[0]*e[4] - e[3]*e[1]); + + return m; +} } // love diff --git a/src/common/Matrix.h b/src/common/Matrix.h index 6b864c085..f6f24fbe3 100644 --- a/src/common/Matrix.h +++ b/src/common/Matrix.h @@ -28,9 +28,9 @@ namespace love { /** - * This class is the basis for all transformations in LOVE. Althought not - * really needed for 2D, it contains 4x4 elements to be compatible with - * OpenGL without conversions. + * This class is the basis for all transformations in LOVE. Although not really + * needed for 2D, it contains 4x4 elements to be compatible with OpenGL without + * conversions. **/ class Matrix4 { @@ -174,6 +174,54 @@ private: }; // Matrix4 +class Matrix3 +{ +public: + + Matrix3(); + + /** + * Constructs a 3x3 matrix from the upper left section of a 4x4 matrix. + **/ + Matrix3(const Matrix4 &mat4); + + ~Matrix3(); + + /** + * Resets this matrix to the identity matrix. + **/ + void setIdentity(); + + Matrix3 operator * (const Matrix3 &m) const; + void operator *= (const Matrix3 &m); + + /** + * Gets a pointer to the 9 array elements. + **/ + const float *getElements() const; + + /** + * Calculates the inverse of the transpose of this matrix. + **/ + Matrix3 transposedInverse() const; + + /** + * Transforms an array of vertices by this matrix. + **/ + template + void transform(V *dst, const V *src, int size) const; + +private: + + /** + * | e0 e3 e6 + * | e1 e4 e7 + * | e2 e5 e8 + **/ + float e[9]; + +}; // Matrix3 + // | x | // | y | // | 0 | @@ -197,6 +245,25 @@ void Matrix4::transform(V *dst, const V *src, int size) const } } +// | x | +// | y | +// | 1 | +// | e0 e3 e6 | +// | e1 e4 e7 | +// | e2 e5 e8 | +template +void Matrix3::transform(V *dst, const V *src, int size) const +{ + for (int i = 0; i < size; i++) + { + float x = (e[0]*src[i].x) + (e[3]*src[i].y) + (e[6]); + float y = (e[1]*src[i].x) + (e[4]*src[i].y) + (e[7]); + + dst[i].x = x; + dst[i].y = y; + } +} + } //love #endif// LOVE_MATRIX_H diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 9997067d0..226eb37cb 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -716,6 +716,16 @@ void Shader::checkSetBuiltinUniforms() if (location >= 0) glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements()); + // Also upload the re-calculated normal matrix, if possible. The + // normal matrix is the transpose of the inverse of the rotation + // portion (top-left 3x3) of the transform matrix. + location = builtinUniforms[BUILTIN_NORMAL_MATRIX]; + if (location >= 0) + { + Matrix3 normalmatrix = Matrix3(curxform).transposedInverse(); + glUniformMatrix3fv(location, 1, GL_FALSE, normalmatrix.getElements()); + } + tpmatrixneedsupdate = true; lastTransformMatrix = curxform; } @@ -885,6 +895,7 @@ StringMap::Entry Shader::built {"TransformMatrix", Shader::BUILTIN_TRANSFORM_MATRIX}, {"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX}, {"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX}, + {"NormalMatrix", Shader::BUILTIN_NORMAL_MATRIX}, {"love_PointSize", Shader::BUILTIN_POINT_SIZE}, {"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE}, }; diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 3a5258c8e..47e7d294b 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -61,6 +61,7 @@ public: BUILTIN_TRANSFORM_MATRIX = 0, BUILTIN_PROJECTION_MATRIX, BUILTIN_TRANSFORM_PROJECTION_MATRIX, + BUILTIN_NORMAL_MATRIX, BUILTIN_POINT_SIZE, BUILTIN_SCREEN_SIZE, BUILTIN_MAX_ENUM diff --git a/src/modules/graphics/opengl/wrap_Graphics.lua b/src/modules/graphics/opengl/wrap_Graphics.lua index fd8072d7e..a78f0f84e 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.lua +++ b/src/modules/graphics/opengl/wrap_Graphics.lua @@ -57,10 +57,12 @@ GLSL.UNIFORMS = [[ uniform LOVE_UNIFORM_PRECISION mat4 TransformMatrix; uniform LOVE_UNIFORM_PRECISION mat4 ProjectionMatrix; uniform LOVE_UNIFORM_PRECISION mat4 TransformProjectionMatrix; +uniform LOVE_UNIFORM_PRECISION mat3 NormalMatrix; #else #define TransformMatrix gl_ModelViewMatrix #define ProjectionMatrix gl_ProjectionMatrix #define TransformProjectionMatrix gl_ModelViewProjectionMatrix +#define NormalMatrix gl_NormalMatrix #endif uniform mediump vec4 love_ScreenSize;]]