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
|