LCOV - code coverage report
Current view: top level - source/maths - Matrix3D.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 52 86 60.5 %
Date: 2023-01-19 00:18:29 Functions: 10 19 52.6 %

          Line data    Source code
       1             : /* Copyright (C) 2022 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : /*
      19             :  * A Matrix class used for holding and manipulating transformation
      20             :  * info.
      21             :  */
      22             : 
      23             : #ifndef INCLUDED_MATRIX3D
      24             : #define INCLUDED_MATRIX3D
      25             : 
      26             : #include "maths/Vector3D.h"
      27             : #include "maths/Vector4D.h"
      28             : #include "ps/containers/Span.h"
      29             : 
      30             : class CQuaternion;
      31             : 
      32             : // CMatrix3D: a 4x4 matrix class for common operations in 3D
      33             : class CMatrix3D
      34             : {
      35             : public:
      36             :     // the matrix data itself - accessible as either longhand names
      37             :     // or via a flat or 2d array
      38             :     // NOTE: _xy means row x, column y in the mathematical notation of this matrix, so don't be
      39             :     // fooled by the way they're listed below
      40             :     union
      41             :     {
      42             :         struct
      43             :         {
      44             :             float _11, _21, _31, _41;
      45             :             float _12, _22, _32, _42;
      46             :             float _13, _23, _33, _43;
      47             :             float _14, _24, _34, _44;
      48             :         };
      49             :         float _data[16];
      50             :         float _data2d[4][4];
      51             :         // (Be aware that m(0,2) == _data2d[2][0] == _13, etc. This is to be considered a feature.)
      52             :     };
      53             : 
      54             : public:
      55             :     // constructors
      56         768 :     CMatrix3D ()
      57         768 :     {
      58         768 :     }
      59             : 
      60          29 :     CMatrix3D(
      61             :         float a11, float a12, float a13, float a14,
      62             :         float a21, float a22, float a23, float a24,
      63             :         float a31, float a32, float a33, float a34,
      64          29 :         float a41, float a42, float a43, float a44) :
      65             :         _11(a11), _12(a12), _13(a13), _14(a14),
      66             :         _21(a21), _22(a22), _23(a23), _24(a24),
      67             :         _31(a31), _32(a32), _33(a33), _34(a34),
      68          29 :         _41(a41), _42(a42), _43(a43), _44(a44)
      69             :     {
      70          29 :     }
      71             : 
      72             :     CMatrix3D(float data[]) :
      73             :         _11(data[0]), _21(data[1]), _31(data[2]), _41(data[3]),
      74             :         _12(data[4]), _22(data[5]), _32(data[6]), _42(data[7]),
      75             :         _13(data[8]), _23(data[9]), _33(data[10]), _43(data[11]),
      76             :         _14(data[12]), _24(data[13]), _34(data[14]), _44(data[15])
      77             :     {
      78             :     }
      79             : 
      80             :     // accessors to individual elements of matrix
      81             :     // NOTE: in this function definition, 'col' and 'row' represent the column and row into the
      82             :     // internal element matrix which is the transposed of the mathematical notation, so the first
      83             :     // and second arguments here are actually the row and column into the mathematical notation.
      84         192 :     float& operator()(int col, int row)
      85             :     {
      86         192 :         return _data[row*4+col];
      87             :     }
      88           0 :     const float& operator()(int col, int row) const
      89             :     {
      90           0 :         return _data[row*4+col];
      91             :     }
      92             : 
      93           0 :     float& operator[](int idx)
      94             :     {
      95           0 :         return _data[idx];
      96             :     }
      97           0 :     const float& operator[](int idx) const
      98             :     {
      99           0 :         return _data[idx];
     100             :     }
     101             : 
     102             :     // matrix multiplication
     103          28 :     CMatrix3D operator*(const CMatrix3D &matrix) const
     104             :     {
     105             :         return CMatrix3D(
     106          28 :             _11*matrix._11 + _12*matrix._21 + _13*matrix._31 + _14*matrix._41,
     107          28 :             _11*matrix._12 + _12*matrix._22 + _13*matrix._32 + _14*matrix._42,
     108          28 :             _11*matrix._13 + _12*matrix._23 + _13*matrix._33 + _14*matrix._43,
     109          28 :             _11*matrix._14 + _12*matrix._24 + _13*matrix._34 + _14*matrix._44,
     110             : 
     111          28 :             _21*matrix._11 + _22*matrix._21 + _23*matrix._31 + _24*matrix._41,
     112          28 :             _21*matrix._12 + _22*matrix._22 + _23*matrix._32 + _24*matrix._42,
     113          28 :             _21*matrix._13 + _22*matrix._23 + _23*matrix._33 + _24*matrix._43,
     114          28 :             _21*matrix._14 + _22*matrix._24 + _23*matrix._34 + _24*matrix._44,
     115             : 
     116          28 :             _31*matrix._11 + _32*matrix._21 + _33*matrix._31 + _34*matrix._41,
     117          28 :             _31*matrix._12 + _32*matrix._22 + _33*matrix._32 + _34*matrix._42,
     118          28 :             _31*matrix._13 + _32*matrix._23 + _33*matrix._33 + _34*matrix._43,
     119          28 :             _31*matrix._14 + _32*matrix._24 + _33*matrix._34 + _34*matrix._44,
     120             : 
     121          28 :             _41*matrix._11 + _42*matrix._21 + _43*matrix._31 + _44*matrix._41,
     122          28 :             _41*matrix._12 + _42*matrix._22 + _43*matrix._32 + _44*matrix._42,
     123          28 :             _41*matrix._13 + _42*matrix._23 + _43*matrix._33 + _44*matrix._43,
     124          28 :             _41*matrix._14 + _42*matrix._24 + _43*matrix._34 + _44*matrix._44
     125         448 :         );
     126             :     }
     127             : 
     128             :     // matrix multiplication/assignment
     129           4 :     CMatrix3D& operator*=(const CMatrix3D &matrix)
     130             :     {
     131           4 :         Concatenate(matrix);
     132           4 :         return *this;
     133             :     }
     134             : 
     135             :     // matrix scaling
     136             :     CMatrix3D operator*(float f) const
     137             :     {
     138             :         return CMatrix3D(
     139             :             _11*f, _12*f, _13*f, _14*f,
     140             :             _21*f, _22*f, _23*f, _24*f,
     141             :             _31*f, _32*f, _33*f, _34*f,
     142             :             _41*f, _42*f, _43*f, _44*f
     143             :         );
     144             :     }
     145             : 
     146             :     // matrix addition
     147             :     CMatrix3D operator+(const CMatrix3D &m) const
     148             :     {
     149             :         return CMatrix3D(
     150             :             _11+m._11, _12+m._12, _13+m._13, _14+m._14,
     151             :             _21+m._21, _22+m._22, _23+m._23, _24+m._24,
     152             :             _31+m._31, _32+m._32, _33+m._33, _34+m._34,
     153             :             _41+m._41, _42+m._42, _43+m._43, _44+m._44
     154             :         );
     155             :     }
     156             : 
     157             :     // matrix addition/assignment
     158             :     CMatrix3D& operator+=(const CMatrix3D &m)
     159             :     {
     160             :         _11 += m._11; _21 += m._21; _31 += m._31; _41 += m._41;
     161             :         _12 += m._12; _22 += m._22; _32 += m._32; _42 += m._42;
     162             :         _13 += m._13; _23 += m._23; _33 += m._33; _43 += m._43;
     163             :         _14 += m._14; _24 += m._24; _34 += m._34; _44 += m._44;
     164             :         return *this;
     165             :     }
     166             : 
     167             :     // equality
     168           0 :     bool operator==(const CMatrix3D &m) const
     169             :     {
     170           0 :         return _11 == m._11 && _21 == m._21 && _31 == m._31 && _41 == m._41 &&
     171           0 :                  _12 == m._12 && _22 == m._22 && _32 == m._32 && _42 == m._42 &&
     172           0 :                  _13 == m._13 && _23 == m._23 && _33 == m._33 && _43 == m._43 &&
     173           0 :                  _14 == m._14 && _24 == m._24 && _34 == m._34 && _44 == m._44;
     174             :     }
     175             : 
     176             :     // inequality
     177             :     bool operator!=(const CMatrix3D& m) const
     178             :     {
     179             :         return !(*this == m);
     180             :     }
     181             : 
     182             :     // set this matrix to the identity matrix
     183             :     void SetIdentity();
     184             :     // set this matrix to the zero matrix
     185             :     void SetZero();
     186             :     // set this matrix to the orthogonal projection matrix
     187             :     void SetOrtho(float left, float right, float bottom, float top, float near, float far);
     188             :     // set this matrix to the perspective projection matrix
     189             :     void SetPerspective(float fov, float aspect, float near, float far);
     190             :     void SetPerspectiveTile(float fov, float aspect, float near, float far, int tiles, int tile_x, int tile_y);
     191             : 
     192             :     // concatenate arbitrary matrix onto this matrix
     193          14 :     void Concatenate(const CMatrix3D& m)
     194             :     {
     195          14 :         (*this) = m * (*this);
     196          14 :     }
     197             : 
     198             :     // blend matrix using only 4x3 subset
     199           0 :     void Blend(const CMatrix3D& m, float f)
     200             :     {
     201           0 :         _11 = m._11*f; _21 = m._21*f; _31 = m._31*f;
     202           0 :         _12 = m._12*f; _22 = m._22*f; _32 = m._32*f;
     203           0 :         _13 = m._13*f; _23 = m._23*f; _33 = m._33*f;
     204           0 :         _14 = m._14*f; _24 = m._24*f; _34 = m._34*f;
     205           0 :     }
     206             : 
     207             :     // blend matrix using only 4x3 and add onto existing blend
     208           0 :     void AddBlend(const CMatrix3D& m, float f)
     209             :     {
     210           0 :         _11 += m._11*f; _21 += m._21*f; _31 += m._31*f;
     211           0 :         _12 += m._12*f; _22 += m._22*f; _32 += m._32*f;
     212           0 :         _13 += m._13*f; _23 += m._23*f; _33 += m._33*f;
     213           0 :         _14 += m._14*f; _24 += m._24*f; _34 += m._34*f;
     214           0 :     }
     215             : 
     216             :     // set this matrix to a rotation matrix for a rotation about X axis of given angle
     217             :     void SetXRotation(float angle);
     218             :     // set this matrix to a rotation matrix for a rotation about Y axis of given angle
     219             :     void SetYRotation(float angle);
     220             :     // set this matrix to a rotation matrix for a rotation about Z axis of given angle
     221             :     void SetZRotation(float angle);
     222             :     // set this matrix to a rotation described by given quaternion
     223             :     void SetRotation(const CQuaternion& quat);
     224             : 
     225             :     // concatenate a rotation about the X axis onto this matrix
     226             :     void RotateX(float angle);
     227             :     // concatenate a rotation about the Y axis onto this matrix
     228             :     void RotateY(float angle);
     229             :     // concatenate a rotation about the Z axis onto this matrix
     230             :     void RotateZ(float angle);
     231             :     // concatenate a rotation described by given quaternion
     232             :     void Rotate(const CQuaternion& quat);
     233             : 
     234             :     // sets this matrix to the given translation matrix (any existing transformation will be overwritten)
     235             :     void SetTranslation(float x, float y, float z);
     236             :     void SetTranslation(const CVector3D& vector);
     237             : 
     238             :     // concatenate given translation onto this matrix. Assumes the current
     239             :     // matrix is an affine transformation (i.e. the bottom row is [0,0,0,1])
     240             :     // as an optimisation.
     241             :     void Translate(float x, float y, float z);
     242             :     void Translate(const CVector3D& vector);
     243             : 
     244             :     // apply translation after this matrix (M = M * T)
     245             :     void PostTranslate(float x, float y, float z);
     246             : 
     247             :     // set this matrix to the given scaling matrix
     248             :     void SetScaling(float x_scale, float y_scale, float z_scale);
     249             : 
     250             :     // concatenate given scaling matrix onto this matrix
     251             :     void Scale(float x_scale, float y_scale, float z_scale);
     252             : 
     253             :     // calculate the inverse of this matrix, store in dst
     254             :     void GetInverse(CMatrix3D& dst) const;
     255             : 
     256             :     // return the inverse of this matrix
     257             :     CMatrix3D GetInverse() const;
     258             : 
     259             :     // calculate the transpose of this matrix, store in dst
     260             :     CMatrix3D GetTranspose() const;
     261             : 
     262             :     // return the translation component of this matrix
     263             :     CVector3D GetTranslation() const;
     264             :     // return left vector, derived from rotation
     265             :     CVector3D GetLeft() const;
     266             :     // return up vector, derived from rotation
     267             :     CVector3D GetUp() const;
     268             :     // return forward vector, derived from rotation
     269             :     CVector3D GetIn() const;
     270             :     // return a quaternion representing the matrix's rotation
     271             :     CQuaternion GetRotation() const;
     272             :     // return the angle of rotation around the Y axis in range [-pi,pi]
     273             :     // (based on projecting the X axis onto the XZ plane)
     274             :     float GetYRotation() const;
     275             : 
     276             :     // transform a 3D vector by this matrix
     277          45 :     CVector3D Transform(const CVector3D &vector) const
     278             :     {
     279          45 :         CVector3D result;
     280          45 :         Transform(vector, result);
     281          45 :         return result;
     282             :     }
     283             : 
     284          45 :     void Transform(const CVector3D& vector, CVector3D& result) const
     285             :     {
     286          45 :         result.X = _11*vector.X + _12*vector.Y + _13*vector.Z + _14;
     287          45 :         result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z + _24;
     288          45 :         result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34;
     289          45 :     }
     290             : 
     291             :     // transform a 4D vector by this matrix
     292         100 :     CVector4D Transform(const CVector4D &vector) const
     293             :     {
     294         100 :         CVector4D result;
     295         100 :         Transform(vector, result);
     296         100 :         return result;
     297             :     }
     298             : 
     299         100 :     void Transform(const CVector4D& vector, CVector4D& result) const
     300             :     {
     301         100 :         result.X = _11*vector.X + _12*vector.Y + _13*vector.Z + _14*vector.W;
     302         100 :         result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z + _24*vector.W;
     303         100 :         result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34*vector.W;
     304         100 :         result.W = _41*vector.X + _42*vector.Y + _43*vector.Z + _44*vector.W;
     305         100 :     }
     306             : 
     307             :     // rotate a vector by this matrix
     308           0 :     CVector3D Rotate(const CVector3D& vector) const
     309             :     {
     310           0 :         CVector3D result;
     311           0 :         Rotate(vector, result);
     312           0 :         return result;
     313             :     }
     314             : 
     315           0 :     void Rotate(const CVector3D& vector, CVector3D& result) const
     316             :     {
     317           0 :         result.X = _11*vector.X + _12*vector.Y + _13*vector.Z;
     318           0 :         result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z;
     319           0 :         result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z;
     320           0 :     }
     321             : 
     322             :     // rotate a vector by the transpose of this matrix
     323             :     void RotateTransposed(const CVector3D& vector,CVector3D& result) const;
     324             :     CVector3D RotateTransposed(const CVector3D& vector) const;
     325             : 
     326             :     // Returns 16 element array of floats, e.g. for mat4 uniforms.
     327           0 :     PS::span<const float> AsFloatArray() const
     328             :     {
     329             :         // Additional check to prevent a weird compiler has a different
     330             :         // alignement for an array and a class members.
     331             :         static_assert(
     332             :             sizeof(CMatrix3D) == sizeof(float) * 16u &&
     333             :             offsetof(CMatrix3D, _data) == 0 &&
     334             :             offsetof(CMatrix3D, _11) == 0 &&
     335             :             offsetof(CMatrix3D, _44) == sizeof(float) * 15u,
     336             :             "CMatrix3D should be properly layouted to use AsFloatArray");
     337           0 :         return PS::span<const float>(_data, 16);
     338             :     }
     339             : };
     340             : 
     341             : #endif // INCLUDED_MATRIX3D

Generated by: LCOV version 1.13