ソースを参照

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
marauder2k7 1 年間 前
コミット
888332a85c

+ 5 - 1
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<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class Point3F;
 class MoveManager;
 class MoveList;

+ 6 - 1
Engine/source/T3D/physics/physicsCollision.h

@@ -28,7 +28,12 @@
 #endif
 
 class Point3F;
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class PlaneF;
 
 
@@ -84,4 +89,4 @@ public:
                                  const MatrixF &localXfm ) = 0;
 };
 
-#endif // _T3D_PHYSICS_PHYSICSCOLLISION_H_
+#endif // _T3D_PHYSICS_PHYSICSCOLLISION_H_

+ 6 - 1
Engine/source/T3D/physics/physicsObject.h

@@ -34,7 +34,12 @@
 #endif
 
 class PhysicsWorld;
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class Point3F;
 class Box3F;
 
@@ -88,4 +93,4 @@ protected:
    U32 mQueuedEvent;
 };
 
-#endif // _T3D_PHYSICS_PHYSICSOBJECT_H_
+#endif // _T3D_PHYSICS_PHYSICSOBJECT_H_

+ 5 - 0
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<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class AngAxisF;
 class QuatF;
 class String;

+ 5 - 0
Engine/source/core/stream/bitStream.h

@@ -45,7 +45,12 @@
 //
 
 class Point3F;
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class HuffmanProcessor;
 class BitVector;
 class QuatF;

+ 5 - 0
Engine/source/gfx/gfxShader.h

@@ -60,7 +60,12 @@
 class Point2I;
 class Point2F;
 class LinearColorF;
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class GFXShader;
 class GFXVertexFormat;
 

+ 6 - 0
Engine/source/math/mAngAxis.h

@@ -27,7 +27,13 @@
 #include "math/mPoint3.h"
 #endif
 
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
+
 class QuatF;
 
 //----------------------------------------------------------------------------

+ 5 - 0
Engine/source/math/mBox.h

@@ -36,7 +36,12 @@
 #endif
 
 
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class SphereF;
 
 

