From dd25f1c58a753e0fa4bd6a6f03eea1bfabf9d540 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 27 Jul 2024 15:29:54 +0100 Subject: [PATCH 01/29] backup initial implemenation of templated classes : Matrix class first. --- Engine/source/math/mMatrix.cpp | 374 +++++++++++++++++++++++++++++++++ Engine/source/math/mMatrix.h | 279 ++++++++++++++++++++++++ 2 files changed, 653 insertions(+) diff --git a/Engine/source/math/mMatrix.cpp b/Engine/source/math/mMatrix.cpp index d8205838f..119c3c0a4 100644 --- a/Engine/source/math/mMatrix.cpp +++ b/Engine/source/math/mMatrix.cpp @@ -209,3 +209,377 @@ EngineFieldTable::Field MatrixFEngineExport::getMatrixField() typedef MatrixF ThisType; return _FIELD_AS(F32, m, m, 16, ""); } + +//------------------------------------ +// Templatized matrix class to replace MATRIXF above +// row-major for now, since torque says it uses that +// but in future could cut down on transpose calls if +// we switch to column major. +//------------------------------------ + +template +const Matrix Matrix::Identity = []() { + Matrix identity(true); + return identity; +}(); + +template +Matrix::Matrix(const EulerF& e) +{ + set(e); +} + +template +Matrix& Matrix::set(const EulerF& e) +{ + // when the template refactor is done, euler will be able to be setup in different ways + AssertFatal(rows >= 3 && cols >= 3, "EulerF can only initialize 3x3 or more"); + static_assert(std::is_same::value, "Can only initialize eulers with floats for now"); + + F32 cosPitch, sinPitch; + mSinCos(e.x, sinPitch, cosPitch); + + F32 cosYaw, sinYaw; + mSinCos(e.y, sinYaw, cosYaw); + + F32 cosRoll, sinRoll; + mSinCos(e.z, sinRoll, cosRoll); + + enum { + AXIS_X = (1 << 0), + AXIS_Y = (1 << 1), + AXIS_Z = (1 << 2) + }; + + U32 axis = 0; + if (e.x != 0.0f) axis |= AXIS_X; + if (e.y != 0.0f) axis |= AXIS_Y; + if (e.z != 0.0f) axis |= AXIS_Z; + + switch (axis) { + case 0: + (*this) = Matrix(true); + break; + case AXIS_X: + (*this)(0, 0) = 1.0f; (*this)(1, 0) = 0.0f; (*this)(2, 0) = 0.0f; + (*this)(0, 1) = 0.0f; (*this)(1, 1) = cosPitch; (*this)(2, 1) = -sinPitch; + (*this)(0, 2) = 0.0f; (*this)(1, 2) = sinPitch; (*this)(2, 2) = cosPitch; + break; + case AXIS_Y: + (*this)(0, 0) = cosYaw; (*this)(1, 0) = 0.0f; (*this)(2, 0) = sinYaw; + (*this)(0, 1) = 0.0f; (*this)(1, 1) = 1.0f; (*this)(2, 1) = 0.0f; + (*this)(0, 2) = -sinYaw; (*this)(1, 2) = 0.0f; (*this)(2, 2) = cosYaw; + break; + case AXIS_Z: + (*this)(0, 0) = cosRoll; (*this)(1, 0) = -sinRoll; (*this)(2, 0) = 0.0f; + (*this)(0, 1) = sinRoll; (*this)(1, 1) = cosRoll; (*this)(2, 1) = 0.0f; + (*this)(0, 2) = 0.0f; (*this)(1, 2) = 0.0f; (*this)(2, 2) = 0.0f; + break; + default: + F32 r1 = cosYaw * cosRoll; + F32 r2 = cosYaw * sinRoll; + F32 r3 = sinYaw * cosRoll; + F32 r4 = sinYaw * sinRoll; + + // the matrix looks like this: + // r1 - (r4 * sin(x)) r2 + (r3 * sin(x)) -cos(x) * sin(y) + // -cos(x) * sin(z) cos(x) * cos(z) sin(x) + // r3 + (r2 * sin(x)) r4 - (r1 * sin(x)) cos(x) * cos(y) + // + // where: + // r1 = cos(y) * cos(z) + // r2 = cos(y) * sin(z) + // r3 = sin(y) * cos(z) + // r4 = sin(y) * sin(z) + + // init the euler 3x3 rotation matrix. + (*this)(0, 0) = r1 - (r4 * sinPitch); (*this)(1, 0) = -cosPitch * sinRoll; (*this)(2, 0) = r3 + (r2 * sinPitch); + (*this)(0, 1) = r2 + (r3 * sinPitch); (*this)(1, 1) = cosPitch * cosRoll; (*this)(2, 1) = r4 - (r1 * sinPitch); + (*this)(0, 2) = -cosPitch * sinYaw; (*this)(1, 2) = sinPitch; (*this)(2, 2) = cosPitch * cosYaw; + break; + } + + if (rows == 4) { + (*this)(3, 0) = 0.0f; + (*this)(3, 1) = 0.0f; + (*this)(3, 2) = 0.0f; + } + + if (cols == 4) { + (*this)(0, 3) = 0.0f; + (*this)(1, 3) = 0.0f; + (*this)(2, 3) = 0.0f; + } + + if (rows == 4 && cols == 4) { + (*this)(3, 3) = 1.0f; + } + + return(*this); +} + +template +Matrix::Matrix(const EulerF& e, const Point3F p) +{ + set(e, p); +} + +template +Matrix& Matrix::set(const EulerF& e, const Point3F p) +{ + AssertFatal(rows >= 3 && cols >= 4, "Euler and Point can only initialize 3x4 or more"); + // call set euler, this already sets the last row if it exists. + set(e); + + // does this need to multiply with the result of the euler? or are we just setting position. + (*this)(0, 3) = p.x; + (*this)(1, 3) = p.y; + (*this)(2, 3) = p.z; + + return (*this); +} + +template +Matrix& Matrix::inverse() +{ + // TODO: insert return statement here + AssertFatal(rows == cols, "Can only perform inverse on square matrices."); + const U32 size = rows; + + // Create augmented matrix [this | I] + Matrix augmentedMatrix; + Matrix resultMatrix; + + for (U32 i = 0; i < size; i++) { + for (U32 j = 0; j < size; j++) { + augmentedMatrix(i, j) = (*this)(i, j); + augmentedMatrix(i, j + size) = (i == j) ? static_cast(1) : static_cast(0); + } + } + + // Apply gauss-joran elimination + for (U32 i = 0; i < size; i++) { + U32 pivotRow = i; + + for (U32 k = i + 1; k < size; k++) { + // use std::abs until the templated math functions are in place. + if (std::abs(augmentedMatrix(k, i)) > std::abs(augmentedMatrix(pivotRow, i))) { + pivotRow = k; + } + } + + // Swap if needed. + if (i != pivotRow) { + for (U32 j = 0; j < 2 * size; j++) { + std::swap(augmentedMatrix(i, j), augmentedMatrix(pivotRow, j)); + } + } + + // Early out if pivot is 0, return a new empty matrix. + if (augmentedMatrix(i, i) == static_cast(0)) { + return Matrix(); + } + + DATA_TYPE pivotVal = augmentedMatrix(i, i); + + // scale the pivot + for (U32 j = 0; j < 2 * size; ++j) { + augmentedMatrix(i, j) /= pivotVal; + } + + // Eliminate the current column in all other rows + for (std::size_t k = 0; k < size; k++) { + if (k != i) { + DATA_TYPE factor = augmentedMatrix(k, i); + for (std::size_t j = 0; j < 2 * size; ++j) { + augmentedMatrix(k, j) -= factor * augmentedMatrix(i, j); + } + } + } + } + + for (U32 i = 0; i < size; i++) { + for (U32 j = 0; j < size; j++) { + resultMatrix(i, j) = augmentedMatrix(i, j + size); + } + } + + return resultMatrix; +} + +template +void Matrix::invert() +{ + (*this) = inverse(); +} + +template +Matrix& Matrix::setCrossProduct(const Point3F& p) +{ + AssertFatal(rows == 4 && cols == 4, "Cross product only supported on 4x4 for now"); + + (*this)(0, 0) = 0; + (*this)(0, 1) = -p.z; + (*this)(0, 2) = p.y; + (*this)(0, 3) = 0; + + (*this)(1, 0) = p.z; + (*this)(1, 1) = 0; + (*this)(1, 2) = -p.x; + (*this)(1, 3) = 0; + + (*this)(2, 0) = -p.y; + (*this)(2, 1) = p.x; + (*this)(2, 2) = 0; + (*this)(2, 3) = 0; + + (*this)(3, 0) = 0; + (*this)(3, 1) = 0; + (*this)(3, 2) = 0; + (*this)(3, 3) = 1; + + return (*this); +} + +template +Matrix& Matrix::setTensorProduct(const Point3F& p, const Point3F& q) +{ + AssertFatal(rows == 4 && cols == 4, "Tensor product only supported on 4x4 for now"); + + (*this)(0, 0) = p.x * q.x; + (*this)(0, 1) = p.x * q.y; + (*this)(0, 2) = p.x * q.z; + (*this)(0, 3) = 0; + + (*this)(1, 0) = p.y * q.x; + (*this)(1, 1) = p.y * q.y; + (*this)(1, 2) = p.y * q.z; + (*this)(1, 3) = 0; + + (*this)(2, 0) = p.z * q.x; + (*this)(2, 1) = p.z * q.y; + (*this)(2, 2) = p.z * q.z; + (*this)(2, 3) = 0; + + (*this)(3, 0) = 0; + (*this)(3, 1) = 0; + (*this)(3, 2) = 0; + (*this)(3, 3) = 1; + + return (*this); +} + +template +bool Matrix::isAffine() const +{ + if ((*this)(rows - 1, cols - 1) != 1.0f) { + return false; + } + + for (U32 col = 0; col < cols - 1; ++col) { + if ((*this)(rows - 1, col) != 0.0f) { + return false; + } + } + + Point3F one, two, three; + getColumn(0, &one); + getColumn(1, &two); + getColumn(2, &three); + + // check columns + { + if (mDot(one, two) > 0.0001f || + mDot(one, three) > 0.0001f || + mDot(two, three) > 0.0001f) + return false; + + if (mFabs(1.0f - one.lenSquared()) > 0.0001f || + mFabs(1.0f - two.lenSquared()) > 0.0001f || + mFabs(1.0f - three.lenSquared()) > 0.0001f) + return false; + } + + getRow(0, &one); + getRow(1, &two); + getRow(2, &three); + // check rows + { + if (mDot(one, two) > 0.0001f || + mDot(one, three) > 0.0001f || + mDot(two, three) > 0.0001f) + return false; + + if (mFabs(1.0f - one.lenSquared()) > 0.0001f || + mFabs(1.0f - two.lenSquared()) > 0.0001f || + mFabs(1.0f - three.lenSquared()) > 0.0001f) + return false; + } + + return true; +} + + +template +EulerF Matrix::toEuler() const +{ + AssertFatal(rows >= 3 && cols >= 3, "Euler rotations require at least a 3x3 matrix."); + // Extract rotation matrix components + const DATA_TYPE m00 = (*this)(0, 0); + const DATA_TYPE m01 = (*this)(0, 1); + const DATA_TYPE m02 = (*this)(0, 2); + const DATA_TYPE m10 = (*this)(1, 0); + const DATA_TYPE m11 = (*this)(1, 1); + const DATA_TYPE m21 = (*this)(2, 1); + const DATA_TYPE m22 = (*this)(2, 2); + + // like all others assume float for now. + EulerF r; + + r.x = mAsin(mClampF(m21, -1.0, 1.0)); + if (mCos(r.x) != 0.0f) { + r.y = mAtan2(-m02, m22); // yaw + r.z = mAtan2(-m10, m11); // roll + } + else { + r.y = 0.0f; + r.z = mAtan2(m01, m00); // this rolls when pitch is +90 degrees + } + + return r; +} + +template +void Matrix::dumpMatrix(const char* caption) const +{ + U32 size = (caption == NULL) ? 0 : dStrlen(caption); + FrameTemp spacer(size + 1); + char* spacerRef = spacer; + + // is_floating_point should return true for floats and doubles. + const char* formatSpec = std::is_floating_point_v ? " %-8.4f" : " %d"; + + dMemset(spacerRef, ' ', size); + // null terminate. + spacerRef[size] = '\0'; + + /*Con::printf("%s = | %-8.4f %-8.4f %-8.4f %-8.4f |", caption, m[idx(0, 0)], m[idx(0, 1)], m[idx(0, 2)], m[idx(0, 3)]); + Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(1, 0)], m[idx(1, 1)], m[idx(1, 2)], m[idx(1, 3)]); + Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(2, 0)], m[idx(2, 1)], m[idx(2, 2)], m[idx(2, 3)]); + Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(3, 0)], m[idx(3, 1)], m[idx(3, 2)], m[idx(3, 3)]);*/ + + StringBuilder str; + str.format("%s = |", caption); + for (U32 i = 0; i < rows; i++) { + if (i > 0) { + str.append(spacerRef); + } + + for (U32 j = 0; j < cols; j++) { + str.format(formatSpec, (*this)(i, j)); + } + str.append(" |\n"); + } + + Con::printf("%s", str.end().c_str()); +} diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 18981eeea..9c53fa1c2 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -620,4 +620,283 @@ inline void mTransformPlane(const MatrixF& mat, const Point3F& scale, const Plan m_matF_x_scale_x_planeF(mat, &scale.x, &plane.x, &result->x); } +//------------------------------------ +// Templatized matrix class to replace MATRIXF above +// row-major for now, since torque says it uses that +// but in future could cut down on transpose calls if +// we switch to column major. +//------------------------------------ + +template +class Matrix { + friend class MatrixTemplateExport; +private: + DATA_TYPE data[rows * cols]; + +public: + + static_assert(rows >= 2 && cols >= 2, "Matrix must have at least 2 rows and 2 cols."); + + // ------ Setters and initializers ------ + explicit Matrix(bool identity = false) { + std::fill(data, data + (rows * cols), DATA_TYPE(0)); + + if (identity) { + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + // others already get filled with 0 + if (j == i) + (*this)(i, j) = static_cast(1); + } + } + } + } + + explicit Matrix(const EulerF& e); + /// Make this an identity matrix. + Matrix& identity(); + + Matrix& set(const EulerF& e); + + Matrix(const EulerF& e, const Point3F p); + Matrix& set(const EulerF& e, const Point3F p); + + Matrix& inverse(); + Matrix& transpose(); + void invert(); + + Matrix& setCrossProduct(const Point3F& p); + Matrix& setTensorProduct(const Point3F& p, const Point3F& q); + + /// M * Matrix(p) -> M + Matrix& scale(const Point3F& s); + Matrix& scale(DATA_TYPE s) { return scale(Point3F(s, s, s)); } + + // ------ Getters ------ + bool isAffine() const; + Point3F getScale() const; + EulerF toEuler() const; + + Point3F getPosition() const; + + void getColumn(S32 col, Point4F* cptr) const; + Point4F getColumn4F(S32 col) const { Point4F ret; getColumn(col, &ret); return ret; } + + void getColumn(S32 col, Point3F* cptr) const; + Point3F getColumn3F(S32 col) const { Point3F ret; getColumn(col, &ret); return ret; } + + void getRow(S32 row, Point4F* cptr) const; + Point4F getRow4F(S32 row) const { Point4F ret; getRow(row, &ret); return ret; } + + void getRow(S32 row, Point3F* cptr) const; + Point3F getRow3F(S32 row) const { Point3F ret; getRow(row, &ret); return ret; } + + DATA_TYPE* getData() { + return data; + } + + const DATA_TYPE* getData() const { + return data; + } + + void dumpMatrix(const char* caption = NULL) const; + // Static identity matrix + static const Matrix Identity; + + // ------ Operators ------ + + operator DATA_TYPE* () { return (data); } + operator const DATA_TYPE* () const { return (DATA_TYPE*)(data); } + + DATA_TYPE& operator()(U32 row, U32 col) { + if (row >= rows || col >= cols) + AssertFatal(false, "Matrix indices out of range"); + + return data[col * rows + row]; + } + + const DATA_TYPE& operator()(U32 row, U32 col) const { + if (row >= rows || col >= cols) + AssertFatal(false, "Matrix indices out of range"); + + return data[col * rows + row]; + } + +}; + +//-------------------------------------------- +// INLINE FUNCTIONS +//-------------------------------------------- +template +inline Matrix& Matrix::transpose() +{ + // square matrices can just swap, non square requires a temp mat. + if (rows == cols) { + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + std::swap((*this)(j, i), (*this)(i, j)); + } + } + } + else { + Matrix result; + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + result(j, i) = (*this)(i, j); + } + } + std::copy(std::begin(result.data), std::end(result.data), std::begin(data)); + } + + return (*this); +} + +template +inline Matrix& Matrix::identity() +{ + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + if (j == i) + (*this)(i, j) = static_cast(1); + else + (*this)(i, j) = static_cast(0); + } + } + + return (*this); +} + +template +inline Matrix& Matrix::scale(const Point3F& s) +{ + // torques scale applies directly, does not create another matrix to multiply with the translation matrix. + AssertFatal(rows >= 3 && cols >= 3, "Scale can only be applied 3x3 or more"); + for (U32 i = 0; i < 3; i++) { + for (U32 j = 0; j < 3; j++) { + DATA_TYPE scale = (i == 0) ? s.x : (i == 1) ? s.y : s.z; + (*this)(i, j) *= scale; + } + } + + return (*this); +} + +template +inline Point3F Matrix::getScale() const +{ + // this function assumes the matrix has scale applied through the scale(const Point3F& s) function. + // for now assume float since we have point3F. + AssertFatal(rows >= 3 && cols >= 3, "Scale can only be applied 3x3 or more"); + + Point3F scale; + + scale.x = mSqrt((*this)(0, 0) * (*this)(0, 0) + (*this)(1, 0) * (*this)(1, 0) + (*this)(2, 0) * (*this)(2, 0)); + scale.y = mSqrt((*this)(0, 1) * (*this)(0, 1) + (*this)(1, 1) * (*this)(1, 1) + (*this)(2, 1) * (*this)(2, 1)); + scale.z = mSqrt((*this)(0, 2) * (*this)(0, 2) + (*this)(1, 2) * (*this)(1, 2) + (*this)(2, 2) * (*this)(2, 2)); + + return scale; +} + + + +template +inline Point3F Matrix::getPosition() const +{ + Point3F pos; + getColumn(3, &pos); + return pos; +} + +template +inline void Matrix::getColumn(S32 col, Point4F* cptr) const +{ + if (rows >= 2) + { + cptr->x = (*this)(0, col); + cptr->y = (*this)(1, col); + } + + if (rows >= 3) + cptr->z = (*this)(2, col); + else + cptr->z = 0.0f; + + if (rows >= 4) + cptr->w = (*this)(3, col); + else + cptr->w = 0.0f; +} + +template +inline void Matrix::getColumn(S32 col, Point3F* cptr) const +{ + if (rows >= 2) + { + cptr->x = (*this)(0, col); + cptr->y = (*this)(1, col); + } + + if (rows >= 3) + cptr->z = (*this)(2, col); + else + cptr->z = 0.0f; +} + +template +inline void Matrix::getRow(S32 row, Point4F* cptr) const +{ + if (cols >= 2) + { + cptr->x = (*this)(row, 0); + cptr->y = (*this)(row, 1); + } + + if (cols >= 3) + cptr->z = (*this)(row, 2); + else + cptr->z = 0.0f; + + if (cols >= 4) + cptr->w = (*this)(row, 3); + else + cptr->w = 0.0f; +} + +template +inline void Matrix::getRow(S32 row, Point3F* cptr) const +{ + if (cols >= 2) + { + cptr->x = (*this)(row, 0); + cptr->y = (*this)(row, 1); + } + + if (cols >= 3) + cptr->z = (*this)(row, 2); + else + cptr->z = 0.0f; +} + +//-------------------------------------------- +// INLINE FUNCTIONS END +//-------------------------------------------- + +typedef Matrix Matrix4F; + +class MatrixTemplateExport +{ +public: + template + static EngineFieldTable::Field getMatrixField(); +}; + +template +inline EngineFieldTable::Field MatrixTemplateExport::getMatrixField() +{ + typedef Matrix ThisType; + return _FIELD_AS(T, data, data, rows * cols, ""); +} + + + #endif //_MMATRIX_H_ From 0f02c878efc8664309ead9daecd6355792ebd689 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 27 Jul 2024 23:06:59 +0100 Subject: [PATCH 02/29] Update mMatrix.h setColumn setRow isIdentity only a few functions left --- Engine/source/math/mMatrix.h | 84 ++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 9c53fa1c2..bdd167aee 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -672,9 +672,17 @@ public: Matrix& scale(const Point3F& s); Matrix& scale(DATA_TYPE s) { return scale(Point3F(s, s, s)); } + void setColumn(S32 col, const Point4F& cptr); + void setColumn(S32 col, const Point3F& cptr); + + void setRow(S32 row, const Point4F& cptr); + void setRow(S32 row, const Point3F& cptr); + // ------ Getters ------ bool isAffine() const; + bool isIdentity() const; Point3F getScale() const; + EulerF toEuler() const; Point3F getPosition() const; @@ -781,6 +789,26 @@ inline Matrix& Matrix::scale(const return (*this); } +template +inline bool Matrix::isIdentity() const { + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + if (j == i) { + if((*this)(i, j) != static_cast(1)) { + return false; + } + } + else { + if((*this)(i, j) != static_cast(0)) { + return false; + } + } + } + } + + return true; +} + template inline Point3F Matrix::getScale() const { @@ -842,6 +870,34 @@ inline void Matrix::getColumn(S32 col, Point3F* cptr) con cptr->z = 0.0f; } +template +inline void Matrix::setColumn(S32 col, const Point4F &cptr) { + if(rows >= 2) + { + (*this)(0, col) = cptr.x; + (*this)(1, col) = cptr.y; + } + + if(rows >= 3) + (*this)(2, col) = cptr.z; + + if(rows >= 4) + (*this)(3, col) = cptr.w; +} + +template +inline void Matrix::setColumn(S32 col, const Point3F &cptr) { + if(rows >= 2) + { + (*this)(0, col) = cptr.x; + (*this)(1, col) = cptr.y; + } + + if(rows >= 3) + (*this)(2, col) = cptr.z; + +} + template inline void Matrix::getRow(S32 row, Point4F* cptr) const { @@ -877,6 +933,34 @@ inline void Matrix::getRow(S32 row, Point3F* cptr) const cptr->z = 0.0f; } +template +inline void Matrix::setRow(S32 row, const Point4F& cptr) { + if(cols >= 2) + { + (*this)(row, 0) = cptr.x; + (*this)(row, 1) = cptr.y; + } + + if(cols >= 3) + (*this)(row, 2) = cptr.z; + + if(cols >= 4) + (*this)(row, 3) = cptr.w; +} + +template +inline void Matrix::setRow(S32 row, const Point3F& cptr) { + if(cols >= 2) + { + (*this)(row, 0) = cptr.x; + (*this)(row, 1) = cptr.y; + } + + if(cols >= 3) + (*this)(row, 2) = cptr.z; + +} + //-------------------------------------------- // INLINE FUNCTIONS END //-------------------------------------------- From c0bcb8bd00a3f199591463245f501fc4f3c901c0 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 28 Jul 2024 06:38:11 +0100 Subject: [PATCH 03/29] Update mMatrix.cpp fix comment, torque is already column major, even though doc says its row major --- Engine/source/math/mMatrix.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Engine/source/math/mMatrix.cpp b/Engine/source/math/mMatrix.cpp index 119c3c0a4..90928153f 100644 --- a/Engine/source/math/mMatrix.cpp +++ b/Engine/source/math/mMatrix.cpp @@ -212,9 +212,6 @@ EngineFieldTable::Field MatrixFEngineExport::getMatrixField() //------------------------------------ // Templatized matrix class to replace MATRIXF above -// row-major for now, since torque says it uses that -// but in future could cut down on transpose calls if -// we switch to column major. //------------------------------------ template From 02b5e85f61e7b2e87cfa8c5ce310966ef6e56beb Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 28 Jul 2024 07:04:23 +0100 Subject: [PATCH 04/29] implement struct example --- Engine/source/math/mMatrix.h | 3 --- Engine/source/math/mathTypes.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index bdd167aee..e2717e985 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -622,9 +622,6 @@ inline void mTransformPlane(const MatrixF& mat, const Point3F& scale, const Plan //------------------------------------ // Templatized matrix class to replace MATRIXF above -// row-major for now, since torque says it uses that -// but in future could cut down on transpose calls if -// we switch to column major. //------------------------------------ template diff --git a/Engine/source/math/mathTypes.cpp b/Engine/source/math/mathTypes.cpp index 5beb3f9b0..751f3e31b 100644 --- a/Engine/source/math/mathTypes.cpp +++ b/Engine/source/math/mathTypes.cpp @@ -108,6 +108,13 @@ IMPLEMENT_STRUCT( MatrixF, MatrixFEngineExport::getMatrixField(), END_IMPLEMENT_STRUCT; +IMPLEMENT_STRUCT(Matrix4F, + Matrix4F, MathTypes, + "") + + MatrixTemplateExport::getMatrixField(), + + END_IMPLEMENT_STRUCT; IMPLEMENT_STRUCT( AngAxisF, AngAxisF, MathTypes, "" ) From 2cee5f7e1053a76e62e95543ceccf1001b53ca25 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 28 Jul 2024 09:02:49 +0100 Subject: [PATCH 05/29] mul and operators add mul functions and operators code conformity changes --- Engine/source/math/mMatrix.cpp | 40 +++++++++- Engine/source/math/mMatrix.h | 141 ++++++++++++++++++++++++++++++++- 2 files changed, 175 insertions(+), 6 deletions(-) diff --git a/Engine/source/math/mMatrix.cpp b/Engine/source/math/mMatrix.cpp index 90928153f..9c75d740b 100644 --- a/Engine/source/math/mMatrix.cpp +++ b/Engine/source/math/mMatrix.cpp @@ -380,15 +380,15 @@ Matrix& Matrix::inverse() DATA_TYPE pivotVal = augmentedMatrix(i, i); // scale the pivot - for (U32 j = 0; j < 2 * size; ++j) { + for (U32 j = 0; j < 2 * size; j++) { augmentedMatrix(i, j) /= pivotVal; } // Eliminate the current column in all other rows - for (std::size_t k = 0; k < size; k++) { + for (U32 k = 0; k < size; k++) { if (k != i) { DATA_TYPE factor = augmentedMatrix(k, i); - for (std::size_t j = 0; j < 2 * size; ++j) { + for (U32 j = 0; j < 2 * size; j++) { augmentedMatrix(k, j) -= factor * augmentedMatrix(i, j); } } @@ -466,6 +466,40 @@ Matrix& Matrix::setTensorProduct(c return (*this); } +template +void Matrix::mul(Box3F& box) const +{ + AssertFatal(rows == 4 && cols == 4, "Multiplying Box3F with matrix requires 4x4"); + + // Create an array of all 8 corners of the box + Point3F corners[8] = { + Point3F(box.minExtents.x, box.minExtents.y, box.minExtents.z), + Point3F(box.minExtents.x, box.minExtents.y, box.maxExtents.z), + Point3F(box.minExtents.x, box.maxExtents.y, box.minExtents.z), + Point3F(box.minExtents.x, box.maxExtents.y, box.maxExtents.z), + Point3F(box.maxExtents.x, box.minExtents.y, box.minExtents.z), + Point3F(box.maxExtents.x, box.minExtents.y, box.maxExtents.z), + Point3F(box.maxExtents.x, box.maxExtents.y, box.minExtents.z), + Point3F(box.maxExtents.x, box.maxExtents.y, box.maxExtents.z), + }; + + for (U32 i = 0; i < 8; i++) { + corners[i] = (*this) * corners[i]; + } + + box.minExtents = corners[0]; + box.maxExtents = corners[0]; + for (U32 i = 1; i < 8; ++i) { + box.minExtents.x = mMin(box.minExtents.x, corners[i].x); + box.minExtents.y = mMin(box.minExtents.y, corners[i].y); + box.minExtents.z = mMin(box.minExtents.z, corners[i].z); + + box.maxExtents.x = mMax(box.maxExtents.x, corners[i].x); + box.maxExtents.y = mMax(box.maxExtents.y, corners[i].y); + box.maxExtents.z = mMax(box.maxExtents.z, corners[i].z); + } +} + template bool Matrix::isAffine() const { diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index e2717e985..98785dd54 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -674,7 +674,61 @@ public: void setRow(S32 row, const Point4F& cptr); void setRow(S32 row, const Point3F& cptr); - + + ///< M * a -> M + Matrix& mul(const Matrix& a) + { return *this * a; } + ///< a * M -> M + Matrix& mulL(const Matrix& a) + { return *this = a * *this; } + ///< a * b -> M + Matrix& mul(const Matrix& a, const Matrix& b) + { return *this = a * b; } + ///< M * a -> M + Matrix& mul(const F32 a) + { return *this * a; } + ///< a * b -> M + Matrix& mul(const Matrix& a, const F32 b) + { return *this = a * b; } + + + ///< M * p -> p (full [4x4] * [1x4]) + void mul(Point4F& p) const { p = *this * p; } + ///< M * p -> p (assume w = 1.0f) + void mulP(Point3F& p) const { p = *this * p; } + ///< M * p -> d (assume w = 1.0f) + void mulP(const Point3F& p, Point3F* d) const { *d = *this * p; } + ///< M * v -> v (assume w = 0.0f) + void mulV(VectorF& v) const + { + AssertFatal(rows == 4 && cols == 4, "Multiplying VectorF with matrix requires 4x4"); + VectorF result( + (*this)(0, 0) * v.x + (*this)(0, 1) * v.y + (*this)(0, 2) * v.z, + (*this)(1, 0) * v.x + (*this)(1, 1) * v.y + (*this)(1, 2) * v.z, + (*this)(2, 0) * v.x + (*this)(2, 1) * v.y + (*this)(2, 2) * v.z + ); + + v = result; + + } + ///< M * v -> d (assume w = 0.0f) + void mulV(const VectorF& v, Point3F* d) const + { + AssertFatal(rows == 4 && cols == 4, "Multiplying VectorF with matrix requires 4x4"); + VectorF result( + (*this)(0, 0) * v.x + (*this)(0, 1) * v.y + (*this)(0, 2) * v.z, + (*this)(1, 0) * v.x + (*this)(1, 1) * v.y + (*this)(1, 2) * v.z, + (*this)(2, 0) * v.x + (*this)(2, 1) * v.y + (*this)(2, 2) * v.z + ); + + d->x = result.x; + d->y = result.y; + d->z = result.z; + } + + ///< Axial box -> Axial Box (too big a function to be inline) + void mul(Box3F& box) const; + // ------ Getters ------ bool isAffine() const; bool isIdentity() const; @@ -710,17 +764,98 @@ public: // ------ Operators ------ + Matrix operator * (const Matrix& other) const { + Matrix result; + + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + result(i, j) = 0; + for (U32 k = 0; k < cols; k++) { + result(i, j) += (*this)(i, k) * other(k, j); + } + } + } + + return result; + } + + Matrix operator *= (const Matrix& other) { + *this = *this * other; + return *this; + } + + Matrix operator * (const DATA_TYPE scalar) const { + Matrix result; + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + result(i, j) = (*this)(i, j) * scalar; + } + } + + return result; + } + Matrix& operator *= (const DATA_TYPE scalar) { + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + (*this)(i, j) *= scalar; + } + } + + return *this; + } + + Point3F operator*(const Point3F& point) const { + AssertFatal(rows == 4 && cols == 4, "Multiplying point3 with matrix requires 4x4"); + return Point3F( + (*this)(0, 0) * point.x + (*this)(0, 1) * point.y + (*this)(0, 2) * point.z + (*this)(0, 3), + (*this)(1, 0) * point.x + (*this)(1, 1) * point.y + (*this)(1, 2) * point.z + (*this)(1, 3), + (*this)(2, 0) * point.x + (*this)(2, 1) * point.y + (*this)(2, 2) * point.z + (*this)(2, 3) + ); + } + + Point4F operator*(const Point4F& point) const { + AssertFatal(rows == 4 && cols == 4, "Multiplying point4 with matrix requires 4x4"); + return Point4F( + (*this)(0, 0) * point.x + (*this)(0, 1) * point.y + (*this)(0, 2) * point.z + (*this)(0, 3) * point.w, + (*this)(1, 0) * point.x + (*this)(1, 1) * point.y + (*this)(1, 2) * point.z + (*this)(1, 3) * point.w, + (*this)(2, 0) * point.x + (*this)(2, 1) * point.y + (*this)(2, 2) * point.z + (*this)(2, 3) * point.w, + (*this)(3, 0) * point.x + (*this)(3, 1) * point.y + (*this)(3, 2) * point.z + (*this)(3, 3) * point.w + ); + } + + Matrix& operator = (const Matrix& other) { + if (this != &other) { + std::copy(other.data, other.data + rows * cols, this->data); + } + + return *this; + } + + bool operator == (const Matrix& other) const { + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + if ((*this)(i, j) != other(i, j)) + return false; + } + } + return true; + } + + bool operator != (const Matrix& other) const { + return !(*this == other); + } + operator DATA_TYPE* () { return (data); } operator const DATA_TYPE* () const { return (DATA_TYPE*)(data); } - DATA_TYPE& operator()(U32 row, U32 col) { + DATA_TYPE& operator () (U32 row, U32 col) { if (row >= rows || col >= cols) AssertFatal(false, "Matrix indices out of range"); return data[col * rows + row]; } - const DATA_TYPE& operator()(U32 row, U32 col) const { + const DATA_TYPE& operator () (U32 row, U32 col) const { if (row >= rows || col >= cols) AssertFatal(false, "Matrix indices out of range"); From 8f8cc32636122bd454f2089b6589410fa46a1568 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 28 Jul 2024 11:54:44 +0100 Subject: [PATCH 06/29] normalize and affineInverse added functions for normalize and affineInverse --- Engine/source/math/mMatrix.cpp | 25 +++++++++++++++++++++++-- Engine/source/math/mMatrix.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Engine/source/math/mMatrix.cpp b/Engine/source/math/mMatrix.cpp index 9c75d740b..0a152ad6c 100644 --- a/Engine/source/math/mMatrix.cpp +++ b/Engine/source/math/mMatrix.cpp @@ -372,9 +372,9 @@ Matrix& Matrix::inverse() } } - // Early out if pivot is 0, return a new empty matrix. + // Early out if pivot is 0, return identity matrix. if (augmentedMatrix(i, i) == static_cast(0)) { - return Matrix(); + return Matrix(true); } DATA_TYPE pivotVal = augmentedMatrix(i, i); @@ -550,6 +550,27 @@ bool Matrix::isAffine() const return true; } +template +Matrix& Matrix::affineInverse() +{ + AssertFatal(rows >= 4 && cols >= 4, "affineInverse requires at least 4x4"); + Matrix subMatrix; + + for (U32 i = 0; i < 3; i++) { + for (U32 j = 0; j < 3; j++) { + subMatrix(i, j) = (*this)(i, j); + } + } + + subMatrix.transpose(); + + Point3F pos = getPosition(); + (*this)(0, 3) = mDot(subMatrix.getColumn3F(0), pos); + (*this)(1, 3) = mDot(subMatrix.getColumn3F(1), pos); + (*this)(2, 3) = mDot(subMatrix.getColumn3F(2), pos); + + return *this; +} template EulerF Matrix::toEuler() const diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 98785dd54..fe715298e 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -653,6 +653,8 @@ public: /// Make this an identity matrix. Matrix& identity(); + void normalize(); + Matrix& set(const EulerF& e); Matrix(const EulerF& e, const Point3F p); @@ -730,8 +732,14 @@ public: void mul(Box3F& box) const; // ------ Getters ------ + // col * rows + row + // static U32 idx(U32 i, U32 j) { return (i * rows + j); } bool isAffine() const; bool isIdentity() const; + /// Take inverse of matrix assuming it is affine (rotation, + /// scale, sheer, translation only). + Matrix& affineInverse(); + Point3F getScale() const; EulerF toEuler() const; @@ -906,6 +914,26 @@ inline Matrix& Matrix::identity() return (*this); } +template +inline void Matrix::normalize() +{ + AssertFatal(rows >= 3 && cols >= 3, "Normalize can only be applied 3x3 or more"); + Point3F col0, col1, col2; + getColumn(0, &col0); + getColumn(1, &col1); + + mCross(col0, col1, &col2); + mCross(col2, col0, &col1); + + col0.normalize(); + col1.normalize(); + col2.normalize(); + + setColumn(0, col0); + setColumn(1, col1); + setColumn(2, col2); +} + template inline Matrix& Matrix::scale(const Point3F& s) { From 888332a85c647b0d981d40ce12d272d574e40903 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 28 Jul 2024 14:35:34 +0100 Subject: [PATCH 07/29] rest of the implementation apparently templated classes need all functions to be inline, otherwise unresolved symbols macro for switching between matrixf and templated few functions that were missed --- Engine/source/T3D/gameBase/gameConnection.h | 6 +- Engine/source/T3D/physics/physicsCollision.h | 7 +- Engine/source/T3D/physics/physicsObject.h | 7 +- Engine/source/console/propertyParsing.h | 5 + Engine/source/core/stream/bitStream.h | 5 + Engine/source/gfx/gfxShader.h | 5 + Engine/source/math/mAngAxis.h | 6 + Engine/source/math/mBox.h | 5 + Engine/source/math/mMatrix.cpp | 427 +------------- Engine/source/math/mMatrix.h | 583 ++++++++++++++++++- Engine/source/math/mOrientedBox.h | 5 + Engine/source/math/mQuat.h | 5 + Engine/source/math/mathTypes.cpp | 13 +- Engine/source/math/mathTypes.h | 5 + Engine/source/scene/sgUtil.h | 5 + 15 files changed, 652 insertions(+), 437 deletions(-) diff --git a/Engine/source/T3D/gameBase/gameConnection.h b/Engine/source/T3D/gameBase/gameConnection.h index c9e32e14b..61558be3d 100644 --- a/Engine/source/T3D/gameBase/gameConnection.h +++ b/Engine/source/T3D/gameBase/gameConnection.h @@ -52,8 +52,12 @@ enum GameConnectionConstants class IDisplayDevice; class SFXProfile; +#ifndef USE_TEMPLATE_MATRIX class MatrixF; -class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class Point3F; class MoveManager; class MoveList; diff --git a/Engine/source/T3D/physics/physicsCollision.h b/Engine/source/T3D/physics/physicsCollision.h index d6e51f843..0f4e5a095 100644 --- a/Engine/source/T3D/physics/physicsCollision.h +++ b/Engine/source/T3D/physics/physicsCollision.h @@ -28,7 +28,12 @@ #endif class Point3F; +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class PlaneF; @@ -84,4 +89,4 @@ public: const MatrixF &localXfm ) = 0; }; -#endif // _T3D_PHYSICS_PHYSICSCOLLISION_H_ \ No newline at end of file +#endif // _T3D_PHYSICS_PHYSICSCOLLISION_H_ diff --git a/Engine/source/T3D/physics/physicsObject.h b/Engine/source/T3D/physics/physicsObject.h index 12697ce96..4bc7a38f3 100644 --- a/Engine/source/T3D/physics/physicsObject.h +++ b/Engine/source/T3D/physics/physicsObject.h @@ -34,7 +34,12 @@ #endif class PhysicsWorld; +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class Point3F; class Box3F; @@ -88,4 +93,4 @@ protected: U32 mQueuedEvent; }; -#endif // _T3D_PHYSICS_PHYSICSOBJECT_H_ \ No newline at end of file +#endif // _T3D_PHYSICS_PHYSICSOBJECT_H_ diff --git a/Engine/source/console/propertyParsing.h b/Engine/source/console/propertyParsing.h index 90272f9da..f782df2b4 100644 --- a/Engine/source/console/propertyParsing.h +++ b/Engine/source/console/propertyParsing.h @@ -35,7 +35,12 @@ class RectI; class RectF; class Box3I; class Box3F; +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class AngAxisF; class QuatF; class String; diff --git a/Engine/source/core/stream/bitStream.h b/Engine/source/core/stream/bitStream.h index dc2107519..0fe5895d6 100644 --- a/Engine/source/core/stream/bitStream.h +++ b/Engine/source/core/stream/bitStream.h @@ -45,7 +45,12 @@ // class Point3F; +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class HuffmanProcessor; class BitVector; class QuatF; diff --git a/Engine/source/gfx/gfxShader.h b/Engine/source/gfx/gfxShader.h index b7f23a9e3..edb20a127 100644 --- a/Engine/source/gfx/gfxShader.h +++ b/Engine/source/gfx/gfxShader.h @@ -60,7 +60,12 @@ class Point2I; class Point2F; class LinearColorF; +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class GFXShader; class GFXVertexFormat; diff --git a/Engine/source/math/mAngAxis.h b/Engine/source/math/mAngAxis.h index a5adca3a7..02845902b 100644 --- a/Engine/source/math/mAngAxis.h +++ b/Engine/source/math/mAngAxis.h @@ -27,7 +27,13 @@ #include "math/mPoint3.h" #endif +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif + class QuatF; //---------------------------------------------------------------------------- diff --git a/Engine/source/math/mBox.h b/Engine/source/math/mBox.h index b81775bb0..1cff4ccc9 100644 --- a/Engine/source/math/mBox.h +++ b/Engine/source/math/mBox.h @@ -36,7 +36,12 @@ #endif +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class SphereF; diff --git a/Engine/source/math/mMatrix.cpp b/Engine/source/math/mMatrix.cpp index 0a152ad6c..727caab42 100644 --- a/Engine/source/math/mMatrix.cpp +++ b/Engine/source/math/mMatrix.cpp @@ -29,6 +29,8 @@ #include "console/enginePrimitives.h" #include "console/engineTypes.h" +#ifndef USE_TEMPLATE_MATRIX + const MatrixF MatrixF::Identity( true ); // idx(i,j) is index to element in column i, row j @@ -210,428 +212,11 @@ EngineFieldTable::Field MatrixFEngineExport::getMatrixField() return _FIELD_AS(F32, m, m, 16, ""); } +#else // !USE_TEMPLATE_MATRIX + //------------------------------------ // Templatized matrix class to replace MATRIXF above +// due to templated class, all functions need to be inline //------------------------------------ -template -const Matrix Matrix::Identity = []() { - Matrix identity(true); - return identity; -}(); - -template -Matrix::Matrix(const EulerF& e) -{ - set(e); -} - -template -Matrix& Matrix::set(const EulerF& e) -{ - // when the template refactor is done, euler will be able to be setup in different ways - AssertFatal(rows >= 3 && cols >= 3, "EulerF can only initialize 3x3 or more"); - static_assert(std::is_same::value, "Can only initialize eulers with floats for now"); - - F32 cosPitch, sinPitch; - mSinCos(e.x, sinPitch, cosPitch); - - F32 cosYaw, sinYaw; - mSinCos(e.y, sinYaw, cosYaw); - - F32 cosRoll, sinRoll; - mSinCos(e.z, sinRoll, cosRoll); - - enum { - AXIS_X = (1 << 0), - AXIS_Y = (1 << 1), - AXIS_Z = (1 << 2) - }; - - U32 axis = 0; - if (e.x != 0.0f) axis |= AXIS_X; - if (e.y != 0.0f) axis |= AXIS_Y; - if (e.z != 0.0f) axis |= AXIS_Z; - - switch (axis) { - case 0: - (*this) = Matrix(true); - break; - case AXIS_X: - (*this)(0, 0) = 1.0f; (*this)(1, 0) = 0.0f; (*this)(2, 0) = 0.0f; - (*this)(0, 1) = 0.0f; (*this)(1, 1) = cosPitch; (*this)(2, 1) = -sinPitch; - (*this)(0, 2) = 0.0f; (*this)(1, 2) = sinPitch; (*this)(2, 2) = cosPitch; - break; - case AXIS_Y: - (*this)(0, 0) = cosYaw; (*this)(1, 0) = 0.0f; (*this)(2, 0) = sinYaw; - (*this)(0, 1) = 0.0f; (*this)(1, 1) = 1.0f; (*this)(2, 1) = 0.0f; - (*this)(0, 2) = -sinYaw; (*this)(1, 2) = 0.0f; (*this)(2, 2) = cosYaw; - break; - case AXIS_Z: - (*this)(0, 0) = cosRoll; (*this)(1, 0) = -sinRoll; (*this)(2, 0) = 0.0f; - (*this)(0, 1) = sinRoll; (*this)(1, 1) = cosRoll; (*this)(2, 1) = 0.0f; - (*this)(0, 2) = 0.0f; (*this)(1, 2) = 0.0f; (*this)(2, 2) = 0.0f; - break; - default: - F32 r1 = cosYaw * cosRoll; - F32 r2 = cosYaw * sinRoll; - F32 r3 = sinYaw * cosRoll; - F32 r4 = sinYaw * sinRoll; - - // the matrix looks like this: - // r1 - (r4 * sin(x)) r2 + (r3 * sin(x)) -cos(x) * sin(y) - // -cos(x) * sin(z) cos(x) * cos(z) sin(x) - // r3 + (r2 * sin(x)) r4 - (r1 * sin(x)) cos(x) * cos(y) - // - // where: - // r1 = cos(y) * cos(z) - // r2 = cos(y) * sin(z) - // r3 = sin(y) * cos(z) - // r4 = sin(y) * sin(z) - - // init the euler 3x3 rotation matrix. - (*this)(0, 0) = r1 - (r4 * sinPitch); (*this)(1, 0) = -cosPitch * sinRoll; (*this)(2, 0) = r3 + (r2 * sinPitch); - (*this)(0, 1) = r2 + (r3 * sinPitch); (*this)(1, 1) = cosPitch * cosRoll; (*this)(2, 1) = r4 - (r1 * sinPitch); - (*this)(0, 2) = -cosPitch * sinYaw; (*this)(1, 2) = sinPitch; (*this)(2, 2) = cosPitch * cosYaw; - break; - } - - if (rows == 4) { - (*this)(3, 0) = 0.0f; - (*this)(3, 1) = 0.0f; - (*this)(3, 2) = 0.0f; - } - - if (cols == 4) { - (*this)(0, 3) = 0.0f; - (*this)(1, 3) = 0.0f; - (*this)(2, 3) = 0.0f; - } - - if (rows == 4 && cols == 4) { - (*this)(3, 3) = 1.0f; - } - - return(*this); -} - -template -Matrix::Matrix(const EulerF& e, const Point3F p) -{ - set(e, p); -} - -template -Matrix& Matrix::set(const EulerF& e, const Point3F p) -{ - AssertFatal(rows >= 3 && cols >= 4, "Euler and Point can only initialize 3x4 or more"); - // call set euler, this already sets the last row if it exists. - set(e); - - // does this need to multiply with the result of the euler? or are we just setting position. - (*this)(0, 3) = p.x; - (*this)(1, 3) = p.y; - (*this)(2, 3) = p.z; - - return (*this); -} - -template -Matrix& Matrix::inverse() -{ - // TODO: insert return statement here - AssertFatal(rows == cols, "Can only perform inverse on square matrices."); - const U32 size = rows; - - // Create augmented matrix [this | I] - Matrix augmentedMatrix; - Matrix resultMatrix; - - for (U32 i = 0; i < size; i++) { - for (U32 j = 0; j < size; j++) { - augmentedMatrix(i, j) = (*this)(i, j); - augmentedMatrix(i, j + size) = (i == j) ? static_cast(1) : static_cast(0); - } - } - - // Apply gauss-joran elimination - for (U32 i = 0; i < size; i++) { - U32 pivotRow = i; - - for (U32 k = i + 1; k < size; k++) { - // use std::abs until the templated math functions are in place. - if (std::abs(augmentedMatrix(k, i)) > std::abs(augmentedMatrix(pivotRow, i))) { - pivotRow = k; - } - } - - // Swap if needed. - if (i != pivotRow) { - for (U32 j = 0; j < 2 * size; j++) { - std::swap(augmentedMatrix(i, j), augmentedMatrix(pivotRow, j)); - } - } - - // Early out if pivot is 0, return identity matrix. - if (augmentedMatrix(i, i) == static_cast(0)) { - return Matrix(true); - } - - DATA_TYPE pivotVal = augmentedMatrix(i, i); - - // scale the pivot - for (U32 j = 0; j < 2 * size; j++) { - augmentedMatrix(i, j) /= pivotVal; - } - - // Eliminate the current column in all other rows - for (U32 k = 0; k < size; k++) { - if (k != i) { - DATA_TYPE factor = augmentedMatrix(k, i); - for (U32 j = 0; j < 2 * size; j++) { - augmentedMatrix(k, j) -= factor * augmentedMatrix(i, j); - } - } - } - } - - for (U32 i = 0; i < size; i++) { - for (U32 j = 0; j < size; j++) { - resultMatrix(i, j) = augmentedMatrix(i, j + size); - } - } - - return resultMatrix; -} - -template -void Matrix::invert() -{ - (*this) = inverse(); -} - -template -Matrix& Matrix::setCrossProduct(const Point3F& p) -{ - AssertFatal(rows == 4 && cols == 4, "Cross product only supported on 4x4 for now"); - - (*this)(0, 0) = 0; - (*this)(0, 1) = -p.z; - (*this)(0, 2) = p.y; - (*this)(0, 3) = 0; - - (*this)(1, 0) = p.z; - (*this)(1, 1) = 0; - (*this)(1, 2) = -p.x; - (*this)(1, 3) = 0; - - (*this)(2, 0) = -p.y; - (*this)(2, 1) = p.x; - (*this)(2, 2) = 0; - (*this)(2, 3) = 0; - - (*this)(3, 0) = 0; - (*this)(3, 1) = 0; - (*this)(3, 2) = 0; - (*this)(3, 3) = 1; - - return (*this); -} - -template -Matrix& Matrix::setTensorProduct(const Point3F& p, const Point3F& q) -{ - AssertFatal(rows == 4 && cols == 4, "Tensor product only supported on 4x4 for now"); - - (*this)(0, 0) = p.x * q.x; - (*this)(0, 1) = p.x * q.y; - (*this)(0, 2) = p.x * q.z; - (*this)(0, 3) = 0; - - (*this)(1, 0) = p.y * q.x; - (*this)(1, 1) = p.y * q.y; - (*this)(1, 2) = p.y * q.z; - (*this)(1, 3) = 0; - - (*this)(2, 0) = p.z * q.x; - (*this)(2, 1) = p.z * q.y; - (*this)(2, 2) = p.z * q.z; - (*this)(2, 3) = 0; - - (*this)(3, 0) = 0; - (*this)(3, 1) = 0; - (*this)(3, 2) = 0; - (*this)(3, 3) = 1; - - return (*this); -} - -template -void Matrix::mul(Box3F& box) const -{ - AssertFatal(rows == 4 && cols == 4, "Multiplying Box3F with matrix requires 4x4"); - - // Create an array of all 8 corners of the box - Point3F corners[8] = { - Point3F(box.minExtents.x, box.minExtents.y, box.minExtents.z), - Point3F(box.minExtents.x, box.minExtents.y, box.maxExtents.z), - Point3F(box.minExtents.x, box.maxExtents.y, box.minExtents.z), - Point3F(box.minExtents.x, box.maxExtents.y, box.maxExtents.z), - Point3F(box.maxExtents.x, box.minExtents.y, box.minExtents.z), - Point3F(box.maxExtents.x, box.minExtents.y, box.maxExtents.z), - Point3F(box.maxExtents.x, box.maxExtents.y, box.minExtents.z), - Point3F(box.maxExtents.x, box.maxExtents.y, box.maxExtents.z), - }; - - for (U32 i = 0; i < 8; i++) { - corners[i] = (*this) * corners[i]; - } - - box.minExtents = corners[0]; - box.maxExtents = corners[0]; - for (U32 i = 1; i < 8; ++i) { - box.minExtents.x = mMin(box.minExtents.x, corners[i].x); - box.minExtents.y = mMin(box.minExtents.y, corners[i].y); - box.minExtents.z = mMin(box.minExtents.z, corners[i].z); - - box.maxExtents.x = mMax(box.maxExtents.x, corners[i].x); - box.maxExtents.y = mMax(box.maxExtents.y, corners[i].y); - box.maxExtents.z = mMax(box.maxExtents.z, corners[i].z); - } -} - -template -bool Matrix::isAffine() const -{ - if ((*this)(rows - 1, cols - 1) != 1.0f) { - return false; - } - - for (U32 col = 0; col < cols - 1; ++col) { - if ((*this)(rows - 1, col) != 0.0f) { - return false; - } - } - - Point3F one, two, three; - getColumn(0, &one); - getColumn(1, &two); - getColumn(2, &three); - - // check columns - { - if (mDot(one, two) > 0.0001f || - mDot(one, three) > 0.0001f || - mDot(two, three) > 0.0001f) - return false; - - if (mFabs(1.0f - one.lenSquared()) > 0.0001f || - mFabs(1.0f - two.lenSquared()) > 0.0001f || - mFabs(1.0f - three.lenSquared()) > 0.0001f) - return false; - } - - getRow(0, &one); - getRow(1, &two); - getRow(2, &three); - // check rows - { - if (mDot(one, two) > 0.0001f || - mDot(one, three) > 0.0001f || - mDot(two, three) > 0.0001f) - return false; - - if (mFabs(1.0f - one.lenSquared()) > 0.0001f || - mFabs(1.0f - two.lenSquared()) > 0.0001f || - mFabs(1.0f - three.lenSquared()) > 0.0001f) - return false; - } - - return true; -} - -template -Matrix& Matrix::affineInverse() -{ - AssertFatal(rows >= 4 && cols >= 4, "affineInverse requires at least 4x4"); - Matrix subMatrix; - - for (U32 i = 0; i < 3; i++) { - for (U32 j = 0; j < 3; j++) { - subMatrix(i, j) = (*this)(i, j); - } - } - - subMatrix.transpose(); - - Point3F pos = getPosition(); - (*this)(0, 3) = mDot(subMatrix.getColumn3F(0), pos); - (*this)(1, 3) = mDot(subMatrix.getColumn3F(1), pos); - (*this)(2, 3) = mDot(subMatrix.getColumn3F(2), pos); - - return *this; -} - -template -EulerF Matrix::toEuler() const -{ - AssertFatal(rows >= 3 && cols >= 3, "Euler rotations require at least a 3x3 matrix."); - // Extract rotation matrix components - const DATA_TYPE m00 = (*this)(0, 0); - const DATA_TYPE m01 = (*this)(0, 1); - const DATA_TYPE m02 = (*this)(0, 2); - const DATA_TYPE m10 = (*this)(1, 0); - const DATA_TYPE m11 = (*this)(1, 1); - const DATA_TYPE m21 = (*this)(2, 1); - const DATA_TYPE m22 = (*this)(2, 2); - - // like all others assume float for now. - EulerF r; - - r.x = mAsin(mClampF(m21, -1.0, 1.0)); - if (mCos(r.x) != 0.0f) { - r.y = mAtan2(-m02, m22); // yaw - r.z = mAtan2(-m10, m11); // roll - } - else { - r.y = 0.0f; - r.z = mAtan2(m01, m00); // this rolls when pitch is +90 degrees - } - - return r; -} - -template -void Matrix::dumpMatrix(const char* caption) const -{ - U32 size = (caption == NULL) ? 0 : dStrlen(caption); - FrameTemp spacer(size + 1); - char* spacerRef = spacer; - - // is_floating_point should return true for floats and doubles. - const char* formatSpec = std::is_floating_point_v ? " %-8.4f" : " %d"; - - dMemset(spacerRef, ' ', size); - // null terminate. - spacerRef[size] = '\0'; - - /*Con::printf("%s = | %-8.4f %-8.4f %-8.4f %-8.4f |", caption, m[idx(0, 0)], m[idx(0, 1)], m[idx(0, 2)], m[idx(0, 3)]); - Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(1, 0)], m[idx(1, 1)], m[idx(1, 2)], m[idx(1, 3)]); - Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(2, 0)], m[idx(2, 1)], m[idx(2, 2)], m[idx(2, 3)]); - Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(3, 0)], m[idx(3, 1)], m[idx(3, 2)], m[idx(3, 3)]);*/ - - StringBuilder str; - str.format("%s = |", caption); - for (U32 i = 0; i < rows; i++) { - if (i > 0) { - str.append(spacerRef); - } - - for (U32 j = 0; j < cols; j++) { - str.format(formatSpec, (*this)(i, j)); - } - str.append(" |\n"); - } - - Con::printf("%s", str.end().c_str()); -} +#endif // !USE_TEMPLATE_MATRIX diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index fe715298e..503ede5a0 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -39,6 +39,7 @@ #include "console/engineTypeInfo.h" #endif +#ifndef USE_TEMPLATE_MATRIX /// 4x4 Matrix Class /// @@ -620,6 +621,8 @@ inline void mTransformPlane(const MatrixF& mat, const Point3F& scale, const Plan m_matF_x_scale_x_planeF(mat, &scale.x, &plane.x, &result->x); } +#else // !USE_TEMPLATE_MATRIX + //------------------------------------ // Templatized matrix class to replace MATRIXF above //------------------------------------ @@ -652,7 +655,7 @@ public: explicit Matrix(const EulerF& e); /// Make this an identity matrix. Matrix& identity(); - + void reverseProjection(); void normalize(); Matrix& set(const EulerF& e); @@ -660,7 +663,7 @@ public: Matrix(const EulerF& e, const Point3F p); Matrix& set(const EulerF& e, const Point3F p); - Matrix& inverse(); + Matrix inverse(); Matrix& transpose(); void invert(); @@ -673,13 +676,18 @@ public: void setColumn(S32 col, const Point4F& cptr); void setColumn(S32 col, const Point3F& cptr); - void setRow(S32 row, const Point4F& cptr); void setRow(S32 row, const Point3F& cptr); + void displace(const Point3F& delta); + bool fullInverse(); + + void setPosition(const Point3F& pos) { setColumn(3, pos); } ///< M * a -> M Matrix& mul(const Matrix& a) - { return *this * a; } + { + *this = *this * a; return *this; + } ///< a * M -> M Matrix& mulL(const Matrix& a) { return *this = a * *this; } @@ -732,13 +740,23 @@ public: void mul(Box3F& box) const; // ------ Getters ------ + bool isNaN() { + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + if (mIsNaN_F((*this)(i, j))) + return true; + } + } + + return false; + } // col * rows + row - // static U32 idx(U32 i, U32 j) { return (i * rows + j); } + static U32 idx(U32 i, U32 j) { return (i * rows + j); } bool isAffine() const; bool isIdentity() const; /// Take inverse of matrix assuming it is affine (rotation, /// scale, sheer, translation only). - Matrix& affineInverse(); + Matrix affineInverse(); Point3F getScale() const; @@ -758,6 +776,10 @@ public: void getRow(S32 row, Point3F* cptr) const; Point3F getRow3F(S32 row) const { Point3F ret; getRow(row, &ret); return ret; } + VectorF getRightVector() const; + VectorF getForwardVector() const; + VectorF getUpVector() const; + DATA_TYPE* getData() { return data; } @@ -766,6 +788,24 @@ public: return data; } + void transposeTo(Matrix& matrix) const { + for (U32 i = 0; i < rows; ++i) { + for (U32 j = 0; j < cols; ++j) { + matrix(j, i) = (*this)(i, j); + } + } + } + + void invertTo(Matrix* matrix) { + Matrix invMatrix = this->inverse(); + + for (U32 i = 0; i < rows; ++i) { + for (U32 j = 0; j < cols; ++j) { + (*matrix)(j, i) = invMatrix(i, j); + } + } + } + void dumpMatrix(const char* caption = NULL) const; // Static identity matrix static const Matrix Identity; @@ -1093,6 +1133,30 @@ inline void Matrix::getRow(S32 row, Point3F* cptr) const cptr->z = 0.0f; } +template +inline VectorF Matrix::getRightVector() const +{ + VectorF vec; + getColumn(0, &vec); + return vec; +} + +template +inline VectorF Matrix::getForwardVector() const +{ + VectorF vec; + getColumn(1, &vec); + return vec; +} + +template +inline VectorF Matrix::getUpVector() const +{ + VectorF vec; + getColumn(2, &vec); + return vec; +} + template inline void Matrix::setRow(S32 row, const Point4F& cptr) { if(cols >= 2) @@ -1121,11 +1185,514 @@ inline void Matrix::setRow(S32 row, const Point3F& cptr) } +template +inline void Matrix::displace(const Point3F& delta) +{ + (*this)(0, 3) += delta.x; + (*this)(1, 3) += delta.y; + (*this)(2, 3) += delta.z; +} + + +template +void Matrix::reverseProjection() +{ + AssertFatal(rows == 4 && cols == 4, "reverseProjection requires a 4x4 matrix."); + + (*this)(2, 0) = (*this)(3, 0) - (*this)(2, 0); + (*this)(2, 1) = (*this)(3, 1) - (*this)(2, 1); + (*this)(2, 2) = (*this)(3, 2) - (*this)(2, 2); + (*this)(2, 3) = (*this)(3, 3) - (*this)(2, 3); +} + +template +const Matrix Matrix::Identity = []() { + Matrix identity(true); + return identity; +}(); + +template +Matrix::Matrix(const EulerF& e) +{ + set(e); +} + +template +Matrix& Matrix::set(const EulerF& e) +{ + // when the template refactor is done, euler will be able to be setup in different ways + AssertFatal(rows >= 3 && cols >= 3, "EulerF can only initialize 3x3 or more"); + static_assert(std::is_same::value, "Can only initialize eulers with floats for now"); + + F32 cosPitch, sinPitch; + mSinCos(e.x, sinPitch, cosPitch); + + F32 cosYaw, sinYaw; + mSinCos(e.y, sinYaw, cosYaw); + + F32 cosRoll, sinRoll; + mSinCos(e.z, sinRoll, cosRoll); + + enum { + AXIS_X = (1 << 0), + AXIS_Y = (1 << 1), + AXIS_Z = (1 << 2) + }; + + U32 axis = 0; + if (e.x != 0.0f) axis |= AXIS_X; + if (e.y != 0.0f) axis |= AXIS_Y; + if (e.z != 0.0f) axis |= AXIS_Z; + + switch (axis) { + case 0: + (*this) = Matrix(true); + break; + case AXIS_X: + (*this)(0, 0) = 1.0f; (*this)(1, 0) = 0.0f; (*this)(2, 0) = 0.0f; + (*this)(0, 1) = 0.0f; (*this)(1, 1) = cosPitch; (*this)(2, 1) = -sinPitch; + (*this)(0, 2) = 0.0f; (*this)(1, 2) = sinPitch; (*this)(2, 2) = cosPitch; + break; + case AXIS_Y: + (*this)(0, 0) = cosYaw; (*this)(1, 0) = 0.0f; (*this)(2, 0) = sinYaw; + (*this)(0, 1) = 0.0f; (*this)(1, 1) = 1.0f; (*this)(2, 1) = 0.0f; + (*this)(0, 2) = -sinYaw; (*this)(1, 2) = 0.0f; (*this)(2, 2) = cosYaw; + break; + case AXIS_Z: + (*this)(0, 0) = cosRoll; (*this)(1, 0) = -sinRoll; (*this)(2, 0) = 0.0f; + (*this)(0, 1) = sinRoll; (*this)(1, 1) = cosRoll; (*this)(2, 1) = 0.0f; + (*this)(0, 2) = 0.0f; (*this)(1, 2) = 0.0f; (*this)(2, 2) = 0.0f; + break; + default: + F32 r1 = cosYaw * cosRoll; + F32 r2 = cosYaw * sinRoll; + F32 r3 = sinYaw * cosRoll; + F32 r4 = sinYaw * sinRoll; + + // the matrix looks like this: + // r1 - (r4 * sin(x)) r2 + (r3 * sin(x)) -cos(x) * sin(y) + // -cos(x) * sin(z) cos(x) * cos(z) sin(x) + // r3 + (r2 * sin(x)) r4 - (r1 * sin(x)) cos(x) * cos(y) + // + // where: + // r1 = cos(y) * cos(z) + // r2 = cos(y) * sin(z) + // r3 = sin(y) * cos(z) + // r4 = sin(y) * sin(z) + + // init the euler 3x3 rotation matrix. + (*this)(0, 0) = r1 - (r4 * sinPitch); (*this)(1, 0) = -cosPitch * sinRoll; (*this)(2, 0) = r3 + (r2 * sinPitch); + (*this)(0, 1) = r2 + (r3 * sinPitch); (*this)(1, 1) = cosPitch * cosRoll; (*this)(2, 1) = r4 - (r1 * sinPitch); + (*this)(0, 2) = -cosPitch * sinYaw; (*this)(1, 2) = sinPitch; (*this)(2, 2) = cosPitch * cosYaw; + break; + } + + if (rows == 4) { + (*this)(3, 0) = 0.0f; + (*this)(3, 1) = 0.0f; + (*this)(3, 2) = 0.0f; + } + + if (cols == 4) { + (*this)(0, 3) = 0.0f; + (*this)(1, 3) = 0.0f; + (*this)(2, 3) = 0.0f; + } + + if (rows == 4 && cols == 4) { + (*this)(3, 3) = 1.0f; + } + + return(*this); +} + +template +Matrix::Matrix(const EulerF& e, const Point3F p) +{ + set(e, p); +} + +template +Matrix& Matrix::set(const EulerF& e, const Point3F p) +{ + AssertFatal(rows >= 3 && cols >= 4, "Euler and Point can only initialize 3x4 or more"); + // call set euler, this already sets the last row if it exists. + set(e); + + // does this need to multiply with the result of the euler? or are we just setting position. + (*this)(0, 3) = p.x; + (*this)(1, 3) = p.y; + (*this)(2, 3) = p.z; + + return (*this); +} + +template +Matrix Matrix::inverse() +{ + // TODO: insert return statement here + AssertFatal(rows == cols, "Can only perform inverse on square matrices."); + const U32 size = rows; + + // Create augmented matrix [this | I] + Matrix augmentedMatrix; + Matrix resultMatrix; + + for (U32 i = 0; i < size; i++) { + for (U32 j = 0; j < size; j++) { + augmentedMatrix(i, j) = (*this)(i, j); + augmentedMatrix(i, j + size) = (i == j) ? static_cast(1) : static_cast(0); + } + } + + // Apply gauss-joran elimination + for (U32 i = 0; i < size; i++) { + U32 pivotRow = i; + + for (U32 k = i + 1; k < size; k++) { + // use std::abs until the templated math functions are in place. + if (std::abs(augmentedMatrix(k, i)) > std::abs(augmentedMatrix(pivotRow, i))) { + pivotRow = k; + } + } + + // Swap if needed. + if (i != pivotRow) { + for (U32 j = 0; j < 2 * size; j++) { + std::swap(augmentedMatrix(i, j), augmentedMatrix(pivotRow, j)); + } + } + + // Early out if pivot is 0, return identity matrix. + if (augmentedMatrix(i, i) == static_cast(0)) { + return Matrix(true); + } + + DATA_TYPE pivotVal = augmentedMatrix(i, i); + + // scale the pivot + for (U32 j = 0; j < 2 * size; j++) { + augmentedMatrix(i, j) /= pivotVal; + } + + // Eliminate the current column in all other rows + for (U32 k = 0; k < size; k++) { + if (k != i) { + DATA_TYPE factor = augmentedMatrix(k, i); + for (U32 j = 0; j < 2 * size; j++) { + augmentedMatrix(k, j) -= factor * augmentedMatrix(i, j); + } + } + } + } + + for (U32 i = 0; i < size; i++) { + for (U32 j = 0; j < size; j++) { + resultMatrix(i, j) = augmentedMatrix(i, j + size); + } + } + + return resultMatrix; +} + +template +inline bool Matrix::fullInverse() +{ + Matrix inv = this->inverse(); + + if (inv.isIdentity()) + return false; + + *this = inv; + return true; +} + +template +inline void Matrix::invert() +{ + (*this) = inverse(); +} + +template +inline Matrix& Matrix::setCrossProduct(const Point3F& p) +{ + AssertFatal(rows == 4 && cols == 4, "Cross product only supported on 4x4 for now"); + + (*this)(0, 0) = 0; + (*this)(0, 1) = -p.z; + (*this)(0, 2) = p.y; + (*this)(0, 3) = 0; + + (*this)(1, 0) = p.z; + (*this)(1, 1) = 0; + (*this)(1, 2) = -p.x; + (*this)(1, 3) = 0; + + (*this)(2, 0) = -p.y; + (*this)(2, 1) = p.x; + (*this)(2, 2) = 0; + (*this)(2, 3) = 0; + + (*this)(3, 0) = 0; + (*this)(3, 1) = 0; + (*this)(3, 2) = 0; + (*this)(3, 3) = 1; + + return (*this); +} + +template +inline Matrix& Matrix::setTensorProduct(const Point3F& p, const Point3F& q) +{ + AssertFatal(rows == 4 && cols == 4, "Tensor product only supported on 4x4 for now"); + + (*this)(0, 0) = p.x * q.x; + (*this)(0, 1) = p.x * q.y; + (*this)(0, 2) = p.x * q.z; + (*this)(0, 3) = 0; + + (*this)(1, 0) = p.y * q.x; + (*this)(1, 1) = p.y * q.y; + (*this)(1, 2) = p.y * q.z; + (*this)(1, 3) = 0; + + (*this)(2, 0) = p.z * q.x; + (*this)(2, 1) = p.z * q.y; + (*this)(2, 2) = p.z * q.z; + (*this)(2, 3) = 0; + + (*this)(3, 0) = 0; + (*this)(3, 1) = 0; + (*this)(3, 2) = 0; + (*this)(3, 3) = 1; + + return (*this); +} + +template +inline void Matrix::mul(Box3F& box) const +{ + AssertFatal(rows == 4 && cols == 4, "Multiplying Box3F with matrix requires 4x4"); + + // Create an array of all 8 corners of the box + Point3F corners[8] = { + Point3F(box.minExtents.x, box.minExtents.y, box.minExtents.z), + Point3F(box.minExtents.x, box.minExtents.y, box.maxExtents.z), + Point3F(box.minExtents.x, box.maxExtents.y, box.minExtents.z), + Point3F(box.minExtents.x, box.maxExtents.y, box.maxExtents.z), + Point3F(box.maxExtents.x, box.minExtents.y, box.minExtents.z), + Point3F(box.maxExtents.x, box.minExtents.y, box.maxExtents.z), + Point3F(box.maxExtents.x, box.maxExtents.y, box.minExtents.z), + Point3F(box.maxExtents.x, box.maxExtents.y, box.maxExtents.z), + }; + + for (U32 i = 0; i < 8; i++) { + corners[i] = (*this) * corners[i]; + } + + box.minExtents = corners[0]; + box.maxExtents = corners[0]; + for (U32 i = 1; i < 8; ++i) { + box.minExtents.x = mMin(box.minExtents.x, corners[i].x); + box.minExtents.y = mMin(box.minExtents.y, corners[i].y); + box.minExtents.z = mMin(box.minExtents.z, corners[i].z); + + box.maxExtents.x = mMax(box.maxExtents.x, corners[i].x); + box.maxExtents.y = mMax(box.maxExtents.y, corners[i].y); + box.maxExtents.z = mMax(box.maxExtents.z, corners[i].z); + } +} + +template +inline bool Matrix::isAffine() const +{ + if ((*this)(rows - 1, cols - 1) != 1.0f) { + return false; + } + + for (U32 col = 0; col < cols - 1; ++col) { + if ((*this)(rows - 1, col) != 0.0f) { + return false; + } + } + + Point3F one, two, three; + getColumn(0, &one); + getColumn(1, &two); + getColumn(2, &three); + + // check columns + { + if (mDot(one, two) > 0.0001f || + mDot(one, three) > 0.0001f || + mDot(two, three) > 0.0001f) + return false; + + if (mFabs(1.0f - one.lenSquared()) > 0.0001f || + mFabs(1.0f - two.lenSquared()) > 0.0001f || + mFabs(1.0f - three.lenSquared()) > 0.0001f) + return false; + } + + getRow(0, &one); + getRow(1, &two); + getRow(2, &three); + // check rows + { + if (mDot(one, two) > 0.0001f || + mDot(one, three) > 0.0001f || + mDot(two, three) > 0.0001f) + return false; + + if (mFabs(1.0f - one.lenSquared()) > 0.0001f || + mFabs(1.0f - two.lenSquared()) > 0.0001f || + mFabs(1.0f - three.lenSquared()) > 0.0001f) + return false; + } + + return true; +} + +template +inline Matrix Matrix::affineInverse() +{ + AssertFatal(rows >= 4 && cols >= 4, "affineInverse requires at least 4x4"); + Matrix subMatrix; + + for (U32 i = 0; i < 3; i++) { + for (U32 j = 0; j < 3; j++) { + subMatrix(i, j) = (*this)(i, j); + } + } + + subMatrix.transpose(); + + Point3F pos = getPosition(); + (*this)(0, 3) = mDot(subMatrix.getColumn3F(0), pos); + (*this)(1, 3) = mDot(subMatrix.getColumn3F(1), pos); + (*this)(2, 3) = mDot(subMatrix.getColumn3F(2), pos); + + return *this; +} + +template +inline EulerF Matrix::toEuler() const +{ + AssertFatal(rows >= 3 && cols >= 3, "Euler rotations require at least a 3x3 matrix."); + // Extract rotation matrix components + const DATA_TYPE m00 = (*this)(0, 0); + const DATA_TYPE m01 = (*this)(0, 1); + const DATA_TYPE m02 = (*this)(0, 2); + const DATA_TYPE m10 = (*this)(1, 0); + const DATA_TYPE m11 = (*this)(1, 1); + const DATA_TYPE m21 = (*this)(2, 1); + const DATA_TYPE m22 = (*this)(2, 2); + + // like all others assume float for now. + EulerF r; + + r.x = mAsin(mClampF(m21, -1.0, 1.0)); + if (mCos(r.x) != 0.0f) { + r.y = mAtan2(-m02, m22); // yaw + r.z = mAtan2(-m10, m11); // roll + } + else { + r.y = 0.0f; + r.z = mAtan2(m01, m00); // this rolls when pitch is +90 degrees + } + + return r; +} + +template +inline void Matrix::dumpMatrix(const char* caption) const +{ + U32 size = (caption == NULL) ? 0 : dStrlen(caption); + FrameTemp spacer(size + 1); + char* spacerRef = spacer; + + // is_floating_point should return true for floats and doubles. + const char* formatSpec = std::is_floating_point_v ? " %-8.4f" : " %d"; + + dMemset(spacerRef, ' ', size); + // null terminate. + spacerRef[size] = '\0'; + + /*Con::printf("%s = | %-8.4f %-8.4f %-8.4f %-8.4f |", caption, m[idx(0, 0)], m[idx(0, 1)], m[idx(0, 2)], m[idx(0, 3)]); + Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(1, 0)], m[idx(1, 1)], m[idx(1, 2)], m[idx(1, 3)]); + Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(2, 0)], m[idx(2, 1)], m[idx(2, 2)], m[idx(2, 3)]); + Con::printf("%s | %-8.4f %-8.4f %-8.4f %-8.4f |", spacerRef, m[idx(3, 0)], m[idx(3, 1)], m[idx(3, 2)], m[idx(3, 3)]);*/ + + StringBuilder str; + str.format("%s = |", caption); + for (U32 i = 0; i < rows; i++) { + if (i > 0) { + str.append(spacerRef); + } + + for (U32 j = 0; j < cols; j++) { + str.format(formatSpec, (*this)(i, j)); + } + str.append(" |\n"); + } + + Con::printf("%s", str.end().c_str()); +} + +//------------------------------------ +// Non-member methods +//------------------------------------ + +template +inline void mTransformPlane( + const Matrix& mat, + const Point3F& scale, + const PlaneF& plane, + PlaneF* result +) { + AssertFatal(Rows == 4 && Cols == 4, "Matrix must be 4x4"); + + // Create a non-const copy of the matrix + Matrix matCopy = mat; + + // Create the inverse scale matrix + Matrix invScale = Matrix::Identity; + invScale(0, 0) = 1.0f / scale.x; + invScale(1, 1) = 1.0f / scale.y; + invScale(2, 2) = 1.0f / scale.z; + + // Compute the inverse transpose of the matrix + Matrix invTrMatrix = matCopy.transpose().affineInverse() * invScale; + + // Transform the plane normal + Point3F norm(plane.x, plane.y, plane.z); + norm = invTrMatrix * norm; + float normLength = std::sqrt(norm.x * norm.x + norm.y * norm.y + norm.z * norm.z); + norm.x /= normLength; + norm.y /= normLength; + norm.z /= normLength; + + // Transform the plane point + Point3F point = norm * (-plane.d); + Matrix temp = mat; + point.x *= scale.x; + point.y *= scale.y; + point.z *= scale.z; + point = temp * point; + + // Recompute the plane distance + PlaneF resultPlane(point, norm); + result->x = resultPlane.x; + result->y = resultPlane.y; + result->z = resultPlane.z; + result->d = resultPlane.d; +} + //-------------------------------------------- // INLINE FUNCTIONS END //-------------------------------------------- -typedef Matrix Matrix4F; +typedef Matrix MatrixF; class MatrixTemplateExport { @@ -1141,6 +1708,6 @@ inline EngineFieldTable::Field MatrixTemplateExport::getMatrixField() return _FIELD_AS(T, data, data, rows * cols, ""); } - +#endif // !USE_TEMPLATE_MATRIX #endif //_MMATRIX_H_ diff --git a/Engine/source/math/mOrientedBox.h b/Engine/source/math/mOrientedBox.h index 422dd8f27..9af32874e 100644 --- a/Engine/source/math/mOrientedBox.h +++ b/Engine/source/math/mOrientedBox.h @@ -32,7 +32,12 @@ #endif +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class Box3F; diff --git a/Engine/source/math/mQuat.h b/Engine/source/math/mQuat.h index d713b405d..1af1a5a95 100644 --- a/Engine/source/math/mQuat.h +++ b/Engine/source/math/mQuat.h @@ -27,7 +27,12 @@ #include "math/mPoint3.h" #endif +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class AngAxisF; //---------------------------------------------------------------------------- diff --git a/Engine/source/math/mathTypes.cpp b/Engine/source/math/mathTypes.cpp index 751f3e31b..ef7616340 100644 --- a/Engine/source/math/mathTypes.cpp +++ b/Engine/source/math/mathTypes.cpp @@ -101,6 +101,7 @@ IMPLEMENT_STRUCT( RectF, FIELD( extent, extent, 1, "The width and height of the Rect.") END_IMPLEMENT_STRUCT; +#ifndef USE_TEMPLATE_MATRIX IMPLEMENT_STRUCT( MatrixF, MatrixF, MathTypes, "" ) @@ -108,13 +109,15 @@ IMPLEMENT_STRUCT( MatrixF, MatrixFEngineExport::getMatrixField(), END_IMPLEMENT_STRUCT; -IMPLEMENT_STRUCT(Matrix4F, - Matrix4F, MathTypes, - "") +#else +IMPLEMENT_STRUCT(MatrixF, +MatrixF, MathTypes, +"") - MatrixTemplateExport::getMatrixField(), +MatrixTemplateExport::getMatrixField(), - END_IMPLEMENT_STRUCT; +END_IMPLEMENT_STRUCT; +#endif IMPLEMENT_STRUCT( AngAxisF, AngAxisF, MathTypes, "" ) diff --git a/Engine/source/math/mathTypes.h b/Engine/source/math/mathTypes.h index 043d59e1f..08818f685 100644 --- a/Engine/source/math/mathTypes.h +++ b/Engine/source/math/mathTypes.h @@ -38,7 +38,12 @@ class Point3F; class Point4F; class RectI; class RectF; +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class Box3F; class EaseF; class AngAxisF; diff --git a/Engine/source/scene/sgUtil.h b/Engine/source/scene/sgUtil.h index be83c7c57..4a5b982eb 100644 --- a/Engine/source/scene/sgUtil.h +++ b/Engine/source/scene/sgUtil.h @@ -32,7 +32,12 @@ class Frustum; class RectI; +#ifndef USE_TEMPLATE_MATRIX class MatrixF; +#else +template class Matrix; +typedef Matrix MatrixF; +#endif class PlaneF; struct SGWinding From c61d36b799ea9f8b24e3525d8db99510a2e303fc Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 28 Jul 2024 19:36:07 +0100 Subject: [PATCH 08/29] closest backup closest working example, no errors or warnings from compile, matrices arent correct though yet. --- Engine/source/math/mMatrix.h | 52 +++++++++++++++---- .../math/util/matrixSetDelegateMethods.h | 25 ++++++++- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 503ede5a0..29e39c276 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -796,15 +796,8 @@ public: } } - void invertTo(Matrix* matrix) { - Matrix invMatrix = this->inverse(); - - for (U32 i = 0; i < rows; ++i) { - for (U32 j = 0; j < cols; ++j) { - (*matrix)(j, i) = invMatrix(i, j); - } - } - } + void invertTo(Matrix* matrix) const; + void invertTo(Matrix* matrix); void dumpMatrix(const char* caption = NULL) const; // Static identity matrix @@ -1157,6 +1150,47 @@ inline VectorF Matrix::getUpVector() const return vec; } +template +inline void Matrix::invertTo(Matrix* matrix) const +{ + Matrix invMatrix; + for (U32 i = 0; i < rows; ++i) { + for (U32 j = 0; j < cols; ++j) { + invMatrix(i, j) = (*this)(i, j); + } + } + + invMatrix.inverse(); + + for (U32 i = 0; i < rows; ++i) { + for (U32 j = 0; j < cols; ++j) { + (*matrix)(j, i) = invMatrix(i, j); + } + } + + (*matrix)(3, 0) = (*this)(3, 0); + (*matrix)(3, 1) = (*this)(3, 1); + (*matrix)(3, 2) = (*this)(3, 2); + (*matrix)(3, 3) = (*this)(3, 3); +} + +template +inline void Matrix::invertTo(Matrix* matrix) +{ + Matrix invMatrix = this->inverse(); + + for (U32 i = 0; i < rows; ++i) { + for (U32 j = 0; j < cols; ++j) { + (*matrix)(i, j) = invMatrix(i, j); + } + } + + (*matrix)(3, 0) = (*this)(3, 0); + (*matrix)(3, 1) = (*this)(3, 1); + (*matrix)(3, 2) = (*this)(3, 2); + (*matrix)(3, 3) = (*this)(3, 3); +} + template inline void Matrix::setRow(S32 row, const Point4F& cptr) { if(cols >= 2) diff --git a/Engine/source/math/util/matrixSetDelegateMethods.h b/Engine/source/math/util/matrixSetDelegateMethods.h index f5d237472..c2b375814 100644 --- a/Engine/source/math/util/matrixSetDelegateMethods.h +++ b/Engine/source/math/util/matrixSetDelegateMethods.h @@ -22,7 +22,7 @@ #ifndef _MATRIXSETDELEGATES_H_ #define _MATRIXSETDELEGATES_H_ - // Access to the direct value +#ifndef USE_TEMPLATE_MATRIX #define MATRIX_SET_GET_VALUE_FN(xfm) _transform_##xfm #define MATRIX_SET_GET_VALUE(xfm) inline const MatrixF &MATRIX_SET_GET_VALUE_FN(xfm)() { return mTransform[xfm]; } #define MATRIX_SET_BIND_VALUE(xfm) mEvalDelegate[xfm].bind(this, &MatrixSet::MATRIX_SET_GET_VALUE_FN(xfm)) @@ -44,5 +44,28 @@ return mTransform[matC]; \ } +#else + // Access to the direct value +#define MATRIX_SET_GET_VALUE_FN(xfm) _transform_##xfm +#define MATRIX_SET_GET_VALUE(xfm) inline const MatrixF &MATRIX_SET_GET_VALUE_FN(xfm)() { return mTransform[xfm]; } +#define MATRIX_SET_BIND_VALUE(xfm) mEvalDelegate[xfm].bind(this, &MatrixSet::MATRIX_SET_GET_VALUE_FN(xfm)) +#define MATRIX_SET_IS_INVERSE_OF_FN(inv_xfm, src_xfm) _##inv_xfm##_is_inverse_of_##src_xfm +#define MATRIX_SET_IS_INVERSE_OF(inv_xfm, src_xfm) inline const MatrixF &MATRIX_SET_IS_INVERSE_OF_FN(inv_xfm, src_xfm)() \ + { \ + mEvalDelegate[src_xfm]().invertTo(&mTransform[inv_xfm]); \ + MATRIX_SET_BIND_VALUE(inv_xfm); \ + return mTransform[inv_xfm]; \ + } + + +#define MATRIX_SET_MULT_ASSIGN_FN(matA, matB, matC) _##matC##_is_##matA##_x_##matB +#define MATRIX_SET_MULT_ASSIGN(matA, matB, matC) inline const MatrixF &MATRIX_SET_MULT_ASSIGN_FN(matA, matB, matC)() \ + { \ + mTransform[matC].mul(mEvalDelegate[matA](),mEvalDelegate[matB]()); \ + MATRIX_SET_BIND_VALUE(matC); \ + return mTransform[matC]; \ + } + +#endif #endif // _MATRIXSETDELEGATES_H_ From 504b549ac0d8121a005bbd440649d49fcbb15149 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 28 Jul 2024 19:38:02 +0100 Subject: [PATCH 09/29] Update mMatrix.h --- Engine/source/math/mMatrix.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 29e39c276..da8d2a6d3 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -1164,14 +1164,9 @@ inline void Matrix::invertTo(Matrix @@ -1184,11 +1179,6 @@ inline void Matrix::invertTo(Matrix From 2fa15191ae47d9757ab81ba495d80906549bebf2 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 28 Jul 2024 20:40:26 +0100 Subject: [PATCH 10/29] Update mMatrix.h most working example --- Engine/source/math/mMatrix.h | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index da8d2a6d3..4c6092fb5 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -750,8 +750,8 @@ public: return false; } - // col * rows + row - static U32 idx(U32 i, U32 j) { return (i * rows + j); } + // row + col * cols + static U32 idx(U32 i, U32 j) { return (i + j * cols); } bool isAffine() const; bool isIdentity() const; /// Take inverse of matrix assuming it is affine (rotation, @@ -893,14 +893,14 @@ public: if (row >= rows || col >= cols) AssertFatal(false, "Matrix indices out of range"); - return data[col * rows + row]; + return data[idx(col,row)]; } const DATA_TYPE& operator () (U32 row, U32 col) const { if (row >= rows || col >= cols) AssertFatal(false, "Matrix indices out of range"); - return data[col * rows + row]; + return data[idx(col, row)]; } }; @@ -911,23 +911,13 @@ public: template inline Matrix& Matrix::transpose() { - // square matrices can just swap, non square requires a temp mat. - if (rows == cols) { - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { - std::swap((*this)(j, i), (*this)(i, j)); - } + Matrix result; + for (U32 i = 0; i < rows; i++) { + for (U32 j = 0; j < cols; j++) { + result(j, i) = (*this)(i, j); } } - else { - Matrix result; - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { - result(j, i) = (*this)(i, j); - } - } - std::copy(std::begin(result.data), std::end(result.data), std::begin(data)); - } + std::copy(std::begin(result.data), std::end(result.data), std::begin(data)); return (*this); } From 75c5a0919b825d0613ec44fb6bbf78fdef8012cb Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 29 Jul 2024 16:39:08 +0100 Subject: [PATCH 11/29] Update mMatrix.h silence issues from macos clang --- Engine/source/math/mMatrix.h | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 4c6092fb5..d5c80482c 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -39,6 +39,18 @@ #include "console/engineTypeInfo.h" #endif +#ifndef _FRAMEALLOCATOR_H_ +#include "core/frameAllocator.h" +#endif + +#ifndef _STRINGFUNCTIONS_H_ +#include "core/strings/stringFunctions.h" +#endif + +#ifndef _CONSOLE_H_ +#include "console/console.h" +#endif + #ifndef USE_TEMPLATE_MATRIX /// 4x4 Matrix Class @@ -1657,26 +1669,23 @@ inline void Matrix::dumpMatrix(const char* caption) const // Non-member methods //------------------------------------ -template inline void mTransformPlane( - const Matrix& mat, + const MatrixF& mat, const Point3F& scale, const PlaneF& plane, PlaneF* result ) { - AssertFatal(Rows == 4 && Cols == 4, "Matrix must be 4x4"); - // Create a non-const copy of the matrix - Matrix matCopy = mat; + MatrixF matCopy = mat; // Create the inverse scale matrix - Matrix invScale = Matrix::Identity; + MatrixF invScale = MatrixF::Identity; invScale(0, 0) = 1.0f / scale.x; invScale(1, 1) = 1.0f / scale.y; invScale(2, 2) = 1.0f / scale.z; // Compute the inverse transpose of the matrix - Matrix invTrMatrix = matCopy.transpose().affineInverse() * invScale; + MatrixF invTrMatrix = matCopy.transpose().affineInverse() * invScale; // Transform the plane normal Point3F norm(plane.x, plane.y, plane.z); @@ -1688,7 +1697,7 @@ inline void mTransformPlane( // Transform the plane point Point3F point = norm * (-plane.d); - Matrix temp = mat; + MMatrixF temp = mat; point.x *= scale.x; point.y *= scale.y; point.z *= scale.z; From 54bb31c8bc223874db09fe04a45918ada6e7e4de Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 29 Jul 2024 17:24:23 +0100 Subject: [PATCH 12/29] Update mMatrix.h bracket lines change functions to match mmath_c to figure out where the issue is. --- Engine/source/math/mMatrix.h | 298 +++++++++++++++++++++-------------- 1 file changed, 176 insertions(+), 122 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index d5c80482c..4591df37d 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -664,7 +664,10 @@ public: } } - explicit Matrix(const EulerF& e); + explicit Matrix(const EulerF& e) { + set(e); + } + /// Make this an identity matrix. Matrix& identity(); void reverseProjection(); @@ -768,7 +771,7 @@ public: bool isIdentity() const; /// Take inverse of matrix assuming it is affine (rotation, /// scale, sheer, translation only). - Matrix affineInverse(); + Matrix& affineInverse(); Point3F getScale() const; @@ -816,15 +819,17 @@ public: static const Matrix Identity; // ------ Operators ------ - - Matrix operator * (const Matrix& other) const { + friend Matrix operator*(const Matrix& m1, const Matrix& m2) { Matrix result; - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { - result(i, j) = 0; - for (U32 k = 0; k < cols; k++) { - result(i, j) += (*this)(i, k) * other(k, j); + for (U32 i = 0; i < rows; ++i) + { + for (U32 j = 0; j < cols; ++j) + { + result(i, j) = 0; // Initialize result element to 0 + for (U32 k = 0; k < cols; ++k) + { + result(i, j) += m1(i, k) * m2(k, j); } } } @@ -839,8 +844,10 @@ public: Matrix operator * (const DATA_TYPE scalar) const { Matrix result; - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { + for (U32 i = 0; i < rows; i++) + { + for (U32 j = 0; j < cols; j++) + { result(i, j) = (*this)(i, j) * scalar; } } @@ -848,8 +855,10 @@ public: return result; } Matrix& operator *= (const DATA_TYPE scalar) { - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { + for (U32 i = 0; i < rows; i++) + { + for (U32 j = 0; j < cols; j++) + { (*this)(i, j) *= scalar; } } @@ -885,8 +894,10 @@ public: } bool operator == (const Matrix& other) const { - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { + for (U32 i = 0; i < rows; i++) + { + for (U32 j = 0; j < cols; j++) + { if ((*this)(i, j) != other(i, j)) return false; } @@ -923,22 +934,23 @@ public: template inline Matrix& Matrix::transpose() { - Matrix result; - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { - result(j, i) = (*this)(i, j); + AssertFatal(rows == cols, "Transpose can only be performed on square matrices."); + + for (U32 i = 0; i < rows; ++i) { + for (U32 j = i + 1; j < cols; ++j) { + std::swap((*this)(i, j), (*this)(j, i)); } } - std::copy(std::begin(result.data), std::end(result.data), std::begin(data)); - return (*this); } template inline Matrix& Matrix::identity() { - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { + for (U32 i = 0; i < rows; i++) + { + for (U32 j = 0; j < cols; j++) + { if (j == i) (*this)(i, j) = static_cast(1); else @@ -973,28 +985,33 @@ template inline Matrix& Matrix::scale(const Point3F& s) { // torques scale applies directly, does not create another matrix to multiply with the translation matrix. - AssertFatal(rows >= 3 && cols >= 3, "Scale can only be applied 3x3 or more"); - for (U32 i = 0; i < 3; i++) { - for (U32 j = 0; j < 3; j++) { - DATA_TYPE scale = (i == 0) ? s.x : (i == 1) ? s.y : s.z; - (*this)(i, j) *= scale; - } - } + AssertFatal(rows >= 4 && cols >= 4, "Scale can only be applied 4x4 or more"); + + (*this)(0, 0) *= s.x; (*this)(0, 1) *= s.y; (*this)(0, 2) *= s.z; + (*this)(1, 0) *= s.x; (*this)(1, 1) *= s.y; (*this)(1, 2) *= s.z; + (*this)(2, 0) *= s.x; (*this)(2, 1) *= s.y; (*this)(2, 2) *= s.z; + (*this)(3, 0) *= s.x; (*this)(3, 1) *= s.y; (*this)(3, 2) *= s.z; return (*this); } template inline bool Matrix::isIdentity() const { - for (U32 i = 0; i < rows; i++) { - for (U32 j = 0; j < cols; j++) { - if (j == i) { - if((*this)(i, j) != static_cast(1)) { + for (U32 i = 0; i < rows; i++) + { + for (U32 j = 0; j < cols; j++) + { + if (j == i) + { + if((*this)(i, j) != static_cast(1)) + { return false; } } - else { - if((*this)(i, j) != static_cast(0)) { + else + { + if((*this)(i, j) != static_cast(0)) + { return false; } } @@ -1009,7 +1026,7 @@ inline Point3F Matrix::getScale() const { // this function assumes the matrix has scale applied through the scale(const Point3F& s) function. // for now assume float since we have point3F. - AssertFatal(rows >= 3 && cols >= 3, "Scale can only be applied 3x3 or more"); + AssertFatal(rows >= 4 && cols >= 4, "Scale can only be applied 4x4 or more"); Point3F scale; @@ -1156,16 +1173,20 @@ template inline void Matrix::invertTo(Matrix* matrix) const { Matrix invMatrix; - for (U32 i = 0; i < rows; ++i) { - for (U32 j = 0; j < cols; ++j) { + for (U32 i = 0; i < rows; ++i) + { + for (U32 j = 0; j < cols; ++j) + { invMatrix(i, j) = (*this)(i, j); } } invMatrix.inverse(); - for (U32 i = 0; i < rows; ++i) { - for (U32 j = 0; j < cols; ++j) { + for (U32 i = 0; i < rows; ++i) + { + for (U32 j = 0; j < cols; ++j) + { (*matrix)(i, j) = invMatrix(i, j); } } @@ -1176,8 +1197,10 @@ inline void Matrix::invertTo(Matrix invMatrix = this->inverse(); - for (U32 i = 0; i < rows; ++i) { - for (U32 j = 0; j < cols; ++j) { + for (U32 i = 0; i < rows; ++i) + { + for (U32 j = 0; j < cols; ++j) + { (*matrix)(i, j) = invMatrix(i, j); } } @@ -1221,7 +1244,7 @@ inline void Matrix::displace(const Point3F& delta) template -void Matrix::reverseProjection() +inline void Matrix::reverseProjection() { AssertFatal(rows == 4 && cols == 4, "reverseProjection requires a 4x4 matrix."); @@ -1238,13 +1261,7 @@ const Matrix Matrix::Identity = [] }(); template -Matrix::Matrix(const EulerF& e) -{ - set(e); -} - -template -Matrix& Matrix::set(const EulerF& e) +inline Matrix& Matrix::set(const EulerF& e) { // when the template refactor is done, euler will be able to be setup in different ways AssertFatal(rows >= 3 && cols >= 3, "EulerF can only initialize 3x3 or more"); @@ -1313,19 +1330,22 @@ Matrix& Matrix::set(const EulerF& break; } - if (rows == 4) { + if (rows == 4) + { (*this)(3, 0) = 0.0f; (*this)(3, 1) = 0.0f; (*this)(3, 2) = 0.0f; } - if (cols == 4) { + if (cols == 4) + { (*this)(0, 3) = 0.0f; (*this)(1, 3) = 0.0f; (*this)(2, 3) = 0.0f; } - if (rows == 4 && cols == 4) { + if (rows == 4 && cols == 4) + { (*this)(3, 3) = 1.0f; } @@ -1339,7 +1359,7 @@ Matrix::Matrix(const EulerF& e, const Point3F p) } template -Matrix& Matrix::set(const EulerF& e, const Point3F p) +inline Matrix& Matrix::set(const EulerF& e, const Point3F p) { AssertFatal(rows >= 3 && cols >= 4, "Euler and Point can only initialize 3x4 or more"); // call set euler, this already sets the last row if it exists. @@ -1354,7 +1374,7 @@ Matrix& Matrix::set(const EulerF& } template -Matrix Matrix::inverse() +inline Matrix Matrix::inverse() { // TODO: insert return statement here AssertFatal(rows == cols, "Can only perform inverse on square matrices."); @@ -1364,18 +1384,22 @@ Matrix Matrix::inverse() Matrix augmentedMatrix; Matrix resultMatrix; - for (U32 i = 0; i < size; i++) { - for (U32 j = 0; j < size; j++) { + for (U32 i = 0; i < size; i++) + { + for (U32 j = 0; j < size; j++) + { augmentedMatrix(i, j) = (*this)(i, j); augmentedMatrix(i, j + size) = (i == j) ? static_cast(1) : static_cast(0); } } // Apply gauss-joran elimination - for (U32 i = 0; i < size; i++) { + for (U32 i = 0; i < size; i++) + { U32 pivotRow = i; - for (U32 k = i + 1; k < size; k++) { + for (U32 k = i + 1; k < size; k++) + { // use std::abs until the templated math functions are in place. if (std::abs(augmentedMatrix(k, i)) > std::abs(augmentedMatrix(pivotRow, i))) { pivotRow = k; @@ -1383,37 +1407,46 @@ Matrix Matrix::inverse() } // Swap if needed. - if (i != pivotRow) { - for (U32 j = 0; j < 2 * size; j++) { + if (i != pivotRow) + { + for (U32 j = 0; j < 2 * size; j++) + { std::swap(augmentedMatrix(i, j), augmentedMatrix(pivotRow, j)); } } // Early out if pivot is 0, return identity matrix. - if (augmentedMatrix(i, i) == static_cast(0)) { + if (augmentedMatrix(i, i) == static_cast(0)) + { return Matrix(true); } DATA_TYPE pivotVal = augmentedMatrix(i, i); // scale the pivot - for (U32 j = 0; j < 2 * size; j++) { + for (U32 j = 0; j < 2 * size; j++) + { augmentedMatrix(i, j) /= pivotVal; } // Eliminate the current column in all other rows - for (U32 k = 0; k < size; k++) { - if (k != i) { + for (U32 k = 0; k < size; k++) + { + if (k != i) + { DATA_TYPE factor = augmentedMatrix(k, i); - for (U32 j = 0; j < 2 * size; j++) { + for (U32 j = 0; j < 2 * size; j++) + { augmentedMatrix(k, j) -= factor * augmentedMatrix(i, j); } } } } - for (U32 i = 0; i < size; i++) { - for (U32 j = 0; j < size; j++) { + for (U32 i = 0; i < size; i++) + { + for (U32 j = 0; j < size; j++) + { resultMatrix(i, j) = augmentedMatrix(i, j + size); } } @@ -1500,44 +1533,40 @@ inline void Matrix::mul(Box3F& box) const { AssertFatal(rows == 4 && cols == 4, "Multiplying Box3F with matrix requires 4x4"); - // Create an array of all 8 corners of the box - Point3F corners[8] = { - Point3F(box.minExtents.x, box.minExtents.y, box.minExtents.z), - Point3F(box.minExtents.x, box.minExtents.y, box.maxExtents.z), - Point3F(box.minExtents.x, box.maxExtents.y, box.minExtents.z), - Point3F(box.minExtents.x, box.maxExtents.y, box.maxExtents.z), - Point3F(box.maxExtents.x, box.minExtents.y, box.minExtents.z), - Point3F(box.maxExtents.x, box.minExtents.y, box.maxExtents.z), - Point3F(box.maxExtents.x, box.maxExtents.y, box.minExtents.z), - Point3F(box.maxExtents.x, box.maxExtents.y, box.maxExtents.z), - }; + // Save original min and max + Point3F originalMin = box.minExtents; + Point3F originalMax = box.maxExtents; - for (U32 i = 0; i < 8; i++) { - corners[i] = (*this) * corners[i]; - } + // Initialize min and max with the translation part of the matrix + box.minExtents.x = box.maxExtents.x = (*this)(0, 3); + box.minExtents.y = box.maxExtents.y = (*this)(1, 3); + box.minExtents.z = box.maxExtents.z = (*this)(2, 3); - box.minExtents = corners[0]; - box.maxExtents = corners[0]; - for (U32 i = 1; i < 8; ++i) { - box.minExtents.x = mMin(box.minExtents.x, corners[i].x); - box.minExtents.y = mMin(box.minExtents.y, corners[i].y); - box.minExtents.z = mMin(box.minExtents.z, corners[i].z); + for (U32 i = 0; i < 3; ++i) { + #define Do_One_Row(j) { \ + DATA_TYPE a = ((*this)(i, j) * originalMin[j]); \ + DATA_TYPE b = ((*this)(i, j) * originalMax[j]); \ + if (a < b) { box.minExtents[i] += a; box.maxExtents[i] += b; } \ + else { box.minExtents[i] += b; box.maxExtents[i] += a; } } - box.maxExtents.x = mMax(box.maxExtents.x, corners[i].x); - box.maxExtents.y = mMax(box.maxExtents.y, corners[i].y); - box.maxExtents.z = mMax(box.maxExtents.z, corners[i].z); + Do_One_Row(0); + Do_One_Row(1); + Do_One_Row(2); } } template inline bool Matrix::isAffine() const { - if ((*this)(rows - 1, cols - 1) != 1.0f) { + if ((*this)(rows - 1, cols - 1) != 1.0f) + { return false; } - for (U32 col = 0; col < cols - 1; ++col) { - if ((*this)(rows - 1, col) != 0.0f) { + for (U32 col = 0; col < cols - 1; ++col) + { + if ((*this)(rows - 1, col) != 0.0f) + { return false; } } @@ -1580,23 +1609,23 @@ inline bool Matrix::isAffine() const } template -inline Matrix Matrix::affineInverse() +inline Matrix& Matrix::affineInverse() { AssertFatal(rows >= 4 && cols >= 4, "affineInverse requires at least 4x4"); - Matrix subMatrix; + Matrix temp = *this; - for (U32 i = 0; i < 3; i++) { - for (U32 j = 0; j < 3; j++) { - subMatrix(i, j) = (*this)(i, j); - } - } + // Transpose rotation part + (*this)(0, 1) = temp(1, 0); + (*this)(0, 2) = temp(2, 0); + (*this)(1, 0) = temp(0, 1); + (*this)(1, 2) = temp(2, 1); + (*this)(2, 0) = temp(0, 2); + (*this)(2, 1) = temp(1, 2); - subMatrix.transpose(); - - Point3F pos = getPosition(); - (*this)(0, 3) = mDot(subMatrix.getColumn3F(0), pos); - (*this)(1, 3) = mDot(subMatrix.getColumn3F(1), pos); - (*this)(2, 3) = mDot(subMatrix.getColumn3F(2), pos); + // Adjust translation part + (*this)(0, 3) = -(temp(0, 0) * temp(0, 3) + temp(0, 1) * temp(1, 3) + temp(0, 2) * temp(2, 3)); + (*this)(1, 3) = -(temp(1, 0) * temp(0, 3) + temp(1, 1) * temp(1, 3) + temp(1, 2) * temp(2, 3)); + (*this)(2, 3) = -(temp(2, 0) * temp(0, 3) + temp(2, 1) * temp(1, 3) + temp(2, 2) * temp(2, 3)); return *this; } @@ -1618,11 +1647,13 @@ inline EulerF Matrix::toEuler() const EulerF r; r.x = mAsin(mClampF(m21, -1.0, 1.0)); - if (mCos(r.x) != 0.0f) { + if (mCos(r.x) != 0.0f) + { r.y = mAtan2(-m02, m22); // yaw r.z = mAtan2(-m10, m11); // roll } - else { + else + { r.y = 0.0f; r.z = mAtan2(m01, m00); // this rolls when pitch is +90 degrees } @@ -1651,12 +1682,15 @@ inline void Matrix::dumpMatrix(const char* caption) const StringBuilder str; str.format("%s = |", caption); - for (U32 i = 0; i < rows; i++) { - if (i > 0) { + for (U32 i = 0; i < rows; i++) + { + if (i > 0) + { str.append(spacerRef); } - for (U32 j = 0; j < cols; j++) { + for (U32 j = 0; j < cols; j++) + { str.format(formatSpec, (*this)(i, j)); } str.append(" |\n"); @@ -1684,24 +1718,44 @@ inline void mTransformPlane( invScale(1, 1) = 1.0f / scale.y; invScale(2, 2) = 1.0f / scale.z; + const Point3F shear(mat(0, 3), mat(1, 3), mat(2, 3)); + + const Point3F row0 = mat.getRow3F(0); + const Point3F row1 = mat.getRow3F(1); + const Point3F row2 = mat.getRow3F(2); + + const F32 A = -mDot(row0, shear); + const F32 B = -mDot(row1, shear); + const F32 C = -mDot(row2, shear); + // Compute the inverse transpose of the matrix - MatrixF invTrMatrix = matCopy.transpose().affineInverse() * invScale; + MatrixF invTrMatrix = MatrixF::Identity; + invTrMatrix(0, 0) = mat(0, 0); + invTrMatrix(0, 1) = mat(0, 1); + invTrMatrix(0, 2) = mat(0, 2); + invTrMatrix(1, 0) = mat(1, 0); + invTrMatrix(1, 1) = mat(1, 1); + invTrMatrix(1, 2) = mat(1, 2); + invTrMatrix(2, 0) = mat(2, 0); + invTrMatrix(2, 1) = mat(2, 1); + invTrMatrix(2, 2) = mat(2, 2); + invTrMatrix(3, 0) = A; + invTrMatrix(3, 1) = B; + invTrMatrix(3, 2) = C; + invTrMatrix.mul(invScale); // Transform the plane normal Point3F norm(plane.x, plane.y, plane.z); - norm = invTrMatrix * norm; - float normLength = std::sqrt(norm.x * norm.x + norm.y * norm.y + norm.z * norm.z); - norm.x /= normLength; - norm.y /= normLength; - norm.z /= normLength; + invTrMatrix.mulP(norm); + norm.normalize(); // Transform the plane point - Point3F point = norm * (-plane.d); - MMatrixF temp = mat; + Point3F point = norm * -plane.d; + MatrixF temp = mat; point.x *= scale.x; point.y *= scale.y; point.z *= scale.z; - point = temp * point; + temp.mulP(point); // Recompute the plane distance PlaneF resultPlane(point, norm); From f77ff37e083048e33500b41d33c4849fc9a6d825 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 29 Jul 2024 19:24:33 +0100 Subject: [PATCH 13/29] Create mathMatrixTest.cpp committed tests for matrix class so far all tests are matching between templated and stock matrixf class --- Engine/source/testing/mathMatrixTest.cpp | 108 +++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Engine/source/testing/mathMatrixTest.cpp diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp new file mode 100644 index 000000000..aa2b74370 --- /dev/null +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -0,0 +1,108 @@ +#include "testing/unitTesting.h" + +#include "platform/platform.h" +#include "console/simBase.h" +#include "console/consoleTypes.h" +#include "console/scriptObjects.h" +#include "console/simBase.h" +#include "console/engineAPI.h" +#include "math/mMath.h" + +TEST(MatrixTest, TestIdentityInit) +{ + MatrixF test(true); + + EXPECT_NEAR(test(0, 0), 1.0f, 0.001f); + EXPECT_NEAR(test(1, 1), 1.0f, 0.001f); + EXPECT_NEAR(test(2, 2), 1.0f, 0.001f); + EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + +TEST(MatrixTest, TestIdentitySet) +{ + MatrixF test(false); + test.identity(); + + EXPECT_NEAR(test(0, 0), 1.0f, 0.001f); + EXPECT_NEAR(test(1, 1), 1.0f, 0.001f); + EXPECT_NEAR(test(2, 2), 1.0f, 0.001f); + EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + +TEST(MatrixTest, TestIsIdentity) +{ + MatrixF test(true); + EXPECT_TRUE(test.isIdentity()); +} + +TEST(MatrixTest, TestEulerInit) +{ + MatrixF test(EulerF(1.0f, 0.0f, 1.0f)); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + + +TEST(MatrixTest, TestEulerSet) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f)); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + + +TEST(MatrixTest, TestEulerPointInit) +{ + MatrixF test(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + + +TEST(MatrixTest, TestEulerPointSet) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + +TEST(MatrixTest, TestSetCrossProduct) +{ + MatrixF test(true); + + test.setCrossProduct(Point3F(5.0f, 0.0f, 1.0f)); + + EXPECT_NEAR(test(0, 0), 0.0f, 0.001f); EXPECT_NEAR(test(0, 1), -1.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 1.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0, 0.001f); EXPECT_NEAR(test(1, 2), -5.0f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 5.0f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + +TEST(MatrixTest, TestSetTensorProduct) +{ + MatrixF test(true); + + test.setTensorProduct(Point3F(5.0f, 2.0f, 1.0f), Point3F(5.0f, 2.0f, 1.0f)); + + EXPECT_NEAR(test(0, 0), 25.0f, 0.001f); EXPECT_NEAR(test(0, 1), 10.0f, 0.001f); EXPECT_NEAR(test(0, 2), 5.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 10.0f, 0.001f); EXPECT_NEAR(test(1, 1), 4.0, 0.001f); EXPECT_NEAR(test(1, 2), 2.0f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 5.0f, 0.001f); EXPECT_NEAR(test(2, 1), 2.0f, 0.001f); EXPECT_NEAR(test(2, 2), 1.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + From 409f523dc39fc0f54647e952bde9478e272b40e1 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 29 Jul 2024 20:01:39 +0100 Subject: [PATCH 14/29] Update mathMatrixTest.cpp more tests that match between template and matrixf --- Engine/source/testing/mathMatrixTest.cpp | 98 ++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index aa2b74370..27c336892 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -106,3 +106,101 @@ TEST(MatrixTest, TestSetTensorProduct) EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestMulFunction) +{ + MatrixF test(true); + + test(0, 0) = 1.0f; test(0, 1) = 2.0f; test(0, 2) = 3.0f; test(0, 3) = 4.0f; + test(1, 0) = 4.0f; test(1, 1) = 1.0f; test(1, 2) = 2.0f; test(1, 3) = 3.0f; + test(2, 0) = 3.0f; test(2, 1) = 4.0f; test(2, 2) = 1.0f; test(2, 3) = 2.0f; + test(3, 0) = 2.0f; test(3, 1) = 3.0f; test(3, 2) = 4.0f; test(3, 3) = 1.0f; + + MatrixF test2(true); + + test2(0, 0) = 4.0f; test2(0, 1) = 3.0f; test2(0, 2) = 2.0f; test2(0, 3) = 1.0f; + test2(1, 0) = 1.0f; test2(1, 1) = 4.0f; test2(1, 2) = 3.0f; test2(1, 3) = 2.0f; + test2(2, 0) = 2.0f; test2(2, 1) = 1.0f; test2(2, 2) = 4.0f; test2(2, 3) = 3.0f; + test2(3, 0) = 3.0f; test2(3, 1) = 2.0f; test2(3, 2) = 1.0f; test2(3, 3) = 4.0f; + + test.mul(test2); + + EXPECT_NEAR(test(0, 0), 24.0f, 0.001f); EXPECT_NEAR(test(0, 1), 22.0f, 0.001f); EXPECT_NEAR(test(0, 2), 24.0f, 0.001f); EXPECT_NEAR(test(0, 3), 30.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 30.0f, 0.001f); EXPECT_NEAR(test(1, 1), 24.0f, 0.001f); EXPECT_NEAR(test(1, 2), 22.0f, 0.001f); EXPECT_NEAR(test(1, 3), 24.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 24.0f, 0.001f); EXPECT_NEAR(test(2, 1), 30.0f, 0.001f); EXPECT_NEAR(test(2, 2), 24.0f, 0.001f); EXPECT_NEAR(test(2, 3), 22.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 22.0f, 0.001f); EXPECT_NEAR(test(3, 1), 24.0f, 0.001f); EXPECT_NEAR(test(3, 2), 30.0f, 0.001f); EXPECT_NEAR(test(3, 3), 24.0f, 0.001f); +} + +TEST(MatrixTest, TestMulOperator) +{ + MatrixF test(true); + + test(0, 0) = 1.0f; test(0, 1) = 2.0f; test(0, 2) = 3.0f; test(0, 3) = 4.0f; + test(1, 0) = 4.0f; test(1, 1) = 1.0f; test(1, 2) = 2.0f; test(1, 3) = 3.0f; + test(2, 0) = 3.0f; test(2, 1) = 4.0f; test(2, 2) = 1.0f; test(2, 3) = 2.0f; + test(3, 0) = 2.0f; test(3, 1) = 3.0f; test(3, 2) = 4.0f; test(3, 3) = 1.0f; + + MatrixF test2(true); + + test2(0, 0) = 4.0f; test2(0, 1) = 3.0f; test2(0, 2) = 2.0f; test2(0, 3) = 1.0f; + test2(1, 0) = 1.0f; test2(1, 1) = 4.0f; test2(1, 2) = 3.0f; test2(1, 3) = 2.0f; + test2(2, 0) = 2.0f; test2(2, 1) = 1.0f; test2(2, 2) = 4.0f; test2(2, 3) = 3.0f; + test2(3, 0) = 3.0f; test2(3, 1) = 2.0f; test2(3, 2) = 1.0f; test2(3, 3) = 4.0f; + + test = test * test2; + + EXPECT_NEAR(test(0, 0), 24.0f, 0.001f); EXPECT_NEAR(test(0, 1), 22.0f, 0.001f); EXPECT_NEAR(test(0, 2), 24.0f, 0.001f); EXPECT_NEAR(test(0, 3), 30.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 30.0f, 0.001f); EXPECT_NEAR(test(1, 1), 24.0f, 0.001f); EXPECT_NEAR(test(1, 2), 22.0f, 0.001f); EXPECT_NEAR(test(1, 3), 24.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 24.0f, 0.001f); EXPECT_NEAR(test(2, 1), 30.0f, 0.001f); EXPECT_NEAR(test(2, 2), 24.0f, 0.001f); EXPECT_NEAR(test(2, 3), 22.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 22.0f, 0.001f); EXPECT_NEAR(test(3, 1), 24.0f, 0.001f); EXPECT_NEAR(test(3, 2), 30.0f, 0.001f); EXPECT_NEAR(test(3, 3), 24.0f, 0.001f); +} + +TEST(MatrixTest, TestMulLFunction) +{ + MatrixF test(true); + + test(0, 0) = 1.0f; test(0, 1) = 2.0f; test(0, 2) = 3.0f; test(0, 3) = 4.0f; + test(1, 0) = 4.0f; test(1, 1) = 1.0f; test(1, 2) = 2.0f; test(1, 3) = 3.0f; + test(2, 0) = 3.0f; test(2, 1) = 4.0f; test(2, 2) = 1.0f; test(2, 3) = 2.0f; + test(3, 0) = 2.0f; test(3, 1) = 3.0f; test(3, 2) = 4.0f; test(3, 3) = 1.0f; + + MatrixF test2(true); + + test2(0, 0) = 4.0f; test2(0, 1) = 3.0f; test2(0, 2) = 2.0f; test2(0, 3) = 1.0f; + test2(1, 0) = 1.0f; test2(1, 1) = 4.0f; test2(1, 2) = 3.0f; test2(1, 3) = 2.0f; + test2(2, 0) = 2.0f; test2(2, 1) = 1.0f; test2(2, 2) = 4.0f; test2(2, 3) = 3.0f; + test2(3, 0) = 3.0f; test2(3, 1) = 2.0f; test2(3, 2) = 1.0f; test2(3, 3) = 4.0f; + + test.mulL(test2); + + EXPECT_NEAR(test(0, 0), 24.0f, 0.001f); EXPECT_NEAR(test(0, 1), 22.0f, 0.001f); EXPECT_NEAR(test(0, 2), 24.0f, 0.001f); EXPECT_NEAR(test(0, 3), 30.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 30.0f, 0.001f); EXPECT_NEAR(test(1, 1), 24.0f, 0.001f); EXPECT_NEAR(test(1, 2), 22.0f, 0.001f); EXPECT_NEAR(test(1, 3), 24.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 24.0f, 0.001f); EXPECT_NEAR(test(2, 1), 30.0f, 0.001f); EXPECT_NEAR(test(2, 2), 24.0f, 0.001f); EXPECT_NEAR(test(2, 3), 22.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 22.0f, 0.001f); EXPECT_NEAR(test(3, 1), 24.0f, 0.001f); EXPECT_NEAR(test(3, 2), 30.0f, 0.001f); EXPECT_NEAR(test(3, 3), 24.0f, 0.001f); +} + +TEST(MatrixTest, TestMulArgMatrixFunction) +{ + MatrixF testResult(true); + + MatrixF test(true); + + test(0, 0) = 1.0f; test(0, 1) = 2.0f; test(0, 2) = 3.0f; test(0, 3) = 4.0f; + test(1, 0) = 4.0f; test(1, 1) = 1.0f; test(1, 2) = 2.0f; test(1, 3) = 3.0f; + test(2, 0) = 3.0f; test(2, 1) = 4.0f; test(2, 2) = 1.0f; test(2, 3) = 2.0f; + test(3, 0) = 2.0f; test(3, 1) = 3.0f; test(3, 2) = 4.0f; test(3, 3) = 1.0f; + + MatrixF test2(true); + + test2(0, 0) = 4.0f; test2(0, 1) = 3.0f; test2(0, 2) = 2.0f; test2(0, 3) = 1.0f; + test2(1, 0) = 1.0f; test2(1, 1) = 4.0f; test2(1, 2) = 3.0f; test2(1, 3) = 2.0f; + test2(2, 0) = 2.0f; test2(2, 1) = 1.0f; test2(2, 2) = 4.0f; test2(2, 3) = 3.0f; + test2(3, 0) = 3.0f; test2(3, 1) = 2.0f; test2(3, 2) = 1.0f; test2(3, 3) = 4.0f; + + testResult.mul(test2, test); + + EXPECT_NEAR(testResult(0, 0), 24.0f, 0.001f); EXPECT_NEAR(testResult(0, 1), 22.0f, 0.001f); EXPECT_NEAR(testResult(0, 2), 24.0f, 0.001f); EXPECT_NEAR(testResult(0, 3), 30.0f, 0.001f); + EXPECT_NEAR(testResult(1, 0), 30.0f, 0.001f); EXPECT_NEAR(testResult(1, 1), 24.0f, 0.001f); EXPECT_NEAR(testResult(1, 2), 22.0f, 0.001f); EXPECT_NEAR(testResult(1, 3), 24.0f, 0.001f); + EXPECT_NEAR(testResult(2, 0), 24.0f, 0.001f); EXPECT_NEAR(testResult(2, 1), 30.0f, 0.001f); EXPECT_NEAR(testResult(2, 2), 24.0f, 0.001f); EXPECT_NEAR(testResult(2, 3), 22.0f, 0.001f); + EXPECT_NEAR(testResult(3, 0), 22.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 24.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 30.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 24.0f, 0.001f); +} + From fc058aaa5ca7f4967552c0efa7f758b925bfe236 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 29 Jul 2024 20:45:30 +0100 Subject: [PATCH 15/29] Update mathMatrixTest.cpp change mul tests to use more real world examples --- Engine/source/testing/mathMatrixTest.cpp | 94 ++++++++---------------- 1 file changed, 30 insertions(+), 64 deletions(-) diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 27c336892..833ccd6d8 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -109,73 +109,49 @@ TEST(MatrixTest, TestSetTensorProduct) TEST(MatrixTest, TestMulFunction) { MatrixF test(true); - - test(0, 0) = 1.0f; test(0, 1) = 2.0f; test(0, 2) = 3.0f; test(0, 3) = 4.0f; - test(1, 0) = 4.0f; test(1, 1) = 1.0f; test(1, 2) = 2.0f; test(1, 3) = 3.0f; - test(2, 0) = 3.0f; test(2, 1) = 4.0f; test(2, 2) = 1.0f; test(2, 3) = 2.0f; - test(3, 0) = 2.0f; test(3, 1) = 3.0f; test(3, 2) = 4.0f; test(3, 3) = 1.0f; - - MatrixF test2(true); - - test2(0, 0) = 4.0f; test2(0, 1) = 3.0f; test2(0, 2) = 2.0f; test2(0, 3) = 1.0f; - test2(1, 0) = 1.0f; test2(1, 1) = 4.0f; test2(1, 2) = 3.0f; test2(1, 3) = 2.0f; - test2(2, 0) = 2.0f; test2(2, 1) = 1.0f; test2(2, 2) = 4.0f; test2(2, 3) = 3.0f; - test2(3, 0) = 3.0f; test2(3, 1) = 2.0f; test2(3, 2) = 1.0f; test2(3, 3) = 4.0f; + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); test.mul(test2); - EXPECT_NEAR(test(0, 0), 24.0f, 0.001f); EXPECT_NEAR(test(0, 1), 22.0f, 0.001f); EXPECT_NEAR(test(0, 2), 24.0f, 0.001f); EXPECT_NEAR(test(0, 3), 30.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 30.0f, 0.001f); EXPECT_NEAR(test(1, 1), 24.0f, 0.001f); EXPECT_NEAR(test(1, 2), 22.0f, 0.001f); EXPECT_NEAR(test(1, 3), 24.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 24.0f, 0.001f); EXPECT_NEAR(test(2, 1), 30.0f, 0.001f); EXPECT_NEAR(test(2, 2), 24.0f, 0.001f); EXPECT_NEAR(test(2, 3), 22.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 22.0f, 0.001f); EXPECT_NEAR(test(3, 1), 24.0f, 0.001f); EXPECT_NEAR(test(3, 2), 30.0f, 0.001f); EXPECT_NEAR(test(3, 3), 24.0f, 0.001f); + // mulL result + /*(null) = | 0.5403 -0.4546 0.7081 0.0000 | + | 0.8415 0.2919 -0.4546 0.0000 | + | 0.0000 0.8415 0.5403 0.0000 | + | 4.3845 -0.8479 3.1714 1.0000 |*/ + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 2.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } TEST(MatrixTest, TestMulOperator) { MatrixF test(true); - - test(0, 0) = 1.0f; test(0, 1) = 2.0f; test(0, 2) = 3.0f; test(0, 3) = 4.0f; - test(1, 0) = 4.0f; test(1, 1) = 1.0f; test(1, 2) = 2.0f; test(1, 3) = 3.0f; - test(2, 0) = 3.0f; test(2, 1) = 4.0f; test(2, 2) = 1.0f; test(2, 3) = 2.0f; - test(3, 0) = 2.0f; test(3, 1) = 3.0f; test(3, 2) = 4.0f; test(3, 3) = 1.0f; - - MatrixF test2(true); - - test2(0, 0) = 4.0f; test2(0, 1) = 3.0f; test2(0, 2) = 2.0f; test2(0, 3) = 1.0f; - test2(1, 0) = 1.0f; test2(1, 1) = 4.0f; test2(1, 2) = 3.0f; test2(1, 3) = 2.0f; - test2(2, 0) = 2.0f; test2(2, 1) = 1.0f; test2(2, 2) = 4.0f; test2(2, 3) = 3.0f; - test2(3, 0) = 3.0f; test2(3, 1) = 2.0f; test2(3, 2) = 1.0f; test2(3, 3) = 4.0f; + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); test = test * test2; - EXPECT_NEAR(test(0, 0), 24.0f, 0.001f); EXPECT_NEAR(test(0, 1), 22.0f, 0.001f); EXPECT_NEAR(test(0, 2), 24.0f, 0.001f); EXPECT_NEAR(test(0, 3), 30.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 30.0f, 0.001f); EXPECT_NEAR(test(1, 1), 24.0f, 0.001f); EXPECT_NEAR(test(1, 2), 22.0f, 0.001f); EXPECT_NEAR(test(1, 3), 24.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 24.0f, 0.001f); EXPECT_NEAR(test(2, 1), 30.0f, 0.001f); EXPECT_NEAR(test(2, 2), 24.0f, 0.001f); EXPECT_NEAR(test(2, 3), 22.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 22.0f, 0.001f); EXPECT_NEAR(test(3, 1), 24.0f, 0.001f); EXPECT_NEAR(test(3, 2), 30.0f, 0.001f); EXPECT_NEAR(test(3, 3), 24.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 2.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } TEST(MatrixTest, TestMulLFunction) { MatrixF test(true); - - test(0, 0) = 1.0f; test(0, 1) = 2.0f; test(0, 2) = 3.0f; test(0, 3) = 4.0f; - test(1, 0) = 4.0f; test(1, 1) = 1.0f; test(1, 2) = 2.0f; test(1, 3) = 3.0f; - test(2, 0) = 3.0f; test(2, 1) = 4.0f; test(2, 2) = 1.0f; test(2, 3) = 2.0f; - test(3, 0) = 2.0f; test(3, 1) = 3.0f; test(3, 2) = 4.0f; test(3, 3) = 1.0f; - - MatrixF test2(true); - - test2(0, 0) = 4.0f; test2(0, 1) = 3.0f; test2(0, 2) = 2.0f; test2(0, 3) = 1.0f; - test2(1, 0) = 1.0f; test2(1, 1) = 4.0f; test2(1, 2) = 3.0f; test2(1, 3) = 2.0f; - test2(2, 0) = 2.0f; test2(2, 1) = 1.0f; test2(2, 2) = 4.0f; test2(2, 3) = 3.0f; - test2(3, 0) = 3.0f; test2(3, 1) = 2.0f; test2(3, 2) = 1.0f; test2(3, 3) = 4.0f; + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); test.mulL(test2); - EXPECT_NEAR(test(0, 0), 24.0f, 0.001f); EXPECT_NEAR(test(0, 1), 22.0f, 0.001f); EXPECT_NEAR(test(0, 2), 24.0f, 0.001f); EXPECT_NEAR(test(0, 3), 30.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 30.0f, 0.001f); EXPECT_NEAR(test(1, 1), 24.0f, 0.001f); EXPECT_NEAR(test(1, 2), 22.0f, 0.001f); EXPECT_NEAR(test(1, 3), 24.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 24.0f, 0.001f); EXPECT_NEAR(test(2, 1), 30.0f, 0.001f); EXPECT_NEAR(test(2, 2), 24.0f, 0.001f); EXPECT_NEAR(test(2, 3), 22.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 22.0f, 0.001f); EXPECT_NEAR(test(3, 1), 24.0f, 0.001f); EXPECT_NEAR(test(3, 2), 30.0f, 0.001f); EXPECT_NEAR(test(3, 3), 24.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 4.3845f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), -0.8479f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 3.1714, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } TEST(MatrixTest, TestMulArgMatrixFunction) @@ -183,24 +159,14 @@ TEST(MatrixTest, TestMulArgMatrixFunction) MatrixF testResult(true); MatrixF test(true); - - test(0, 0) = 1.0f; test(0, 1) = 2.0f; test(0, 2) = 3.0f; test(0, 3) = 4.0f; - test(1, 0) = 4.0f; test(1, 1) = 1.0f; test(1, 2) = 2.0f; test(1, 3) = 3.0f; - test(2, 0) = 3.0f; test(2, 1) = 4.0f; test(2, 2) = 1.0f; test(2, 3) = 2.0f; - test(3, 0) = 2.0f; test(3, 1) = 3.0f; test(3, 2) = 4.0f; test(3, 3) = 1.0f; - - MatrixF test2(true); - - test2(0, 0) = 4.0f; test2(0, 1) = 3.0f; test2(0, 2) = 2.0f; test2(0, 3) = 1.0f; - test2(1, 0) = 1.0f; test2(1, 1) = 4.0f; test2(1, 2) = 3.0f; test2(1, 3) = 2.0f; - test2(2, 0) = 2.0f; test2(2, 1) = 1.0f; test2(2, 2) = 4.0f; test2(2, 3) = 3.0f; - test2(3, 0) = 3.0f; test2(3, 1) = 2.0f; test2(3, 2) = 1.0f; test2(3, 3) = 4.0f; + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); testResult.mul(test2, test); - EXPECT_NEAR(testResult(0, 0), 24.0f, 0.001f); EXPECT_NEAR(testResult(0, 1), 22.0f, 0.001f); EXPECT_NEAR(testResult(0, 2), 24.0f, 0.001f); EXPECT_NEAR(testResult(0, 3), 30.0f, 0.001f); - EXPECT_NEAR(testResult(1, 0), 30.0f, 0.001f); EXPECT_NEAR(testResult(1, 1), 24.0f, 0.001f); EXPECT_NEAR(testResult(1, 2), 22.0f, 0.001f); EXPECT_NEAR(testResult(1, 3), 24.0f, 0.001f); - EXPECT_NEAR(testResult(2, 0), 24.0f, 0.001f); EXPECT_NEAR(testResult(2, 1), 30.0f, 0.001f); EXPECT_NEAR(testResult(2, 2), 24.0f, 0.001f); EXPECT_NEAR(testResult(2, 3), 22.0f, 0.001f); - EXPECT_NEAR(testResult(3, 0), 22.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 24.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 30.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 24.0f, 0.001f); + EXPECT_NEAR(testResult(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(testResult(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(testResult(0, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(0, 3), 4.3845f, 0.001f); + EXPECT_NEAR(testResult(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(testResult(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(testResult(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(testResult(1, 3), -0.8479f, 0.001f); + EXPECT_NEAR(testResult(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(testResult(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(testResult(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(testResult(2, 3), 3.1714, 0.001f); + EXPECT_NEAR(testResult(3, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 1.0f, 0.001f); } From 8c19f6d8cafad8532764d6e515bb7612f9559312 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 29 Jul 2024 21:50:33 +0100 Subject: [PATCH 16/29] inverse function fixed inverse function, was not returning correctly. --- Engine/source/math/mMatrix.h | 12 ++++++------ Engine/source/testing/mathMatrixTest.cpp | 21 +++++++++++++++------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 4591df37d..de2fd1af6 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -678,7 +678,7 @@ public: Matrix(const EulerF& e, const Point3F p); Matrix& set(const EulerF& e, const Point3F p); - Matrix inverse(); + Matrix& inverse(); Matrix& transpose(); void invert(); @@ -1374,7 +1374,7 @@ inline Matrix& Matrix::set(const E } template -inline Matrix Matrix::inverse() +inline Matrix& Matrix::inverse() { // TODO: insert return statement here AssertFatal(rows == cols, "Can only perform inverse on square matrices."); @@ -1382,7 +1382,6 @@ inline Matrix Matrix::inverse() // Create augmented matrix [this | I] Matrix augmentedMatrix; - Matrix resultMatrix; for (U32 i = 0; i < size; i++) { @@ -1418,7 +1417,8 @@ inline Matrix Matrix::inverse() // Early out if pivot is 0, return identity matrix. if (augmentedMatrix(i, i) == static_cast(0)) { - return Matrix(true); + this->identity(); + return *this; } DATA_TYPE pivotVal = augmentedMatrix(i, i); @@ -1447,11 +1447,11 @@ inline Matrix Matrix::inverse() { for (U32 j = 0; j < size; j++) { - resultMatrix(i, j) = augmentedMatrix(i, j + size); + (*this)(i, j) = augmentedMatrix(i, j + size); } } - return resultMatrix; + return (*this); } template diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 833ccd6d8..5807989b5 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -114,12 +114,6 @@ TEST(MatrixTest, TestMulFunction) test.mul(test2); - // mulL result - /*(null) = | 0.5403 -0.4546 0.7081 0.0000 | - | 0.8415 0.2919 -0.4546 0.0000 | - | 0.0000 0.8415 0.5403 0.0000 | - | 4.3845 -0.8479 3.1714 1.0000 |*/ - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 2.0f, 0.001f); EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); @@ -170,3 +164,18 @@ TEST(MatrixTest, TestMulArgMatrixFunction) EXPECT_NEAR(testResult(3, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestInverse) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + test.inverse(); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), -5.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} From 5883e3d45be61a49746501e29622bc99f0e25435 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 29 Jul 2024 22:46:16 +0100 Subject: [PATCH 17/29] Update mathMatrixTest.cpp test box multiplication test transformPlane --- Engine/source/testing/mathMatrixTest.cpp | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 5807989b5..a2e7da5e1 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -164,6 +164,20 @@ TEST(MatrixTest, TestMulArgMatrixFunction) EXPECT_NEAR(testResult(3, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestMulBox) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + Box3F testBox(1.0f); + + test.mul(testBox); + + EXPECT_NEAR(testBox.minExtents.x, 4.5f, 0.001f); EXPECT_NEAR(testBox.minExtents.y, 1.5f, 0.001f); EXPECT_NEAR(testBox.minExtents.z, 0.5f, 0.001f); + EXPECT_NEAR(testBox.maxExtents.x, 5.5f, 0.001f); EXPECT_NEAR(testBox.maxExtents.y, 2.5f, 0.001f); EXPECT_NEAR(testBox.maxExtents.z, 1.5f, 0.001f); +} + TEST(MatrixTest, TestInverse) { MatrixF test(true); @@ -179,3 +193,23 @@ TEST(MatrixTest, TestInverse) EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } + +TEST(MatrixTest, TestTransformPlane) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + PlaneF plane(Point3F(0.0f, 0.0f, 0.0f), Point3F(0.0f, 0.0f, 1.0f)); + + PlaneF res; + mTransformPlane(test, Point3F(1.0f, 1.0f, 1.0f), plane, &res); + + EXPECT_NEAR(res.x, 0.0f, 0.001f); + EXPECT_NEAR(res.y, 0.8414f, 0.001f); + EXPECT_NEAR(res.z, 0.5403f, 0.001f); + EXPECT_NEAR(res.d, -1.0f, 0.001f); + +} From a5de2d9add1059e475b97053dbb382c8f3288659 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 30 Jul 2024 07:20:57 +0100 Subject: [PATCH 18/29] tests added more unit tests to match values between templated and matrix tests showed discrepancies in affineInverse, fixed the function to return what is expected. --- Engine/source/math/mMatrix.h | 6 +-- Engine/source/testing/mathMatrixTest.cpp | 68 ++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index de2fd1af6..abb451591 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -1623,9 +1623,9 @@ inline Matrix& Matrix::affineInver (*this)(2, 1) = temp(1, 2); // Adjust translation part - (*this)(0, 3) = -(temp(0, 0) * temp(0, 3) + temp(0, 1) * temp(1, 3) + temp(0, 2) * temp(2, 3)); - (*this)(1, 3) = -(temp(1, 0) * temp(0, 3) + temp(1, 1) * temp(1, 3) + temp(1, 2) * temp(2, 3)); - (*this)(2, 3) = -(temp(2, 0) * temp(0, 3) + temp(2, 1) * temp(1, 3) + temp(2, 2) * temp(2, 3)); + (*this)(0, 3) = -(temp(0, 0) * temp(0, 3) + temp(1, 0) * temp(1, 3) + temp(2, 0) * temp(2, 3)); + (*this)(1, 3) = -(temp(0, 1) * temp(0, 3) + temp(1, 1) * temp(1, 3) + temp(2, 1) * temp(2, 3)); + (*this)(2, 3) = -(temp(0, 2) * temp(0, 3) + temp(1, 2) * temp(1, 3) + temp(2, 2) * temp(2, 3)); return *this; } diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index a2e7da5e1..8e3a67232 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -194,6 +194,74 @@ TEST(MatrixTest, TestInverse) EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestInvertTo) +{ + MatrixF test1(true); + test1.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test1.mulL(test2); + + MatrixF test(true); + + test1.invertTo(&test); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), -5.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + +TEST(MatrixTest, TestAffineInverse) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + test.affineInverse(); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), -5.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + +TEST(MatrixTest, TestTranspose) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + test.transpose(); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 4.3845f, 0.001f); EXPECT_NEAR(test(3, 1), -0.8479f, 0.001f); EXPECT_NEAR(test(3, 2), 3.1714, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + +TEST(MatrixTest, TestTransposeTo) +{ + MatrixF test1(true); + test1.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test1.mulL(test2); + + MatrixF test(true); + + test1.transposeTo(test); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 4.3845f, 0.001f); EXPECT_NEAR(test(3, 1), -0.8479f, 0.001f); EXPECT_NEAR(test(3, 2), 3.1714, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + TEST(MatrixTest, TestTransformPlane) { MatrixF test(true); From d03851958d201444fff40b4596b6776deafcf025 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 30 Jul 2024 08:30:42 +0100 Subject: [PATCH 19/29] more fixes more unit tests revealed more discrepancies fixes applied. --- Engine/source/math/mMatrix.h | 22 +-- Engine/source/testing/mathMatrixTest.cpp | 183 +++++++++++++++++++++++ 2 files changed, 189 insertions(+), 16 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index abb451591..8b92778bd 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -700,9 +700,7 @@ public: ///< M * a -> M Matrix& mul(const Matrix& a) - { - *this = *this * a; return *this; - } + { return *this = *this * a; } ///< a * M -> M Matrix& mulL(const Matrix& a) { return *this = a * *this; } @@ -711,7 +709,7 @@ public: { return *this = a * b; } ///< M * a -> M Matrix& mul(const F32 a) - { return *this * a; } + { return *this = *this * a; } ///< a * b -> M Matrix& mul(const Matrix& a, const F32 b) { return *this = a * b; } @@ -1634,28 +1632,20 @@ template inline EulerF Matrix::toEuler() const { AssertFatal(rows >= 3 && cols >= 3, "Euler rotations require at least a 3x3 matrix."); - // Extract rotation matrix components - const DATA_TYPE m00 = (*this)(0, 0); - const DATA_TYPE m01 = (*this)(0, 1); - const DATA_TYPE m02 = (*this)(0, 2); - const DATA_TYPE m10 = (*this)(1, 0); - const DATA_TYPE m11 = (*this)(1, 1); - const DATA_TYPE m21 = (*this)(2, 1); - const DATA_TYPE m22 = (*this)(2, 2); // like all others assume float for now. EulerF r; - r.x = mAsin(mClampF(m21, -1.0, 1.0)); + r.x = mAsin(mClampF((*this)(1,2), -1.0, 1.0)); if (mCos(r.x) != 0.0f) { - r.y = mAtan2(-m02, m22); // yaw - r.z = mAtan2(-m10, m11); // roll + r.y = mAtan2(-(*this)(0, 2), (*this)(2, 2)); // yaw + r.z = mAtan2(-(*this)(1, 0), (*this)(1, 1)); // roll } else { r.y = 0.0f; - r.z = mAtan2(m01, m00); // this rolls when pitch is +90 degrees + r.z = mAtan2((*this)(0, 1), (*this)(0, 0)); // this rolls when pitch is +90 degrees } return r; diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 8e3a67232..8b22e795f 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -7,6 +7,7 @@ #include "console/simBase.h" #include "console/engineAPI.h" #include "math/mMath.h" +#include "math/util/frustum.h" TEST(MatrixTest, TestIdentityInit) { @@ -58,6 +59,16 @@ TEST(MatrixTest, TestEulerSet) EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestToEuler) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f)); + + EulerF euler = test.toEuler(); + + EXPECT_NEAR(euler.x, 1.0f, 0.001f); EXPECT_NEAR(euler.y, 0.0f, 0.001f); EXPECT_NEAR(euler.z, 1.0f, 0.001f); +} TEST(MatrixTest, TestEulerPointInit) { @@ -164,6 +175,111 @@ TEST(MatrixTest, TestMulArgMatrixFunction) EXPECT_NEAR(testResult(3, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestMulScalarFunction) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + test.mul(2.0f); + + EXPECT_NEAR(test(0, 0), 1.0806f, 0.001f); EXPECT_NEAR(test(0, 1), 1.6829f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 8.7689f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.9093f, 0.001f); EXPECT_NEAR(test(1, 1), 0.5839f, 0.001f); EXPECT_NEAR(test(1, 2), 1.6829f, 0.001f); EXPECT_NEAR(test(1, 3), -1.6958f, 0.001f); + EXPECT_NEAR(test(2, 0), 1.4161f, 0.001f); EXPECT_NEAR(test(2, 1), -0.9093f, 0.001f); EXPECT_NEAR(test(2, 2), 1.0806f, 0.001f); EXPECT_NEAR(test(2, 3), 6.3427f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 2.0f, 0.001f); +} + +TEST(MatrixTest, TestMulMatScalarFunction) +{ + MatrixF testTran(true); + testTran.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + testTran.mulL(test2); + + MatrixF test(true); + test.mul(testTran, 2.0f); + + EXPECT_NEAR(test(0, 0), 1.0806f, 0.001f); EXPECT_NEAR(test(0, 1), 1.6829f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 8.7689f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.9093f, 0.001f); EXPECT_NEAR(test(1, 1), 0.5839f, 0.001f); EXPECT_NEAR(test(1, 2), 1.6829f, 0.001f); EXPECT_NEAR(test(1, 3), -1.6958f, 0.001f); + EXPECT_NEAR(test(2, 0), 1.4161f, 0.001f); EXPECT_NEAR(test(2, 1), -0.9093f, 0.001f); EXPECT_NEAR(test(2, 2), 1.0806f, 0.001f); EXPECT_NEAR(test(2, 3), 6.3427f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 2.0f, 0.001f); +} + +TEST(MatrixTest, TestMulPoint4) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + Point4F testPoint(0.5f, 1.0f, 2.0f, 1.0f); + test.mul(testPoint); + + EXPECT_NEAR(testPoint.x, 5.496f, 0.001f); EXPECT_NEAR(testPoint.y, 0.899f, 0.001f); EXPECT_NEAR(testPoint.z, 4.151f, 0.001f); EXPECT_NEAR(testPoint.w, 1.0f, 0.001f); +} + +TEST(MatrixTest, TestMulPoint3) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + Point3F testPoint(0.5f, 1.0f, 2.0f); + test.mulP(testPoint); + + EXPECT_NEAR(testPoint.x, 5.496f, 0.001f); EXPECT_NEAR(testPoint.y, 0.899f, 0.001f); EXPECT_NEAR(testPoint.z, 4.151f, 0.001f); +} + +TEST(MatrixTest, TestMulPoint3ToPoint3) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + Point3F point(0.5f, 1.0f, 2.0f); + Point3F testPoint; + test.mulP(point, &testPoint); + + EXPECT_NEAR(testPoint.x, 5.496f, 0.001f); EXPECT_NEAR(testPoint.y, 0.899f, 0.001f); EXPECT_NEAR(testPoint.z, 4.151f, 0.001f); +} + +TEST(MatrixTest, TestMulVector) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + VectorF testPoint(0.5f, 1.0f, 2.0f); + test.mulV(testPoint); + + EXPECT_NEAR(testPoint.x, 1.111f, 0.001f); EXPECT_NEAR(testPoint.y, 1.747f, 0.001f); EXPECT_NEAR(testPoint.z, 0.979f, 0.001f); +} + +TEST(MatrixTest, TestMulVectorToPoint3) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + VectorF vec(0.5f, 1.0f, 2.0f); + Point3F testPoint; + test.mulV(vec, &testPoint); + + EXPECT_NEAR(testPoint.x, 1.111f, 0.001f); EXPECT_NEAR(testPoint.y, 1.747f, 0.001f); EXPECT_NEAR(testPoint.z, 0.979f, 0.001f); +} + TEST(MatrixTest, TestMulBox) { MatrixF test(true); @@ -178,6 +294,30 @@ TEST(MatrixTest, TestMulBox) EXPECT_NEAR(testBox.maxExtents.x, 5.5f, 0.001f); EXPECT_NEAR(testBox.maxExtents.y, 2.5f, 0.001f); EXPECT_NEAR(testBox.maxExtents.z, 1.5f, 0.001f); } +TEST(MatrixTest, TestReverseProjection) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + + Frustum testFrustum(false, -1.0f, 1.0f, 1.0f, -1.0f, 0.1f, 100.0f, test); + + testFrustum.getProjectionMatrix(&test); + + + // test before and after reverse. + EXPECT_NEAR(test(0, 0), 0.1f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.1, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), -0.001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.1001f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + + test.reverseProjection(); + + EXPECT_NEAR(test(0, 0), 0.1f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.1, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 1.001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), -0.1001f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); +} + TEST(MatrixTest, TestInverse) { MatrixF test(true); @@ -212,6 +352,49 @@ TEST(MatrixTest, TestInvertTo) EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestIsAffine) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + EXPECT_TRUE(test.isAffine()); +} + +TEST(MatrixTest, TestScale) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + test.scale(2.0f); + + EXPECT_NEAR(test(0, 0), 1.0806f, 0.001f); EXPECT_NEAR(test(0, 1), 1.6829f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 4.3845f, 0.001f); + EXPECT_NEAR(test(1, 0), -0.9093f, 0.001f); EXPECT_NEAR(test(1, 1), 0.5839f, 0.001f); EXPECT_NEAR(test(1, 2), 1.6829f, 0.001f); EXPECT_NEAR(test(1, 3), -0.8479f, 0.001f); + EXPECT_NEAR(test(2, 0), 1.4161f, 0.001f); EXPECT_NEAR(test(2, 1), -0.9093f, 0.001f); EXPECT_NEAR(test(2, 2), 1.0806f, 0.001f); EXPECT_NEAR(test(2, 3), 3.1714f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + +TEST(MatrixTest, TestGetScale) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + test.scale(2.0f); + + Point3F scale; + scale = test.getScale(); + + EXPECT_NEAR(scale.x, 2.0f, 0.001f); EXPECT_NEAR(scale.y, 2.0f, 0.001f); EXPECT_NEAR(scale.z, 2.0f, 0.001f); +} + TEST(MatrixTest, TestAffineInverse) { MatrixF test(true); From f96e044d891a745243a9fbb804776530441b409e Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 30 Jul 2024 13:00:32 +0100 Subject: [PATCH 20/29] unit tests and fixes implemented the rest of the tests euler single dimension angle tests now pass, missed 1.0f in z --- Engine/source/math/mMatrix.h | 36 +- Engine/source/testing/mathMatrixTest.cpp | 522 +++++++++++++++++++++++ 2 files changed, 555 insertions(+), 3 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 8b92778bd..211c17f32 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -713,7 +713,10 @@ public: ///< a * b -> M Matrix& mul(const Matrix& a, const F32 b) { return *this = a * b; } - + Matrix& add(const Matrix& a) + { + return *this = *this += a; + } ///< M * p -> p (full [4x4] * [1x4]) void mul(Point4F& p) const { p = *this * p; } @@ -840,6 +843,33 @@ public: return *this; } + Matrix operator+(const Matrix& m2) { + Matrix result; + + for (U32 i = 0; i < rows; ++i) + { + for (U32 j = 0; j < cols; ++j) + { + result(i, j) = 0; // Initialize result element to 0 + result(i, j) = (*this)(i, j) + m2(i, j); + } + } + + return result; + } + + Matrix operator+=(const Matrix& m2) { + for (U32 i = 0; i < rows; ++i) + { + for (U32 j = 0; j < cols; ++j) + { + (*this)(i, j) += m2(i, j); + } + } + + return (*this); + } + Matrix operator * (const DATA_TYPE scalar) const { Matrix result; for (U32 i = 0; i < rows; i++) @@ -917,7 +947,7 @@ public: return data[idx(col,row)]; } - const DATA_TYPE& operator () (U32 row, U32 col) const { + DATA_TYPE operator () (U32 row, U32 col) const { if (row >= rows || col >= cols) AssertFatal(false, "Matrix indices out of range"); @@ -1302,7 +1332,7 @@ inline Matrix& Matrix::set(const E case AXIS_Z: (*this)(0, 0) = cosRoll; (*this)(1, 0) = -sinRoll; (*this)(2, 0) = 0.0f; (*this)(0, 1) = sinRoll; (*this)(1, 1) = cosRoll; (*this)(2, 1) = 0.0f; - (*this)(0, 2) = 0.0f; (*this)(1, 2) = 0.0f; (*this)(2, 2) = 0.0f; + (*this)(0, 2) = 0.0f; (*this)(1, 2) = 0.0f; (*this)(2, 2) = 1.0f; break; default: F32 r1 = cosYaw * cosRoll; diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 8b22e795f..f3cc6a233 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -93,6 +93,472 @@ TEST(MatrixTest, TestEulerPointSet) EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestGetColumn4) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point4F column; + + test.getColumn(0, &column); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 0), 0.001f); + EXPECT_NEAR(column.z, test(2, 0), 0.001f); + EXPECT_NEAR(column.w, test(3, 0), 0.001f); + + test.getColumn(1, &column); + + EXPECT_NEAR(column.x, test(0, 1), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 1), 0.001f); + EXPECT_NEAR(column.w, test(3, 1), 0.001f); + + test.getColumn(2, &column); + + EXPECT_NEAR(column.x, test(0, 2), 0.001f); + EXPECT_NEAR(column.y, test(1, 2), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.w, test(3, 2), 0.001f); + + test.getColumn(3, &column); + + EXPECT_NEAR(column.x, test(0, 3), 0.001f); + EXPECT_NEAR(column.y, test(1, 3), 0.001f); + EXPECT_NEAR(column.z, test(2, 3), 0.001f); + EXPECT_NEAR(column.w, test(3, 3), 0.001f); + +} + +TEST(MatrixTest, TestGetRow4) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point4F column; + + test.getRow(0, &column); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(0, 1), 0.001f); + EXPECT_NEAR(column.z, test(0, 2), 0.001f); + EXPECT_NEAR(column.w, test(0, 3), 0.001f); + + test.getRow(1, &column); + + EXPECT_NEAR(column.x, test(1, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(1, 2), 0.001f); + EXPECT_NEAR(column.w, test(1, 3), 0.001f); + + test.getRow(2, &column); + + EXPECT_NEAR(column.x, test(2, 0), 0.001f); + EXPECT_NEAR(column.y, test(2, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.w, test(2, 3), 0.001f); + + test.getRow(3, &column); + + EXPECT_NEAR(column.x, test(3, 0), 0.001f); + EXPECT_NEAR(column.y, test(3, 1), 0.001f); + EXPECT_NEAR(column.z, test(3, 2), 0.001f); + EXPECT_NEAR(column.w, test(3, 3), 0.001f); +} + +TEST(MatrixTest, TestGetColumn3) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point3F column; + + test.getColumn(0, &column); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 0), 0.001f); + EXPECT_NEAR(column.z, test(2, 0), 0.001f); + + test.getColumn(1, &column); + + EXPECT_NEAR(column.x, test(0, 1), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 1), 0.001f); + + test.getColumn(2, &column); + + EXPECT_NEAR(column.x, test(0, 2), 0.001f); + EXPECT_NEAR(column.y, test(1, 2), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + + test.getColumn(3, &column); + + EXPECT_NEAR(column.x, test(0, 3), 0.001f); + EXPECT_NEAR(column.y, test(1, 3), 0.001f); + EXPECT_NEAR(column.z, test(2, 3), 0.001f); + +} + +TEST(MatrixTest, TestGetRow3) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point3F column; + + test.getRow(0, &column); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(0, 1), 0.001f); + EXPECT_NEAR(column.z, test(0, 2), 0.001f); + + test.getRow(1, &column); + + EXPECT_NEAR(column.x, test(1, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(1, 2), 0.001f); + + test.getRow(2, &column); + + EXPECT_NEAR(column.x, test(2, 0), 0.001f); + EXPECT_NEAR(column.y, test(2, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + + test.getRow(3, &column); + + EXPECT_NEAR(column.x, test(3, 0), 0.001f); + EXPECT_NEAR(column.y, test(3, 1), 0.001f); + EXPECT_NEAR(column.z, test(3, 2), 0.001f); +} + +TEST(MatrixTest, TestGetColumn4F) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point4F column; + + column = test.getColumn4F(0); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 0), 0.001f); + EXPECT_NEAR(column.z, test(2, 0), 0.001f); + EXPECT_NEAR(column.w, test(3, 0), 0.001f); + + column = test.getColumn4F(1); + + EXPECT_NEAR(column.x, test(0, 1), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 1), 0.001f); + EXPECT_NEAR(column.w, test(3, 1), 0.001f); + + column = test.getColumn4F(2); + + EXPECT_NEAR(column.x, test(0, 2), 0.001f); + EXPECT_NEAR(column.y, test(1, 2), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.w, test(3, 2), 0.001f); + + column = test.getColumn4F(3); + + EXPECT_NEAR(column.x, test(0, 3), 0.001f); + EXPECT_NEAR(column.y, test(1, 3), 0.001f); + EXPECT_NEAR(column.z, test(2, 3), 0.001f); + EXPECT_NEAR(column.w, test(3, 3), 0.001f); + +} + +TEST(MatrixTest, TestGetRow4F) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point4F column; + + column = test.getRow4F(0); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(0, 1), 0.001f); + EXPECT_NEAR(column.z, test(0, 2), 0.001f); + EXPECT_NEAR(column.w, test(0, 3), 0.001f); + + column = test.getRow4F(1); + + EXPECT_NEAR(column.x, test(1, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(1, 2), 0.001f); + EXPECT_NEAR(column.w, test(1, 3), 0.001f); + + column = test.getRow4F(2); + + EXPECT_NEAR(column.x, test(2, 0), 0.001f); + EXPECT_NEAR(column.y, test(2, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.w, test(2, 3), 0.001f); + + column = test.getRow4F(3); + + EXPECT_NEAR(column.x, test(3, 0), 0.001f); + EXPECT_NEAR(column.y, test(3, 1), 0.001f); + EXPECT_NEAR(column.z, test(3, 2), 0.001f); + EXPECT_NEAR(column.w, test(3, 3), 0.001f); +} + +TEST(MatrixTest, TestGetColumn3F) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point3F column; + + column = test.getColumn3F(0); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 0), 0.001f); + EXPECT_NEAR(column.z, test(2, 0), 0.001f); + + column = test.getColumn3F(1); + + EXPECT_NEAR(column.x, test(0, 1), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 1), 0.001f); + + column = test.getColumn3F(2); + + EXPECT_NEAR(column.x, test(0, 2), 0.001f); + EXPECT_NEAR(column.y, test(1, 2), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + + column = test.getColumn3F(3); + + EXPECT_NEAR(column.x, test(0, 3), 0.001f); + EXPECT_NEAR(column.y, test(1, 3), 0.001f); + EXPECT_NEAR(column.z, test(2, 3), 0.001f); + +} + +TEST(MatrixTest, TestGetRow3F) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point3F column; + + column = test.getRow3F(0); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(0, 1), 0.001f); + EXPECT_NEAR(column.z, test(0, 2), 0.001f); + + column = test.getRow3F(1); + + EXPECT_NEAR(column.x, test(1, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(1, 2), 0.001f); + + column = test.getRow3F(2); + + EXPECT_NEAR(column.x, test(2, 0), 0.001f); + EXPECT_NEAR(column.y, test(2, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + + column = test.getRow3F(3); + + EXPECT_NEAR(column.x, test(3, 0), 0.001f); + EXPECT_NEAR(column.y, test(3, 1), 0.001f); + EXPECT_NEAR(column.z, test(3, 2), 0.001f); +} + +TEST(MatrixTest, TestSetColumn4) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point4F column(1.0f, 1.0f, 1.0f, 1.0f); + + test.setColumn(0, column); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 0), 0.001f); + EXPECT_NEAR(column.z, test(2, 0), 0.001f); + EXPECT_NEAR(column.w, test(3, 0), 0.001f); + + test.setColumn(1, column); + + EXPECT_NEAR(column.x, test(0, 1), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 1), 0.001f); + EXPECT_NEAR(column.w, test(3, 1), 0.001f); + + test.setColumn(2, column); + + EXPECT_NEAR(column.x, test(0, 2), 0.001f); + EXPECT_NEAR(column.y, test(1, 2), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.w, test(3, 2), 0.001f); + + test.setColumn(3, column); + + EXPECT_NEAR(column.x, test(0, 3), 0.001f); + EXPECT_NEAR(column.y, test(1, 3), 0.001f); + EXPECT_NEAR(column.z, test(2, 3), 0.001f); + EXPECT_NEAR(column.w, test(3, 3), 0.001f); +} + +TEST(MatrixTest, TestSetRow4) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point4F column(1.0f, 1.0f, 1.0f, 1.0f); + + test.setRow(0, column); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(0, 1), 0.001f); + EXPECT_NEAR(column.z, test(0, 2), 0.001f); + EXPECT_NEAR(column.w, test(0, 3), 0.001f); + + test.setRow(1, column); + + EXPECT_NEAR(column.x, test(1, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(1, 2), 0.001f); + EXPECT_NEAR(column.w, test(1, 3), 0.001f); + + test.setRow(2, column); + + EXPECT_NEAR(column.x, test(2, 0), 0.001f); + EXPECT_NEAR(column.y, test(2, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.w, test(2, 3), 0.001f); + + test.setRow(3, column); + + EXPECT_NEAR(column.x, test(3, 0), 0.001f); + EXPECT_NEAR(column.y, test(3, 1), 0.001f); + EXPECT_NEAR(column.z, test(3, 2), 0.001f); + EXPECT_NEAR(column.w, test(3, 3), 0.001f); +} + +TEST(MatrixTest, TestSetColumn3) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point3F column(1.0f, 1.0f, 1.0f); + + test.setColumn(0, column); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 0), 0.001f); + EXPECT_NEAR(column.z, test(2, 0), 0.001f); + + test.setColumn(1, column); + + EXPECT_NEAR(column.x, test(0, 1), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 1), 0.001f); + + test.setColumn(2, column); + + EXPECT_NEAR(column.x, test(0, 2), 0.001f); + EXPECT_NEAR(column.y, test(1, 2), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + + test.setColumn(3, column); + + EXPECT_NEAR(column.x, test(0, 3), 0.001f); + EXPECT_NEAR(column.y, test(1, 3), 0.001f); + EXPECT_NEAR(column.z, test(2, 3), 0.001f); +} + +TEST(MatrixTest, TestSetRow3) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point3F column(1.0f, 1.0f, 1.0f); + + test.setRow(0, column); + + EXPECT_NEAR(column.x, test(0, 0), 0.001f); + EXPECT_NEAR(column.y, test(0, 1), 0.001f); + EXPECT_NEAR(column.z, test(0, 2), 0.001f); + + test.setRow(1, column); + + EXPECT_NEAR(column.x, test(1, 0), 0.001f); + EXPECT_NEAR(column.y, test(1, 1), 0.001f); + EXPECT_NEAR(column.z, test(1, 2), 0.001f); + + test.setRow(2, column); + + EXPECT_NEAR(column.x, test(2, 0), 0.001f); + EXPECT_NEAR(column.y, test(2, 1), 0.001f); + EXPECT_NEAR(column.z, test(2, 2), 0.001f); + + test.setRow(3, column); + + EXPECT_NEAR(column.x, test(3, 0), 0.001f); + EXPECT_NEAR(column.y, test(3, 1), 0.001f); + EXPECT_NEAR(column.z, test(3, 2), 0.001f); +} + +TEST(MatrixTest, TestDisplace) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + Point3F column(1.0f, 1.0f, 1.0f); + + test.displace(column); + + EXPECT_NEAR(test(0, 3), 6.0f, 0.001f); + EXPECT_NEAR(test(1, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(2, 3), 2.0f, 0.001f); +} + +TEST(MatrixTest, TestGetVectorFunctions) +{ + MatrixF test(true); + + test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); + + VectorF vector; + + vector = test.getRightVector(); + + EXPECT_NEAR(vector.x, test(0, 0), 0.001f); + EXPECT_NEAR(vector.y, test(1, 0), 0.001f); + EXPECT_NEAR(vector.z, test(2, 0), 0.001f); + + vector = test.getForwardVector(); + + EXPECT_NEAR(vector.x, test(0, 1), 0.001f); + EXPECT_NEAR(vector.y, test(1, 1), 0.001f); + EXPECT_NEAR(vector.z, test(2, 1), 0.001f); + + vector = test.getUpVector(); + + EXPECT_NEAR(vector.x, test(0, 2), 0.001f); + EXPECT_NEAR(vector.y, test(1, 2), 0.001f); + EXPECT_NEAR(vector.z, test(2, 2), 0.001f); +} + TEST(MatrixTest, TestSetCrossProduct) { MatrixF test(true); @@ -175,6 +641,21 @@ TEST(MatrixTest, TestMulArgMatrixFunction) EXPECT_NEAR(testResult(3, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestMulArgMultipleRotationMatrix) +{ + MatrixF testResult(true); + + MatrixF xRot(EulerF(-1.54f, 0.0f, 0.0f)); + MatrixF zRot(EulerF(0.0f, 0.0f, -1.57f)); + + testResult.mul(zRot, xRot); + + EXPECT_NEAR(testResult(0, 0), 0.0008f, 0.001f); EXPECT_NEAR(testResult(0, 1), -0.0308f, 0.001f);EXPECT_NEAR(testResult(0, 2), 0.9995f, 0.001f); EXPECT_NEAR(testResult(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(testResult(1, 0), 1.0f, 0.001f); EXPECT_NEAR(testResult(1, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(1, 2), -0.0008f, 0.001f); EXPECT_NEAR(testResult(1, 3), 0.0f, 0.001f); + EXPECT_NEAR(testResult(2, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(2, 1), 0.9995f, 0.001f); EXPECT_NEAR(testResult(2, 2), 0.0308f, 0.001f); EXPECT_NEAR(testResult(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(testResult(3, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 1.0f, 0.001f); +} + TEST(MatrixTest, TestMulScalarFunction) { MatrixF test(true); @@ -294,6 +775,31 @@ TEST(MatrixTest, TestMulBox) EXPECT_NEAR(testBox.maxExtents.x, 5.5f, 0.001f); EXPECT_NEAR(testBox.maxExtents.y, 2.5f, 0.001f); EXPECT_NEAR(testBox.maxExtents.z, 1.5f, 0.001f); } +TEST(MatrixTest, TestMatrixAdd) +{ + MatrixF test(true); + MatrixF test2(true); + for (U32 i = 0; i < 4; i++) + { + for (U32 j = 0; j < 4; j++) + { + test(i, j) = 1.0f; + test2(i, j) = 1.0f; + } + } + + test.add(test2); + + for (U32 i = 0; i < 4; i++) + { + for (U32 j = 0; j < 4; j++) + { + EXPECT_NEAR(test(i,j), 2.0f, 0.001f); + } + } + +} + TEST(MatrixTest, TestReverseProjection) { MatrixF test(true); @@ -352,6 +858,22 @@ TEST(MatrixTest, TestInvertTo) EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); } +TEST(MatrixTest, TestFullInverse) +{ + MatrixF test(true); + test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); + MatrixF test2(EulerF(1.0f, 0.0f, 1.0f)); + + test.mulL(test2); + + EXPECT_TRUE(test.fullInverse()); + + EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), -5.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); +} + TEST(MatrixTest, TestIsAffine) { MatrixF test(true); From 4078f3ad4ed8e3cd88b20a72e9ad0769f2a7d163 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 30 Jul 2024 17:54:16 +0100 Subject: [PATCH 21/29] inverse fixes further tests showed issues with inverse function, now to better match what was originally happening, the inverse only happens on the 3x3 portion of the matrix and translation is handled separately. Frustum test now uses more real world examples of a projection matrix. Test for the full unproject stack of math to test its result as unproject was where the issue about inverse originated --- Engine/source/math/mMatrix.h | 23 ++++++++++-- Engine/source/testing/mathMatrixTest.cpp | 48 +++++++++++++++++------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 211c17f32..8226bb12c 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -698,6 +698,17 @@ public: void setPosition(const Point3F& pos) { setColumn(3, pos); } + DATA_TYPE determinant() const { + AssertFatal(rows == cols, "Determinant is only defined for square matrices."); + // For simplicity, only implement for 3x3 matrices + AssertFatal(rows >= 3 && cols >= 3, "Determinant only for 3x3 or more"); // Ensure the matrix is 3x3 + DATA_TYPE det = + data[0] * (data[4] * data[8] - data[5] * data[7]) - + data[1] * (data[3] * data[8] - data[5] * data[6]) + + data[2] * (data[3] * data[7] - data[4] * data[6]); + return det; + } + ///< M * a -> M Matrix& mul(const Matrix& a) { return *this = *this * a; } @@ -1406,10 +1417,10 @@ inline Matrix& Matrix::inverse() { // TODO: insert return statement here AssertFatal(rows == cols, "Can only perform inverse on square matrices."); - const U32 size = rows; + const U32 size = rows - 1; // Create augmented matrix [this | I] - Matrix augmentedMatrix; + Matrix augmentedMatrix; for (U32 i = 0; i < size; i++) { @@ -1449,12 +1460,12 @@ inline Matrix& Matrix::inverse() return *this; } - DATA_TYPE pivotVal = augmentedMatrix(i, i); + DATA_TYPE pivotVal = 1.0f / augmentedMatrix(i, i); // scale the pivot for (U32 j = 0; j < 2 * size; j++) { - augmentedMatrix(i, j) /= pivotVal; + augmentedMatrix(i, j) *= pivotVal; } // Eliminate the current column in all other rows @@ -1479,6 +1490,10 @@ inline Matrix& Matrix::inverse() } } + Point3F pos = -this->getPosition(); + mulV(pos); + this->setPosition(pos); + return (*this); } diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index f3cc6a233..9237bc8b3 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -8,6 +8,7 @@ #include "console/engineAPI.h" #include "math/mMath.h" #include "math/util/frustum.h" +#include "math/mathUtils.h" TEST(MatrixTest, TestIdentityInit) { @@ -800,28 +801,47 @@ TEST(MatrixTest, TestMatrixAdd) } -TEST(MatrixTest, TestReverseProjection) +TEST(MatrixTest, TestFrustumProjectionMatrix) { MatrixF test(true); - test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); - - Frustum testFrustum(false, -1.0f, 1.0f, 1.0f, -1.0f, 0.1f, 100.0f, test); + Frustum testFrustum(false, -0.119894862f, 0.119894862f, 0.0767327100f, -0.0767327100f, 0.1f, 1000.0f); testFrustum.getProjectionMatrix(&test); - - // test before and after reverse. - EXPECT_NEAR(test(0, 0), 0.1f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.1, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), -0.001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.1001f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.8341f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 1.3032f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), -0.0001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.1f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); test.reverseProjection(); - EXPECT_NEAR(test(0, 0), 0.1f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.1, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 1.001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), -0.1001f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.8341f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 1.3032f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 1.0001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), -0.1f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + + test.inverse(); + + EXPECT_NEAR(test(0, 0), 1.1989f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.9999f, 0.001f); EXPECT_NEAR(test(1, 3), 0.1f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 0.7673f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + +} + +TEST(MatrixTest, TestUnProjectStack) +{ + MatrixF saveModel(true); + MatrixF saveProjection(true); + RectI renderRect(0 ,0, 1600, 1024); + + Frustum testFrustum(false, -0.119894862f, 0.119894862f, 0.0767327100f, -0.0767327100f, 0.1f, 1000.0f); + + testFrustum.getProjectionMatrix(&saveProjection); + + Point3F dest; + MathUtils::mProjectScreenToWorld(Point3F(626.0f, 600.0f, 1.0f), &dest, renderRect, saveModel, saveProjection, 0.1f, 10.0f); + EXPECT_NEAR(dest.x, -0.2868f, 0.001f); EXPECT_NEAR(dest.y, 1.1998f, 0.001f); EXPECT_NEAR(dest.z, -0.1450f, 0.001f); } TEST(MatrixTest, TestInverse) From ab4b4cbf969da48cefdfaf29e23bb50d4b2c2a69 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 31 Jul 2024 17:32:00 +0100 Subject: [PATCH 22/29] cramer for inverse added #if block around inverse methods to track down shadow bug uses old inverse method as default for now. --- Engine/source/math/mMatrix.h | 351 ++++++++++++++++++----- Engine/source/testing/mathMatrixTest.cpp | 67 +++++ 2 files changed, 349 insertions(+), 69 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 8226bb12c..aed956f6d 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -127,6 +127,10 @@ public: EulerF toEuler() const; + F32 determinant() const { + return m_matF_determinant(*this); + } + /// Compute the inverse of the matrix. /// /// Computes inverse of full 4x4 matrix. Returns false and performs no inverse if @@ -702,11 +706,9 @@ public: AssertFatal(rows == cols, "Determinant is only defined for square matrices."); // For simplicity, only implement for 3x3 matrices AssertFatal(rows >= 3 && cols >= 3, "Determinant only for 3x3 or more"); // Ensure the matrix is 3x3 - DATA_TYPE det = - data[0] * (data[4] * data[8] - data[5] * data[7]) - - data[1] * (data[3] * data[8] - data[5] * data[6]) + - data[2] * (data[3] * data[7] - data[4] * data[6]); - return det; + return (*this)(0, 0) * ((*this)(1, 1) * (*this)(2, 2) - (*this)(1, 2) * (*this)(2, 1)) + + (*this)(1, 0) * ((*this)(0, 2) * (*this)(2, 1) - (*this)(0, 1) * (*this)(2, 2)) + + (*this)(2, 0) * ((*this)(0, 1) * (*this)(1, 2) - (*this)(0, 2) * (*this)(1, 1)); } ///< M * a -> M @@ -823,6 +825,12 @@ public: } } + void swap(DATA_TYPE& a, DATA_TYPE& b) { + DATA_TYPE temp = a; + a = b; + b = temp; + } + void invertTo(Matrix* matrix) const; void invertTo(Matrix* matrix); @@ -834,17 +842,25 @@ public: friend Matrix operator*(const Matrix& m1, const Matrix& m2) { Matrix result; - for (U32 i = 0; i < rows; ++i) - { - for (U32 j = 0; j < cols; ++j) - { - result(i, j) = 0; // Initialize result element to 0 - for (U32 k = 0; k < cols; ++k) - { - result(i, j) += m1(i, k) * m2(k, j); - } - } - } + result(0, 0) = m1(0, 0) * m2(0, 0) + m1(0, 1) * m2(1, 0) + m1(0, 2) * m2(2, 0) + m1(0, 3) * m2(3, 0); + result(0, 1) = m1(0, 0) * m2(0, 1) + m1(0, 1) * m2(1, 1) + m1(0, 2) * m2(2, 1) + m1(0, 3) * m2(3, 1); + result(0, 2) = m1(0, 0) * m2(0, 2) + m1(0, 1) * m2(1, 2) + m1(0, 2) * m2(2, 2) + m1(0, 3) * m2(3, 2); + result(0, 3) = m1(0, 0) * m2(0, 3) + m1(0, 1) * m2(1, 3) + m1(0, 2) * m2(2, 3) + m1(0, 3) * m2(3, 3); + + result(1, 0) = m1(1, 0) * m2(0, 0) + m1(1, 1) * m2(1, 0) + m1(1, 2) * m2(2, 0) + m1(1, 3) * m2(3, 0); + result(1, 1) = m1(1, 0) * m2(0, 1) + m1(1, 1) * m2(1, 1) + m1(1, 2) * m2(2, 1) + m1(1, 3) * m2(3, 1); + result(1, 2) = m1(1, 0) * m2(0, 2) + m1(1, 1) * m2(1, 2) + m1(1, 2) * m2(2, 2) + m1(1, 3) * m2(3, 2); + result(1, 3) = m1(1, 0) * m2(0, 3) + m1(1, 1) * m2(1, 3) + m1(1, 2) * m2(2, 3) + m1(1, 3) * m2(3, 3); + + result(2, 0) = m1(2, 0) * m2(0, 0) + m1(2, 1) * m2(1, 0) + m1(2, 2) * m2(2, 0) + m1(2, 3) * m2(3, 0); + result(2, 1) = m1(2, 0) * m2(0, 1) + m1(2, 1) * m2(1, 1) + m1(2, 2) * m2(2, 1) + m1(2, 3) * m2(3, 1); + result(2, 2) = m1(2, 0) * m2(0, 2) + m1(2, 1) * m2(1, 2) + m1(2, 2) * m2(2, 2) + m1(2, 3) * m2(3, 2); + result(2, 3) = m1(2, 0) * m2(0, 3) + m1(2, 1) * m2(1, 3) + m1(2, 2) * m2(2, 3) + m1(2, 3) * m2(3, 3); + + result(3, 0) = m1(3, 0) * m2(0, 0) + m1(3, 1) * m2(1, 0) + m1(3, 2) * m2(2, 0) + m1(3, 3) * m2(3, 0); + result(3, 1) = m1(3, 0) * m2(0, 1) + m1(3, 1) * m2(1, 1) + m1(3, 2) * m2(2, 1) + m1(3, 3) * m2(3, 1); + result(3, 2) = m1(3, 0) * m2(0, 2) + m1(3, 1) * m2(1, 2) + m1(3, 2) * m2(2, 2) + m1(3, 3) * m2(3, 2); + result(3, 3) = m1(3, 0) * m2(0, 3) + m1(3, 1) * m2(1, 3) + m1(3, 2) * m2(2, 3) + m1(3, 3) * m2(3, 3); return result; } @@ -907,13 +923,14 @@ public: Point3F operator*(const Point3F& point) const { AssertFatal(rows == 4 && cols == 4, "Multiplying point3 with matrix requires 4x4"); - return Point3F( - (*this)(0, 0) * point.x + (*this)(0, 1) * point.y + (*this)(0, 2) * point.z + (*this)(0, 3), - (*this)(1, 0) * point.x + (*this)(1, 1) * point.y + (*this)(1, 2) * point.z + (*this)(1, 3), - (*this)(2, 0) * point.x + (*this)(2, 1) * point.y + (*this)(2, 2) * point.z + (*this)(2, 3) - ); - } + Point3F result; + result.x = (*this)(0, 0) * point.x + (*this)(0, 1) * point.y + (*this)(0, 2) * point.z + (*this)(0, 3); + result.y = (*this)(1, 0) * point.x + (*this)(1, 1) * point.y + (*this)(1, 2) * point.z + (*this)(1, 3); + result.z = (*this)(2, 0) * point.x + (*this)(2, 1) * point.y + (*this)(2, 2) * point.z + (*this)(2, 3); + return result; + } + Point4F operator*(const Point4F& point) const { AssertFatal(rows == 4 && cols == 4, "Multiplying point4 with matrix requires 4x4"); return Point4F( @@ -964,7 +981,6 @@ public: return data[idx(col, row)]; } - }; //-------------------------------------------- @@ -975,11 +991,13 @@ inline Matrix& Matrix::transpose() { AssertFatal(rows == cols, "Transpose can only be performed on square matrices."); - for (U32 i = 0; i < rows; ++i) { - for (U32 j = i + 1; j < cols; ++j) { - std::swap((*this)(i, j), (*this)(j, i)); - } - } + swap((*this)(0, 1), (*this)(1, 0)); + swap((*this)(0, 2), (*this)(2, 0)); + swap((*this)(0, 3), (*this)(3, 0)); + swap((*this)(1, 2), (*this)(2, 1)); + swap((*this)(1, 3), (*this)(3, 1)); + swap((*this)(2, 3), (*this)(3, 2)); + return (*this); } @@ -1331,9 +1349,9 @@ inline Matrix& Matrix::set(const E (*this) = Matrix(true); break; case AXIS_X: - (*this)(0, 0) = 1.0f; (*this)(1, 0) = 0.0f; (*this)(2, 0) = 0.0f; - (*this)(0, 1) = 0.0f; (*this)(1, 1) = cosPitch; (*this)(2, 1) = -sinPitch; - (*this)(0, 2) = 0.0f; (*this)(1, 2) = sinPitch; (*this)(2, 2) = cosPitch; + (*this)(0, 0) = 1.0f; (*this)(0, 1) = 0.0f; (*this)(0, 2) = 0.0f; + (*this)(1, 0) = 0.0f; (*this)(1, 1) = cosPitch; (*this)(1, 2) = sinPitch; + (*this)(2, 0) = 0.0f; (*this)(2, 1) = -sinPitch; (*this)(2, 2) = cosPitch; break; case AXIS_Y: (*this)(0, 0) = cosYaw; (*this)(1, 0) = 0.0f; (*this)(2, 0) = sinYaw; @@ -1341,9 +1359,9 @@ inline Matrix& Matrix::set(const E (*this)(0, 2) = -sinYaw; (*this)(1, 2) = 0.0f; (*this)(2, 2) = cosYaw; break; case AXIS_Z: - (*this)(0, 0) = cosRoll; (*this)(1, 0) = -sinRoll; (*this)(2, 0) = 0.0f; - (*this)(0, 1) = sinRoll; (*this)(1, 1) = cosRoll; (*this)(2, 1) = 0.0f; - (*this)(0, 2) = 0.0f; (*this)(1, 2) = 0.0f; (*this)(2, 2) = 1.0f; + (*this)(0, 0) = cosRoll; (*this)(0, 1) = sinRoll; (*this)(0, 2) = 0.0f; + (*this)(1, 0) = -sinRoll; (*this)(1, 1) = cosRoll; (*this)(1, 2) = 0.0f; + (*this)(2, 0) = 0.0f; (*this)(2, 1) = 0.0f; (*this)(2, 2) = 1.0f; break; default: F32 r1 = cosYaw * cosRoll; @@ -1363,9 +1381,9 @@ inline Matrix& Matrix::set(const E // r4 = sin(y) * sin(z) // init the euler 3x3 rotation matrix. - (*this)(0, 0) = r1 - (r4 * sinPitch); (*this)(1, 0) = -cosPitch * sinRoll; (*this)(2, 0) = r3 + (r2 * sinPitch); - (*this)(0, 1) = r2 + (r3 * sinPitch); (*this)(1, 1) = cosPitch * cosRoll; (*this)(2, 1) = r4 - (r1 * sinPitch); - (*this)(0, 2) = -cosPitch * sinYaw; (*this)(1, 2) = sinPitch; (*this)(2, 2) = cosPitch * cosYaw; + (*this)(0, 0) = r1 - (r4 * sinPitch); (*this)(0, 1) = r2 + (r3 * sinPitch); (*this)(0, 2) = -cosPitch * sinYaw; + (*this)(1, 0) = -cosPitch * sinRoll; (*this)(1, 1) = cosPitch * cosRoll; (*this)(1, 2) = sinPitch; + (*this)(2, 0) = r3 + (r2 * sinPitch); (*this)(2, 1) = r4 - (r1 * sinPitch); (*this)(2, 2) = cosPitch * cosYaw; break; } @@ -1415,9 +1433,13 @@ inline Matrix& Matrix::set(const E template inline Matrix& Matrix::inverse() { - // TODO: insert return statement here +#if 0 + // NOTE: Gauss-Jordan elimination is yielding unpredictable results due to precission handling and + // numbers near 0.0 + // AssertFatal(rows == cols, "Can only perform inverse on square matrices."); const U32 size = rows - 1; + const DATA_TYPE pivot_eps = static_cast(1e-20); // Smaller epsilon to handle numerical precision // Create augmented matrix [this | I] Matrix augmentedMatrix; @@ -1436,11 +1458,14 @@ inline Matrix& Matrix::inverse() { U32 pivotRow = i; + DATA_TYPE pivotValue = std::abs(augmentedMatrix(i, i)); + for (U32 k = i + 1; k < size; k++) { - // use std::abs until the templated math functions are in place. - if (std::abs(augmentedMatrix(k, i)) > std::abs(augmentedMatrix(pivotRow, i))) { + DATA_TYPE curValue = std::abs(augmentedMatrix(k, i)); + if (curValue > pivotValue) { pivotRow = k; + pivotValue = curValue; } } @@ -1449,18 +1474,20 @@ inline Matrix& Matrix::inverse() { for (U32 j = 0; j < 2 * size; j++) { - std::swap(augmentedMatrix(i, j), augmentedMatrix(pivotRow, j)); + DATA_TYPE temp = augmentedMatrix(i, j); + augmentedMatrix(i, j) = augmentedMatrix(pivotRow, j); + augmentedMatrix(pivotRow, j) = temp; } } // Early out if pivot is 0, return identity matrix. - if (augmentedMatrix(i, i) == static_cast(0)) + if (std::abs(augmentedMatrix(i, i)) < pivot_eps) { this->identity(); return *this; } - DATA_TYPE pivotVal = 1.0f / augmentedMatrix(i, i); + DATA_TYPE pivotVal = static_cast(1.0) / augmentedMatrix(i, i); // scale the pivot for (U32 j = 0; j < 2 * size; j++) @@ -1489,6 +1516,44 @@ inline Matrix& Matrix::inverse() (*this)(i, j) = augmentedMatrix(i, j + size); } } +#else + AssertFatal(rows == cols, "Can only perform inverse on square matrices."); + AssertFatal(rows >= 3 && cols >= 3, "Must be at least a 3x3 matrix"); + DATA_TYPE det = determinant(); + + // Check if the determinant is non-zero + if (std::abs(det) < static_cast(1e-10)) { + this->identity(); // Return the identity matrix if the determinant is zero + return *this; + } + + DATA_TYPE invDet = DATA_TYPE(1) / det; + + Matrix temp; + + // Calculate the inverse of the 3x3 upper-left submatrix using Cramer's rule + temp(0, 0) = ((*this)(1, 1) * (*this)(2, 2) - (*this)(1, 2) * (*this)(2, 1)) * invDet; + temp(0, 1) = ((*this)(2, 1) * (*this)(0, 2) - (*this)(2, 2) * (*this)(0, 1)) * invDet; + temp(0, 2) = ((*this)(0, 1) * (*this)(1, 2) - (*this)(0, 2) * (*this)(1, 1)) * invDet; + + temp(1, 0) = ((*this)(1, 2) * (*this)(2, 0) - (*this)(1, 0) * (*this)(2, 2)) * invDet; + temp(1, 1) = ((*this)(2, 2) * (*this)(0, 0) - (*this)(2, 0) * (*this)(0, 2)) * invDet; + temp(1, 2) = ((*this)(0, 2) * (*this)(1, 0) - (*this)(0, 0) * (*this)(1, 2)) * invDet; + + temp(2, 0) = ((*this)(1, 0) * (*this)(2, 1) - (*this)(1, 1) * (*this)(2, 0)) * invDet; + temp(2, 1) = ((*this)(2, 0) * (*this)(0, 1) - (*this)(2, 1) * (*this)(0, 0)) * invDet; + temp(2, 2) = ((*this)(0, 0) * (*this)(1, 1) - (*this)(0, 1) * (*this)(1, 0)) * invDet; + + // Copy the 3x3 inverse back into this matrix + for (U32 i = 0; i < 3; ++i) + { + for (U32 j = 0; j < 3; ++j) + { + (*this)(i, j) = temp(i, j); + } + } + +#endif Point3F pos = -this->getPosition(); mulV(pos); @@ -1500,13 +1565,136 @@ inline Matrix& Matrix::inverse() template inline bool Matrix::fullInverse() { - Matrix inv = this->inverse(); +#if 0 + // NOTE: Gauss-Jordan elimination is yielding unpredictable results due to precission handling and + // numbers near 0.0 + AssertFatal(rows == cols, "Can only perform inverse on square matrices."); + const U32 size = rows; + const DATA_TYPE pivot_eps = static_cast(1e-20); // Smaller epsilon to handle numerical precision - if (inv.isIdentity()) + // Create augmented matrix [this | I] + Matrix augmentedMatrix; + + for (U32 i = 0; i < size; i++) + { + for (U32 j = 0; j < size; j++) + { + augmentedMatrix(i, j) = (*this)(i, j); + augmentedMatrix(i, j + size) = (i == j) ? static_cast(1) : static_cast(0); + } + } + + // Apply gauss-joran elimination + for (U32 i = 0; i < size; i++) + { + U32 pivotRow = i; + + DATA_TYPE pivotValue = std::abs(augmentedMatrix(i, i)); + + for (U32 k = i + 1; k < size; k++) + { + DATA_TYPE curValue = std::abs(augmentedMatrix(k, i)); + if (curValue > pivotValue) { + pivotRow = k; + pivotValue = curValue; + } + } + + // Swap if needed. + if (i != pivotRow) + { + for (U32 j = 0; j < 2 * size; j++) + { + DATA_TYPE temp = augmentedMatrix(i, j); + augmentedMatrix(i, j) = augmentedMatrix(pivotRow, j); + augmentedMatrix(pivotRow, j) = temp; + } + } + + // Early out if pivot is 0, return identity matrix. + if (std::abs(augmentedMatrix(i, i)) < pivot_eps) + { + return false; + } + + DATA_TYPE pivotVal = static_cast(1.0) / augmentedMatrix(i, i); + + // scale the pivot + for (U32 j = 0; j < 2 * size; j++) + { + augmentedMatrix(i, j) *= pivotVal; + } + + // Eliminate the current column in all other rows + for (U32 k = 0; k < size; k++) + { + if (k != i) + { + DATA_TYPE factor = augmentedMatrix(k, i); + for (U32 j = 0; j < 2 * size; j++) + { + augmentedMatrix(k, j) -= factor * augmentedMatrix(i, j); + } + } + } + } + + for (U32 i = 0; i < size; i++) + { + for (U32 j = 0; j < size; j++) + { + (*this)(i, j) = augmentedMatrix(i, j + size); + } + } +#else + AssertFatal(rows == cols, "Can only perform inverse on square matrices."); + AssertFatal(rows >= 4 && cols >= 4, "Can only perform fullInverse on minimum 4x4 matrix"); + + Point4F a, b, c, d; + getRow(0, &a); + getRow(1, &b); + getRow(2, &c); + getRow(3, &d); + + F32 det = a.x * b.y * c.z * d.w - a.x * b.y * c.w * d.z - a.x * c.y * b.z * d.w + a.x * c.y * b.w * d.z + a.x * d.y * b.z * c.w - a.x * d.y * b.w * c.z + - b.x * a.y * c.z * d.w + b.x * a.y * c.w * d.z + b.x * c.y * a.z * d.w - b.x * c.y * a.w * d.z - b.x * d.y * a.z * c.w + b.x * d.y * a.w * c.z + + c.x * a.y * b.z * d.w - c.x * a.y * b.w * d.z - c.x * b.y * a.z * d.w + c.x * b.y * a.w * d.z + c.x * d.y * a.z * b.w - c.x * d.y * a.w * b.z + - d.x * a.y * b.z * c.w + d.x * a.y * b.w * c.z + d.x * b.y * a.z * c.w - d.x * b.y * a.w * c.z - d.x * c.y * a.z * b.w + d.x * c.y * a.w * b.z; + + if (mFabs(det) < 0.00001f) return false; - *this = inv; + Point4F aa, bb, cc, dd; + aa.x = b.y * c.z * d.w - b.y * c.w * d.z - c.y * b.z * d.w + c.y * b.w * d.z + d.y * b.z * c.w - d.y * b.w * c.z; + aa.y = -a.y * c.z * d.w + a.y * c.w * d.z + c.y * a.z * d.w - c.y * a.w * d.z - d.y * a.z * c.w + d.y * a.w * c.z; + aa.z = a.y * b.z * d.w - a.y * b.w * d.z - b.y * a.z * d.w + b.y * a.w * d.z + d.y * a.z * b.w - d.y * a.w * b.z; + aa.w = -a.y * b.z * c.w + a.y * b.w * c.z + b.y * a.z * c.w - b.y * a.w * c.z - c.y * a.z * b.w + c.y * a.w * b.z; + + bb.x = -b.x * c.z * d.w + b.x * c.w * d.z + c.x * b.z * d.w - c.x * b.w * d.z - d.x * b.z * c.w + d.x * b.w * c.z; + bb.y = a.x * c.z * d.w - a.x * c.w * d.z - c.x * a.z * d.w + c.x * a.w * d.z + d.x * a.z * c.w - d.x * a.w * c.z; + bb.z = -a.x * b.z * d.w + a.x * b.w * d.z + b.x * a.z * d.w - b.x * a.w * d.z - d.x * a.z * b.w + d.x * a.w * b.z; + bb.w = a.x * b.z * c.w - a.x * b.w * c.z - b.x * a.z * c.w + b.x * a.w * c.z + c.x * a.z * b.w - c.x * a.w * b.z; + + cc.x = b.x * c.y * d.w - b.x * c.w * d.y - c.x * b.y * d.w + c.x * b.w * d.y + d.x * b.y * c.w - d.x * b.w * c.y; + cc.y = -a.x * c.y * d.w + a.x * c.w * d.y + c.x * a.y * d.w - c.x * a.w * d.y - d.x * a.y * c.w + d.x * a.w * c.y; + cc.z = a.x * b.y * d.w - a.x * b.w * d.y - b.x * a.y * d.w + b.x * a.w * d.y + d.x * a.y * b.w - d.x * a.w * b.y; + cc.w = -a.x * b.y * c.w + a.x * b.w * c.y + b.x * a.y * c.w - b.x * a.w * c.y - c.x * a.y * b.w + c.x * a.w * b.y; + + dd.x = -b.x * c.y * d.z + b.x * c.z * d.y + c.x * b.y * d.z - c.x * b.z * d.y - d.x * b.y * c.z + d.x * b.z * c.y; + dd.y = a.x * c.y * d.z - a.x * c.z * d.y - c.x * a.y * d.z + c.x * a.z * d.y + d.x * a.y * c.z - d.x * a.z * c.y; + dd.z = -a.x * b.y * d.z + a.x * b.z * d.y + b.x * a.y * d.z - b.x * a.z * d.y - d.x * a.y * b.z + d.x * a.z * b.y; + dd.w = a.x * b.y * c.z - a.x * b.z * c.y - b.x * a.y * c.z + b.x * a.z * c.y + c.x * a.y * b.z - c.x * a.z * b.y; + + setRow(0, aa); + setRow(1, bb); + setRow(2, cc); + setRow(3, dd); + + mul(1.0f / det); +#endif + return true; + } template @@ -1576,39 +1764,67 @@ inline void Matrix::mul(Box3F& box) const { AssertFatal(rows == 4 && cols == 4, "Multiplying Box3F with matrix requires 4x4"); - // Save original min and max - Point3F originalMin = box.minExtents; - Point3F originalMax = box.maxExtents; + // Extract the min and max extents + const Point3F& originalMin = box.minExtents; + const Point3F& originalMax = box.maxExtents; - // Initialize min and max with the translation part of the matrix - box.minExtents.x = box.maxExtents.x = (*this)(0, 3); - box.minExtents.y = box.maxExtents.y = (*this)(1, 3); - box.minExtents.z = box.maxExtents.z = (*this)(2, 3); + // Array to store transformed corners + Point3F transformedCorners[8]; - for (U32 i = 0; i < 3; ++i) { - #define Do_One_Row(j) { \ - DATA_TYPE a = ((*this)(i, j) * originalMin[j]); \ - DATA_TYPE b = ((*this)(i, j) * originalMax[j]); \ - if (a < b) { box.minExtents[i] += a; box.maxExtents[i] += b; } \ - else { box.minExtents[i] += b; box.maxExtents[i] += a; } } + // Compute all 8 corners of the box + Point3F corners[8] = { + {originalMin.x, originalMin.y, originalMin.z}, + {originalMax.x, originalMin.y, originalMin.z}, + {originalMin.x, originalMax.y, originalMin.z}, + {originalMax.x, originalMax.y, originalMin.z}, + {originalMin.x, originalMin.y, originalMax.z}, + {originalMax.x, originalMin.y, originalMax.z}, + {originalMin.x, originalMax.y, originalMax.z}, + {originalMax.x, originalMax.y, originalMax.z} + }; - Do_One_Row(0); - Do_One_Row(1); - Do_One_Row(2); + // Transform each corner + for (U32 i = 0; i < 8; ++i) + { + const Point3F& corner = corners[i]; + transformedCorners[i].x = (*this)(0, 0) * corner.x + (*this)(0, 1) * corner.y + (*this)(0, 2) * corner.z + (*this)(0, 3); + transformedCorners[i].y = (*this)(1, 0) * corner.x + (*this)(1, 1) * corner.y + (*this)(1, 2) * corner.z + (*this)(1, 3); + transformedCorners[i].z = (*this)(2, 0) * corner.x + (*this)(2, 1) * corner.y + (*this)(2, 2) * corner.z + (*this)(2, 3); } + + // Initialize min and max extents to the transformed values + Point3F newMin = transformedCorners[0]; + Point3F newMax = transformedCorners[0]; + + // Compute the new min and max extents from the transformed corners + for (U32 i = 1; i < 8; ++i) + { + const Point3F& corner = transformedCorners[i]; + if (corner.x < newMin.x) newMin.x = corner.x; + if (corner.y < newMin.y) newMin.y = corner.y; + if (corner.z < newMin.z) newMin.z = corner.z; + + if (corner.x > newMax.x) newMax.x = corner.x; + if (corner.y > newMax.y) newMax.y = corner.y; + if (corner.z > newMax.z) newMax.z = corner.z; + } + + // Update the box with the new min and max extents + box.minExtents = newMin; + box.maxExtents = newMax; } template inline bool Matrix::isAffine() const { - if ((*this)(rows - 1, cols - 1) != 1.0f) + if ((*this)(3, 3) != 1.0f) { return false; } for (U32 col = 0; col < cols - 1; ++col) { - if ((*this)(rows - 1, col) != 0.0f) + if ((*this)(3, col) != 0.0f) { return false; } @@ -1744,11 +1960,8 @@ inline void mTransformPlane( const PlaneF& plane, PlaneF* result ) { - // Create a non-const copy of the matrix - MatrixF matCopy = mat; - // Create the inverse scale matrix - MatrixF invScale = MatrixF::Identity; + MatrixF invScale(true); invScale(0, 0) = 1.0f / scale.x; invScale(1, 1) = 1.0f / scale.y; invScale(2, 2) = 1.0f / scale.z; @@ -1764,7 +1977,7 @@ inline void mTransformPlane( const F32 C = -mDot(row2, shear); // Compute the inverse transpose of the matrix - MatrixF invTrMatrix = MatrixF::Identity; + MatrixF invTrMatrix(true); invTrMatrix(0, 0) = mat(0, 0); invTrMatrix(0, 1) = mat(0, 1); invTrMatrix(0, 2) = mat(0, 2); diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 9237bc8b3..99ee7be62 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -801,6 +801,73 @@ TEST(MatrixTest, TestMatrixAdd) } +TEST(MatrixTest, TestCalcPlaneCulls) +{ + Point3F lightDir(-0.346188605f, -0.742403805f, -0.573576510f); + const F32 shadowDistance = 100.0f; + // frustum transform + MatrixF test(true); + + test(0, 0) = -0.8930f; test(0, 1) = 0.3043f; test(0, 2) = 0.3314f; test(0, 3) = -8.3111f; + test(1, 0) = -0.4499f; test(1, 1) = -0.6039f; test(1, 2) = -0.6578f; test(1, 3) = 8.4487f; + test(2, 0) = -0.0f; test(2, 1) = -0.7366f; test(2, 2) = 0.6763f; test(2, 3) = 12.5414f; + test(0, 0) = 0.00f; test(0, 1) = 0.0f; test(0, 2) = 0.0f; test(0, 3) = 1.0f; + + Box3F viewBB(-shadowDistance, -shadowDistance, -shadowDistance, + shadowDistance, shadowDistance, shadowDistance); + + Frustum testFrustum(false, -0.119894862f, 0.119894862f, 0.0767327100f, -0.0767327100f, 0.1f, 1000.0f, test); + testFrustum.getTransform().mul(viewBB); + + testFrustum.cropNearFar(0.1f, shadowDistance); + + PlaneF lightFarPlane, lightNearPlane; + + Point3F viewDir = testFrustum.getTransform().getForwardVector(); + EXPECT_NEAR(viewDir.x, 0.0f, 0.001f); EXPECT_NEAR(viewDir.y, -0.6039f, 0.001f); EXPECT_NEAR(viewDir.z, -0.7365f, 0.001f); + + viewDir.normalize(); + const Point3F viewPosition = testFrustum.getPosition(); + EXPECT_NEAR(viewPosition.x, 1.0f, 0.001f); EXPECT_NEAR(viewPosition.y, 8.4486f, 0.001f); EXPECT_NEAR(viewPosition.z, 12.5414f, 0.001f); + + const F32 viewDistance = testFrustum.getBounds().len(); + EXPECT_NEAR(viewDistance, 243.6571f, 0.001f); + + lightNearPlane = PlaneF(viewPosition + (viewDistance * -lightDir), lightDir); + + const Point3F lightFarPlanePos = viewPosition + (viewDistance * lightDir); + lightFarPlane = PlaneF(lightFarPlanePos, -lightDir); + + MatrixF invLightFarPlaneMat(true); + + MatrixF lightFarPlaneMat = MathUtils::createOrientFromDir(-lightDir); + lightFarPlaneMat.setPosition(lightFarPlanePos); + lightFarPlaneMat.invertTo(&invLightFarPlaneMat); + + Vector projVertices; + + //project all frustum vertices into plane + // all vertices are 2d and local to far plane + projVertices.setSize(8); + for (int i = 0; i < 8; ++i) // + { + const Point3F& point = testFrustum.getPoints()[i]; + + Point3F localPoint(lightFarPlane.project(point)); + invLightFarPlaneMat.mulP(localPoint); + projVertices[i] = Point2F(localPoint.x, localPoint.z); + } + + EXPECT_NEAR(projVertices[0].x, 0.0240f, 0.001f); EXPECT_NEAR(projVertices[0].y, 0.0117f, 0.001f); + EXPECT_NEAR(projVertices[1].x, 0.0696f, 0.001f); EXPECT_NEAR(projVertices[1].y, 0.0678f, 0.001f); + EXPECT_NEAR(projVertices[2].x, -0.0186f, 0.001f); EXPECT_NEAR(projVertices[2].y, -0.1257f, 0.001f); + EXPECT_NEAR(projVertices[3].x, 0.0269f, 0.001f); EXPECT_NEAR(projVertices[3].y, -0.0696f, 0.001f); + EXPECT_NEAR(projVertices[4].x, 24.0571f, 0.001f); EXPECT_NEAR(projVertices[4].y, 11.7618f, 0.001f); + EXPECT_NEAR(projVertices[5].x, 69.6498f, 0.001f); EXPECT_NEAR(projVertices[5].y, 67.8426f, 0.001f); + EXPECT_NEAR(projVertices[6].x, -18.6059f, 0.001f); EXPECT_NEAR(projVertices[6].y, -125.7341f, 0.001f); + EXPECT_NEAR(projVertices[7].x, 26.9866f, 0.001f); EXPECT_NEAR(projVertices[7].y, -69.6534f, 0.001f); +} + TEST(MatrixTest, TestFrustumProjectionMatrix) { MatrixF test(true); From 165a2bea01cab3c654e61b4be91db81e877d91c4 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 31 Jul 2024 18:52:18 +0100 Subject: [PATCH 23/29] fix fix invertTo function unitTest to make sure matrix calling invertTo does not get changed. reimplemented gauss jordan. --- Engine/source/math/mMatrix.h | 17 ++++-- Engine/source/testing/mathMatrixTest.cpp | 73 ++---------------------- 2 files changed, 19 insertions(+), 71 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index aed956f6d..0283502b8 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -734,7 +734,14 @@ public: ///< M * p -> p (full [4x4] * [1x4]) void mul(Point4F& p) const { p = *this * p; } ///< M * p -> p (assume w = 1.0f) - void mulP(Point3F& p) const { p = *this * p; } + void mulP(Point3F& p) const { + Point3F result; + result.x = (*this)(0, 0) * p.x + (*this)(0, 1) * p.y + (*this)(0, 2) * p.z + (*this)(0, 3); + result.y = (*this)(1, 0) * p.x + (*this)(1, 1) * p.y + (*this)(1, 2) * p.z + (*this)(1, 3); + result.z = (*this)(2, 0) * p.x + (*this)(2, 1) * p.y + (*this)(2, 2) * p.z + (*this)(2, 3); + + p = result; + } ///< M * p -> d (assume w = 1.0f) void mulP(const Point3F& p, Point3F* d) const { *d = *this * p; } ///< M * v -> v (assume w = 0.0f) @@ -1252,7 +1259,9 @@ inline void Matrix::invertTo(Matrix inline void Matrix::invertTo(Matrix* matrix) { - Matrix invMatrix = this->inverse(); + Matrix invMatrix = *this; + + invMatrix.inverse(); for (U32 i = 0; i < rows; ++i) { @@ -1433,7 +1442,7 @@ inline Matrix& Matrix::set(const E template inline Matrix& Matrix::inverse() { -#if 0 +#if 1 // NOTE: Gauss-Jordan elimination is yielding unpredictable results due to precission handling and // numbers near 0.0 // @@ -1565,7 +1574,7 @@ inline Matrix& Matrix::inverse() template inline bool Matrix::fullInverse() { -#if 0 +#if 1 // NOTE: Gauss-Jordan elimination is yielding unpredictable results due to precission handling and // numbers near 0.0 AssertFatal(rows == cols, "Can only perform inverse on square matrices."); diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 99ee7be62..37e5b5a52 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -801,73 +801,6 @@ TEST(MatrixTest, TestMatrixAdd) } -TEST(MatrixTest, TestCalcPlaneCulls) -{ - Point3F lightDir(-0.346188605f, -0.742403805f, -0.573576510f); - const F32 shadowDistance = 100.0f; - // frustum transform - MatrixF test(true); - - test(0, 0) = -0.8930f; test(0, 1) = 0.3043f; test(0, 2) = 0.3314f; test(0, 3) = -8.3111f; - test(1, 0) = -0.4499f; test(1, 1) = -0.6039f; test(1, 2) = -0.6578f; test(1, 3) = 8.4487f; - test(2, 0) = -0.0f; test(2, 1) = -0.7366f; test(2, 2) = 0.6763f; test(2, 3) = 12.5414f; - test(0, 0) = 0.00f; test(0, 1) = 0.0f; test(0, 2) = 0.0f; test(0, 3) = 1.0f; - - Box3F viewBB(-shadowDistance, -shadowDistance, -shadowDistance, - shadowDistance, shadowDistance, shadowDistance); - - Frustum testFrustum(false, -0.119894862f, 0.119894862f, 0.0767327100f, -0.0767327100f, 0.1f, 1000.0f, test); - testFrustum.getTransform().mul(viewBB); - - testFrustum.cropNearFar(0.1f, shadowDistance); - - PlaneF lightFarPlane, lightNearPlane; - - Point3F viewDir = testFrustum.getTransform().getForwardVector(); - EXPECT_NEAR(viewDir.x, 0.0f, 0.001f); EXPECT_NEAR(viewDir.y, -0.6039f, 0.001f); EXPECT_NEAR(viewDir.z, -0.7365f, 0.001f); - - viewDir.normalize(); - const Point3F viewPosition = testFrustum.getPosition(); - EXPECT_NEAR(viewPosition.x, 1.0f, 0.001f); EXPECT_NEAR(viewPosition.y, 8.4486f, 0.001f); EXPECT_NEAR(viewPosition.z, 12.5414f, 0.001f); - - const F32 viewDistance = testFrustum.getBounds().len(); - EXPECT_NEAR(viewDistance, 243.6571f, 0.001f); - - lightNearPlane = PlaneF(viewPosition + (viewDistance * -lightDir), lightDir); - - const Point3F lightFarPlanePos = viewPosition + (viewDistance * lightDir); - lightFarPlane = PlaneF(lightFarPlanePos, -lightDir); - - MatrixF invLightFarPlaneMat(true); - - MatrixF lightFarPlaneMat = MathUtils::createOrientFromDir(-lightDir); - lightFarPlaneMat.setPosition(lightFarPlanePos); - lightFarPlaneMat.invertTo(&invLightFarPlaneMat); - - Vector projVertices; - - //project all frustum vertices into plane - // all vertices are 2d and local to far plane - projVertices.setSize(8); - for (int i = 0; i < 8; ++i) // - { - const Point3F& point = testFrustum.getPoints()[i]; - - Point3F localPoint(lightFarPlane.project(point)); - invLightFarPlaneMat.mulP(localPoint); - projVertices[i] = Point2F(localPoint.x, localPoint.z); - } - - EXPECT_NEAR(projVertices[0].x, 0.0240f, 0.001f); EXPECT_NEAR(projVertices[0].y, 0.0117f, 0.001f); - EXPECT_NEAR(projVertices[1].x, 0.0696f, 0.001f); EXPECT_NEAR(projVertices[1].y, 0.0678f, 0.001f); - EXPECT_NEAR(projVertices[2].x, -0.0186f, 0.001f); EXPECT_NEAR(projVertices[2].y, -0.1257f, 0.001f); - EXPECT_NEAR(projVertices[3].x, 0.0269f, 0.001f); EXPECT_NEAR(projVertices[3].y, -0.0696f, 0.001f); - EXPECT_NEAR(projVertices[4].x, 24.0571f, 0.001f); EXPECT_NEAR(projVertices[4].y, 11.7618f, 0.001f); - EXPECT_NEAR(projVertices[5].x, 69.6498f, 0.001f); EXPECT_NEAR(projVertices[5].y, 67.8426f, 0.001f); - EXPECT_NEAR(projVertices[6].x, -18.6059f, 0.001f); EXPECT_NEAR(projVertices[6].y, -125.7341f, 0.001f); - EXPECT_NEAR(projVertices[7].x, 26.9866f, 0.001f); EXPECT_NEAR(projVertices[7].y, -69.6534f, 0.001f); -} - TEST(MatrixTest, TestFrustumProjectionMatrix) { MatrixF test(true); @@ -943,6 +876,12 @@ TEST(MatrixTest, TestInvertTo) EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + + // make sure our original matrix is unchanged + EXPECT_NEAR(test1(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test1(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test1(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test1(0, 3), 4.3845f, 0.001f); + EXPECT_NEAR(test1(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test1(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test1(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test1(1, 3), -0.8479f, 0.001f); + EXPECT_NEAR(test1(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test1(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test1(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test1(2, 3), 3.1714, 0.001f); + EXPECT_NEAR(test1(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test1(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test1(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test1(3, 3), 1.0f, 0.001f); } TEST(MatrixTest, TestFullInverse) From 219792cc30ede8565b8c41a4dffd1985d3dd09d2 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 31 Jul 2024 18:54:22 +0100 Subject: [PATCH 24/29] Update mMatrix.h returning identity no longer necessary as fullinverse is its own algo --- Engine/source/math/mMatrix.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 0283502b8..57e6b72ae 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -1492,7 +1492,6 @@ inline Matrix& Matrix::inverse() // Early out if pivot is 0, return identity matrix. if (std::abs(augmentedMatrix(i, i)) < pivot_eps) { - this->identity(); return *this; } From b5e729c179293dd4c84ed83df1201e219bbe77d0 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 31 Jul 2024 19:02:23 +0100 Subject: [PATCH 25/29] Update mMatrix.h add default destructor --- Engine/source/math/mMatrix.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 57e6b72ae..6c4fe3b6b 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -672,6 +672,8 @@ public: set(e); } + ~Matrix() = default; + /// Make this an identity matrix. Matrix& identity(); void reverseProjection(); From 699fa5ef776a5ffd16c872bae8c40366f26a1a21 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 1 Aug 2024 03:33:07 +0100 Subject: [PATCH 26/29] Update mMatrix.h invertTo should always just be const return loop to * operator, explicit will not allow for scaling of rows and cols --- Engine/source/math/mMatrix.h | 46 ++++++++---------------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 6c4fe3b6b..47787acc5 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -841,7 +841,6 @@ public: } void invertTo(Matrix* matrix) const; - void invertTo(Matrix* matrix); void dumpMatrix(const char* caption = NULL) const; // Static identity matrix @@ -851,25 +850,16 @@ public: friend Matrix operator*(const Matrix& m1, const Matrix& m2) { Matrix result; - result(0, 0) = m1(0, 0) * m2(0, 0) + m1(0, 1) * m2(1, 0) + m1(0, 2) * m2(2, 0) + m1(0, 3) * m2(3, 0); - result(0, 1) = m1(0, 0) * m2(0, 1) + m1(0, 1) * m2(1, 1) + m1(0, 2) * m2(2, 1) + m1(0, 3) * m2(3, 1); - result(0, 2) = m1(0, 0) * m2(0, 2) + m1(0, 1) * m2(1, 2) + m1(0, 2) * m2(2, 2) + m1(0, 3) * m2(3, 2); - result(0, 3) = m1(0, 0) * m2(0, 3) + m1(0, 1) * m2(1, 3) + m1(0, 2) * m2(2, 3) + m1(0, 3) * m2(3, 3); - - result(1, 0) = m1(1, 0) * m2(0, 0) + m1(1, 1) * m2(1, 0) + m1(1, 2) * m2(2, 0) + m1(1, 3) * m2(3, 0); - result(1, 1) = m1(1, 0) * m2(0, 1) + m1(1, 1) * m2(1, 1) + m1(1, 2) * m2(2, 1) + m1(1, 3) * m2(3, 1); - result(1, 2) = m1(1, 0) * m2(0, 2) + m1(1, 1) * m2(1, 2) + m1(1, 2) * m2(2, 2) + m1(1, 3) * m2(3, 2); - result(1, 3) = m1(1, 0) * m2(0, 3) + m1(1, 1) * m2(1, 3) + m1(1, 2) * m2(2, 3) + m1(1, 3) * m2(3, 3); - - result(2, 0) = m1(2, 0) * m2(0, 0) + m1(2, 1) * m2(1, 0) + m1(2, 2) * m2(2, 0) + m1(2, 3) * m2(3, 0); - result(2, 1) = m1(2, 0) * m2(0, 1) + m1(2, 1) * m2(1, 1) + m1(2, 2) * m2(2, 1) + m1(2, 3) * m2(3, 1); - result(2, 2) = m1(2, 0) * m2(0, 2) + m1(2, 1) * m2(1, 2) + m1(2, 2) * m2(2, 2) + m1(2, 3) * m2(3, 2); - result(2, 3) = m1(2, 0) * m2(0, 3) + m1(2, 1) * m2(1, 3) + m1(2, 2) * m2(2, 3) + m1(2, 3) * m2(3, 3); - - result(3, 0) = m1(3, 0) * m2(0, 0) + m1(3, 1) * m2(1, 0) + m1(3, 2) * m2(2, 0) + m1(3, 3) * m2(3, 0); - result(3, 1) = m1(3, 0) * m2(0, 1) + m1(3, 1) * m2(1, 1) + m1(3, 2) * m2(2, 1) + m1(3, 3) * m2(3, 1); - result(3, 2) = m1(3, 0) * m2(0, 2) + m1(3, 1) * m2(1, 2) + m1(3, 2) * m2(2, 2) + m1(3, 3) * m2(3, 2); - result(3, 3) = m1(3, 0) * m2(0, 3) + m1(3, 1) * m2(1, 3) + m1(3, 2) * m2(2, 3) + m1(3, 3) * m2(3, 3); + for (U32 i = 0; i < rows; ++i) { + for (U32 j = 0; j < cols; ++j) + { + result(i, j) = static_cast(0); + for (U32 k = 0; k < cols; ++k) + { + result(i, j) += m1(i, k) * m2(k, j); + } + } + } return result; } @@ -1258,22 +1248,6 @@ inline void Matrix::invertTo(Matrix -inline void Matrix::invertTo(Matrix* matrix) -{ - Matrix invMatrix = *this; - - invMatrix.inverse(); - - for (U32 i = 0; i < rows; ++i) - { - for (U32 j = 0; j < cols; ++j) - { - (*matrix)(i, j) = invMatrix(i, j); - } - } -} - template inline void Matrix::setRow(S32 row, const Point4F& cptr) { if(cols >= 2) From b72b7882c276d690e6d5164125cdd16e39317dfa Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 1 Aug 2024 05:04:13 +0100 Subject: [PATCH 27/29] unit test improved precision change matrix unit tests to use POINT_EPSILON macro for testing precision remove old matrix test class, was not used anyway --- Engine/source/math/test/mMatrixTest.cpp | 93 ---- Engine/source/testing/mathMatrixTest.cpp | 598 +++++++++++------------ 2 files changed, 299 insertions(+), 392 deletions(-) delete mode 100644 Engine/source/math/test/mMatrixTest.cpp diff --git a/Engine/source/math/test/mMatrixTest.cpp b/Engine/source/math/test/mMatrixTest.cpp deleted file mode 100644 index b5276ce22..000000000 --- a/Engine/source/math/test/mMatrixTest.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2014 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -#ifdef TORQUE_TESTS_ENABLED -#include "testing/unitTesting.h" -#include "platform/platform.h" -#include "math/mMatrix.h" -#include "math/mRandom.h" - -extern void default_matF_x_matF_C(const F32 *a, const F32 *b, F32 *mresult); -extern void mInstallLibrary_ASM(); - -// If we're x86 and not Mac, then include these. There's probably a better way to do this. -#if defined(WIN32) && defined(TORQUE_CPU_X86) -void Athlon_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result); -void SSE_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result); -#endif - -#if defined( __VEC__ ) -extern void vec_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result); -#endif - -TEST(MatrixF, MultiplyImplmentations) -{ - F32 m1[16], m2[16], mrC[16]; - - // I am not positive that the best way to do this is to use random numbers - // but I think that using some kind of standard matrix may not always catch - // all problems. - for (S32 i = 0; i < 16; i++) - { - m1[i] = gRandGen.randF(); - m2[i] = gRandGen.randF(); - } - - // C will be the baseline - default_matF_x_matF_C(m1, m2, mrC); - -#if defined(WIN32) && defined(TORQUE_CPU_X86) - // Check the CPU info - U32 cpuProperties = Platform::SystemInfo.processor.properties; - bool same; - - // Test SSE if it is available - F32 mrSSE[16]; - if (cpuProperties & CPU_PROP_SSE) - { - SSE_MatrixF_x_MatrixF(m1, m2, mrSSE); - - same = true; - for (S32 i = 0; i < 16; i++) - same &= mIsEqual(mrC[i], mrSSE[i]); - - EXPECT_TRUE(same) << "Matrix multiplication verification failed. (C vs. SSE)"; - } - - same = true; -#endif - - // If Altivec exists, test it! -#if defined(__VEC__) - bool same = false; - F32 mrVEC[16]; - - vec_MatrixF_x_MatrixF(m1, m2, mrVEC); - - for (S32 i = 0; i < 16; i++) - same &= isEqual(mrC[i], mrVEC[i]); - - EXPECT_TRUE(same) << "Matrix multiplication verification failed. (C vs. Altivec)"; -#endif -} - -#endif \ No newline at end of file diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 37e5b5a52..8d9b4e576 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -14,10 +14,10 @@ TEST(MatrixTest, TestIdentityInit) { MatrixF test(true); - EXPECT_NEAR(test(0, 0), 1.0f, 0.001f); - EXPECT_NEAR(test(1, 1), 1.0f, 0.001f); - EXPECT_NEAR(test(2, 2), 1.0f, 0.001f); - EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 1), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 2), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestIdentitySet) @@ -25,10 +25,10 @@ TEST(MatrixTest, TestIdentitySet) MatrixF test(false); test.identity(); - EXPECT_NEAR(test(0, 0), 1.0f, 0.001f); - EXPECT_NEAR(test(1, 1), 1.0f, 0.001f); - EXPECT_NEAR(test(2, 2), 1.0f, 0.001f); - EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 1), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 2), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestIsIdentity) @@ -41,10 +41,10 @@ TEST(MatrixTest, TestEulerInit) { MatrixF test(EulerF(1.0f, 0.0f, 1.0f)); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } @@ -54,10 +54,10 @@ TEST(MatrixTest, TestEulerSet) test.set(EulerF(1.0f, 0.0f, 1.0f)); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestToEuler) @@ -68,17 +68,17 @@ TEST(MatrixTest, TestToEuler) EulerF euler = test.toEuler(); - EXPECT_NEAR(euler.x, 1.0f, 0.001f); EXPECT_NEAR(euler.y, 0.0f, 0.001f); EXPECT_NEAR(euler.z, 1.0f, 0.001f); + EXPECT_NEAR(euler.x, 1.0f, POINT_EPSILON); EXPECT_NEAR(euler.y, 0.0f, POINT_EPSILON); EXPECT_NEAR(euler.z, 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestEulerPointInit) { MatrixF test(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 5.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } @@ -88,10 +88,10 @@ TEST(MatrixTest, TestEulerPointSet) test.set(EulerF(1.0f, 0.0f, 1.0f), Point3F(5.0f, 0.0f, 1.0f)); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 5.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestGetColumn4) @@ -104,31 +104,31 @@ TEST(MatrixTest, TestGetColumn4) test.getColumn(0, &column); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 0), 0.001f); - EXPECT_NEAR(column.z, test(2, 0), 0.001f); - EXPECT_NEAR(column.w, test(3, 0), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 0), POINT_EPSILON); test.getColumn(1, &column); - EXPECT_NEAR(column.x, test(0, 1), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 1), 0.001f); - EXPECT_NEAR(column.w, test(3, 1), 0.001f); + EXPECT_NEAR(column.x, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 1), POINT_EPSILON); test.getColumn(2, &column); - EXPECT_NEAR(column.x, test(0, 2), 0.001f); - EXPECT_NEAR(column.y, test(1, 2), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); - EXPECT_NEAR(column.w, test(3, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 2), POINT_EPSILON); test.getColumn(3, &column); - EXPECT_NEAR(column.x, test(0, 3), 0.001f); - EXPECT_NEAR(column.y, test(1, 3), 0.001f); - EXPECT_NEAR(column.z, test(2, 3), 0.001f); - EXPECT_NEAR(column.w, test(3, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 3), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 3), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 3), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 3), POINT_EPSILON); } @@ -142,31 +142,31 @@ TEST(MatrixTest, TestGetRow4) test.getRow(0, &column); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(0, 1), 0.001f); - EXPECT_NEAR(column.z, test(0, 2), 0.001f); - EXPECT_NEAR(column.w, test(0, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(0, 3), POINT_EPSILON); test.getRow(1, &column); - EXPECT_NEAR(column.x, test(1, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(1, 2), 0.001f); - EXPECT_NEAR(column.w, test(1, 3), 0.001f); + EXPECT_NEAR(column.x, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(1, 3), POINT_EPSILON); test.getRow(2, &column); - EXPECT_NEAR(column.x, test(2, 0), 0.001f); - EXPECT_NEAR(column.y, test(2, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); - EXPECT_NEAR(column.w, test(2, 3), 0.001f); + EXPECT_NEAR(column.x, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(2, 3), POINT_EPSILON); test.getRow(3, &column); - EXPECT_NEAR(column.x, test(3, 0), 0.001f); - EXPECT_NEAR(column.y, test(3, 1), 0.001f); - EXPECT_NEAR(column.z, test(3, 2), 0.001f); - EXPECT_NEAR(column.w, test(3, 3), 0.001f); + EXPECT_NEAR(column.x, test(3, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(3, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(3, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 3), POINT_EPSILON); } TEST(MatrixTest, TestGetColumn3) @@ -179,27 +179,27 @@ TEST(MatrixTest, TestGetColumn3) test.getColumn(0, &column); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 0), 0.001f); - EXPECT_NEAR(column.z, test(2, 0), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 0), POINT_EPSILON); test.getColumn(1, &column); - EXPECT_NEAR(column.x, test(0, 1), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 1), 0.001f); + EXPECT_NEAR(column.x, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 1), POINT_EPSILON); test.getColumn(2, &column); - EXPECT_NEAR(column.x, test(0, 2), 0.001f); - EXPECT_NEAR(column.y, test(1, 2), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); test.getColumn(3, &column); - EXPECT_NEAR(column.x, test(0, 3), 0.001f); - EXPECT_NEAR(column.y, test(1, 3), 0.001f); - EXPECT_NEAR(column.z, test(2, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 3), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 3), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 3), POINT_EPSILON); } @@ -213,27 +213,27 @@ TEST(MatrixTest, TestGetRow3) test.getRow(0, &column); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(0, 1), 0.001f); - EXPECT_NEAR(column.z, test(0, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(0, 2), POINT_EPSILON); test.getRow(1, &column); - EXPECT_NEAR(column.x, test(1, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(1, 2), 0.001f); + EXPECT_NEAR(column.x, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(1, 2), POINT_EPSILON); test.getRow(2, &column); - EXPECT_NEAR(column.x, test(2, 0), 0.001f); - EXPECT_NEAR(column.y, test(2, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.x, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); test.getRow(3, &column); - EXPECT_NEAR(column.x, test(3, 0), 0.001f); - EXPECT_NEAR(column.y, test(3, 1), 0.001f); - EXPECT_NEAR(column.z, test(3, 2), 0.001f); + EXPECT_NEAR(column.x, test(3, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(3, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(3, 2), POINT_EPSILON); } TEST(MatrixTest, TestGetColumn4F) @@ -246,31 +246,31 @@ TEST(MatrixTest, TestGetColumn4F) column = test.getColumn4F(0); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 0), 0.001f); - EXPECT_NEAR(column.z, test(2, 0), 0.001f); - EXPECT_NEAR(column.w, test(3, 0), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 0), POINT_EPSILON); column = test.getColumn4F(1); - EXPECT_NEAR(column.x, test(0, 1), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 1), 0.001f); - EXPECT_NEAR(column.w, test(3, 1), 0.001f); + EXPECT_NEAR(column.x, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 1), POINT_EPSILON); column = test.getColumn4F(2); - EXPECT_NEAR(column.x, test(0, 2), 0.001f); - EXPECT_NEAR(column.y, test(1, 2), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); - EXPECT_NEAR(column.w, test(3, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 2), POINT_EPSILON); column = test.getColumn4F(3); - EXPECT_NEAR(column.x, test(0, 3), 0.001f); - EXPECT_NEAR(column.y, test(1, 3), 0.001f); - EXPECT_NEAR(column.z, test(2, 3), 0.001f); - EXPECT_NEAR(column.w, test(3, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 3), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 3), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 3), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 3), POINT_EPSILON); } @@ -284,31 +284,31 @@ TEST(MatrixTest, TestGetRow4F) column = test.getRow4F(0); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(0, 1), 0.001f); - EXPECT_NEAR(column.z, test(0, 2), 0.001f); - EXPECT_NEAR(column.w, test(0, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(0, 3), POINT_EPSILON); column = test.getRow4F(1); - EXPECT_NEAR(column.x, test(1, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(1, 2), 0.001f); - EXPECT_NEAR(column.w, test(1, 3), 0.001f); + EXPECT_NEAR(column.x, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(1, 3), POINT_EPSILON); column = test.getRow4F(2); - EXPECT_NEAR(column.x, test(2, 0), 0.001f); - EXPECT_NEAR(column.y, test(2, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); - EXPECT_NEAR(column.w, test(2, 3), 0.001f); + EXPECT_NEAR(column.x, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(2, 3), POINT_EPSILON); column = test.getRow4F(3); - EXPECT_NEAR(column.x, test(3, 0), 0.001f); - EXPECT_NEAR(column.y, test(3, 1), 0.001f); - EXPECT_NEAR(column.z, test(3, 2), 0.001f); - EXPECT_NEAR(column.w, test(3, 3), 0.001f); + EXPECT_NEAR(column.x, test(3, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(3, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(3, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 3), POINT_EPSILON); } TEST(MatrixTest, TestGetColumn3F) @@ -321,27 +321,27 @@ TEST(MatrixTest, TestGetColumn3F) column = test.getColumn3F(0); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 0), 0.001f); - EXPECT_NEAR(column.z, test(2, 0), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 0), POINT_EPSILON); column = test.getColumn3F(1); - EXPECT_NEAR(column.x, test(0, 1), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 1), 0.001f); + EXPECT_NEAR(column.x, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 1), POINT_EPSILON); column = test.getColumn3F(2); - EXPECT_NEAR(column.x, test(0, 2), 0.001f); - EXPECT_NEAR(column.y, test(1, 2), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); column = test.getColumn3F(3); - EXPECT_NEAR(column.x, test(0, 3), 0.001f); - EXPECT_NEAR(column.y, test(1, 3), 0.001f); - EXPECT_NEAR(column.z, test(2, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 3), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 3), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 3), POINT_EPSILON); } @@ -355,27 +355,27 @@ TEST(MatrixTest, TestGetRow3F) column = test.getRow3F(0); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(0, 1), 0.001f); - EXPECT_NEAR(column.z, test(0, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(0, 2), POINT_EPSILON); column = test.getRow3F(1); - EXPECT_NEAR(column.x, test(1, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(1, 2), 0.001f); + EXPECT_NEAR(column.x, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(1, 2), POINT_EPSILON); column = test.getRow3F(2); - EXPECT_NEAR(column.x, test(2, 0), 0.001f); - EXPECT_NEAR(column.y, test(2, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.x, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); column = test.getRow3F(3); - EXPECT_NEAR(column.x, test(3, 0), 0.001f); - EXPECT_NEAR(column.y, test(3, 1), 0.001f); - EXPECT_NEAR(column.z, test(3, 2), 0.001f); + EXPECT_NEAR(column.x, test(3, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(3, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(3, 2), POINT_EPSILON); } TEST(MatrixTest, TestSetColumn4) @@ -388,31 +388,31 @@ TEST(MatrixTest, TestSetColumn4) test.setColumn(0, column); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 0), 0.001f); - EXPECT_NEAR(column.z, test(2, 0), 0.001f); - EXPECT_NEAR(column.w, test(3, 0), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 0), POINT_EPSILON); test.setColumn(1, column); - EXPECT_NEAR(column.x, test(0, 1), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 1), 0.001f); - EXPECT_NEAR(column.w, test(3, 1), 0.001f); + EXPECT_NEAR(column.x, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 1), POINT_EPSILON); test.setColumn(2, column); - EXPECT_NEAR(column.x, test(0, 2), 0.001f); - EXPECT_NEAR(column.y, test(1, 2), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); - EXPECT_NEAR(column.w, test(3, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 2), POINT_EPSILON); test.setColumn(3, column); - EXPECT_NEAR(column.x, test(0, 3), 0.001f); - EXPECT_NEAR(column.y, test(1, 3), 0.001f); - EXPECT_NEAR(column.z, test(2, 3), 0.001f); - EXPECT_NEAR(column.w, test(3, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 3), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 3), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 3), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 3), POINT_EPSILON); } TEST(MatrixTest, TestSetRow4) @@ -425,31 +425,31 @@ TEST(MatrixTest, TestSetRow4) test.setRow(0, column); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(0, 1), 0.001f); - EXPECT_NEAR(column.z, test(0, 2), 0.001f); - EXPECT_NEAR(column.w, test(0, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(0, 3), POINT_EPSILON); test.setRow(1, column); - EXPECT_NEAR(column.x, test(1, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(1, 2), 0.001f); - EXPECT_NEAR(column.w, test(1, 3), 0.001f); + EXPECT_NEAR(column.x, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(1, 3), POINT_EPSILON); test.setRow(2, column); - EXPECT_NEAR(column.x, test(2, 0), 0.001f); - EXPECT_NEAR(column.y, test(2, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); - EXPECT_NEAR(column.w, test(2, 3), 0.001f); + EXPECT_NEAR(column.x, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(2, 3), POINT_EPSILON); test.setRow(3, column); - EXPECT_NEAR(column.x, test(3, 0), 0.001f); - EXPECT_NEAR(column.y, test(3, 1), 0.001f); - EXPECT_NEAR(column.z, test(3, 2), 0.001f); - EXPECT_NEAR(column.w, test(3, 3), 0.001f); + EXPECT_NEAR(column.x, test(3, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(3, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(3, 2), POINT_EPSILON); + EXPECT_NEAR(column.w, test(3, 3), POINT_EPSILON); } TEST(MatrixTest, TestSetColumn3) @@ -462,27 +462,27 @@ TEST(MatrixTest, TestSetColumn3) test.setColumn(0, column); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 0), 0.001f); - EXPECT_NEAR(column.z, test(2, 0), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 0), POINT_EPSILON); test.setColumn(1, column); - EXPECT_NEAR(column.x, test(0, 1), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 1), 0.001f); + EXPECT_NEAR(column.x, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 1), POINT_EPSILON); test.setColumn(2, column); - EXPECT_NEAR(column.x, test(0, 2), 0.001f); - EXPECT_NEAR(column.y, test(1, 2), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); test.setColumn(3, column); - EXPECT_NEAR(column.x, test(0, 3), 0.001f); - EXPECT_NEAR(column.y, test(1, 3), 0.001f); - EXPECT_NEAR(column.z, test(2, 3), 0.001f); + EXPECT_NEAR(column.x, test(0, 3), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 3), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 3), POINT_EPSILON); } TEST(MatrixTest, TestSetRow3) @@ -495,27 +495,27 @@ TEST(MatrixTest, TestSetRow3) test.setRow(0, column); - EXPECT_NEAR(column.x, test(0, 0), 0.001f); - EXPECT_NEAR(column.y, test(0, 1), 0.001f); - EXPECT_NEAR(column.z, test(0, 2), 0.001f); + EXPECT_NEAR(column.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(0, 2), POINT_EPSILON); test.setRow(1, column); - EXPECT_NEAR(column.x, test(1, 0), 0.001f); - EXPECT_NEAR(column.y, test(1, 1), 0.001f); - EXPECT_NEAR(column.z, test(1, 2), 0.001f); + EXPECT_NEAR(column.x, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(1, 2), POINT_EPSILON); test.setRow(2, column); - EXPECT_NEAR(column.x, test(2, 0), 0.001f); - EXPECT_NEAR(column.y, test(2, 1), 0.001f); - EXPECT_NEAR(column.z, test(2, 2), 0.001f); + EXPECT_NEAR(column.x, test(2, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(2, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(2, 2), POINT_EPSILON); test.setRow(3, column); - EXPECT_NEAR(column.x, test(3, 0), 0.001f); - EXPECT_NEAR(column.y, test(3, 1), 0.001f); - EXPECT_NEAR(column.z, test(3, 2), 0.001f); + EXPECT_NEAR(column.x, test(3, 0), POINT_EPSILON); + EXPECT_NEAR(column.y, test(3, 1), POINT_EPSILON); + EXPECT_NEAR(column.z, test(3, 2), POINT_EPSILON); } TEST(MatrixTest, TestDisplace) @@ -528,9 +528,9 @@ TEST(MatrixTest, TestDisplace) test.displace(column); - EXPECT_NEAR(test(0, 3), 6.0f, 0.001f); - EXPECT_NEAR(test(1, 3), 1.0f, 0.001f); - EXPECT_NEAR(test(2, 3), 2.0f, 0.001f); + EXPECT_NEAR(test(0, 3), 6.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 3), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 3), 2.0f, POINT_EPSILON); } TEST(MatrixTest, TestGetVectorFunctions) @@ -543,21 +543,21 @@ TEST(MatrixTest, TestGetVectorFunctions) vector = test.getRightVector(); - EXPECT_NEAR(vector.x, test(0, 0), 0.001f); - EXPECT_NEAR(vector.y, test(1, 0), 0.001f); - EXPECT_NEAR(vector.z, test(2, 0), 0.001f); + EXPECT_NEAR(vector.x, test(0, 0), POINT_EPSILON); + EXPECT_NEAR(vector.y, test(1, 0), POINT_EPSILON); + EXPECT_NEAR(vector.z, test(2, 0), POINT_EPSILON); vector = test.getForwardVector(); - EXPECT_NEAR(vector.x, test(0, 1), 0.001f); - EXPECT_NEAR(vector.y, test(1, 1), 0.001f); - EXPECT_NEAR(vector.z, test(2, 1), 0.001f); + EXPECT_NEAR(vector.x, test(0, 1), POINT_EPSILON); + EXPECT_NEAR(vector.y, test(1, 1), POINT_EPSILON); + EXPECT_NEAR(vector.z, test(2, 1), POINT_EPSILON); vector = test.getUpVector(); - EXPECT_NEAR(vector.x, test(0, 2), 0.001f); - EXPECT_NEAR(vector.y, test(1, 2), 0.001f); - EXPECT_NEAR(vector.z, test(2, 2), 0.001f); + EXPECT_NEAR(vector.x, test(0, 2), POINT_EPSILON); + EXPECT_NEAR(vector.y, test(1, 2), POINT_EPSILON); + EXPECT_NEAR(vector.z, test(2, 2), POINT_EPSILON); } TEST(MatrixTest, TestSetCrossProduct) @@ -566,10 +566,10 @@ TEST(MatrixTest, TestSetCrossProduct) test.setCrossProduct(Point3F(5.0f, 0.0f, 1.0f)); - EXPECT_NEAR(test(0, 0), 0.0f, 0.001f); EXPECT_NEAR(test(0, 1), -1.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 1.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0, 0.001f); EXPECT_NEAR(test(1, 2), -5.0f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 5.0f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), -1.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 1.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.0, POINT_EPSILON); EXPECT_NEAR(test(1, 2), -5.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 5.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestSetTensorProduct) @@ -578,10 +578,10 @@ TEST(MatrixTest, TestSetTensorProduct) test.setTensorProduct(Point3F(5.0f, 2.0f, 1.0f), Point3F(5.0f, 2.0f, 1.0f)); - EXPECT_NEAR(test(0, 0), 25.0f, 0.001f); EXPECT_NEAR(test(0, 1), 10.0f, 0.001f); EXPECT_NEAR(test(0, 2), 5.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 10.0f, 0.001f); EXPECT_NEAR(test(1, 1), 4.0, 0.001f); EXPECT_NEAR(test(1, 2), 2.0f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 5.0f, 0.001f); EXPECT_NEAR(test(2, 1), 2.0f, 0.001f); EXPECT_NEAR(test(2, 2), 1.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 25.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 10.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 5.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 10.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 4.0, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 2.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 5.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 2.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 1.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulFunction) @@ -592,10 +592,10 @@ TEST(MatrixTest, TestMulFunction) test.mul(test2); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 2.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 5.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 2.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulOperator) @@ -606,10 +606,10 @@ TEST(MatrixTest, TestMulOperator) test = test * test2; - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 5.0f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), 2.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 1.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 5.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 2.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulLFunction) @@ -620,10 +620,10 @@ TEST(MatrixTest, TestMulLFunction) test.mulL(test2); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 4.3845f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 3), -0.8479f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 3.1714, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 4.3845f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), -0.8479f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 3.1714, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulArgMatrixFunction) @@ -636,10 +636,10 @@ TEST(MatrixTest, TestMulArgMatrixFunction) testResult.mul(test2, test); - EXPECT_NEAR(testResult(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(testResult(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(testResult(0, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(0, 3), 4.3845f, 0.001f); - EXPECT_NEAR(testResult(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(testResult(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(testResult(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(testResult(1, 3), -0.8479f, 0.001f); - EXPECT_NEAR(testResult(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(testResult(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(testResult(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(testResult(2, 3), 3.1714, 0.001f); - EXPECT_NEAR(testResult(3, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(testResult(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(testResult(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(testResult(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(0, 3), 4.3845f, POINT_EPSILON); + EXPECT_NEAR(testResult(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(testResult(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(testResult(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(testResult(1, 3), -0.8479f, POINT_EPSILON); + EXPECT_NEAR(testResult(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(testResult(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(testResult(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(testResult(2, 3), 3.1714, POINT_EPSILON); + EXPECT_NEAR(testResult(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulArgMultipleRotationMatrix) @@ -651,10 +651,10 @@ TEST(MatrixTest, TestMulArgMultipleRotationMatrix) testResult.mul(zRot, xRot); - EXPECT_NEAR(testResult(0, 0), 0.0008f, 0.001f); EXPECT_NEAR(testResult(0, 1), -0.0308f, 0.001f);EXPECT_NEAR(testResult(0, 2), 0.9995f, 0.001f); EXPECT_NEAR(testResult(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(testResult(1, 0), 1.0f, 0.001f); EXPECT_NEAR(testResult(1, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(1, 2), -0.0008f, 0.001f); EXPECT_NEAR(testResult(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(testResult(2, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(2, 1), 0.9995f, 0.001f); EXPECT_NEAR(testResult(2, 2), 0.0308f, 0.001f); EXPECT_NEAR(testResult(2, 3), 0.0f, 0.001f); - EXPECT_NEAR(testResult(3, 0), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 1), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 2), 0.0f, 0.001f); EXPECT_NEAR(testResult(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(testResult(0, 0), 0.0008f, POINT_EPSILON); EXPECT_NEAR(testResult(0, 1), -0.0308f, POINT_EPSILON);EXPECT_NEAR(testResult(0, 2), 0.9995f, POINT_EPSILON); EXPECT_NEAR(testResult(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(testResult(1, 0), 1.0f, POINT_EPSILON); EXPECT_NEAR(testResult(1, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(1, 2), -0.0008f, POINT_EPSILON); EXPECT_NEAR(testResult(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(testResult(2, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(2, 1), 0.9995f, POINT_EPSILON); EXPECT_NEAR(testResult(2, 2), 0.0308f, POINT_EPSILON); EXPECT_NEAR(testResult(2, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(testResult(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(testResult(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulScalarFunction) @@ -667,10 +667,10 @@ TEST(MatrixTest, TestMulScalarFunction) test.mul(2.0f); - EXPECT_NEAR(test(0, 0), 1.0806f, 0.001f); EXPECT_NEAR(test(0, 1), 1.6829f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 8.7689f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.9093f, 0.001f); EXPECT_NEAR(test(1, 1), 0.5839f, 0.001f); EXPECT_NEAR(test(1, 2), 1.6829f, 0.001f); EXPECT_NEAR(test(1, 3), -1.6958f, 0.001f); - EXPECT_NEAR(test(2, 0), 1.4161f, 0.001f); EXPECT_NEAR(test(2, 1), -0.9093f, 0.001f); EXPECT_NEAR(test(2, 2), 1.0806f, 0.001f); EXPECT_NEAR(test(2, 3), 6.3427f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 2.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 1.0806f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 1.6829f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 8.7689f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.9093f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.5839f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 1.6829f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), -1.6958f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 1.4161f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.9093f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 1.0806f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 6.3427f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 2.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulMatScalarFunction) @@ -684,10 +684,10 @@ TEST(MatrixTest, TestMulMatScalarFunction) MatrixF test(true); test.mul(testTran, 2.0f); - EXPECT_NEAR(test(0, 0), 1.0806f, 0.001f); EXPECT_NEAR(test(0, 1), 1.6829f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 8.7689f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.9093f, 0.001f); EXPECT_NEAR(test(1, 1), 0.5839f, 0.001f); EXPECT_NEAR(test(1, 2), 1.6829f, 0.001f); EXPECT_NEAR(test(1, 3), -1.6958f, 0.001f); - EXPECT_NEAR(test(2, 0), 1.4161f, 0.001f); EXPECT_NEAR(test(2, 1), -0.9093f, 0.001f); EXPECT_NEAR(test(2, 2), 1.0806f, 0.001f); EXPECT_NEAR(test(2, 3), 6.3427f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 2.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 1.0806f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 1.6829f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 8.7689f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.9093f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.5839f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 1.6829f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), -1.6958f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 1.4161f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.9093f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 1.0806f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 6.3427f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 2.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulPoint4) @@ -701,7 +701,7 @@ TEST(MatrixTest, TestMulPoint4) Point4F testPoint(0.5f, 1.0f, 2.0f, 1.0f); test.mul(testPoint); - EXPECT_NEAR(testPoint.x, 5.496f, 0.001f); EXPECT_NEAR(testPoint.y, 0.899f, 0.001f); EXPECT_NEAR(testPoint.z, 4.151f, 0.001f); EXPECT_NEAR(testPoint.w, 1.0f, 0.001f); + EXPECT_NEAR(testPoint.x, 5.496f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.899f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.151f, POINT_EPSILON); EXPECT_NEAR(testPoint.w, 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulPoint3) @@ -715,7 +715,7 @@ TEST(MatrixTest, TestMulPoint3) Point3F testPoint(0.5f, 1.0f, 2.0f); test.mulP(testPoint); - EXPECT_NEAR(testPoint.x, 5.496f, 0.001f); EXPECT_NEAR(testPoint.y, 0.899f, 0.001f); EXPECT_NEAR(testPoint.z, 4.151f, 0.001f); + EXPECT_NEAR(testPoint.x, 5.496f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.899f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.151f, POINT_EPSILON); } TEST(MatrixTest, TestMulPoint3ToPoint3) @@ -730,7 +730,7 @@ TEST(MatrixTest, TestMulPoint3ToPoint3) Point3F testPoint; test.mulP(point, &testPoint); - EXPECT_NEAR(testPoint.x, 5.496f, 0.001f); EXPECT_NEAR(testPoint.y, 0.899f, 0.001f); EXPECT_NEAR(testPoint.z, 4.151f, 0.001f); + EXPECT_NEAR(testPoint.x, 5.496f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.899f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.151f, POINT_EPSILON); } TEST(MatrixTest, TestMulVector) @@ -744,7 +744,7 @@ TEST(MatrixTest, TestMulVector) VectorF testPoint(0.5f, 1.0f, 2.0f); test.mulV(testPoint); - EXPECT_NEAR(testPoint.x, 1.111f, 0.001f); EXPECT_NEAR(testPoint.y, 1.747f, 0.001f); EXPECT_NEAR(testPoint.z, 0.979f, 0.001f); + EXPECT_NEAR(testPoint.x, 1.111f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 1.747f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 0.979f, POINT_EPSILON); } TEST(MatrixTest, TestMulVectorToPoint3) @@ -759,7 +759,7 @@ TEST(MatrixTest, TestMulVectorToPoint3) Point3F testPoint; test.mulV(vec, &testPoint); - EXPECT_NEAR(testPoint.x, 1.111f, 0.001f); EXPECT_NEAR(testPoint.y, 1.747f, 0.001f); EXPECT_NEAR(testPoint.z, 0.979f, 0.001f); + EXPECT_NEAR(testPoint.x, 1.111f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 1.747f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 0.979f, POINT_EPSILON); } TEST(MatrixTest, TestMulBox) @@ -772,8 +772,8 @@ TEST(MatrixTest, TestMulBox) test.mul(testBox); - EXPECT_NEAR(testBox.minExtents.x, 4.5f, 0.001f); EXPECT_NEAR(testBox.minExtents.y, 1.5f, 0.001f); EXPECT_NEAR(testBox.minExtents.z, 0.5f, 0.001f); - EXPECT_NEAR(testBox.maxExtents.x, 5.5f, 0.001f); EXPECT_NEAR(testBox.maxExtents.y, 2.5f, 0.001f); EXPECT_NEAR(testBox.maxExtents.z, 1.5f, 0.001f); + EXPECT_NEAR(testBox.minExtents.x, 4.5f, POINT_EPSILON); EXPECT_NEAR(testBox.minExtents.y, 1.5f, POINT_EPSILON); EXPECT_NEAR(testBox.minExtents.z, 0.5f, POINT_EPSILON); + EXPECT_NEAR(testBox.maxExtents.x, 5.5f, POINT_EPSILON); EXPECT_NEAR(testBox.maxExtents.y, 2.5f, POINT_EPSILON); EXPECT_NEAR(testBox.maxExtents.z, 1.5f, POINT_EPSILON); } TEST(MatrixTest, TestMatrixAdd) @@ -795,7 +795,7 @@ TEST(MatrixTest, TestMatrixAdd) { for (U32 j = 0; j < 4; j++) { - EXPECT_NEAR(test(i,j), 2.0f, 0.001f); + EXPECT_NEAR(test(i,j), 2.0f, POINT_EPSILON); } } @@ -808,24 +808,24 @@ TEST(MatrixTest, TestFrustumProjectionMatrix) testFrustum.getProjectionMatrix(&test); - EXPECT_NEAR(test(0, 0), 0.8341f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 1.3032f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), -0.0001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.1f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.8341f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 1.3032f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.0001f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 0.1f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 1.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 0.0f, POINT_EPSILON); test.reverseProjection(); - EXPECT_NEAR(test(0, 0), 0.8341f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 1.3032f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 1.0001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), -0.1f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.8341f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 1.3032f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 1.0001f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), -0.1f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 1.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 0.0f, POINT_EPSILON); test.inverse(); - EXPECT_NEAR(test(0, 0), 1.1989f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.9999f, 0.001f); EXPECT_NEAR(test(1, 3), 0.1f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 0.7673f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 1.1989f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 0.9999f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.1f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 0.7673f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 1.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 0.0f, POINT_EPSILON); } @@ -841,7 +841,7 @@ TEST(MatrixTest, TestUnProjectStack) Point3F dest; MathUtils::mProjectScreenToWorld(Point3F(626.0f, 600.0f, 1.0f), &dest, renderRect, saveModel, saveProjection, 0.1f, 10.0f); - EXPECT_NEAR(dest.x, -0.2868f, 0.001f); EXPECT_NEAR(dest.y, 1.1998f, 0.001f); EXPECT_NEAR(dest.z, -0.1450f, 0.001f); + EXPECT_NEAR(dest.x, -0.2868f, POINT_EPSILON); EXPECT_NEAR(dest.y, 1.1998f, POINT_EPSILON); EXPECT_NEAR(dest.z, -0.1450f, POINT_EPSILON); } TEST(MatrixTest, TestInverse) @@ -854,10 +854,10 @@ TEST(MatrixTest, TestInverse) test.inverse(); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), -5.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), -5.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), -2.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), -1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestInvertTo) @@ -872,16 +872,16 @@ TEST(MatrixTest, TestInvertTo) test1.invertTo(&test); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), -5.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), -5.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), -2.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), -1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); // make sure our original matrix is unchanged - EXPECT_NEAR(test1(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test1(0, 1), 0.8415f, 0.001f); EXPECT_NEAR(test1(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test1(0, 3), 4.3845f, 0.001f); - EXPECT_NEAR(test1(1, 0), -0.4546f, 0.001f); EXPECT_NEAR(test1(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test1(1, 2), 0.8415f, 0.001f); EXPECT_NEAR(test1(1, 3), -0.8479f, 0.001f); - EXPECT_NEAR(test1(2, 0), 0.7081f, 0.001f); EXPECT_NEAR(test1(2, 1), -0.4546f, 0.001f); EXPECT_NEAR(test1(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test1(2, 3), 3.1714, 0.001f); - EXPECT_NEAR(test1(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test1(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test1(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test1(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test1(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test1(0, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test1(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test1(0, 3), 4.3845f, POINT_EPSILON); + EXPECT_NEAR(test1(1, 0), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test1(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test1(1, 2), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test1(1, 3), -0.8479f, POINT_EPSILON); + EXPECT_NEAR(test1(2, 0), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test1(2, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test1(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test1(2, 3), 3.1714, POINT_EPSILON); + EXPECT_NEAR(test1(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test1(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test1(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test1(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestFullInverse) @@ -894,10 +894,10 @@ TEST(MatrixTest, TestFullInverse) EXPECT_TRUE(test.fullInverse()); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), -5.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), -5.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), -2.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), -1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestIsAffine) @@ -921,10 +921,10 @@ TEST(MatrixTest, TestScale) test.scale(2.0f); - EXPECT_NEAR(test(0, 0), 1.0806f, 0.001f); EXPECT_NEAR(test(0, 1), 1.6829f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 4.3845f, 0.001f); - EXPECT_NEAR(test(1, 0), -0.9093f, 0.001f); EXPECT_NEAR(test(1, 1), 0.5839f, 0.001f); EXPECT_NEAR(test(1, 2), 1.6829f, 0.001f); EXPECT_NEAR(test(1, 3), -0.8479f, 0.001f); - EXPECT_NEAR(test(2, 0), 1.4161f, 0.001f); EXPECT_NEAR(test(2, 1), -0.9093f, 0.001f); EXPECT_NEAR(test(2, 2), 1.0806f, 0.001f); EXPECT_NEAR(test(2, 3), 3.1714f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 1.0806f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), 1.6829f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 4.3845f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), -0.9093f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.5839f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), 1.6829f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), -0.8479f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 1.4161f, POINT_EPSILON); EXPECT_NEAR(test(2, 1), -0.9093f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 1.0806f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 3.1714f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestGetScale) @@ -940,7 +940,7 @@ TEST(MatrixTest, TestGetScale) Point3F scale; scale = test.getScale(); - EXPECT_NEAR(scale.x, 2.0f, 0.001f); EXPECT_NEAR(scale.y, 2.0f, 0.001f); EXPECT_NEAR(scale.z, 2.0f, 0.001f); + EXPECT_NEAR(scale.x, 2.0f, POINT_EPSILON); EXPECT_NEAR(scale.y, 2.0f, POINT_EPSILON); EXPECT_NEAR(scale.z, 2.0f, POINT_EPSILON); } TEST(MatrixTest, TestAffineInverse) @@ -953,10 +953,10 @@ TEST(MatrixTest, TestAffineInverse) test.affineInverse(); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), -5.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), -2.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), -1.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 0.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), -5.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), -2.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), -1.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 0.0f, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestTranspose) @@ -969,10 +969,10 @@ TEST(MatrixTest, TestTranspose) test.transpose(); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 4.3845f, 0.001f); EXPECT_NEAR(test(3, 1), -0.8479f, 0.001f); EXPECT_NEAR(test(3, 2), 3.1714, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 4.3845f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), -0.8479f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 3.1714, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestTransposeTo) @@ -987,10 +987,10 @@ TEST(MatrixTest, TestTransposeTo) test1.transposeTo(test); - EXPECT_NEAR(test(0, 0), 0.5403f, 0.001f); EXPECT_NEAR(test(0, 1), -0.4546f, 0.001f); EXPECT_NEAR(test(0, 2), 0.7081f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.8415f, 0.001f); EXPECT_NEAR(test(1, 1), 0.2919f, 0.001f); EXPECT_NEAR(test(1, 2), -0.4546f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0, 0.001f); EXPECT_NEAR(test(2, 1), 0.8415f, 0.001f); EXPECT_NEAR(test(2, 2), 0.5403f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(3, 0), 4.3845f, 0.001f); EXPECT_NEAR(test(3, 1), -0.8479f, 0.001f); EXPECT_NEAR(test(3, 2), 3.1714, 0.001f); EXPECT_NEAR(test(3, 3), 1.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(0, 1), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(0, 2), 0.7081f, POINT_EPSILON); EXPECT_NEAR(test(0, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(1, 0), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(1, 1), 0.2919f, POINT_EPSILON); EXPECT_NEAR(test(1, 2), -0.4546f, POINT_EPSILON); EXPECT_NEAR(test(1, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(2, 0), 0.0, POINT_EPSILON); EXPECT_NEAR(test(2, 1), 0.8415f, POINT_EPSILON); EXPECT_NEAR(test(2, 2), 0.5403f, POINT_EPSILON); EXPECT_NEAR(test(2, 3), 0.0f, POINT_EPSILON); + EXPECT_NEAR(test(3, 0), 4.3845f, POINT_EPSILON); EXPECT_NEAR(test(3, 1), -0.8479f, POINT_EPSILON); EXPECT_NEAR(test(3, 2), 3.1714, POINT_EPSILON); EXPECT_NEAR(test(3, 3), 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestTransformPlane) @@ -1006,9 +1006,9 @@ TEST(MatrixTest, TestTransformPlane) PlaneF res; mTransformPlane(test, Point3F(1.0f, 1.0f, 1.0f), plane, &res); - EXPECT_NEAR(res.x, 0.0f, 0.001f); - EXPECT_NEAR(res.y, 0.8414f, 0.001f); - EXPECT_NEAR(res.z, 0.5403f, 0.001f); - EXPECT_NEAR(res.d, -1.0f, 0.001f); + EXPECT_NEAR(res.x, 0.0f, POINT_EPSILON); + EXPECT_NEAR(res.y, 0.8414f, POINT_EPSILON); + EXPECT_NEAR(res.z, 0.5403f, POINT_EPSILON); + EXPECT_NEAR(res.d, -1.0f, POINT_EPSILON); } From 2ed9fbb6ff824120c1aff43dda95f2c1a8c9610e Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 1 Aug 2024 05:07:54 +0100 Subject: [PATCH 28/29] Update mathMatrixTest.cpp --- Engine/source/testing/mathMatrixTest.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index 8d9b4e576..57a8b49d3 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -701,7 +701,7 @@ TEST(MatrixTest, TestMulPoint4) Point4F testPoint(0.5f, 1.0f, 2.0f, 1.0f); test.mul(testPoint); - EXPECT_NEAR(testPoint.x, 5.496f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.899f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.151f, POINT_EPSILON); EXPECT_NEAR(testPoint.w, 1.0f, POINT_EPSILON); + EXPECT_NEAR(testPoint.x, 5.4960f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.8996f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.1513f, POINT_EPSILON); EXPECT_NEAR(testPoint.w, 1.0f, POINT_EPSILON); } TEST(MatrixTest, TestMulPoint3) @@ -715,7 +715,7 @@ TEST(MatrixTest, TestMulPoint3) Point3F testPoint(0.5f, 1.0f, 2.0f); test.mulP(testPoint); - EXPECT_NEAR(testPoint.x, 5.496f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.899f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.151f, POINT_EPSILON); + EXPECT_NEAR(testPoint.x, 5.4960f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.8996f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.1513f, POINT_EPSILON); } TEST(MatrixTest, TestMulPoint3ToPoint3) @@ -730,7 +730,7 @@ TEST(MatrixTest, TestMulPoint3ToPoint3) Point3F testPoint; test.mulP(point, &testPoint); - EXPECT_NEAR(testPoint.x, 5.496f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.899f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.151f, POINT_EPSILON); + EXPECT_NEAR(testPoint.x, 5.4960f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 0.8996f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 4.1513f, POINT_EPSILON); } TEST(MatrixTest, TestMulVector) @@ -744,7 +744,7 @@ TEST(MatrixTest, TestMulVector) VectorF testPoint(0.5f, 1.0f, 2.0f); test.mulV(testPoint); - EXPECT_NEAR(testPoint.x, 1.111f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 1.747f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 0.979f, POINT_EPSILON); + EXPECT_NEAR(testPoint.x, 1.1116f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 1.7475f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 0.9799f, POINT_EPSILON); } TEST(MatrixTest, TestMulVectorToPoint3) @@ -759,7 +759,7 @@ TEST(MatrixTest, TestMulVectorToPoint3) Point3F testPoint; test.mulV(vec, &testPoint); - EXPECT_NEAR(testPoint.x, 1.111f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 1.747f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 0.979f, POINT_EPSILON); + EXPECT_NEAR(testPoint.x, 1.1116f, POINT_EPSILON); EXPECT_NEAR(testPoint.y, 1.7475f, POINT_EPSILON); EXPECT_NEAR(testPoint.z, 0.9799f, POINT_EPSILON); } TEST(MatrixTest, TestMulBox) From 3b4ce5f4b5aaf63f28bf797240ad924a89a8f3e1 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 1 Aug 2024 18:29:38 +0100 Subject: [PATCH 29/29] cmake option cmake option to enable the templated matrix class, this is still in review phase, if it gets merged into main, probably best to remove this options just in case someone activates it accidentally. --- Tools/CMake/torqueConfig.h.in | 2 +- Tools/CMake/torque_configs.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/CMake/torqueConfig.h.in b/Tools/CMake/torqueConfig.h.in index 39b9a7c03..717c05eb1 100644 --- a/Tools/CMake/torqueConfig.h.in +++ b/Tools/CMake/torqueConfig.h.in @@ -32,7 +32,7 @@ /// What's the name of your application? Used in a variety of places. #define TORQUE_APP_NAME "@TORQUE_APP_NAME@" - +#cmakedefine USE_TEMPLATE_MATRIX /// What version of the application specific source code is this? /// /// Version number is major * 1000 + minor * 100 + revision * 10. diff --git a/Tools/CMake/torque_configs.cmake b/Tools/CMake/torque_configs.cmake index 7cfbd2f6b..6a8888826 100644 --- a/Tools/CMake/torque_configs.cmake +++ b/Tools/CMake/torque_configs.cmake @@ -73,7 +73,7 @@ advanced_option(TORQUE_ENABLE_ASSERTS "enables or disable asserts" OFF) advanced_option(TORQUE_TOOLS "Enable or disable the tools" ON) advanced_option(TORQUE_ENABLE_PROFILER "Enable or disable the profiler" OFF) advanced_option(TORQUE_SHOW_LEGACY_FILE_FIELDS "If on, shows legacy direct file path fields in the inspector." OFF) - +advanced_option(USE_TEMPLATE_MATRIX "Set to true to use the new templated matrix class(still in beta)." OFF) #testing advanced_option(TORQUE_TESTING "Unit test build" OFF)