diff options
Diffstat (limited to 'src/math/matrix.h')
-rw-r--r-- | src/math/matrix.h | 630 |
1 files changed, 315 insertions, 315 deletions
diff --git a/src/math/matrix.h b/src/math/matrix.h index 35871cf..9b29f46 100644 --- a/src/math/matrix.h +++ b/src/math/matrix.h @@ -37,356 +37,356 @@ namespace Math /** \struct Matrix math/matrix.h \brief 4x4 matrix - Represents an universal 4x4 matrix that can be used in OpenGL and DirectX engines. - Contains the required methods for operating on matrices (inverting, multiplying, etc.). + Represents an universal 4x4 matrix that can be used in OpenGL and DirectX engines. + Contains the required methods for operating on matrices (inverting, multiplying, etc.). - The internal representation is a 16-value table in column-major order, thus: + The internal representation is a 16-value table in column-major order, thus: - \verbatim + \verbatim m[0 ] m[4 ] m[8 ] m[12] m[1 ] m[5 ] m[9 ] m[13] m[2 ] m[6 ] m[10] m[14] m[3 ] m[7 ] m[11] m[15] \endverbatim - This representation is native to OpenGL; DirectX requires transposing the matrix. + This representation is native to OpenGL; DirectX requires transposing the matrix. - The order of multiplication of matrix and vector is also OpenGL-native - (see the function MatrixVectorMultiply). + The order of multiplication of matrix and vector is also OpenGL-native + (see the function MatrixVectorMultiply). - All methods are made inline to maximize optimization. + All methods are made inline to maximize optimization. - Unit tests for the structure and related functions are in module: math/test/matrix_test.cpp. + Unit tests for the structure and related functions are in module: math/test/matrix_test.cpp. **/ struct Matrix { - //! Matrix values in column-major order - float m[16]; - - //! Creates the indentity matrix - inline Matrix() - { - LoadIdentity(); - } - - //! Creates the matrix from 1D array - /** \a m matrix values in column-major order */ - inline explicit Matrix(const float (&m)[16]) - { - for (int i = 0; i < 16; ++i) - this->m[i] = m[i]; - } - - //! Creates the matrix from 2D array - /** The array's first index is row, second is column. - \a m array with values */ - inline explicit Matrix(const float (&m)[4][4]) - { - for (int c = 0; c < 4; ++c) + //! Matrix values in column-major order + float m[16]; + + //! Creates the indentity matrix + inline Matrix() { - for (int r = 0; r < 4; ++r) - { - this->m[4*c+r] = m[r][c]; - } + LoadIdentity(); } - } - inline void Set(int row, int col, float value) - { - m[(col-1)*4+(row-1)] = value; - } + //! Creates the matrix from 1D array + /** \a m matrix values in column-major order */ + inline explicit Matrix(const float (&m)[16]) + { + for (int i = 0; i < 16; ++i) + this->m[i] = m[i]; + } - inline float Get(int row, int col) - { - return m[(col-1)*4+(row-1)]; - } + //! Creates the matrix from 2D array + /** The array's first index is row, second is column. + \a m array with values */ + inline explicit Matrix(const float (&m)[4][4]) + { + for (int c = 0; c < 4; ++c) + { + for (int r = 0; r < 4; ++r) + { + this->m[4*c+r] = m[r][c]; + } + } + } - //! Loads the zero matrix - inline void LoadZero() - { - for (int i = 0; i < 16; ++i) - m[i] = 0.0f; - } - - //! Loads the identity matrix - inline void LoadIdentity() - { - LoadZero(); - /* (1,1) */ m[0 ] = 1.0f; - /* (2,2) */ m[5 ] = 1.0f; - /* (3,3) */ m[10] = 1.0f; - /* (4,4) */ m[15] = 1.0f; - } - - //! Transposes the matrix - inline void Transpose() - { - /* (2,1) <-> (1,2) */ Swap(m[1 ], m[4 ]); - /* (3,1) <-> (1,3) */ Swap(m[2 ], m[8 ]); - /* (4,1) <-> (1,4) */ Swap(m[3 ], m[12]); - /* (3,2) <-> (2,3) */ Swap(m[6 ], m[9 ]); - /* (4,2) <-> (2,4) */ Swap(m[7 ], m[13]); - /* (4,3) <-> (3,4) */ Swap(m[11], m[14]); - } - - //! Calculates the determinant of the matrix - /** \returns the determinant */ - inline float Det() const - { - float result = 0.0f; - for (int i = 0; i < 4; ++i) + inline void Set(int row, int col, float value) { - result += m[i] * Cofactor(i, 0); + m[(col-1)*4+(row-1)] = value; } - return result; - } - //! Calculates the cofactor of the matrix - /** \a r row (0 to 3) - \a c column (0 to 3) - \returns the cofactor */ - inline float Cofactor(int r, int c) const - { - assert(r >= 0 && r <= 3); - assert(c >= 0 && c <= 3); + inline float Get(int row, int col) + { + return m[(col-1)*4+(row-1)]; + } - float result = 0.0f; + //! Loads the zero matrix + inline void LoadZero() + { + for (int i = 0; i < 16; ++i) + m[i] = 0.0f; + } - /* That looks horrible, I know. But it's fast :) */ + //! Loads the identity matrix + inline void LoadIdentity() + { + LoadZero(); + /* (1,1) */ m[0 ] = 1.0f; + /* (2,2) */ m[5 ] = 1.0f; + /* (3,3) */ m[10] = 1.0f; + /* (4,4) */ m[15] = 1.0f; + } - switch (4*r + c) + //! Transposes the matrix + inline void Transpose() { - // r=0, c=0 - /* 05 09 13 - 06 10 14 - 07 11 15 */ - case 0: - result = + m[5 ] * (m[10] * m[15] - m[14] * m[11]) - - m[9 ] * (m[6 ] * m[15] - m[14] * m[7 ]) - + m[13] * (m[6 ] * m[11] - m[10] * m[7 ]); - break; - - // r=0, c=1 - /* 01 09 13 - 02 10 14 - 03 11 15 */ - case 1: - result = - m[1 ] * (m[10] * m[15] - m[14] * m[11]) - + m[9 ] * (m[2 ] * m[15] - m[14] * m[3 ]) - - m[13] * (m[2 ] * m[11] - m[10] * m[3 ]); - break; - - // r=0, c=2 - /* 01 05 13 - 02 06 14 - 03 07 15 */ - case 2: - result = + m[1 ] * (m[6 ] * m[15] - m[14] * m[7 ]) - - m[5 ] * (m[2 ] * m[15] - m[14] * m[3 ]) - + m[13] * (m[2 ] * m[7 ] - m[6 ] * m[3 ]); - break; - - // r=0, c=3 - /* 01 05 09 - 02 06 10 - 03 07 11 */ - case 3: - result = - m[1 ] * (m[6 ] * m[11] - m[10] * m[7 ]) - + m[5 ] * (m[2 ] * m[11] - m[10] * m[3 ]) - - m[9 ] * (m[2 ] * m[7 ] - m[6 ] * m[3 ]); - break; - - // r=1, c=0 - /* 04 08 12 - 06 10 14 - 07 11 15 */ - case 4: - result = - m[4 ] * (m[10] * m[15] - m[14] * m[11]) - + m[8 ] * (m[6 ] * m[15] - m[14] * m[7 ]) - - m[12] * (m[6 ] * m[11] - m[10] * m[7 ]); - break; - - // r=1, c=1 - /* 00 08 12 - 02 10 14 - 03 11 15 */ - case 5: - result = + m[0 ] * (m[10] * m[15] - m[14] * m[11]) - - m[8 ] * (m[2 ] * m[15] - m[14] * m[3 ]) - + m[12] * (m[2 ] * m[11] - m[10] * m[3 ]); - break; - - // r=1, c=2 - /* 00 04 12 - 02 06 14 - 03 07 15 */ - case 6: - result = - m[0 ] * (m[6 ] * m[15] - m[14] * m[7 ]) - + m[4 ] * (m[2 ] * m[15] - m[14] * m[3 ]) - - m[12] * (m[2 ] * m[7 ] - m[6 ] * m[3 ]); - break; - - // r=1, c=3 - /* 00 04 08 - 02 06 10 - 03 07 11 */ - case 7: - result = + m[0 ] * (m[6 ] * m[11] - m[10] * m[7 ]) - - m[4 ] * (m[2 ] * m[11] - m[10] * m[3 ]) - + m[8 ] * (m[2 ] * m[7 ] - m[6 ] * m[3 ]); - break; - - // r=2, c=0 - /* 04 08 12 - 05 09 13 - 07 11 15 */ - case 8: - result = + m[4 ] * (m[9 ] * m[15] - m[13] * m[11]) - - m[8 ] * (m[5 ] * m[15] - m[13] * m[7 ]) - + m[12] * (m[5 ] * m[11] - m[9 ] * m[7 ]); - break; - - // r=2, c=1 - /* 00 08 12 - 01 09 13 - 03 11 15 */ - case 9: - result = - m[0 ] * (m[9 ] * m[15] - m[13] * m[11]) - + m[8 ] * (m[1 ] * m[15] - m[13] * m[3 ]) - - m[12] * (m[1 ] * m[11] - m[9 ] * m[3 ]); - break; - - // r=2, c=2 - /* 00 04 12 - 01 05 13 - 03 07 15 */ - case 10: - result = + m[0 ] * (m[5 ] * m[15] - m[13] * m[7 ]) - - m[4 ] * (m[1 ] * m[15] - m[13] * m[3 ]) - + m[12] * (m[1 ] * m[7 ] - m[5 ] * m[3 ]); - break; - - // r=2, c=3 - /* 00 04 08 - 01 05 09 - 03 07 11 */ - case 11: - result = - m[0 ] * (m[5 ] * m[11] - m[9 ] * m[7 ]) - + m[4 ] * (m[1 ] * m[11] - m[9 ] * m[3 ]) - - m[8 ] * (m[1 ] * m[7 ] - m[5 ] * m[3 ]); - break; - - // r=3, c=0 - /* 04 08 12 - 05 09 13 - 06 10 14 */ - case 12: - result = - m[4 ] * (m[9 ] * m[14] - m[13] * m[10]) - + m[8 ] * (m[5 ] * m[14] - m[13] * m[6 ]) - - m[12] * (m[5 ] * m[10] - m[9 ] * m[6 ]); - break; - - // r=3, c=1 - /* 00 08 12 - 01 09 13 - 02 10 14 */ - case 13: - result = + m[0 ] * (m[9 ] * m[14] - m[13] * m[10]) - - m[8 ] * (m[1 ] * m[14] - m[13] * m[2 ]) - + m[12] * (m[1 ] * m[10] - m[9 ] * m[2 ]); - break; - - // r=3, c=2 - /* 00 04 12 - 01 05 13 - 02 06 14 */ - case 14: - result = - m[0 ] * (m[5 ] * m[14] - m[13] * m[6 ]) - + m[4 ] * (m[1 ] * m[14] - m[13] * m[2 ]) - - m[12] * (m[1 ] * m[6 ] - m[5 ] * m[2 ]); - break; - - // r=3, c=3 - /* 00 04 08 - 01 05 09 - 02 06 10 */ - case 15: - result = + m[0 ] * (m[5 ] * m[10] - m[9 ] * m[6 ]) - - m[4 ] * (m[1 ] * m[10] - m[9 ] * m[2 ]) - + m[8 ] * (m[1 ] * m[6 ] - m[5 ] * m[2 ]); - break; - - default: - break; + /* (2,1) <-> (1,2) */ Swap(m[1 ], m[4 ]); + /* (3,1) <-> (1,3) */ Swap(m[2 ], m[8 ]); + /* (4,1) <-> (1,4) */ Swap(m[3 ], m[12]); + /* (3,2) <-> (2,3) */ Swap(m[6 ], m[9 ]); + /* (4,2) <-> (2,4) */ Swap(m[7 ], m[13]); + /* (4,3) <-> (3,4) */ Swap(m[11], m[14]); } - return result; - } + //! Calculates the determinant of the matrix + /** \returns the determinant */ + inline float Det() const + { + float result = 0.0f; + for (int i = 0; i < 4; ++i) + { + result += m[i] * Cofactor(i, 0); + } + return result; + } - //! Calculates the inverse matrix - /** The determinant of the matrix must not be zero. - \returns the inverted matrix */ - inline Matrix Inverse() const - { - float d = Det(); - assert(! IsZero(d)); + //! Calculates the cofactor of the matrix + /** \a r row (0 to 3) + \a c column (0 to 3) + \returns the cofactor */ + inline float Cofactor(int r, int c) const + { + assert(r >= 0 && r <= 3); + assert(c >= 0 && c <= 3); - float result[16] = { 0.0f }; + float result = 0.0f; - for (int r = 0; r < 4; ++r) - { - for (int c = 0; c < 4; ++c) - { - // Already transposed! - result[4*r+c] = (1.0f / d) * Cofactor(r, c); - } - } + /* That looks horrible, I know. But it's fast :) */ - return Matrix(result); - } + switch (4*r + c) + { + // r=0, c=0 + /* 05 09 13 + 06 10 14 + 07 11 15 */ + case 0: + result = + m[5 ] * (m[10] * m[15] - m[14] * m[11]) + - m[9 ] * (m[6 ] * m[15] - m[14] * m[7 ]) + + m[13] * (m[6 ] * m[11] - m[10] * m[7 ]); + break; + + // r=0, c=1 + /* 01 09 13 + 02 10 14 + 03 11 15 */ + case 1: + result = - m[1 ] * (m[10] * m[15] - m[14] * m[11]) + + m[9 ] * (m[2 ] * m[15] - m[14] * m[3 ]) + - m[13] * (m[2 ] * m[11] - m[10] * m[3 ]); + break; + + // r=0, c=2 + /* 01 05 13 + 02 06 14 + 03 07 15 */ + case 2: + result = + m[1 ] * (m[6 ] * m[15] - m[14] * m[7 ]) + - m[5 ] * (m[2 ] * m[15] - m[14] * m[3 ]) + + m[13] * (m[2 ] * m[7 ] - m[6 ] * m[3 ]); + break; + + // r=0, c=3 + /* 01 05 09 + 02 06 10 + 03 07 11 */ + case 3: + result = - m[1 ] * (m[6 ] * m[11] - m[10] * m[7 ]) + + m[5 ] * (m[2 ] * m[11] - m[10] * m[3 ]) + - m[9 ] * (m[2 ] * m[7 ] - m[6 ] * m[3 ]); + break; + + // r=1, c=0 + /* 04 08 12 + 06 10 14 + 07 11 15 */ + case 4: + result = - m[4 ] * (m[10] * m[15] - m[14] * m[11]) + + m[8 ] * (m[6 ] * m[15] - m[14] * m[7 ]) + - m[12] * (m[6 ] * m[11] - m[10] * m[7 ]); + break; + + // r=1, c=1 + /* 00 08 12 + 02 10 14 + 03 11 15 */ + case 5: + result = + m[0 ] * (m[10] * m[15] - m[14] * m[11]) + - m[8 ] * (m[2 ] * m[15] - m[14] * m[3 ]) + + m[12] * (m[2 ] * m[11] - m[10] * m[3 ]); + break; + + // r=1, c=2 + /* 00 04 12 + 02 06 14 + 03 07 15 */ + case 6: + result = - m[0 ] * (m[6 ] * m[15] - m[14] * m[7 ]) + + m[4 ] * (m[2 ] * m[15] - m[14] * m[3 ]) + - m[12] * (m[2 ] * m[7 ] - m[6 ] * m[3 ]); + break; + + // r=1, c=3 + /* 00 04 08 + 02 06 10 + 03 07 11 */ + case 7: + result = + m[0 ] * (m[6 ] * m[11] - m[10] * m[7 ]) + - m[4 ] * (m[2 ] * m[11] - m[10] * m[3 ]) + + m[8 ] * (m[2 ] * m[7 ] - m[6 ] * m[3 ]); + break; + + // r=2, c=0 + /* 04 08 12 + 05 09 13 + 07 11 15 */ + case 8: + result = + m[4 ] * (m[9 ] * m[15] - m[13] * m[11]) + - m[8 ] * (m[5 ] * m[15] - m[13] * m[7 ]) + + m[12] * (m[5 ] * m[11] - m[9 ] * m[7 ]); + break; + + // r=2, c=1 + /* 00 08 12 + 01 09 13 + 03 11 15 */ + case 9: + result = - m[0 ] * (m[9 ] * m[15] - m[13] * m[11]) + + m[8 ] * (m[1 ] * m[15] - m[13] * m[3 ]) + - m[12] * (m[1 ] * m[11] - m[9 ] * m[3 ]); + break; + + // r=2, c=2 + /* 00 04 12 + 01 05 13 + 03 07 15 */ + case 10: + result = + m[0 ] * (m[5 ] * m[15] - m[13] * m[7 ]) + - m[4 ] * (m[1 ] * m[15] - m[13] * m[3 ]) + + m[12] * (m[1 ] * m[7 ] - m[5 ] * m[3 ]); + break; + + // r=2, c=3 + /* 00 04 08 + 01 05 09 + 03 07 11 */ + case 11: + result = - m[0 ] * (m[5 ] * m[11] - m[9 ] * m[7 ]) + + m[4 ] * (m[1 ] * m[11] - m[9 ] * m[3 ]) + - m[8 ] * (m[1 ] * m[7 ] - m[5 ] * m[3 ]); + break; + + // r=3, c=0 + /* 04 08 12 + 05 09 13 + 06 10 14 */ + case 12: + result = - m[4 ] * (m[9 ] * m[14] - m[13] * m[10]) + + m[8 ] * (m[5 ] * m[14] - m[13] * m[6 ]) + - m[12] * (m[5 ] * m[10] - m[9 ] * m[6 ]); + break; + + // r=3, c=1 + /* 00 08 12 + 01 09 13 + 02 10 14 */ + case 13: + result = + m[0 ] * (m[9 ] * m[14] - m[13] * m[10]) + - m[8 ] * (m[1 ] * m[14] - m[13] * m[2 ]) + + m[12] * (m[1 ] * m[10] - m[9 ] * m[2 ]); + break; + + // r=3, c=2 + /* 00 04 12 + 01 05 13 + 02 06 14 */ + case 14: + result = - m[0 ] * (m[5 ] * m[14] - m[13] * m[6 ]) + + m[4 ] * (m[1 ] * m[14] - m[13] * m[2 ]) + - m[12] * (m[1 ] * m[6 ] - m[5 ] * m[2 ]); + break; + + // r=3, c=3 + /* 00 04 08 + 01 05 09 + 02 06 10 */ + case 15: + result = + m[0 ] * (m[5 ] * m[10] - m[9 ] * m[6 ]) + - m[4 ] * (m[1 ] * m[10] - m[9 ] * m[2 ]) + + m[8 ] * (m[1 ] * m[6 ] - m[5 ] * m[2 ]); + break; + + default: + break; + } - //! Calculates the multiplication of this matrix * given matrix - /** \a right right-hand matrix - \returns multiplication result */ - inline Matrix Multiply(const Matrix &right) const - { - float result[16] = { 0.0f }; + return result; + } - for (int c = 0; c < 4; ++c) + //! Calculates the inverse matrix + /** The determinant of the matrix must not be zero. + \returns the inverted matrix */ + inline Matrix Inverse() const { - for (int r = 0; r < 4; ++r) - { - result[4*c+r] = 0.0f; - for (int i = 0; i < 4; ++i) + float d = Det(); + assert(! IsZero(d)); + + float result[16] = { 0.0f }; + + for (int r = 0; r < 4; ++r) { - result[4*c+r] += m[4*i+r] * right.m[4*c+i]; + for (int c = 0; c < 4; ++c) + { + // Already transposed! + result[4*r+c] = (1.0f / d) * Cofactor(r, c); + } } - } + + return Matrix(result); } - return Matrix(result); - } + //! Calculates the multiplication of this matrix * given matrix + /** \a right right-hand matrix + \returns multiplication result */ + inline Matrix Multiply(const Matrix &right) const + { + float result[16] = { 0.0f }; + + for (int c = 0; c < 4; ++c) + { + for (int r = 0; r < 4; ++r) + { + result[4*c+r] = 0.0f; + for (int i = 0; i < 4; ++i) + { + result[4*c+r] += m[4*i+r] * right.m[4*c+i]; + } + } + } + + return Matrix(result); + } }; // struct Matrix //! Checks if two matrices are equal within given \a tolerance inline bool MatricesEqual(const Matrix &m1, const Matrix &m2, - float tolerance = TOLERANCE) + float tolerance = TOLERANCE) { - for (int i = 0; i < 16; ++i) - { - if (! IsEqual(m1.m[i], m2.m[i], tolerance)) - return false; - } + for (int i = 0; i < 16; ++i) + { + if (! IsEqual(m1.m[i], m2.m[i], tolerance)) + return false; + } - return true; + return true; } //! Convenience function for getting transposed matrix inline Matrix Transpose(const Matrix &m) { - Matrix result = m; - result.Transpose(); - return result; + Matrix result = m; + result.Transpose(); + return result; } //! Convenience function for multiplying a matrix @@ -395,7 +395,7 @@ inline Matrix Transpose(const Matrix &m) \returns multiplied matrices */ inline Matrix MultiplyMatrices(const Matrix &left, const Matrix &right) { - return left.Multiply(right); + return left.Multiply(right); } //! Calculates the result of multiplying m * v @@ -405,27 +405,27 @@ inline Matrix MultiplyMatrices(const Matrix &left, const Matrix &right) [ m.m[2 ] m.m[6 ] m.m[10] m.m[14] ] * [ v.z ] [ m.m[3 ] m.m[7 ] m.m[11] m.m[15] ] [ 1 ] \endverbatim - The result, a 4x1 vector is then converted to 3x1 by dividing - x,y,z coords by the fourth coord (w). */ + The result, a 4x1 vector is then converted to 3x1 by dividing + x,y,z coords by the fourth coord (w). */ inline Vector MatrixVectorMultiply(const Matrix &m, const Vector &v, bool wDivide = false) { - float x = v.x * m.m[0 ] + v.y * m.m[4 ] + v.z * m.m[8 ] + m.m[12]; - float y = v.x * m.m[1 ] + v.y * m.m[5 ] + v.z * m.m[9 ] + m.m[13]; - float z = v.x * m.m[2 ] + v.y * m.m[6 ] + v.z * m.m[10] + m.m[14]; + float x = v.x * m.m[0 ] + v.y * m.m[4 ] + v.z * m.m[8 ] + m.m[12]; + float y = v.x * m.m[1 ] + v.y * m.m[5 ] + v.z * m.m[9 ] + m.m[13]; + float z = v.x * m.m[2 ] + v.y * m.m[6 ] + v.z * m.m[10] + m.m[14]; - if (!wDivide) - return Vector(x, y, z); + if (!wDivide) + return Vector(x, y, z); - float w = v.x * m.m[3 ] + v.y * m.m[7 ] + v.z * m.m[11] + m.m[15]; + float w = v.x * m.m[3 ] + v.y * m.m[7 ] + v.z * m.m[11] + m.m[15]; - if (IsZero(w)) - return Vector(x, y, z); + if (IsZero(w)) + return Vector(x, y, z); - x /= w; - y /= w; - z /= w; + x /= w; + y /= w; + z /= w; - return Vector(x, y, z); + return Vector(x, y, z); } /* @} */ // end of group |