+ 6 - 421
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<typename DATA_TYPE, U32 rows, U32 cols>
-const Matrix<DATA_TYPE, rows, cols> Matrix<DATA_TYPE, rows, cols>::Identity = []() {
-   Matrix<DATA_TYPE, rows, cols> identity(true);
-   return identity;
-}();
-
-template<typename DATA_TYPE, U32 rows, U32 cols>
-Matrix<DATA_TYPE, rows, cols>::Matrix(const EulerF& e)
-{
-   set(e);
-}
-
-template<typename DATA_TYPE, U32 rows, U32 cols>
-Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<DATA_TYPE, float>::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<DATA_TYPE, rows, cols>(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<typename DATA_TYPE, U32 rows, U32 cols>
-Matrix<DATA_TYPE, rows, cols>::Matrix(const EulerF& e, const Point3F p)
-{
-   set(e, p);
-}
-
-template<typename DATA_TYPE, U32 rows, U32 cols>
-Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
-Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<DATA_TYPE, size, 2 * size> augmentedMatrix;
-   Matrix<DATA_TYPE, size, size> 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<DATA_TYPE>(1) : static_cast<DATA_TYPE>(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<DATA_TYPE>(0)) {
-         return Matrix<DATA_TYPE, rows, cols>(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<typename DATA_TYPE, U32 rows, U32 cols>
-void Matrix<DATA_TYPE, rows, cols>::invert()
-{
-   (*this) = inverse();
-}
-
-template<typename DATA_TYPE, U32 rows, U32 cols>
-Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
-Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
-void Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
-bool Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
-Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::affineInverse()
-{
-   AssertFatal(rows >= 4 && cols >= 4, "affineInverse requires at least 4x4");
-   Matrix<DATA_TYPE, 3, 3> 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<typename DATA_TYPE, U32 rows, U32 cols>
-EulerF Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
-void Matrix<DATA_TYPE, rows, cols>::dumpMatrix(const char* caption) const
-{
-   U32 size = (caption == NULL) ? 0 : dStrlen(caption);
-   FrameTemp<char> spacer(size + 1);
-   char* spacerRef = spacer;
-
-   // is_floating_point should return true for floats and doubles.
-   const char* formatSpec = std::is_floating_point_v<DATA_TYPE> ? " %-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

+ 575 - 8
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<DATA_TYPE, rows, cols>& identity();
-
+   void reverseProjection();
    void normalize();
 
    Matrix<DATA_TYPE, rows, cols>& set(const EulerF& e);
@@ -660,7 +663,7 @@ public:
    Matrix(const EulerF& e, const Point3F p);
    Matrix<DATA_TYPE, rows, cols>& set(const EulerF& e, const Point3F p);
 
-   Matrix<DATA_TYPE, rows, cols>& inverse();
+   Matrix<DATA_TYPE, rows, cols> inverse();
    Matrix<DATA_TYPE, rows, cols>& 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<DATA_TYPE, rows, cols>& mul(const Matrix<DATA_TYPE, rows, cols>& a)
-   { return *this * a; }
+   {
+      *this = *this * a;  return *this;
+   }
    ///< a * M -> M
    Matrix<DATA_TYPE, rows, cols>& mulL(const Matrix<DATA_TYPE, rows, cols>& 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<DATA_TYPE, rows, cols>& affineInverse();
+   Matrix<DATA_TYPE, rows, cols> 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<DATA_TYPE, cols, rows>& 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<DATA_TYPE, cols, rows>* matrix) {
+      Matrix<DATA_TYPE, rows, cols> 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<DATA_TYPE, rows, cols>::getRow(S32 row, Point3F* cptr) const
       cptr->z = 0.0f;
 }
 
+template<typename DATA_TYPE, U32 rows, U32 cols>
+inline VectorF Matrix<DATA_TYPE, rows, cols>::getRightVector() const
+{
+   VectorF vec;
+   getColumn(0, &vec);
+   return vec;
+}
+
+template<typename DATA_TYPE, U32 rows, U32 cols>
+inline VectorF Matrix<DATA_TYPE, rows, cols>::getForwardVector() const
+{
+   VectorF vec;
+   getColumn(1, &vec);
+   return vec;
+}
+
+template<typename DATA_TYPE, U32 rows, U32 cols>
+inline VectorF Matrix<DATA_TYPE, rows, cols>::getUpVector() const
+{
+   VectorF vec;
+   getColumn(2, &vec);
+   return vec;
+}
+
 template<typename DATA_TYPE, U32 rows, U32 cols>
 inline void Matrix<DATA_TYPE, rows, cols>::setRow(S32 row, const Point4F& cptr) {
    if(cols >= 2)
@@ -1121,11 +1185,514 @@ inline void Matrix<DATA_TYPE, rows, cols>::setRow(S32 row, const Point3F& cptr)
    
 }
 
+template<typename DATA_TYPE, U32 rows, U32 cols>
+inline void Matrix<DATA_TYPE, rows, cols>::displace(const Point3F& delta)
+{
+   (*this)(0, 3) += delta.x;
+   (*this)(1, 3) += delta.y;
+   (*this)(2, 3) += delta.z;
+}
+
+
+template<typename DATA_TYPE, U32 rows, U32 cols>
+void Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
+const Matrix<DATA_TYPE, rows, cols> Matrix<DATA_TYPE, rows, cols>::Identity = []() {
+   Matrix<DATA_TYPE, rows, cols> identity(true);
+   return identity;
+}();
+
+template<typename DATA_TYPE, U32 rows, U32 cols>
+Matrix<DATA_TYPE, rows, cols>::Matrix(const EulerF& e)
+{
+   set(e);
+}
+
+template<typename DATA_TYPE, U32 rows, U32 cols>
+Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<DATA_TYPE, float>::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<DATA_TYPE, rows, cols>(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<typename DATA_TYPE, U32 rows, U32 cols>
+Matrix<DATA_TYPE, rows, cols>::Matrix(const EulerF& e, const Point3F p)
+{
+   set(e, p);
+}
+
+template<typename DATA_TYPE, U32 rows, U32 cols>
+Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
+Matrix<DATA_TYPE, rows, cols> Matrix<DATA_TYPE, rows, cols>::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<DATA_TYPE, size, 2 * size> augmentedMatrix;
+   Matrix<DATA_TYPE, size, size> 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<DATA_TYPE>(1) : static_cast<DATA_TYPE>(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<DATA_TYPE>(0)) {
+         return Matrix<DATA_TYPE, rows, cols>(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<typename DATA_TYPE, U32 rows, U32 cols>
+inline bool Matrix<DATA_TYPE, rows, cols>::fullInverse()
+{
+   Matrix<DATA_TYPE, rows, cols> inv = this->inverse();
+
+   if (inv.isIdentity())
+      return false;
+
+   *this = inv;
+   return true;
+}
+
+template<typename DATA_TYPE, U32 rows, U32 cols>
+inline void Matrix<DATA_TYPE, rows, cols>::invert()
+{
+   (*this) = inverse();
+}
+
+template<typename DATA_TYPE, U32 rows, U32 cols>
+inline Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
+inline Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
+inline void Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
+inline bool Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
+inline Matrix<DATA_TYPE, rows, cols> Matrix<DATA_TYPE, rows, cols>::affineInverse()
+{
+   AssertFatal(rows >= 4 && cols >= 4, "affineInverse requires at least 4x4");
+   Matrix<DATA_TYPE, 3, 3> 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<typename DATA_TYPE, U32 rows, U32 cols>
+inline EulerF Matrix<DATA_TYPE, rows, cols>::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<typename DATA_TYPE, U32 rows, U32 cols>
+inline void Matrix<DATA_TYPE, rows, cols>::dumpMatrix(const char* caption) const
+{
+   U32 size = (caption == NULL) ? 0 : dStrlen(caption);
+   FrameTemp<char> spacer(size + 1);
+   char* spacerRef = spacer;
+
+   // is_floating_point should return true for floats and doubles.
+   const char* formatSpec = std::is_floating_point_v<DATA_TYPE> ? " %-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<typename DATA_TYPE, std::size_t Rows, std::size_t Cols>
+inline void mTransformPlane(
+   const Matrix<DATA_TYPE, Rows, Cols>& 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<float, 4, 4> matCopy = mat;
+
+   // Create the inverse scale matrix
+   Matrix<DATA_TYPE, 4, 4> invScale = Matrix<DATA_TYPE, 4, 4>::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<DATA_TYPE, 4, 4> 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<DATA_TYPE, 4, 4> 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<F32, 4, 4> Matrix4F;
+typedef Matrix<F32, 4, 4> 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_

+ 5 - 0
Engine/source/math/mOrientedBox.h

@@ -32,7 +32,12 @@
 #endif
 
 
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class Box3F;
 
 

+ 5 - 0
Engine/source/math/mQuat.h

@@ -27,7 +27,12 @@
 #include "math/mPoint3.h"
 #endif
 
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class AngAxisF;
 
 //----------------------------------------------------------------------------

+ 8 - 5
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<F32, 4, 4>(),
+MatrixTemplateExport::getMatrixField<F32, 4, 4>(),
 
-   END_IMPLEMENT_STRUCT;
+END_IMPLEMENT_STRUCT;
+#endif
 IMPLEMENT_STRUCT( AngAxisF,
    AngAxisF, MathTypes,
    "" )

+ 5 - 0
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<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class Box3F;
 class EaseF;
 class AngAxisF;

+ 5 - 0
Engine/source/scene/sgUtil.h

@@ -32,7 +32,12 @@
 
 class Frustum;
 class RectI;
+#ifndef USE_TEMPLATE_MATRIX
 class MatrixF;
+#else
+template<typename DATA_TYPE, U32 rows, U32 cols> class Matrix;
+typedef Matrix<F32, 4, 4> MatrixF;
+#endif
 class PlaneF;
 
 struct SGWinding