/* * Copyright 2014 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MATHFU_MATRIX_H_ #define MATHFU_MATRIX_H_ #include "mathfu/utilities.h" #include "mathfu/vector.h" #include #include /// @file mathfu/matrix.h /// @brief Matrix class and functions. /// @addtogroup mathfu_matrix /// /// MathFu provides a generic Matrix implementation which is specialized /// for 4x4 matrices to take advantage of optimization opportunities using /// SIMD instructions. #ifdef _MSC_VER #pragma warning(push) // The following disables warnings for MATHFU_MAT_OPERATION. // The buffer overrun warning must be disabled as MSVC doesn't treat // "columns" as constant and therefore assumes that it's possible // to overrun arrays indexed by "i". // The conditional expression is constant warning is disabled since // MSVC decides that "columns" *is* constant when unrolling the operation // loop. #pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4789) // buffer overrun #if _MSC_VER >= 1900 // MSVC 2015 #pragma warning(disable : 4456) // allow shadowing in unrolled loops #pragma warning(disable : 4723) // suppress "potential divide by 0" warning #endif // _MSC_VER >= 1900 #endif // _MSC_VER /// @cond MATHFU_INTERNAL /// The stride of a vector (e.g Vector) when cast as an array of floats. #define MATHFU_VECTOR_STRIDE_FLOATS(vector) (sizeof(vector) / sizeof(float)) /// @endcond /// @cond MATHFU_INTERNAL /// This will unroll loops for matrices with <= 4 columns #define MATHFU_MAT_OPERATION(OP) MATHFU_UNROLLED_LOOP(i, columns, OP) /// @endcond /// @cond MATHFU_INTERNAL /// This will perform a given OP on each matrix column and return the result #define MATHFU_MAT_OPERATOR(OP) \ { \ Matrix result; \ MATHFU_MAT_OPERATION(result.data_[i] = (OP)); \ return result; \ } /// @endcond /// @cond MATHFU_INTERNAL /// This will perform a given OP on each matrix column #define MATHFU_MAT_SELF_OPERATOR(OP) \ { \ MATHFU_MAT_OPERATION(OP); \ return *this; \ } /// @endcond /// @cond MATHFU_INTERNAL /// This macro will take the dot product for a row from data1 and a column from /// data2. #define MATHFU_MATRIX_4X4_DOT(data1, data2, r) \ ((data1)[r] * (data2)[0] + (data1)[(r) + 4] * (data2)[1] + \ (data1)[(r) + 8] * (data2)[2] + (data1)[(r) + 12] * (data2)[3]) /// @endcond /// @cond MATHFU_INTERNAL #define MATHFU_MATRIX_3X3_DOT(data1, data2, r, size) \ ((data1)[r] * (data2)[0] + (data1)[(r) + (size)] * (data2)[1] + \ (data1)[(r) + 2 * (size)] * (data2)[2]) /// @endcond namespace mathfu { /// @cond MATHFU_INTERNAL template class Matrix; template inline Matrix IdentityHelper(); template inline bool InverseHelper(const Matrix& m, Matrix* const inverse); template inline void TimesHelper(const Matrix& m1, const Matrix& m2, Matrix* out_m); template static inline Matrix OuterProductHelper( const Vector& v1, const Vector& v2); template inline Matrix PerspectiveHelper(T fovy, T aspect, T znear, T zfar, T handedness); template static inline Matrix OrthoHelper(T left, T right, T bottom, T top, T znear, T zfar, T handedness); template static inline Matrix LookAtHelper(const Vector& at, const Vector& eye, const Vector& up, T handedness); template static inline bool UnProjectHelper(const Vector& window_coord, const Matrix& model_view, const Matrix& projection, const float window_width, const float window_height, Vector& result); template static inline Matrix FromTypeHelper(const CompatibleT& compatible); template static inline CompatibleT ToTypeHelper(const Matrix& m); /// @endcond /// @addtogroup mathfu_matrix /// @{ /// @class Matrix /// @brief Matrix stores a set of "rows" by "columns" elements of type T /// and provides functions that operate on the set of elements. /// /// @tparam T type of each element in the matrix. /// @tparam rows Number of rows in the matrix. /// @tparam columns Number of columns in the matrix. template class Matrix { public: /// @brief Construct a Matrix of uninitialized values. inline Matrix() {} /// @brief Construct a Matrix from another Matrix copying each element. //// /// @param m Matrix that the data will be copied from. inline Matrix(const Matrix& m) { MATHFU_MAT_OPERATION(data_[i] = m.data_[i]); } /// @brief Construct a Matrix from a single float. /// /// @param s Scalar value used to initialize each element of the matrix. explicit inline Matrix(const T& s) { MATHFU_MAT_OPERATION((data_[i] = Vector(s))); } /// @brief Construct a Matrix from four floats. /// /// @note This method only works with a 2x2 Matrix. /// /// @param s00 Value of the first row and column. /// @param s10 Value of the second row, first column. /// @param s01 Value of the first row, second column. /// @param s11 Value of the second row and column. inline Matrix(const T& s00, const T& s10, const T& s01, const T& s11) { MATHFU_STATIC_ASSERT(rows == 2 && columns == 2); data_[0] = Vector(s00, s10); data_[1] = Vector(s01, s11); } /// @brief Create a Matrix from nine floats. /// /// @note This method only works with a 3x3 Matrix. /// /// @param s00 Value of the first row and column. /// @param s10 Value of the second row, first column. /// @param s20 Value of the third row, first column. /// @param s01 Value of the first row, second column. /// @param s11 Value of the second row and column. /// @param s21 Value of the third row, second column. /// @param s02 Value of the first row, third column. /// @param s12 Value of the second row, third column. /// @param s22 Value of the third row and column. inline Matrix(const T& s00, const T& s10, const T& s20, const T& s01, const T& s11, const T& s21, const T& s02, const T& s12, const T& s22) { MATHFU_STATIC_ASSERT(rows == 3 && columns == 3); data_[0] = Vector(s00, s10, s20); data_[1] = Vector(s01, s11, s21); data_[2] = Vector(s02, s12, s22); } /// @brief Creates a Matrix from twelve floats. /// /// @note This method only works with Matrix. /// /// /// @param s00 Value of the first row and column. /// @param s10 Value of the second row, first column. /// @param s20 Value of the third row, first column. /// @param s30 Value of the fourth row, first column. /// @param s01 Value of the first row, second column. /// @param s11 Value of the second row and column. /// @param s21 Value of the third row, second column. /// @param s31 Value of the fourth row, second column. /// @param s02 Value of the first row, third column. /// @param s12 Value of the second row, third column. /// @param s22 Value of the third row and column. /// @param s32 Value of the fourth row, third column. inline Matrix(const T& s00, const T& s10, const T& s20, const T& s30, const T& s01, const T& s11, const T& s21, const T& s31, const T& s02, const T& s12, const T& s22, const T& s32) { MATHFU_STATIC_ASSERT(rows == 4 && columns == 3); data_[0] = Vector(s00, s10, s20, s30); data_[1] = Vector(s01, s11, s21, s31); data_[2] = Vector(s02, s12, s22, s32); } /// @brief Create a Matrix from sixteen floats. /// /// @note This method only works with a 4x4 Matrix. /// /// @param s00 Value of the first row and column. /// @param s10 Value of the second row, first column. /// @param s20 Value of the third row, first column. /// @param s30 Value of the fourth row, first column. /// @param s01 Value of the first row, second column. /// @param s11 Value of the second row and column. /// @param s21 Value of the third row, second column. /// @param s31 Value of the fourth row, second column. /// @param s02 Value of the first row, third column. /// @param s12 Value of the second row, third column. /// @param s22 Value of the third row and column. /// @param s32 Value of the fourth row, third column. /// @param s03 Value of the first row, fourth column. /// @param s13 Value of the second row, fourth column. /// @param s23 Value of the third row, fourth column. /// @param s33 Value of the fourth row and column. inline Matrix(const T& s00, const T& s10, const T& s20, const T& s30, const T& s01, const T& s11, const T& s21, const T& s31, const T& s02, const T& s12, const T& s22, const T& s32, const T& s03, const T& s13, const T& s23, const T& s33) { MATHFU_STATIC_ASSERT(rows == 4 && columns == 4); data_[0] = Vector(s00, s10, s20, s30); data_[1] = Vector(s01, s11, s21, s31); data_[2] = Vector(s02, s12, s22, s32); data_[3] = Vector(s03, s13, s23, s33); } /// @brief Create 4x4 Matrix from 4, 4 element vectors. /// /// @note This method only works with a 4x4 Matrix. /// /// @param column0 Vector used for the first column. /// @param column1 Vector used for the second column. /// @param column2 Vector used for the third column. /// @param column3 Vector used for the fourth column. inline Matrix(const Vector& column0, const Vector& column1, const Vector& column2, const Vector& column3) { MATHFU_STATIC_ASSERT(rows == 4 && columns == 4); data_[0] = column0; data_[1] = column1; data_[2] = column2; data_[3] = column3; } /// @brief Create a Matrix from the first row * column elements of an array. /// /// @param a Array of values that the matrix will be iniitlized to. explicit inline Matrix(const T* const a) { MATHFU_MAT_OPERATION((data_[i] = Vector(&a[i * columns]))); } /// @brief Create a Matrix from an array of "columns", "rows" element packed /// vectors. /// /// @param vectors Array of "columns", "rows" element packed vectors. explicit inline Matrix(const VectorPacked* const vectors) { MATHFU_MAT_OPERATION((data_[i] = Vector(vectors[i]))); } /// @brief Access an element of the matrix. /// /// @param row Index of the row to access. /// @param column Index of the column to access. /// @return Const reference to the element. inline const T& operator()(const int row, const int column) const { return data_[column][row]; } /// @brief Access an element of the Matrix. /// /// @param row Index of the row to access. /// @param column Index of the column to access. /// @return Reference to the data that can be modified by the caller. inline T& operator()(const int row, const int column) { return data_[column][row]; } /// @brief Access an element of the Matrix. /// /// @param i Index of the element to access in flattened memory. Where /// the column accessed is i / rows and the row is i % rows. /// @return Reference to the data that can be modified by the caller. inline const T& operator()(const int i) const { return operator[](i); } /// @brief Access an element of the Matrix. /// /// @param i Index of the element to access in flattened memory. Where /// the column accessed is i / rows and the row is i % rows. /// @return Reference to the data that can be modified by the caller. inline T& operator()(const int i) { return operator[](i); } /// @brief Access an element of the Matrix. /// /// @param i Index of the element to access in flattened memory. Where /// the column accessed is i / rows and the row is i % rows. /// @return Const reference to the data. inline const T& operator[](const int i) const { return const_cast*>(this)->operator[](i); } /// @brief Access an element of the Matrix. /// /// @param i Index of the element to access in flattened memory. Where /// the column accessed is i / rows and the row is i % rows. /// @return Reference to the data that can be modified by the caller. inline T& operator[](const int i) { #if defined(MATHFU_COMPILE_WITH_PADDING) // In this case Vector is padded, so the element offset must be // accessed using the array operator. if (rows == 3) { const int row = i % rows; const int col = i / rows; return data_[col][row]; } else { return reinterpret_cast(data_)[i]; } #else return reinterpret_cast(data_)[i]; #endif // defined(MATHFU_COMPILE_WITH_PADDING) } /// @brief Pack the matrix to an array of "rows" element vectors, /// one vector per matrix column. /// /// @param vector Array of "columns" entries to write to. inline void Pack(VectorPacked* const vector) const { MATHFU_MAT_OPERATION(GetColumn(i).Pack(&vector[i])); } /// @cond MATHFU_INTERNAL /// @brief Access a column vector of the Matrix. /// /// @param i Index of the column to access. /// @return Reference to the data that can be modified by the caller. inline Vector& GetColumn(const int i) { return data_[i]; } /// @brief Access a column vector of the Matrix. /// /// @param i Index of the column to access. /// @return Const reference to the data. inline const Vector& GetColumn(const int i) const { return data_[i]; } /// @endcond /// @brief Negate this Matrix. /// /// @return Matrix containing the result. inline Matrix operator-() const { MATHFU_MAT_OPERATOR(-data_[i]); } /// @brief Add a Matrix to this Matrix. /// /// @param m Matrix to add to this Matrix. /// @return Matrix containing the result. inline Matrix operator+( const Matrix& m) const { MATHFU_MAT_OPERATOR(data_[i] + m.data_[i]); } /// @brief Subtract a Matrix from this Matrix. /// /// @param m Matrix to subtract from this Matrix. /// @return Matrix containing the result. inline Matrix operator-( const Matrix& m) const { MATHFU_MAT_OPERATOR(data_[i] - m.data_[i]); } /// @brief Add a scalar to each element of this Matrix. /// /// @param s Scalar to add to this Matrix. /// @return Matrix containing the result. inline Matrix operator+(const T& s) const { MATHFU_MAT_OPERATOR(data_[i] + s); } /// @brief Subtract a scalar from each element of this Matrix. /// /// @param s Scalar to subtract from this matrix. /// @return Matrix containing the result. inline Matrix operator-(const T& s) const { MATHFU_MAT_OPERATOR(data_[i] - s); } /// @brief Multiply each element of this Matrix with a scalar. /// /// @param s Scalar to multiply with this Matrix. /// @return Matrix containing the result. inline Matrix operator*(const T& s) const { MATHFU_MAT_OPERATOR(data_[i] * s); } /// @brief Divide each element of this Matrix with a scalar. /// /// @param s Scalar to divide this Matrix with. /// @return Matrix containing the result. inline Matrix operator/(const T& s) const { return (*this) * (1 / s); } /// @brief Multiply this Matrix with another Matrix. /// /// @param m Matrix to multiply with this Matrix. /// @return Matrix containing the result. inline Matrix operator*( const Matrix& m) const { Matrix result; TimesHelper(*this, m, &result); return result; } /// @brief Add a Matrix to this Matrix (in-place). /// /// @param m Matrix to add to this Matrix. /// @return Reference to this class. inline Matrix& operator+=( const Matrix& m) { MATHFU_MAT_SELF_OPERATOR(data_[i] += m.data_[i]); } /// @brief Subtract a Matrix from this Matrix (in-place). /// /// @param m Matrix to subtract from this Matrix. /// @return Reference to this class. inline Matrix& operator-=( const Matrix& m) { MATHFU_MAT_SELF_OPERATOR(data_[i] -= m.data_[i]); } /// @brief Add a scalar to each element of this Matrix (in-place). /// /// @param s Scalar to add to each element of this Matrix. /// @return Reference to this class. inline Matrix& operator+=(const T& s) { MATHFU_MAT_SELF_OPERATOR(data_[i] += s); } /// @brief Subtract a scalar from each element of this Matrix (in-place). /// /// @param s Scalar to subtract from each element of this Matrix. /// @return Reference to this class. inline Matrix& operator-=(const T& s) { MATHFU_MAT_SELF_OPERATOR(data_[i] -= s); } /// @brief Multiply each element of this Matrix with a scalar (in-place). /// /// @param s Scalar to multiply with each element of this Matrix. /// @return Reference to this class. inline Matrix& operator*=(const T& s) { MATHFU_MAT_SELF_OPERATOR(data_[i] *= s); } /// @brief Divide each element of this Matrix by a scalar (in-place). /// /// @param s Scalar to divide this Matrix by. /// @return Reference to this class. inline Matrix& operator/=(const T& s) { return (*this) *= (1 / s); } /// @brief Multiply this Matrix with another Matrix (in-place). /// /// @param m Matrix to multiply with this Matrix. /// @return Reference to this class. inline Matrix& operator*=( const Matrix& m) { const Matrix copy_of_this(*this); TimesHelper(copy_of_this, m, this); return *this; } /// @brief Calculate the inverse of this Matrix. /// /// This calculates the inverse Matrix such that /// (m * m).Inverse() is the identity. /// @return Matrix containing the result. inline Matrix Inverse() const { Matrix inverse; InverseHelper(*this, &inverse); return inverse; } /// @brief Calculate the inverse of this Matrix. /// /// This calculates the inverse Matrix such that /// (m * m).Inverse() is the identity. /// By contrast to Inverse() this returns whether the matrix is invertible. /// /// The invertible check simply compares the calculated determinant with /// Constants::GetDeterminantThreshold() to roughly determine whether the /// matrix is invertible. This simple check works in common cases but will /// fail for corner cases where the matrix is a combination of huge and tiny /// values that can't be accurately represented by the floating point /// datatype T. More extensive checks (relative to the input values) are /// possible but far more expensive, complicated and difficult to /// test. /// @return Whether the matrix is invertible. inline bool InverseWithDeterminantCheck( Matrix* const inverse) const { return InverseHelper(*this, inverse); } /// @brief Calculate the transpose of this Matrix. /// /// @return The transpose of the specified Matrix. inline Matrix Transpose() const { Matrix transpose; MATHFU_UNROLLED_LOOP( i, columns, MATHFU_UNROLLED_LOOP( j, rows, transpose.GetColumn(j)[i] = GetColumn(i)[j])) return transpose; } /// @brief Get the 2-dimensional translation of a 2-dimensional affine /// transform. /// /// @note 2-dimensional affine transforms are represented by 3x3 matrices. /// @return Vector with the first two components of column 2 of this Matrix. inline Vector TranslationVector2D() const { MATHFU_STATIC_ASSERT(rows == 3 && columns == 3); return Vector(data_[2][0], data_[2][1]); } /// @brief Get the 3-dimensional translation of a 3-dimensional affine /// transform. /// /// @note 3-dimensional affine transforms are represented by 4x4 matrices. /// @return Vector with the first three components of column 3. inline Vector TranslationVector3D() const { MATHFU_STATIC_ASSERT(rows == 4 && columns == 4); return Vector(data_[3][0], data_[3][1], data_[3][2]); } /// @brief Load from any byte-wise compatible external matrix. /// /// Format should be `columns` vectors, each holding `rows` values of type T. /// /// Use this for safe conversion from external matrix classes. /// Often, external libraries will have their own matrix types that are, /// byte-for-byte, exactly the same as mathfu::Matrix. This function allows /// you to load a mathfu::Matrix from those external types, without potential /// aliasing bugs that are caused by casting. /// /// @note If your external type gives you access to a T*, then you can /// equivalently use the Matrix(const T*) constructor. /// /// @param compatible reference to a byte-wise compatible matrix structure; /// array of columns x rows Ts. /// @returns `compatible` loaded as a mathfu::Matrix. template static inline Matrix FromType(const CompatibleT& compatible) { return FromTypeHelper(compatible); } /// @brief Load into any byte-wise compatible external matrix. /// /// Format should be `columns` vectors, each holding `rows` values of type T. /// /// Use this for safe conversion to external matrix classes. /// Often, external libraries will have their own matrix types that are, /// byte-for-byte, exactly the same as mathfu::Matrix. This function allows /// you to load an external type from a mathfu::Matrix, without potential /// aliasing bugs that are caused by casting. /// /// @param m reference to mathfu::Matrix to convert. /// @returns CompatibleT loaded from m. template static inline CompatibleT ToType(const Matrix& m) { return ToTypeHelper(m); } /// @brief Calculate the outer product of two Vectors. /// /// @return Matrix containing the result. static inline Matrix OuterProduct( const Vector& v1, const Vector& v2) { return OuterProductHelper(v1, v2); } /// @brief Calculate the hadamard / component-wise product of two matrices. /// /// @param m1 First Matrix. /// @param m2 Second Matrix. /// @return Matrix containing the result. static inline Matrix HadamardProduct( const Matrix& m1, const Matrix& m2) { MATHFU_MAT_OPERATOR(m1[i] * m2[i]); } /// @brief Calculate the identity Matrix. /// /// @return Matrix containing the result. static inline Matrix Identity() { return IdentityHelper(); } /// @brief Create a 3x3 translation Matrix from a 2-dimensional Vector. /// /// This matrix will have an empty or zero rotation component. /// /// @param v Vector of size 2. /// @return Matrix containing the result. static inline Matrix FromTranslationVector(const Vector& v) { return Matrix(1, 0, 0, 0, 1, 0, v[0], v[1], 1); } /// @brief Create a 4x4 translation Matrix from a 3-dimensional Vector. /// /// This matrix will have an empty or zero rotation component. /// /// @param v The vector of size 3. /// @return Matrix containing the result. static inline Matrix FromTranslationVector(const Vector& v) { return Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, v[0], v[1], v[2], 1); } /// @brief Create a square Matrix with the diagonal component set to v. /// /// This is an affine transform matrix, so the dimension of the vector is /// one less than the dimension of the matrix. /// /// @param v Vector containing components for scaling. /// @return Matrix with v along the diagonal, and 1 in the bottom right. static inline Matrix FromScaleVector(const Vector& v) { // TODO OPT: Use a helper function in a similar way to Identity to // construct the matrix for the specialized cases 2, 3, 4, and only run // this method in the general case. This will also allow you to use the // helper methods from specialized classes like Matrix. Matrix return_matrix(Identity()); for (int i = 0; i < rows - 1; ++i) return_matrix(i, i) = v[i]; return return_matrix; } /// @brief Create a 4x4 Matrix from a 3x3 rotation Matrix. /// /// This Matrix will have an empty or zero translation component. /// /// @param m 3x3 rotation Matrix. /// @return Matrix containing the result. static inline Matrix FromRotationMatrix(const Matrix& m) { return Matrix(m[0], m[1], m[2], 0, m[3], m[4], m[5], 0, m[6], m[7], m[8], 0, 0, 0, 0, 1); } /// @brief Constructs a Matrix from an AffineTransform. /// /// @param affine An AffineTransform reference to be used to construct /// a Matrix by adding in the 'w' row of [0, 0, 0, 1]. static inline Matrix FromAffineTransform( const Matrix& affine) { return Matrix(affine[0], affine[4], affine[8], static_cast(0), affine[1], affine[5], affine[9], static_cast(0), affine[2], affine[6], affine[10], static_cast(0), affine[3], affine[7], affine[11], static_cast(1)); } /// @brief Converts a Matrix into an AffineTransform. /// /// @param m A Matrix reference to be converted into an /// AffineTransform by dropping the fixed 'w' row. /// /// @return Returns an AffineTransform that contains the essential /// transformation data from the Matrix. static inline Matrix ToAffineTransform(const Matrix& m) { return Matrix(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14]); } /// @brief Create a 3x3 rotation Matrix from a 2D normalized directional /// Vector around the X axis. /// /// @param v 2D normalized directional Vector. /// @return Matrix containing the result. static inline Matrix RotationX(const Vector& v) { return Matrix(1, 0, 0, 0, v.x, v.y, 0, -v.y, v.x); } /// @brief Create a 3x3 rotation Matrix from a 2D normalized directional /// Vector around the Y axis. /// /// @param v 2D normalized directional Vector. /// @return Matrix containing the result. static inline Matrix RotationY(const Vector& v) { return Matrix(v.x, 0, -v.y, 0, 1, 0, v.y, 0, v.x); } /// @brief Create a 3x3 rotation Matrix from a 2D normalized directional /// Vector around the Z axis. /// /// @param v 2D normalized directional Vector. /// @return Matrix containing the result. static inline Matrix RotationZ(const Vector& v) { return Matrix(v.x, v.y, 0, -v.y, v.x, 0, 0, 0, 1); } /// @brief Create a 3x3 rotation Matrix from an angle (in radians) around /// the X axis. /// /// @param angle Angle (in radians). /// @return Matrix containing the result. static inline Matrix RotationX(T angle) { return RotationX(Vector(cosf(angle), sinf(angle))); } /// @brief Create a 3x3 rotation Matrix from an angle (in radians) around /// the Y axis. /// /// @param angle Angle (in radians). /// @return Matrix containing the result. static inline Matrix RotationY(T angle) { return RotationY(Vector(cosf(angle), sinf(angle))); } /// @brief Create a 3x3 rotation Matrix from an angle (in radians) /// around the Z axis. /// /// @param angle Angle (in radians). /// @return Matrix containing the result. static inline Matrix RotationZ(T angle) { return RotationZ(Vector(cosf(angle), sinf(angle))); } /// @brief Create a 4x4 perspective Matrix. /// /// @param fovy Field of view. /// @param aspect Aspect ratio. /// @param znear Near plane location. /// @param zfar Far plane location. /// @param handedness 1.0f for RH, -1.0f for LH /// @return 4x4 perspective Matrix. static inline Matrix Perspective(T fovy, T aspect, T znear, T zfar, T handedness = 1) { return PerspectiveHelper(fovy, aspect, znear, zfar, handedness); } /// @brief Create a 4x4 orthographic Matrix. /// /// @param left Left extent. /// @param right Right extent. /// @param bottom Bottom extent. /// @param top Top extent. /// @param znear Near plane location. /// @param zfar Far plane location. /// @param handedness 1.0f for RH, -1.0f for LH /// @return 4x4 orthographic Matrix. static inline Matrix Ortho(T left, T right, T bottom, T top, T znear, T zfar, T handedness = 1) { return OrthoHelper(left, right, bottom, top, znear, zfar, handedness); } /// @brief Create a 3-dimensional camera Matrix. /// /// @param at The look-at target of the camera. /// @param eye The position of the camera. /// @param up The up vector in the world, for example (0, 1, 0) if the /// y-axis is up. /// @param handedness 1.0f for RH, -1.0f for LH. /// @return 3-dimensional camera Matrix. /// TODO: Change default handedness to +1 so that it matches Perspective(). static inline Matrix LookAt(const Vector& at, const Vector& eye, const Vector& up, T handedness = -1) { return LookAtHelper(at, eye, up, handedness); } /// @brief Get the 3D position in object space from a window coordinate. /// /// @param window_coord The window coordinate. The z value is for depth. /// A window coordinate on the near plane will have 0 as the z value. /// And a window coordinate on the far plane will have 1 as the z value. /// z value should be with in [0, 1] here. /// @param model_view The Model View matrix. /// @param projection The projection matrix. /// @param window_width Width of the window. /// @param window_height Height of the window. /// @return the mapped 3D position in object space. static inline Vector UnProject(const Vector& window_coord, const Matrix& model_view, const Matrix& projection, const float window_width, const float window_height) { Vector result; UnProjectHelper(window_coord, model_view, projection, window_width, window_height, result); return result; } /// @brief Multiply a Vector by a Matrix. /// /// @param v Vector to multiply. /// @param m Matrix to multiply. /// @return Matrix containing the result. friend inline Vector operator*( const Vector& v, const Matrix& m) { const int d = columns; MATHFU_VECTOR_OPERATOR((Vector::DotProduct(m.data_[i], v))); } // Dimensions of the matrix. /// Number of rows in the matrix. static const int kRows = rows; /// Number of columns in the matrix. static const int kColumns = columns; /// Total number of elements in the matrix. static const int kElements = rows * columns; MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE private: Vector data_[columns]; }; /// @} /// @addtogroup mathfu_matrix /// @{ /// @brief Multiply each element of a Matrix by a scalar. /// /// @param s Scalar to multiply by. /// @param m Matrix to multiply. /// @return Matrix containing the result. /// @tparam T Type of each element in the Matrix and the scalar type. /// @tparam rows Number of rows in the matrix. /// @tparam columns Number of columns in the matrix. /// /// @related mathfu::Matrix template inline Matrix operator*(const T& s, const Matrix& m) { return m * s; } /// @brief Multiply a Matrix by a Vector. /// /// @note Template specialized versions are implemented for 2x2, 3x3, and 4x4 /// matrices to increase performance. The 3x3 float is also specialized /// to supported padded the 3-dimensional Vector in SIMD build configurations. /// /// @param m Matrix to multiply. /// @param v Vector to multiply. /// @return Vector containing the result. /// /// @related mathfu::Matrix template inline Vector operator*(const Matrix& m, const Vector& v) { const Vector result(0); int offset = 0; for (int column = 0; column < columns; column++) { for (int row = 0; row < rows; row++) { result[row] += m[offset + row] * v[column]; } offset += rows; } return result; } /// @cond MATHFU_INTERNAL template inline Vector operator*(const Matrix& m, const Vector& v) { return Vector(m[0] * v[0] + m[2] * v[1], m[1] * v[0] + m[3] * v[1]); } /// @endcond /// @cond MATHFU_INTERNAL template inline Vector operator*(const Matrix& m, const Vector& v) { return Vector(MATHFU_MATRIX_3X3_DOT(&m[0], v, 0, 3), MATHFU_MATRIX_3X3_DOT(&m[0], v, 1, 3), MATHFU_MATRIX_3X3_DOT(&m[0], v, 2, 3)); } /// @endcond /// @cond MATHFU_INTERNAL template <> inline Vector operator*(const Matrix& m, const Vector& v) { return Vector( MATHFU_MATRIX_3X3_DOT(&m[0], v, 0, MATHFU_VECTOR_STRIDE_FLOATS(v)), MATHFU_MATRIX_3X3_DOT(&m[0], v, 1, MATHFU_VECTOR_STRIDE_FLOATS(v)), MATHFU_MATRIX_3X3_DOT(&m[0], v, 2, MATHFU_VECTOR_STRIDE_FLOATS(v))); } /// @endcond /// @cond MATHFU_INTERNAL template inline Vector operator*(const Matrix& m, const Vector& v) { return Vector( MATHFU_MATRIX_4X4_DOT(&m[0], v, 0), MATHFU_MATRIX_4X4_DOT(&m[0], v, 1), MATHFU_MATRIX_4X4_DOT(&m[0], v, 2), MATHFU_MATRIX_4X4_DOT(&m[0], v, 3)); } /// @endcond /// @brief Multiply a 4x4 Matrix by a 3-dimensional Vector. /// /// This is provided as a convenience and assumes the vector has a fourth /// component equal to 1. /// /// @param m 4x4 Matrix. /// @param v 3-dimensional Vector. /// @return 3-dimensional Vector result. /// /// @related mathfu::Matrix template inline Vector operator*(const Matrix& m, const Vector& v) { Vector v4(v[0], v[1], v[2], 1); v4 = m * v4; return Vector(v4[0] / v4[3], v4[1] / v4[3], v4[2] / v4[3]); } /// @cond MATHFU_INTERNAL /// @brief Multiply a Matrix with another Matrix. /// /// @note Template specialized versions are implemented for 2x2, 3x3, and 4x4 /// matrices to improve performance. 3x3 float is also specialized because if /// SIMD is used the vectors of this type of length 4. /// /// @param m1 Matrix to multiply. /// @param m2 Matrix to multiply. /// @param out_m Pointer to a Matrix which receives the result. /// /// @tparam T Type of each element in the returned Matrix. /// @tparam size1 Number of rows in the returned Matrix and columns in m1. /// @tparam size2 Number of columns in the returned Matrix and rows in m2. /// @tparam size3 Number of columns in m3. template inline void TimesHelper(const Matrix& m1, const Matrix& m2, Matrix* out_m) { for (int i = 0; i < size1; i++) { for (int j = 0; j < size3; j++) { Vector row; for (int k = 0; k < size2; k++) { row[k] = m1(i, k); } (*out_m)(i, j) = Vector::DotProduct(m2.GetColumn(j), row); } } } /// @endcond /// @cond MATHFU_INTERNAL template inline void TimesHelper(const Matrix& m1, const Matrix& m2, Matrix* out_m) { Matrix& out = *out_m; out[0] = m1[0] * m2[0] + m1[2] * m2[1]; out[1] = m1[1] * m2[0] + m1[3] * m2[1]; out[2] = m1[0] * m2[2] + m1[2] * m2[3]; out[3] = m1[1] * m2[2] + m1[3] * m2[3]; } /// @endcond /// @cond MATHFU_INTERNAL template inline void TimesHelper(const Matrix& m1, const Matrix& m2, Matrix* out_m) { Matrix& out = *out_m; { Vector row(m1[0], m1[3], m1[6]); out[0] = Vector::DotProduct(m2.GetColumn(0), row); out[3] = Vector::DotProduct(m2.GetColumn(1), row); out[6] = Vector::DotProduct(m2.GetColumn(2), row); } { Vector row(m1[1], m1[4], m1[7]); out[1] = Vector::DotProduct(m2.GetColumn(0), row); out[4] = Vector::DotProduct(m2.GetColumn(1), row); out[7] = Vector::DotProduct(m2.GetColumn(2), row); } { Vector row(m1[2], m1[5], m1[8]); out[2] = Vector::DotProduct(m2.GetColumn(0), row); out[5] = Vector::DotProduct(m2.GetColumn(1), row); out[8] = Vector::DotProduct(m2.GetColumn(2), row); } } /// @endcond /// @cond MATHFU_INTERNAL template inline void TimesHelper(const Matrix& m1, const Matrix& m2, Matrix* out_m) { Matrix& out = *out_m; { Vector row(m1[0], m1[4], m1[8], m1[12]); out[0] = Vector::DotProduct(m2.GetColumn(0), row); out[4] = Vector::DotProduct(m2.GetColumn(1), row); out[8] = Vector::DotProduct(m2.GetColumn(2), row); out[12] = Vector::DotProduct(m2.GetColumn(3), row); } { Vector row(m1[1], m1[5], m1[9], m1[13]); out[1] = Vector::DotProduct(m2.GetColumn(0), row); out[5] = Vector::DotProduct(m2.GetColumn(1), row); out[9] = Vector::DotProduct(m2.GetColumn(2), row); out[13] = Vector::DotProduct(m2.GetColumn(3), row); } { Vector row(m1[2], m1[6], m1[10], m1[14]); out[2] = Vector::DotProduct(m2.GetColumn(0), row); out[6] = Vector::DotProduct(m2.GetColumn(1), row); out[10] = Vector::DotProduct(m2.GetColumn(2), row); out[14] = Vector::DotProduct(m2.GetColumn(3), row); } { Vector row(m1[3], m1[7], m1[11], m1[15]); out[3] = Vector::DotProduct(m2.GetColumn(0), row); out[7] = Vector::DotProduct(m2.GetColumn(1), row); out[11] = Vector::DotProduct(m2.GetColumn(2), row); out[15] = Vector::DotProduct(m2.GetColumn(3), row); } } /// @endcond /// @cond MATHFU_INTERNAL /// @brief Compute the identity matrix. /// /// @note There are template specializations for 2x2, 3x3, and 4x4 matrices to /// increase performance. /// /// @return Identity Matrix. /// @tparam T Type of each element in the returned Matrix. /// @tparam rows Number of rows in the returned Matrix. /// @tparam columns Number of columns in the returned Matrix. template inline Matrix IdentityHelper() { Matrix return_matrix(0.f); int min_d = rows < columns ? rows : columns; for (int i = 0; i < min_d; ++i) return_matrix(i, i) = 1; return return_matrix; } /// @endcond /// @cond MATHFU_INTERNAL template inline Matrix IdentityHelper() { return Matrix(1, 0, 0, 1); } /// @endcond /// @cond MATHFU_INTERNAL template inline Matrix IdentityHelper() { return Matrix(1, 0, 0, 0, 1, 0, 0, 0, 1); } /// @endcond /// @cond MATHFU_INTERNAL template inline Matrix IdentityHelper() { return Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } /// @endcond /// @cond MATHFU_INTERNAL /// @brief Compute the outer product of two vectors. /// /// @note There are template specialization for 2x2, 3x3, and 4x4 matrices to /// increase performance. template static inline Matrix OuterProductHelper( const Vector& v1, const Vector& v2) { Matrix result(0); int offset = 0; for (int column = 0; column < columns; column++) { for (int row = 0; row < rows; row++) { result[row + offset] = v1[row] * v2[column]; } offset += rows; } return result; } /// @endcond /// @cond MATHFU_INTERNAL template static inline Matrix OuterProductHelper(const Vector& v1, const Vector& v2) { return Matrix(v1[0] * v2[0], v1[1] * v2[0], v1[0] * v2[1], v1[1] * v2[1]); } /// @endcond /// @cond MATHFU_INTERNAL template static inline Matrix OuterProductHelper(const Vector& v1, const Vector& v2) { return Matrix(v1[0] * v2[0], v1[1] * v2[0], v1[2] * v2[0], v1[0] * v2[1], v1[1] * v2[1], v1[2] * v2[1], v1[0] * v2[2], v1[1] * v2[2], v1[2] * v2[2]); } /// @endcond /// @cond MATHFU_INTERNAL template static inline Matrix OuterProductHelper(const Vector& v1, const Vector& v2) { return Matrix( v1[0] * v2[0], v1[1] * v2[0], v1[2] * v2[0], v1[3] * v2[0], v1[0] * v2[1], v1[1] * v2[1], v1[2] * v2[1], v1[3] * v2[1], v1[0] * v2[2], v1[1] * v2[2], v1[2] * v2[2], v1[3] * v2[2], v1[0] * v2[3], v1[1] * v2[3], v1[2] * v2[3], v1[3] * v2[3]); } /// @endcond /// @cond MATHFU_INTERNAL /// Struct used for template specialization for functions that /// returns constants. template class Constants { public: /// Minimum absolute value of the determinant of an invertible matrix. static T GetDeterminantThreshold() { // No constant defined for the general case. assert(false); return 0; } }; /// @endcond /// Functions that return constants for float values. template <> class Constants { public: /// @brief Minimum absolute value of the determinant of an invertible /// float Matrix. /// /// float values have 23 bits of precision which is roughly /// 1e7f, given that the final step of matrix inversion is multiplication /// with the inverse of the determinant, the minimum value of the /// determinant is 1e-7f before the precision too low to accurately /// calculate the inverse. /// @returns Minimum absolute value of the determinant of an invertible /// float Matrix. /// /// @related mathfu::Matrix::InverseWithDeterminantCheck() static float GetDeterminantThreshold() { return 1e-7f; } }; /// Functions that return constants for double values. template <> class Constants { public: /// @brief Minimum absolute value of the determinant of an invertible /// double Matrix. /// /// double values have 46 bits of precision which is roughly /// 1e15, given that the final step of matrix inversion is multiplication /// with the inverse of the determinant, the minimum value of the /// determinant is 1e-15 before the precision too low to accurately /// calculate the inverse. /// @returns Minimum absolute value of the determinant of an invertible /// double Matrix. /// /// @related mathfu::Matrix::InverseWithDeterminantCheck() static double GetDeterminantThreshold() { return 1e-15; } }; /// @cond MATHFU_INTERNAL /// @brief Compute the inverse of a matrix. /// /// There is template specialization for 2x2, 3x3, and 4x4 matrices to /// increase performance. Inverse is not implemented for dense matrices that /// are not of size 2x2, 3x3, and 4x4. If check_invertible is true the /// determine of the matrix is compared with /// Constants::GetDeterminantThreshold() to roughly determine whether the /// Matrix is invertible. template inline bool InverseHelper(const Matrix& m, Matrix* const inverse) { assert(false); (void)m; *inverse = T::Identity(); return false; } /// @endcond /// @cond MATHFU_INTERNAL template inline bool InverseHelper(const Matrix& m, Matrix* const inverse) { T determinant = m[0] * m[3] - m[1] * m[2]; if (check_invertible && fabs(determinant) < Constants::GetDeterminantThreshold()) { return false; } T inverseDeterminant = 1 / determinant; (*inverse)[0] = inverseDeterminant * m[3]; (*inverse)[1] = -inverseDeterminant * m[1]; (*inverse)[2] = -inverseDeterminant * m[2]; (*inverse)[3] = inverseDeterminant * m[0]; return true; } /// @endcond /// @cond MATHFU_INTERNAL template inline bool InverseHelper(const Matrix& m, Matrix* const inverse) { // Find determinant of matrix. T sub11 = m[4] * m[8] - m[5] * m[7], sub12 = -m[1] * m[8] + m[2] * m[7], sub13 = m[1] * m[5] - m[2] * m[4]; T determinant = m[0] * sub11 + m[3] * sub12 + m[6] * sub13; if (check_invertible && fabs(determinant) < Constants::GetDeterminantThreshold()) { return false; } // Find determinants of 2x2 submatrices for the elements of the inverse. *inverse = Matrix( sub11, sub12, sub13, m[6] * m[5] - m[3] * m[8], m[0] * m[8] - m[6] * m[2], m[3] * m[2] - m[0] * m[5], m[3] * m[7] - m[6] * m[4], m[6] * m[1] - m[0] * m[7], m[0] * m[4] - m[3] * m[1]); *(inverse) *= 1 / determinant; return true; } /// @endcond /// @cond MATHFU_INTERNAL template inline int FindLargestPivotElem(const Matrix& m) { Vector fabs_column(fabs(m[0]), fabs(m[1]), fabs(m[2]), fabs(m[3])); if (fabs_column[0] > fabs_column[1]) { if (fabs_column[0] > fabs_column[2]) { if (fabs_column[0] > fabs_column[3]) { return 0; } else { return 3; } } else if (fabs_column[2] > fabs_column[3]) { return 2; } else { return 3; } } else if (fabs_column[1] > fabs_column[2]) { if (fabs_column[1] > fabs_column[3]) { return 1; } else { return 3; } } else if (fabs_column[2] > fabs_column[3]) { return 2; } else { return 3; } } /// @endcond /// @cond MATHFU_INTERNAL template bool InverseHelper(const Matrix& m, Matrix* const inverse) { // This will find the pivot element. int pivot_elem = FindLargestPivotElem(m); // This will perform the pivot and find the row, column, and 3x3 submatrix // for this pivot. Vector row, column; Matrix matrix; if (pivot_elem == 0) { row = Vector(m[4], m[8], m[12]); column = Vector(m[1], m[2], m[3]); matrix = Matrix(m[5], m[6], m[7], m[9], m[10], m[11], m[13], m[14], m[15]); } else if (pivot_elem == 1) { row = Vector(m[5], m[9], m[13]); column = Vector(m[0], m[2], m[3]); matrix = Matrix(m[4], m[6], m[7], m[8], m[10], m[11], m[12], m[14], m[15]); } else if (pivot_elem == 2) { row = Vector(m[6], m[10], m[14]); column = Vector(m[0], m[1], m[3]); matrix = Matrix(m[4], m[5], m[7], m[8], m[9], m[11], m[12], m[13], m[15]); } else { row = Vector(m[7], m[11], m[15]); column = Vector(m[0], m[1], m[2]); matrix = Matrix(m[4], m[5], m[6], m[8], m[9], m[10], m[12], m[13], m[14]); } T pivot_value = m[pivot_elem]; if (check_invertible && fabs(pivot_value) < Constants::GetDeterminantThreshold()) { return false; } // This will compute the inverse using the row, column, and 3x3 submatrix. T inv = -1 / pivot_value; row *= inv; matrix += Matrix::OuterProduct(column, row); Matrix mat_inverse; if (!InverseHelper(matrix, &mat_inverse) && check_invertible) { return false; } Vector col_inverse = mat_inverse * (column * inv); Vector row_inverse = row * mat_inverse; T pivot_inverse = Vector::DotProduct(row, col_inverse) - inv; if (pivot_elem == 0) { *inverse = Matrix( pivot_inverse, col_inverse[0], col_inverse[1], col_inverse[2], row_inverse[0], mat_inverse[0], mat_inverse[1], mat_inverse[2], row_inverse[1], mat_inverse[3], mat_inverse[4], mat_inverse[5], row_inverse[2], mat_inverse[6], mat_inverse[7], mat_inverse[8]); } else if (pivot_elem == 1) { *inverse = Matrix( row_inverse[0], mat_inverse[0], mat_inverse[1], mat_inverse[2], pivot_inverse, col_inverse[0], col_inverse[1], col_inverse[2], row_inverse[1], mat_inverse[3], mat_inverse[4], mat_inverse[5], row_inverse[2], mat_inverse[6], mat_inverse[7], mat_inverse[8]); } else if (pivot_elem == 2) { *inverse = Matrix( row_inverse[0], mat_inverse[0], mat_inverse[1], mat_inverse[2], row_inverse[1], mat_inverse[3], mat_inverse[4], mat_inverse[5], pivot_inverse, col_inverse[0], col_inverse[1], col_inverse[2], row_inverse[2], mat_inverse[6], mat_inverse[7], mat_inverse[8]); } else { *inverse = Matrix( row_inverse[0], mat_inverse[0], mat_inverse[1], mat_inverse[2], row_inverse[1], mat_inverse[3], mat_inverse[4], mat_inverse[5], row_inverse[2], mat_inverse[6], mat_inverse[7], mat_inverse[8], pivot_inverse, col_inverse[0], col_inverse[1], col_inverse[2]); } return true; } /// @endcond /// @cond MATHFU_INTERNAL /// Create a 4x4 perpective matrix. template inline Matrix PerspectiveHelper(T fovy, T aspect, T znear, T zfar, T handedness) { const T y = 1 / std::tan(fovy * static_cast(.5)); const T x = y / aspect; const T zdist = (znear - zfar); const T zfar_per_zdist = zfar / zdist; return Matrix(x, 0, 0, 0, 0, y, 0, 0, 0, 0, zfar_per_zdist * handedness, -1 * handedness, 0, 0, 2.0f * znear * zfar_per_zdist, 0); } /// @endcond /// @cond MATHFU_INTERNAL /// Create a 4x4 orthographic matrix. template static inline Matrix OrthoHelper(T left, T right, T bottom, T top, T znear, T zfar, T handedness) { return Matrix(static_cast(2) / (right - left), 0, 0, 0, 0, static_cast(2) / (top - bottom), 0, 0, 0, 0, -handedness * static_cast(2) / (zfar - znear), 0, -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(zfar + znear) / (zfar - znear), static_cast(1)); } /// @endcond /// @cond MATHFU_INTERNAL /// Calculate the axes required to construct a 3-dimensional camera matrix that /// looks at "at" from eye position "eye" with the up vector "up". The axes /// are returned in a 4 element "axes" array. template static void LookAtHelperCalculateAxes(const Vector& at, const Vector& eye, const Vector& up, T handedness, Vector* const axes) { // Notice that y-axis is always the same regardless of handedness. axes[2] = (at - eye).Normalized(); axes[0] = Vector::CrossProduct(up, axes[2]).Normalized(); axes[1] = Vector::CrossProduct(axes[2], axes[0]); axes[3] = Vector(handedness * Vector::DotProduct(axes[0], eye), -Vector::DotProduct(axes[1], eye), handedness * Vector::DotProduct(axes[2], eye)); // Default calculation is left-handed (i.e. handedness=-1). // Negate x and z axes for right-handed (i.e. handedness=+1) case. const T neg = -handedness; axes[0] *= neg; axes[2] *= neg; } /// @endcond /// @cond MATHFU_INTERNAL /// Create a 3-dimensional camera matrix. template static inline Matrix LookAtHelper(const Vector& at, const Vector& eye, const Vector& up, T handedness) { Vector axes[4]; LookAtHelperCalculateAxes(at, eye, up, handedness, axes); const Vector column0(axes[0][0], axes[1][0], axes[2][0], 0); const Vector column1(axes[0][1], axes[1][1], axes[2][1], 0); const Vector column2(axes[0][2], axes[1][2], axes[2][2], 0); const Vector column3(axes[3], 1); return Matrix(column0, column1, column2, column3); } /// @endcond /// @cond MATHFU_INTERNAL /// Get the 3D position in object space from a window coordinate. template static inline bool UnProjectHelper(const Vector& window_coord, const Matrix& model_view, const Matrix& projection, const float window_width, const float window_height, Vector& result) { if (window_coord.z < static_cast(0) || window_coord.z > static_cast(1)) { // window_coord.z should be with in [0, 1] // 0: near plane // 1: far plane return false; } Matrix matrix = (projection * model_view).Inverse(); Vector standardized = Vector( static_cast(2) * (window_coord.x - window_width) / window_width + static_cast(1), static_cast(2) * (window_coord.y - window_height) / window_height + static_cast(1), static_cast(2) * window_coord.z - static_cast(1), static_cast(1)); Vector multiply = matrix * standardized; if (multiply.w == static_cast(0)) { return false; } result = multiply.xyz() / multiply.w; return true; } /// @endcond /// @cond MATHFU_INTERNAL template static inline Matrix FromTypeHelper(const CompatibleT& compatible) { // C++11 is required for constructed unions. #if __cplusplus >= 201103L // Use a union instead of reinterpret_cast to avoid aliasing bugs. union ConversionUnion { ConversionUnion() {} // C++11. CompatibleT compatible; VectorPacked packed[columns]; } u; static_assert(sizeof(u.compatible) == sizeof(u.packed), "Conversion size mismatch."); // The read of `compatible` and write to `u.compatible` gets optimized away, // and this becomes essentially a safe reinterpret_cast. u.compatible = compatible; // Call the packed vector constructor with the `compatible` data. return Matrix(u.packed); #else // Use the less-desirable memcpy technique if C++11 is not available. // Most compilers understand memcpy deep enough to avoid replace the function // call with a series of load/stores, which should then get optimized away, // however in the worst case the optimize away may not happen. // Note: Memcpy avoids aliasing bugs because it operates via unsigned char*, // which is allowed to alias any type. // See: // http://stackoverflow.com/questions/15745030/type-punning-with-void-without-breaking-the-strict-aliasing-rule-in-c99 Matrix m; assert(sizeof(m) == sizeof(compatible)); memcpy(&m, &compatible, sizeof(m)); return m; #endif // __cplusplus >= 201103L } /// @endcond /// @cond MATHFU_INTERNAL template static inline CompatibleT ToTypeHelper(const Matrix& m) { // See FromTypeHelper() for comments. #if __cplusplus >= 201103L union ConversionUnion { ConversionUnion() {} CompatibleT compatible; VectorPacked packed[columns]; } u; static_assert(sizeof(u.compatible) == sizeof(u.packed), "Conversion size mismatch."); m.Pack(u.packed); return u.compatible; #else CompatibleT compatible; assert(sizeof(m) == sizeof(compatible)); memcpy(&compatible, &m, sizeof(compatible)); return compatible; #endif // __cplusplus >= 201103L } /// @endcond /// @typedef AffineTransform /// /// @brief A typedef representing a 4x3 float affine transformation. /// Since the last row ('w' row) of an affine transformation is fixed, /// this data type only includes the variable information for the transform. typedef Matrix AffineTransform; /// @} } // namespace mathfu #ifdef _MSC_VER #pragma warning(pop) #endif // Include the specializations to avoid template errors. // See includes at bottom of vector.h for further explanation. #include "mathfu/matrix_4x4.h" #endif // MATHFU_MATRIX_H_