LCOV - code coverage report
Current view: top level - source/maths - Matrix3D.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 233 271 86.0 %
Date: 2023-01-19 00:18:29 Functions: 25 33 75.8 %

          Line data    Source code
       1             : /* Copyright (C) 2019 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             : #include "precompiled.h"
      24             : 
      25             : #include "Matrix3D.h"
      26             : #include "Quaternion.h"
      27             : #include "Vector4D.h"
      28             : 
      29             : //Sets the identity matrix
      30         281 : void CMatrix3D::SetIdentity ()
      31             : {
      32         281 :     _11=1.0f; _12=0.0f; _13=0.0f; _14=0.0f;
      33         281 :     _21=0.0f; _22=1.0f; _23=0.0f; _24=0.0f;
      34         281 :     _31=0.0f; _32=0.0f; _33=1.0f; _34=0.0f;
      35         281 :     _41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
      36         281 : }
      37             : 
      38             : //Sets the zero matrix
      39          15 : void CMatrix3D::SetZero()
      40             : {
      41          15 :     _11=0.0f; _12=0.0f; _13=0.0f; _14=0.0f;
      42          15 :     _21=0.0f; _22=0.0f; _23=0.0f; _24=0.0f;
      43          15 :     _31=0.0f; _32=0.0f; _33=0.0f; _34=0.0f;
      44          15 :     _41=0.0f; _42=0.0f; _43=0.0f; _44=0.0f;
      45          15 : }
      46             : 
      47           6 : void CMatrix3D::SetOrtho(float left, float right, float bottom, float top, float near, float far)
      48             : {
      49             :     // Based on OpenGL spec
      50           6 :     SetZero();
      51           6 :     _11 = 2 / (right - left);
      52           6 :     _22 = 2 / (top - bottom);
      53           6 :     _33 = -2 / (far - near);
      54           6 :     _44 = 1;
      55             : 
      56           6 :     _14 = -(right + left) / (right - left);
      57           6 :     _24 = -(top + bottom) / (top - bottom);
      58           6 :     _34 = -(far + near) / (far - near);
      59           6 : }
      60             : 
      61           8 : void CMatrix3D::SetPerspective(float fov, float aspect, float near, float far)
      62             : {
      63           8 :     const float f = 1.f / tanf(fov / 2.f);
      64             : 
      65           8 :     SetZero();
      66           8 :     _11 = f / aspect;
      67           8 :     _22 = f;
      68           8 :     _33 = -(far + near) / (near - far);
      69           8 :     _34 = 2 * far * near / (near - far);
      70           8 :     _43 = 1;
      71           8 : }
      72             : 
      73           0 : void CMatrix3D::SetPerspectiveTile(float fov, float aspect, float near, float far, int tiles, int tile_x, int tile_y)
      74             : {
      75           0 :     const float f = 1.f / tanf(fov / 2.f);
      76             : 
      77           0 :     SetPerspective(fov, aspect, near, far);
      78           0 :     _11 = tiles * f / aspect;
      79           0 :     _22 = tiles * f;
      80           0 :     _13 = -(1 - tiles + 2 * tile_x);
      81           0 :     _23 = -(1 - tiles + 2 * tile_y);
      82           0 : }
      83             : 
      84             : //The following clear the matrix and set the
      85             : //rotation of each of the 3 axes
      86             : 
      87          16 : void CMatrix3D::SetXRotation (float angle)
      88             : {
      89          16 :     const float Cos = cosf (angle);
      90          16 :     const float Sin = sinf (angle);
      91             : 
      92          16 :     _11=1.0f; _12=0.0f; _13=0.0f; _14=0.0f;
      93          16 :     _21=0.0f; _22=Cos;  _23=-Sin; _24=0.0f;
      94          16 :     _31=0.0f; _32=Sin;  _33=Cos;  _34=0.0f;
      95          16 :     _41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
      96          16 : }
      97             : 
      98          17 : void CMatrix3D::SetYRotation (float angle)
      99             : {
     100          17 :     const float Cos = cosf (angle);
     101          17 :     const float Sin = sinf (angle);
     102             : 
     103          17 :     _11=Cos;  _12=0.0f; _13=Sin;  _14=0.0f;
     104          17 :     _21=0.0f; _22=1.0f; _23=0.0f; _24=0.0f;
     105          17 :     _31=-Sin; _32=0.0f; _33=Cos;  _34=0.0f;
     106          17 :     _41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
     107          17 : }
     108             : 
     109           3 : void CMatrix3D::SetZRotation (float angle)
     110             : {
     111           3 :     const float Cos = cosf (angle);
     112           3 :     const float Sin = sinf (angle);
     113             : 
     114           3 :     _11=Cos;  _12=-Sin; _13=0.0f; _14=0.0f;
     115           3 :     _21=Sin;  _22=Cos;  _23=0.0f; _24=0.0f;
     116           3 :     _31=0.0f; _32=0.0f; _33=1.0f; _34=0.0f;
     117           3 :     _41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
     118           3 : }
     119             : 
     120             : //The following apply a rotation to the matrix
     121             : //about each of the axes;
     122             : 
     123           1 : void CMatrix3D::RotateX (float angle)
     124             : {
     125           1 :     const float Cos = cosf (angle);
     126           1 :     const float Sin = sinf (angle);
     127           1 :     const float tmp_21 = _21;
     128           1 :     const float tmp_22 = _22;
     129           1 :     const float tmp_23 = _23;
     130           1 :     const float tmp_24 = _24;
     131             : 
     132           1 :     _21 = Cos * _21 - Sin * _31;
     133           1 :     _22 = Cos * _22 - Sin * _32;
     134           1 :     _23 = Cos * _23 - Sin * _33;
     135           1 :     _24 = Cos * _24 - Sin * _34;
     136             : 
     137           1 :     _31 = Sin * tmp_21 + Cos * _31;
     138           1 :     _32 = Sin * tmp_22 + Cos * _32;
     139           1 :     _33 = Sin * tmp_23 + Cos * _33;
     140           1 :     _34 = Sin * tmp_24 + Cos * _34;
     141           1 : }
     142             : 
     143          16 : void CMatrix3D::RotateY (float angle)
     144             : {
     145          16 :     const float Cos = cosf (angle);
     146          16 :     const float Sin = sinf (angle);
     147          16 :     const float tmp_11 = _11;
     148          16 :     const float tmp_12 = _12;
     149          16 :     const float tmp_13 = _13;
     150          16 :     const float tmp_14 = _14;
     151             : 
     152          16 :     _11 = Cos * _11 + Sin * _31;
     153          16 :     _12 = Cos * _12 + Sin * _32;
     154          16 :     _13 = Cos * _13 + Sin * _33;
     155          16 :     _14 = Cos * _14 + Sin * _34;
     156             : 
     157          16 :     _31 = -Sin * tmp_11 + Cos * _31;
     158          16 :     _32 = -Sin * tmp_12 + Cos * _32;
     159          16 :     _33 = -Sin * tmp_13 + Cos * _33;
     160          16 :     _34 = -Sin * tmp_14 + Cos * _34;
     161          16 : }
     162             : 
     163          16 : void CMatrix3D::RotateZ (float angle)
     164             : {
     165          16 :     const float Cos = cosf (angle);
     166          16 :     const float Sin = sinf (angle);
     167          16 :     const float tmp_11 = _11;
     168          16 :     const float tmp_12 = _12;
     169          16 :     const float tmp_13 = _13;
     170          16 :     const float tmp_14 = _14;
     171             : 
     172          16 :     _11 = Cos * _11 - Sin * _21;
     173          16 :     _12 = Cos * _12 - Sin * _22;
     174          16 :     _13 = Cos * _13 - Sin * _23;
     175          16 :     _14 = Cos * _14 - Sin * _24;
     176             : 
     177          16 :     _21 = Sin * tmp_11 + Cos * _21;
     178          16 :     _22 = Sin * tmp_12 + Cos * _22;
     179          16 :     _23 = Sin * tmp_13 + Cos * _23;
     180          16 :     _24 = Sin * tmp_14 + Cos * _24;
     181          16 : }
     182             : 
     183             : //Sets the translation of the matrix
     184           3 : void CMatrix3D::SetTranslation (float x, float y, float z)
     185             : {
     186           3 :     _11=1.0f; _12=0.0f; _13=0.0f; _14=x;
     187           3 :     _21=0.0f; _22=1.0f; _23=0.0f; _24=y;
     188           3 :     _31=0.0f; _32=0.0f; _33=1.0f; _34=z;
     189           3 :     _41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
     190           3 : }
     191             : 
     192           1 : void CMatrix3D::SetTranslation(const CVector3D& vector)
     193             : {
     194           1 :     SetTranslation(vector.X, vector.Y, vector.Z);
     195           1 : }
     196             : 
     197             : //Applies a translation to the matrix
     198           0 : void CMatrix3D::Translate(float x, float y, float z)
     199             : {
     200           0 :     _14 += x;
     201           0 :     _24 += y;
     202           0 :     _34 += z;
     203           0 : }
     204             : 
     205          18 : void CMatrix3D::Translate(const CVector3D &vector)
     206             : {
     207          18 :     _14 += vector.X;
     208          18 :     _24 += vector.Y;
     209          18 :     _34 += vector.Z;
     210          18 : }
     211             : 
     212           0 : void CMatrix3D::PostTranslate(float x, float y, float z)
     213             : {
     214             :     // Equivalent to "m.SetTranslation(x, y, z); *this = *this * m;"
     215           0 :     _14 += _11*x + _12*y + _13*z;
     216           0 :     _24 += _21*x + _22*y + _23*z;
     217           0 :     _34 += _31*x + _32*y + _33*z;
     218           0 :     _44 += _41*x + _42*y + _43*z;
     219           0 : }
     220             : 
     221          32 : CVector3D CMatrix3D::GetTranslation() const
     222             : {
     223          32 :     return CVector3D(_14, _24, _34);
     224             : }
     225             : 
     226             : //Clears and sets the scaling of the matrix
     227           2 : void CMatrix3D::SetScaling (float x_scale, float y_scale, float z_scale)
     228             : {
     229           2 :     _11=x_scale; _12=0.0f;    _13=0.0f;    _14=0.0f;
     230           2 :     _21=0.0f;    _22=y_scale; _23=0.0f;    _24=0.0f;
     231           2 :     _31=0.0f;    _32=0.0f;    _33=z_scale; _34=0.0f;
     232           2 :     _41=0.0f;    _42=0.0f;    _43=0.0f;    _44=1.0f;
     233           2 : }
     234             : 
     235             : //Scales the matrix
     236           1 : void CMatrix3D::Scale (float x_scale, float y_scale, float z_scale)
     237             : {
     238           1 :     _11 *= x_scale;
     239           1 :     _12 *= x_scale;
     240           1 :     _13 *= x_scale;
     241           1 :     _14 *= x_scale;
     242             : 
     243           1 :     _21 *= y_scale;
     244           1 :     _22 *= y_scale;
     245           1 :     _23 *= y_scale;
     246           1 :     _24 *= y_scale;
     247             : 
     248           1 :     _31 *= z_scale;
     249           1 :     _32 *= z_scale;
     250           1 :     _33 *= z_scale;
     251           1 :     _34 *= z_scale;
     252           1 : }
     253             : 
     254             : //Returns the transpose of the matrix. For orthonormal
     255             : //matrices, this is the same is the inverse matrix
     256           0 : CMatrix3D CMatrix3D::GetTranspose() const
     257             : {
     258             :     return CMatrix3D(
     259           0 :         _11, _21, _31, _41,
     260           0 :         _12, _22, _32, _42,
     261           0 :         _13, _23, _33, _43,
     262           0 :         _14, _24, _34, _44);
     263             : }
     264             : 
     265             : 
     266             : //Get a vector which points to the left of the matrix
     267          18 : CVector3D CMatrix3D::GetLeft() const
     268             : {
     269          18 :     return CVector3D(-_11, -_21, -_31);
     270             : }
     271             : 
     272             : //Get a vector which points up from the matrix
     273           0 : CVector3D CMatrix3D::GetUp() const
     274             : {
     275           0 :     return CVector3D(_12, _22, _32);
     276             : }
     277             : 
     278             : //Get a vector which points to front of the matrix
     279          13 : CVector3D CMatrix3D::GetIn() const
     280             : {
     281          13 :     return CVector3D(_13, _23, _33);
     282             : }
     283             : 
     284             : ///////////////////////////////////////////////////////////////////////////////
     285             : // RotateTransposed: rotate a vector by the transpose of this matrix
     286           0 : CVector3D CMatrix3D::RotateTransposed(const CVector3D& vector) const
     287             : {
     288           0 :     CVector3D result;
     289           0 :     RotateTransposed(vector,result);
     290           0 :     return result;
     291             : }
     292             : 
     293             : ///////////////////////////////////////////////////////////////////////////////
     294             : // RotateTransposed: rotate a vector by the transpose of this matrix
     295           0 : void CMatrix3D::RotateTransposed(const CVector3D& vector,CVector3D& result) const
     296             : {
     297           0 :     result.X = _11*vector.X + _21*vector.Y + _31*vector.Z;
     298           0 :     result.Y = _12*vector.X + _22*vector.Y + _32*vector.Z;
     299           0 :     result.Z = _13*vector.X + _23*vector.Y + _33*vector.Z;
     300           0 : }
     301             : 
     302             : 
     303          21 : void CMatrix3D::GetInverse(CMatrix3D& dst) const
     304             : {
     305             :     float tmp[12];  // temp array for pairs
     306             :     float src[16];  // array of transpose source matrix
     307             :     float det;      // determinant
     308             : 
     309             :     // transpose matrix
     310         105 :     for (int i = 0; i < 4; ++i) {
     311          84 :         src[i] = _data[i*4];
     312          84 :         src[i + 4] = _data[i*4 + 1];
     313          84 :         src[i + 8] = _data[i*4 + 2];
     314          84 :         src[i + 12] = _data[i*4 + 3];
     315             :     }
     316             : 
     317             :     // calculate pairs for first 8 elements (cofactors)
     318          21 :     tmp[0] = src[10] * src[15];
     319          21 :     tmp[1] = src[11] * src[14];
     320          21 :     tmp[2] = src[9] * src[15];
     321          21 :     tmp[3] = src[11] * src[13];
     322          21 :     tmp[4] = src[9] * src[14];
     323          21 :     tmp[5] = src[10] * src[13];
     324          21 :     tmp[6] = src[8] * src[15];
     325          21 :     tmp[7] = src[11] * src[12];
     326          21 :     tmp[8] = src[8] * src[14];
     327          21 :     tmp[9] = src[10] * src[12];
     328          21 :     tmp[10] = src[8] * src[13];
     329          21 :     tmp[11] = src[9] * src[12];
     330             : 
     331             :     // calculate first 8 elements (cofactors)
     332          21 :     dst._data[0] = (tmp[0]-tmp[1])*src[5] + (tmp[3]-tmp[2])*src[6] + (tmp[4]-tmp[5])*src[7];
     333          21 :     dst._data[1] = (tmp[1]-tmp[0])*src[4] + (tmp[6]-tmp[7])*src[6] + (tmp[9]-tmp[8])*src[7];
     334          21 :     dst._data[2] = (tmp[2]-tmp[3])*src[4] + (tmp[7]-tmp[6])*src[5] + (tmp[10]-tmp[11])*src[7];
     335          21 :     dst._data[3] = (tmp[5]-tmp[4])*src[4] + (tmp[8]-tmp[9])*src[5] + (tmp[11]-tmp[10])*src[6];
     336          21 :     dst._data[4] = (tmp[1]-tmp[0])*src[1] + (tmp[2]-tmp[3])*src[2] + (tmp[5]-tmp[4])*src[3];
     337          21 :     dst._data[5] = (tmp[0]-tmp[1])*src[0] + (tmp[7]-tmp[6])*src[2] + (tmp[8]-tmp[9])*src[3];
     338          21 :     dst._data[6] = (tmp[3]-tmp[2])*src[0] + (tmp[6]-tmp[7])*src[1] + (tmp[11]-tmp[10])*src[3];
     339          21 :     dst._data[7] = (tmp[4]-tmp[5])*src[0] + (tmp[9]-tmp[8])*src[1] + (tmp[10]-tmp[11])*src[2];
     340             : 
     341             :     // calculate pairs for second 8 elements (cofactors)
     342          21 :     tmp[0] = src[2]*src[7];
     343          21 :     tmp[1] = src[3]*src[6];
     344          21 :     tmp[2] = src[1]*src[7];
     345          21 :     tmp[3] = src[3]*src[5];
     346          21 :     tmp[4] = src[1]*src[6];
     347          21 :     tmp[5] = src[2]*src[5];
     348          21 :     tmp[6] = src[0]*src[7];
     349          21 :     tmp[7] = src[3]*src[4];
     350          21 :     tmp[8] = src[0]*src[6];
     351          21 :     tmp[9] = src[2]*src[4];
     352          21 :     tmp[10] = src[0]*src[5];
     353          21 :     tmp[11] = src[1]*src[4];
     354             : 
     355             :     // calculate second 8 elements (cofactors)
     356          21 :     dst._data[8] = (tmp[0]-tmp[1])*src[13] + (tmp[3]-tmp[2])*src[14] + (tmp[4]-tmp[5])*src[15];
     357          21 :     dst._data[9] = (tmp[1]-tmp[0])*src[12] + (tmp[6]-tmp[7])*src[14] + (tmp[9]-tmp[8])*src[15];
     358          21 :     dst._data[10] = (tmp[2]-tmp[3])*src[12] + (tmp[7]-tmp[6])*src[13] + (tmp[10]-tmp[11])*src[15];
     359          21 :     dst._data[11] = (tmp[5]-tmp[4])*src[12] + (tmp[8]-tmp[9])*src[13] + (tmp[11]-tmp[10])*src[14];
     360          21 :     dst._data[12] = (tmp[2]-tmp[3])*src[10] + (tmp[5]-tmp[4])*src[11] + (tmp[1]-tmp[0])*src[9];
     361          21 :     dst._data[13] = (tmp[7]-tmp[6])*src[10] + (tmp[8]-tmp[9])*src[11] + (tmp[0]-tmp[1])*src[8];
     362          21 :     dst._data[14] = (tmp[6]-tmp[7])*src[9] + (tmp[11]-tmp[10])*src[11] + (tmp[3]-tmp[2])*src[8];
     363          21 :     dst._data[15] = (tmp[10]-tmp[11])*src[10] + (tmp[4]-tmp[5])*src[8] + (tmp[9]-tmp[8])*src[9];
     364             : 
     365             :     // calculate matrix inverse
     366          21 :     det=src[0]*dst._data[0]+src[1]*dst._data[1]+src[2]*dst._data[2]+src[3]*dst._data[3];
     367          21 :     det = 1/det;
     368         357 :     for ( int j = 0; j < 16; j++) {
     369         336 :         dst._data[j] *= det;
     370             :     }
     371          21 : }
     372             : 
     373          13 : CMatrix3D CMatrix3D::GetInverse() const
     374             : {
     375          13 :     CMatrix3D r;
     376          13 :     GetInverse(r);
     377          13 :     return r;
     378             : }
     379             : 
     380           3 : void CMatrix3D::Rotate(const CQuaternion& quat)
     381             : {
     382           3 :     CMatrix3D rotationMatrix=quat.ToMatrix();
     383           3 :     Concatenate(rotationMatrix);
     384           3 : }
     385             : 
     386           4 : CQuaternion CMatrix3D::GetRotation() const
     387             : {
     388           4 :     float tr = _data2d[0][0] + _data2d[1][1] + _data2d[2][2];
     389             : 
     390           4 :     int next[] = { 1, 2, 0 };
     391             : 
     392             :     float quat[4];
     393             : 
     394           4 :     if (tr > 0.f)
     395             :     {
     396           2 :         float s = sqrtf(tr + 1.f);
     397           2 :         quat[3] = s * 0.5f;
     398           2 :         s = 0.5f / s;
     399           2 :         quat[0] = (_data2d[1][2] - _data2d[2][1]) * s;
     400           2 :         quat[1] = (_data2d[2][0] - _data2d[0][2]) * s;
     401           2 :         quat[2] = (_data2d[0][1] - _data2d[1][0]) * s;
     402             :     }
     403             :     else
     404             :     {
     405           2 :         int i = 0;
     406           2 :         if (_data2d[1][1] > _data2d[0][0]) i = 1;
     407           2 :         if (_data2d[2][2] > _data2d[i][i]) i = 2;
     408           2 :         int j = next[i];
     409           2 :         int k = next[j];
     410             : 
     411           2 :         float s = sqrtf((_data2d[i][i] - (_data2d[j][j] + _data2d[k][k])) + 1.f);
     412           2 :         quat[i] = s * 0.5f;
     413             : 
     414           2 :         if (s != 0.f) s = 0.5f / s;
     415             : 
     416           2 :         quat[3] = (_data2d[j][k] - _data2d[k][j]) * s;
     417           2 :         quat[j] = (_data2d[i][j] + _data2d[j][i]) * s;
     418           2 :         quat[k] = (_data2d[i][k] + _data2d[k][i]) * s;
     419             :     }
     420             : 
     421           4 :     return CQuaternion(quat[0], quat[1], quat[2], quat[3]);
     422             : }
     423             : 
     424           0 : void CMatrix3D::SetRotation(const CQuaternion& quat)
     425             : {
     426           0 :     quat.ToMatrix(*this);
     427           0 : }
     428             : 
     429          18 : float CMatrix3D::GetYRotation() const
     430             : {
     431             :     // Project the X axis vector onto the XZ plane
     432          18 :     CVector3D axis = -GetLeft();
     433          18 :     axis.Y = 0;
     434             : 
     435             :     // Normalise projected vector
     436             : 
     437          18 :     float len = axis.Length();
     438          18 :     if (len < 0.0001f)
     439           1 :         return 0.f;
     440          17 :     axis *= 1.0f/len;
     441             : 
     442             :     // Negate the return angle to match the SetYRotation convention
     443          17 :     return -atan2(axis.Z, axis.X);
     444           3 : }

Generated by: LCOV version 1.13