diff --git a/src/lol/math/vector.h b/src/lol/math/vector.h index 6811dd71..ed66146d 100644 --- a/src/lol/math/vector.h +++ b/src/lol/math/vector.h @@ -1354,9 +1354,6 @@ template struct Mat2 inline Vec2& operator[](size_t n) { return (&v0)[n]; } inline Vec2 const& operator[](size_t n) const { return (&v0)[n]; } - T det() const; - Mat2 invert() const; - /* Helpers for transformation matrices */ static Mat2 rotate(T angle); @@ -1436,9 +1433,6 @@ template struct Mat3 inline Vec3& operator[](size_t n) { return (&v0)[n]; } inline Vec3 const& operator[](size_t n) const { return (&v0)[n]; } - T det() const; - Mat3 invert() const; - /* Helpers for transformation matrices */ static Mat3 rotate(T angle, T x, T y, T z); static Mat3 rotate(T angle, Vec3 v); @@ -1521,9 +1515,6 @@ template struct Mat4 inline Vec4& operator[](size_t n) { return (&v0)[n]; } inline Vec4 const& operator[](size_t n) const { return (&v0)[n]; } - T det() const; - Mat4 invert() const; - /* Helpers for transformation matrices */ static Mat4 translate(T x, T y, T z); static Mat4 translate(Vec3 v); @@ -1531,16 +1522,18 @@ template struct Mat4 static Mat4 rotate(T angle, Vec3 v); static Mat4 rotate(Quat q); - static inline Mat4 translate(Mat4 mat, Vec3 v) + static inline Mat4 translate(Mat4 const &mat, Vec3 v) { return translate(v) * mat; } - static inline Mat4 rotate(Mat4 mat, T angle, Vec3 v) + static inline Mat4 rotate(Mat4 &mat, T angle, Vec3 v) { return rotate(angle, v) * mat; } + static Mat3 normal(Mat4 const &mat); + /* Helpers for view matrices */ static Mat4 lookat(Vec3 eye, Vec3 center, Vec3 up); @@ -1556,37 +1549,37 @@ template struct Mat4 friend std::ostream &operator<<(std::ostream &stream, Mat4 const &m); #endif - inline Mat4 operator +(Mat4 const m) const + inline Mat4 operator +(Mat4 const &m) const { return Mat4(v0 + m[0], v1 + m[1], v2 + m[2], v3 + m[3]); } - inline Mat4 operator +=(Mat4 const m) + inline Mat4 operator +=(Mat4 const &m) { return *this = *this + m; } - inline Mat4 operator -(Mat4 const m) const + inline Mat4 operator -(Mat4 const &m) const { return Mat4(v0 - m[0], v1 - m[1], v2 - m[2], v3 - m[3]); } - inline Mat4 operator -=(Mat4 const m) + inline Mat4 operator -=(Mat4 const &m) { return *this = *this - m; } - inline Mat4 operator *(Mat4 const m) const + inline Mat4 operator *(Mat4 const &m) const { return Mat4(*this * m[0], *this * m[1], *this * m[2], *this * m[3]); } - inline Mat4 operator *=(Mat4 const m) + inline Mat4 operator *=(Mat4 const &m) { return *this = *this * m; } - inline Vec4 operator *(Vec4 const m) const + inline Vec4 operator *(Vec4 const &m) const { Vec4 ret; for (int j = 0; j < 4; j++) @@ -1602,6 +1595,18 @@ template struct Mat4 Vec4 v0, v1, v2, v3; }; +template T determinant(Mat2 const &); +template T determinant(Mat3 const &); +template T determinant(Mat4 const &); + +template Mat2 transpose(Mat2 const &); +template Mat3 transpose(Mat3 const &); +template Mat4 transpose(Mat4 const &); + +template Mat2 inverse(Mat2 const &); +template Mat3 inverse(Mat3 const &); +template Mat4 inverse(Mat4 const &); + /* * Arbitrarily-sized square matrices; for now this only supports * naive inversion and is used for the Remez inversion method. diff --git a/src/math/vector.cpp b/src/math/vector.cpp index 9dcf0af1..2bd82214 100644 --- a/src/math/vector.cpp +++ b/src/math/vector.cpp @@ -36,6 +36,12 @@ using namespace std; namespace lol { +static inline float det2(float a, float b, + float c, float d) +{ + return a * d - b * c; +} + static inline float det3(float a, float b, float c, float d, float e, float f, float g, float h, float i) @@ -45,7 +51,20 @@ static inline float det3(float a, float b, float c, + c * (d * h - g * e); } -static inline float cofact3(mat4 const &mat, int i, int j) +static inline float cofact(mat2 const &mat, int i, int j) +{ + return mat[(i + 1) & 1][(j + 1) & 1] * (((i + j) & 1) ? -1.0f : 1.0f); +} + +static inline float cofact(mat3 const &mat, int i, int j) +{ + return det2(mat[(i + 1) % 3][(j + 1) % 3], + mat[(i + 2) % 3][(j + 1) % 3], + mat[(i + 1) % 3][(j + 2) % 3], + mat[(i + 2) % 3][(j + 2) % 3]); +} + +static inline float cofact(mat4 const &mat, int i, int j) { return det3(mat[(i + 1) & 3][(j + 1) & 3], mat[(i + 2) & 3][(j + 1) & 3], @@ -58,24 +77,91 @@ static inline float cofact3(mat4 const &mat, int i, int j) mat[(i + 3) & 3][(j + 3) & 3]) * (((i + j) & 1) ? -1.0f : 1.0f); } -template<> float mat4::det() const +template<> float determinant(mat2 const &mat) +{ + return mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]; +} + +template<> mat2 transpose(mat2 const &mat) +{ + mat2 ret; + for (int j = 0; j < 2; j++) + for (int i = 0; i < 2; i++) + ret[j][i] = mat[i][j]; + return ret; +} + +template<> mat2 inverse(mat2 const &mat) +{ + mat2 ret; + float d = determinant(mat); + if (d) + { + d = 1.0f / d; + for (int j = 0; j < 2; j++) + for (int i = 0; i < 2; i++) + ret[j][i] = cofact(mat, i, j) * d; + } + return ret; +} + +template<> float determinant(mat3 const &mat) +{ + return det3(mat[0][0], mat[0][1], mat[0][2], + mat[1][0], mat[1][1], mat[1][2], + mat[2][0], mat[2][1], mat[2][2]); +} + +template<> mat3 transpose(mat3 const &mat) +{ + mat3 ret; + for (int j = 0; j < 3; j++) + for (int i = 0; i < 3; i++) + ret[j][i] = mat[i][j]; + return ret; +} + +template<> mat3 inverse(mat3 const &mat) +{ + mat3 ret; + float d = determinant(mat); + if (d) + { + d = 1.0f / d; + for (int j = 0; j < 3; j++) + for (int i = 0; i < 3; i++) + ret[j][i] = cofact(mat, i, j) * d; + } + return ret; +} + +template<> float determinant(mat4 const &mat) { float ret = 0; for (int n = 0; n < 4; n++) - ret += (*this)[n][0] * cofact3(*this, n, 0); + ret += mat[n][0] * cofact(mat, n, 0); return ret; } -template<> mat4 mat4::invert() const +template<> mat4 transpose(mat4 const &mat) { mat4 ret; - float d = det(); + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) + ret[j][i] = mat[i][j]; + return ret; +} + +template<> mat4 inverse(mat4 const &mat) +{ + mat4 ret; + float d = determinant(mat); if (d) { d = 1.0f / d; for (int j = 0; j < 4; j++) for (int i = 0; i < 4; i++) - ret[j][i] = cofact3(*this, i, j) * d; + ret[j][i] = cofact(mat, i, j) * d; } return ret; } @@ -120,6 +206,23 @@ template<> void quat::printf() const Log::Debug("[ %6.6f %6.6f %6.6f %6.6f ]\n", x, y, z, w); } +template<> void mat2::printf() const +{ + mat2 const &p = *this; + + Log::Debug("[ %6.6f %6.6f\n", p[0][0], p[1][0]); + Log::Debug(" %6.6f %6.6f ]\n", p[0][1], p[1][1]); +} + +template<> void mat3::printf() const +{ + mat3 const &p = *this; + + Log::Debug("[ %6.6f %6.6f %6.6f\n", p[0][0], p[1][0], p[2][0]); + Log::Debug(" %6.6f %6.6f %6.6f\n", p[0][1], p[1][1], p[2][1]); + Log::Debug(" %6.6f %6.6f %6.6f ]\n", p[0][2], p[1][2], p[2][2]); +} + template<> void mat4::printf() const { mat4 const &p = *this; diff --git a/test/Makefile.am b/test/Makefile.am index 9805bf53..61201c40 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -22,8 +22,8 @@ noinst_PROGRAMS = quad benchsuite testsuite TESTS = testsuite testsuite_SOURCES = testsuite.cpp \ - unit/vector.cpp unit/half.cpp unit/trig.cpp unit/build.cpp \ - unit/real.cpp unit/image.cpp unit/quat.cpp unit/cmplx.cpp + unit/vector.cpp unit/matrix.cpp unit/half.cpp unit/trig.cpp \ + unit/build.cpp unit/real.cpp unit/image.cpp unit/quat.cpp unit/cmplx.cpp testsuite_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ testsuite_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@ @PIPI_LIBS@ testsuite_DEPENDENCIES = $(top_builddir)/src/liblol.a diff --git a/test/benchmark/vector.cpp b/test/benchmark/vector.cpp index 21a03045..7659f01b 100644 --- a/test/benchmark/vector.cpp +++ b/test/benchmark/vector.cpp @@ -52,7 +52,7 @@ void bench_matrix(int mode) /* Determinant */ timer.GetMs(); for (size_t i = 0; i < MATRIX_TABLE_SIZE; i++) - pf[i] = pm[i].det(); + pf[i] = determinant(pm[i]); result[1] += timer.GetMs(); /* Multiply matrices */ @@ -70,7 +70,7 @@ void bench_matrix(int mode) /* Invert matrix */ timer.GetMs(); for (size_t i = 0; i < MATRIX_TABLE_SIZE; i++) - pm[i] = pm[i].invert(); + pm[i] = inverse(pm[i]); result[4] += timer.GetMs(); } diff --git a/test/unit/matrix.cpp b/test/unit/matrix.cpp new file mode 100644 index 00000000..d5c4bbb5 --- /dev/null +++ b/test/unit/matrix.cpp @@ -0,0 +1,167 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2012 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/projects/COPYING.WTFPL for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" +#include "lol/unit.h" + +namespace lol +{ + +LOLUNIT_FIXTURE(MatrixTest) +{ + void SetUp() + { + id2 = mat2(1.0f); + tri2 = mat2(vec2(1.0f, 0.0f), + vec2(7.0f, 2.0f)); + inv2 = mat2(vec2(4.0f, 3.0f), + vec2(3.0f, 2.0f)); + + id3 = mat3(1.0f); + tri3 = mat3(vec3(1.0f, 0.0f, 0.0f), + vec3(7.0f, 2.0f, 0.0f), + vec3(1.0f, 5.0f, 3.0f)); + inv3 = mat3(vec3(2.0f, 3.0f, 5.0f), + vec3(3.0f, 2.0f, 3.0f), + vec3(9.0f, 5.0f, 7.0f)); + + id4 = mat4(1.0f); + tri4 = mat4(vec4(1.0f, 0.0f, 0.0f, 0.0f), + vec4(7.0f, 2.0f, 0.0f, 0.0f), + vec4(1.0f, 5.0f, 3.0f, 0.0f), + vec4(8.0f, 9.0f, 2.0f, 4.0f)); + inv4 = mat4(vec4( 1.0f, 1.0f, 2.0f, -1.0f), + vec4(-2.0f, -1.0f, -2.0f, 2.0f), + vec4( 4.0f, 2.0f, 5.0f, -4.0f), + vec4( 5.0f, -3.0f, -7.0f, -6.0f)); + } + + void TearDown() {} + + LOLUNIT_TEST(Determinant) + { + float d1, d2; + + d1 = determinant(tri2); + LOLUNIT_ASSERT_EQUAL(d1, 2.0f); + d2 = determinant(inv2); + LOLUNIT_ASSERT_EQUAL(d2, -1.0f); + + d1 = determinant(tri3); + LOLUNIT_ASSERT_EQUAL(d1, 6.0f); + d2 = determinant(inv3); + LOLUNIT_ASSERT_EQUAL(d2, 1.0f); + + d1 = determinant(tri4); + LOLUNIT_ASSERT_EQUAL(d1, 24.0f); + d2 = determinant(inv4); + LOLUNIT_ASSERT_EQUAL(d2, -1.0f); + } + + LOLUNIT_TEST(Multiplication) + { + mat4 m0 = id4; + mat4 m1 = id4; + mat4 m2 = m0 * m1; + + LOLUNIT_ASSERT_EQUAL(m2[0][0], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][0], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][0], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[3][0], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][1], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][1], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][1], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[3][1], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][2], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][2], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][2], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[3][2], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][3], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][3], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][3], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[3][3], 1.0f); + } + + LOLUNIT_TEST(Inverse2x2) + { + mat2 m0 = inv2; + mat2 m1 = inverse(m0); + + mat2 m2 = m0 * m1; + + LOLUNIT_ASSERT_EQUAL(m2[0][0], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][0], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][1], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][1], 1.0f); + } + + LOLUNIT_TEST(Inverse3x3) + { + mat3 m0 = inv3; + mat3 m1 = inverse(m0); + + mat3 m2 = m0 * m1; + + LOLUNIT_ASSERT_EQUAL(m2[0][0], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][0], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][0], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][1], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][1], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][1], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][2], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][2], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][2], 1.0f); + } + + LOLUNIT_TEST(Inverse4x4) + { + mat4 m0 = inv4; + mat4 m1 = inverse(m0); + + mat4 m2 = m0 * m1; + + LOLUNIT_ASSERT_EQUAL(m2[0][0], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][0], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][0], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[3][0], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][1], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][1], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][1], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[3][1], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][2], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][2], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][2], 1.0f); + LOLUNIT_ASSERT_EQUAL(m2[3][2], 0.0f); + + LOLUNIT_ASSERT_EQUAL(m2[0][3], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[1][3], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[2][3], 0.0f); + LOLUNIT_ASSERT_EQUAL(m2[3][3], 1.0f); + } + + mat2 tri2, id2, inv2; + mat3 tri3, id3, inv3; + mat4 tri4, id4, inv4; +}; + +} /* namespace lol */ + diff --git a/test/unit/vector.cpp b/test/unit/vector.cpp index b068bce2..c39c2e3a 100644 --- a/test/unit/vector.cpp +++ b/test/unit/vector.cpp @@ -20,18 +20,7 @@ namespace lol LOLUNIT_FIXTURE(VectorTest) { - void SetUp() - { - identity = mat4(1.0f); - triangular = mat4(vec4(1.0f, 0.0f, 0.0f, 0.0f), - vec4(7.0f, 2.0f, 0.0f, 0.0f), - vec4(1.0f, 5.0f, 3.0f, 0.0f), - vec4(8.0f, 9.0f, 2.0f, 4.0f)); - invertible = mat4(vec4( 1.0f, 1.0f, 2.0f, -1.0f), - vec4(-2.0f, -1.0f, -2.0f, 2.0f), - vec4( 4.0f, 2.0f, 5.0f, -4.0f), - vec4( 5.0f, -3.0f, -7.0f, -6.0f)); - } + void SetUp() {} void TearDown() {} @@ -135,71 +124,6 @@ LOLUNIT_FIXTURE(VectorTest) LOLUNIT_ASSERT_EQUAL(c.w, 0.0f); LOLUNIT_ASSERT_EQUAL(a3, a1); } - - LOLUNIT_TEST(MatrixDeterminant) - { - float d1 = triangular.det(); - LOLUNIT_ASSERT_EQUAL(d1, 24.0f); - float d2 = invertible.det(); - LOLUNIT_ASSERT_EQUAL(d2, -1.0f); - } - - LOLUNIT_TEST(MatrixMultiplication) - { - mat4 m0 = identity; - mat4 m1 = identity; - mat4 m2 = m0 * m1; - - LOLUNIT_ASSERT_EQUAL(m2[0][0], 1.0f); - LOLUNIT_ASSERT_EQUAL(m2[1][0], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[2][0], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[3][0], 0.0f); - - LOLUNIT_ASSERT_EQUAL(m2[0][1], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[1][1], 1.0f); - LOLUNIT_ASSERT_EQUAL(m2[2][1], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[3][1], 0.0f); - - LOLUNIT_ASSERT_EQUAL(m2[0][2], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[1][2], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[2][2], 1.0f); - LOLUNIT_ASSERT_EQUAL(m2[3][2], 0.0f); - - LOLUNIT_ASSERT_EQUAL(m2[0][3], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[1][3], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[2][3], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[3][3], 1.0f); - } - - LOLUNIT_TEST(MatrixInverse) - { - mat4 m0 = invertible; - mat4 m1 = m0.invert(); - - mat4 m2 = m0 * m1; - - LOLUNIT_ASSERT_EQUAL(m2[0][0], 1.0f); - LOLUNIT_ASSERT_EQUAL(m2[1][0], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[2][0], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[3][0], 0.0f); - - LOLUNIT_ASSERT_EQUAL(m2[0][1], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[1][1], 1.0f); - LOLUNIT_ASSERT_EQUAL(m2[2][1], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[3][1], 0.0f); - - LOLUNIT_ASSERT_EQUAL(m2[0][2], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[1][2], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[2][2], 1.0f); - LOLUNIT_ASSERT_EQUAL(m2[3][2], 0.0f); - - LOLUNIT_ASSERT_EQUAL(m2[0][3], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[1][3], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[2][3], 0.0f); - LOLUNIT_ASSERT_EQUAL(m2[3][3], 1.0f); - } - - mat4 triangular, identity, invertible; }; } /* namespace lol */ diff --git a/win32/testsuite.vcxproj b/win32/testsuite.vcxproj index 9ab94102..9e4b0a90 100644 --- a/win32/testsuite.vcxproj +++ b/win32/testsuite.vcxproj @@ -32,6 +32,7 @@ + @@ -60,4 +61,4 @@ - \ No newline at end of file +