1 /* Copyright (C) 2022 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
19 * A Matrix class used for holding and manipulating transformation
23 #ifndef INCLUDED_MATRIX3D
24 #define INCLUDED_MATRIX3D
26 #include "maths/Vector3D.h"
27 #include "maths/Vector4D.h"
28 #include "ps/containers/Span.h"
32 // CMatrix3D: a 4x4 matrix class for common operations in 3D
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
44 float _11
, _21
, _31
, _41
;
45 float _12
, _22
, _32
, _42
;
46 float _13
, _23
, _33
, _43
;
47 float _14
, _24
, _34
, _44
;
51 // (Be aware that m(0,2) == _data2d[2][0] == _13, etc. This is to be considered a feature.)
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 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 _41(a41
), _42(a42
), _43(a43
), _44(a44
)
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])
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 float& operator()(int col
, int row
)
86 return _data
[row
*4+col
];
88 const float& operator()(int col
, int row
) const
90 return _data
[row
*4+col
];
93 float& operator[](int idx
)
97 const float& operator[](int idx
) const
102 // matrix multiplication
103 CMatrix3D
operator*(const CMatrix3D
&matrix
) const
106 _11
*matrix
._11
+ _12
*matrix
._21
+ _13
*matrix
._31
+ _14
*matrix
._41
,
107 _11
*matrix
._12
+ _12
*matrix
._22
+ _13
*matrix
._32
+ _14
*matrix
._42
,
108 _11
*matrix
._13
+ _12
*matrix
._23
+ _13
*matrix
._33
+ _14
*matrix
._43
,
109 _11
*matrix
._14
+ _12
*matrix
._24
+ _13
*matrix
._34
+ _14
*matrix
._44
,
111 _21
*matrix
._11
+ _22
*matrix
._21
+ _23
*matrix
._31
+ _24
*matrix
._41
,
112 _21
*matrix
._12
+ _22
*matrix
._22
+ _23
*matrix
._32
+ _24
*matrix
._42
,
113 _21
*matrix
._13
+ _22
*matrix
._23
+ _23
*matrix
._33
+ _24
*matrix
._43
,
114 _21
*matrix
._14
+ _22
*matrix
._24
+ _23
*matrix
._34
+ _24
*matrix
._44
,
116 _31
*matrix
._11
+ _32
*matrix
._21
+ _33
*matrix
._31
+ _34
*matrix
._41
,
117 _31
*matrix
._12
+ _32
*matrix
._22
+ _33
*matrix
._32
+ _34
*matrix
._42
,
118 _31
*matrix
._13
+ _32
*matrix
._23
+ _33
*matrix
._33
+ _34
*matrix
._43
,
119 _31
*matrix
._14
+ _32
*matrix
._24
+ _33
*matrix
._34
+ _34
*matrix
._44
,
121 _41
*matrix
._11
+ _42
*matrix
._21
+ _43
*matrix
._31
+ _44
*matrix
._41
,
122 _41
*matrix
._12
+ _42
*matrix
._22
+ _43
*matrix
._32
+ _44
*matrix
._42
,
123 _41
*matrix
._13
+ _42
*matrix
._23
+ _43
*matrix
._33
+ _44
*matrix
._43
,
124 _41
*matrix
._14
+ _42
*matrix
._24
+ _43
*matrix
._34
+ _44
*matrix
._44
128 // matrix multiplication/assignment
129 CMatrix3D
& operator*=(const CMatrix3D
&matrix
)
136 CMatrix3D
operator*(float f
) const
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
147 CMatrix3D
operator+(const CMatrix3D
&m
) const
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
157 // matrix addition/assignment
158 CMatrix3D
& operator+=(const CMatrix3D
&m
)
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
;
168 bool operator==(const CMatrix3D
&m
) const
170 return _11
== m
._11
&& _21
== m
._21
&& _31
== m
._31
&& _41
== m
._41
&&
171 _12
== m
._12
&& _22
== m
._22
&& _32
== m
._32
&& _42
== m
._42
&&
172 _13
== m
._13
&& _23
== m
._23
&& _33
== m
._33
&& _43
== m
._43
&&
173 _14
== m
._14
&& _24
== m
._24
&& _34
== m
._34
&& _44
== m
._44
;
177 bool operator!=(const CMatrix3D
& m
) const
179 return !(*this == m
);
182 // set this matrix to the identity matrix
184 // set this matrix to the zero matrix
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
);
192 // concatenate arbitrary matrix onto this matrix
193 void Concatenate(const CMatrix3D
& m
)
195 (*this) = m
* (*this);
198 // blend matrix using only 4x3 subset
199 void Blend(const CMatrix3D
& m
, float f
)
201 _11
= m
._11
*f
; _21
= m
._21
*f
; _31
= m
._31
*f
;
202 _12
= m
._12
*f
; _22
= m
._22
*f
; _32
= m
._32
*f
;
203 _13
= m
._13
*f
; _23
= m
._23
*f
; _33
= m
._33
*f
;
204 _14
= m
._14
*f
; _24
= m
._24
*f
; _34
= m
._34
*f
;
207 // blend matrix using only 4x3 and add onto existing blend
208 void AddBlend(const CMatrix3D
& m
, float f
)
210 _11
+= m
._11
*f
; _21
+= m
._21
*f
; _31
+= m
._31
*f
;
211 _12
+= m
._12
*f
; _22
+= m
._22
*f
; _32
+= m
._32
*f
;
212 _13
+= m
._13
*f
; _23
+= m
._23
*f
; _33
+= m
._33
*f
;
213 _14
+= m
._14
*f
; _24
+= m
._24
*f
; _34
+= m
._34
*f
;
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
);
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
);
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
);
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
);
244 // apply translation after this matrix (M = M * T)
245 void PostTranslate(float x
, float y
, float z
);
247 // set this matrix to the given scaling matrix
248 void SetScaling(float x_scale
, float y_scale
, float z_scale
);
250 // concatenate given scaling matrix onto this matrix
251 void Scale(float x_scale
, float y_scale
, float z_scale
);
253 // calculate the inverse of this matrix, store in dst
254 void GetInverse(CMatrix3D
& dst
) const;
256 // return the inverse of this matrix
257 CMatrix3D
GetInverse() const;
259 // calculate the transpose of this matrix, store in dst
260 CMatrix3D
GetTranspose() const;
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;
276 // transform a 3D vector by this matrix
277 CVector3D
Transform(const CVector3D
&vector
) const
280 Transform(vector
, result
);
284 void Transform(const CVector3D
& vector
, CVector3D
& result
) const
286 result
.X
= _11
*vector
.X
+ _12
*vector
.Y
+ _13
*vector
.Z
+ _14
;
287 result
.Y
= _21
*vector
.X
+ _22
*vector
.Y
+ _23
*vector
.Z
+ _24
;
288 result
.Z
= _31
*vector
.X
+ _32
*vector
.Y
+ _33
*vector
.Z
+ _34
;
291 // transform a 4D vector by this matrix
292 CVector4D
Transform(const CVector4D
&vector
) const
295 Transform(vector
, result
);
299 void Transform(const CVector4D
& vector
, CVector4D
& result
) const
301 result
.X
= _11
*vector
.X
+ _12
*vector
.Y
+ _13
*vector
.Z
+ _14
*vector
.W
;
302 result
.Y
= _21
*vector
.X
+ _22
*vector
.Y
+ _23
*vector
.Z
+ _24
*vector
.W
;
303 result
.Z
= _31
*vector
.X
+ _32
*vector
.Y
+ _33
*vector
.Z
+ _34
*vector
.W
;
304 result
.W
= _41
*vector
.X
+ _42
*vector
.Y
+ _43
*vector
.Z
+ _44
*vector
.W
;
307 // rotate a vector by this matrix
308 CVector3D
Rotate(const CVector3D
& vector
) const
311 Rotate(vector
, result
);
315 void Rotate(const CVector3D
& vector
, CVector3D
& result
) const
317 result
.X
= _11
*vector
.X
+ _12
*vector
.Y
+ _13
*vector
.Z
;
318 result
.Y
= _21
*vector
.X
+ _22
*vector
.Y
+ _23
*vector
.Z
;
319 result
.Z
= _31
*vector
.X
+ _32
*vector
.Y
+ _33
*vector
.Z
;
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;
326 // Returns 16 element array of floats, e.g. for mat4 uniforms.
327 PS::span
<const float> AsFloatArray() const
329 // Additional check to prevent a weird compiler has a different
330 // alignement for an array and a class members.
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 return PS::span
<const float>(_data
, 16);
341 #endif // INCLUDED_MATRIX3D