فهرست منبع

Re-added the built-in NormalMatrix uniform 3x3 matrix variable to shaders.

Alex Szpakowski 10 سال پیش
والد
کامیت
1e8786879b

+ 97 - 1
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

+ 70 - 3
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 <typename V>
+	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 <typename V>
+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

+ 11 - 0
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<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::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},
 };

+ 1 - 0
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

+ 2 - 0
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;]]