1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#ifndef LOVE_MATRIX_H
22#define LOVE_MATRIX_H
23
24// LOVE
25#include "math.h"
26
27namespace love
28{
29
30/**
31 * This class is the basis for all transformations in LOVE. Although not really
32 * needed for 2D, it contains 4x4 elements to be compatible with OpenGL without
33 * conversions.
34 **/
35class Matrix4
36{
37private:
38
39 static void multiply(const Matrix4 &a, const Matrix4 &b, float t[16]);
40
41public:
42
43 static void multiply(const Matrix4 &a, const Matrix4 &b, Matrix4 &result);
44
45 /**
46 * Creates a new identity matrix.
47 **/
48 Matrix4();
49
50 /**
51 * Creates a new matrix with the transform values set.
52 **/
53 Matrix4(float t00, float t10, float t01, float t11, float x, float y);
54
55 /**
56 * Creates a new matrix from the specified elements. Be sure to pass
57 * exactly 16 elements in!
58 **/
59 Matrix4(const float elements[16]);
60
61 /**
62 * Creates a new matrix from the result of multiplying the two specified
63 * matrices.
64 **/
65 Matrix4(const Matrix4 &a, const Matrix4 &b);
66
67 /**
68 * Creates a new matrix set to a transformation.
69 **/
70 Matrix4(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
71
72 /**
73 * Multiplies this Matrix with another Matrix, changing neither.
74 * @param m The Matrix to multiply with this Matrix.
75 * @return The combined matrix.
76 **/
77 Matrix4 operator * (const Matrix4 &m) const;
78
79 /**
80 * Multiplies a Matrix into this Matrix.
81 * @param m The Matrix to combine into this Matrix.
82 **/
83 void operator *= (const Matrix4 &m);
84
85 /**
86 * Gets a pointer to the 16 array elements.
87 * @return The array elements.
88 **/
89 const float *getElements() const;
90
91 /**
92 * Resets this Matrix to the identity matrix.
93 **/
94 void setIdentity();
95
96 /**
97 * Resets this Matrix to a translation.
98 * @param x Translation along x-axis.
99 * @param y Translation along y-axis.
100 **/
101 void setTranslation(float x, float y);
102
103 /**
104 * Resets this Matrix to a rotation.
105 * @param r The angle in radians.
106 **/
107 void setRotation(float r);
108
109 /**
110 * Resets this Matrix to a scale transformation.
111 * @param sx Scale factor along the x-axis.
112 * @param sy Scale factor along the y-axis.
113 **/
114 void setScale(float sx, float sy);
115
116 /**
117 * Resets this Matrix to a shear transformation.
118 * @param kx Shear along x-axis.
119 * @param ky Shear along y-axis.
120 **/
121 void setShear(float kx, float ky);
122
123 /**
124 * Calculates the scale factors for a 2D affine transform. The output values
125 * are absolute (not signed).
126 **/
127 void getApproximateScale(float &sx, float &sy) const;
128
129 /**
130 * Sets a transformation's values directly. Useful if you want to modify them inplace,
131 * or if you want to create a transformation that's not buildable with setTransformation()
132 * i.e. the inverse of setTransformation() is not easily built with another call
133 * to setTransformation() with tweaked values.
134 *
135 * @param t00 The sx*cos(angle) component of the transformation.
136 * @param t10 The sx*sin(angle) component of the transformation.
137 * @param t01 The sy*(-sin(angle)) component of the transformation.
138 * @param t11 The sy*cos(angle) component of the transformation.
139 * @param x The x translation component of the transformation.
140 * @param y The y translation component of the transformation.
141 **/
142 void setRawTransformation(float t00, float t10, float t01, float t11, float x, float y);
143
144 /**
145 * Creates a transformation with a certain position, orientation, scale
146 * and offset. Perfect for Drawables -- what a coincidence!
147 *
148 * @param x The translation along the x-axis.
149 * @param y The translation along the y-axis.
150 * @param angle The rotation (rad) around the center with offset (ox,oy).
151 * @param sx Scale along x-axis.
152 * @param sy Scale along y-axis.
153 * @param ox The offset for rotation along the x-axis.
154 * @param oy The offset for rotation along the y-axis.
155 * @param kx Shear along x-axis
156 * @param ky Shear along y-axis
157 **/
158 void setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
159
160 /**
161 * Multiplies this Matrix with a translation.
162 * @param x Translation along x-axis.
163 * @param y Translation along y-axis.
164 **/
165 void translate(float x, float y);
166
167 /**
168 * Multiplies this Matrix with a rotation.
169 * @param r Angle in radians.
170 **/
171 void rotate(float r);
172
173 /**
174 * Multiplies this Matrix with a scale transformation.
175 * @param sx Scale factor along the x-axis.
176 * @param sy Scale factor along the y-axis.
177 **/
178 void scale(float sx, float sy);
179
180 /**
181 * Multiplies this Matrix with a shear transformation.
182 * @param kx Shear along the x-axis.
183 * @param ky Shear along the y-axis.
184 **/
185 void shear(float kx, float ky);
186
187 /**
188 * Transforms an array of 2-component vertices by this Matrix. The source
189 * and destination arrays may be the same.
190 **/
191 template <typename Vdst, typename Vsrc>
192 void transformXY(Vdst *dst, const Vsrc *src, int size) const;
193
194 /**
195 * Transforms an array of 2-component vertices by this Matrix, and stores
196 * them in an array of 3-component vertices.
197 **/
198 template <typename Vdst, typename Vsrc>
199 void transformXY0(Vdst *dst, const Vsrc *src, int size) const;
200
201 /**
202 * Transforms an array of 3-component vertices by this Matrix. The source
203 * and destination arrays may be the same.
204 **/
205 template <typename Vdst, typename Vsrc>
206 void transformXYZ(Vdst *dst, const Vsrc *src, int size) const;
207
208 /**
209 * Gets whether this matrix is an affine 2D transform (if the only non-
210 * identity elements are the upper-left 2x2 and 2 translation values in the
211 * 4th column).
212 **/
213 bool isAffine2DTransform() const;
214
215 /**
216 * Computes and returns the inverse of the matrix.
217 **/
218 Matrix4 inverse() const;
219
220 /**
221 * Creates a new orthographic projection matrix.
222 **/
223 static Matrix4 ortho(float left, float right, float bottom, float top, float near, float far);
224
225private:
226
227 /**
228 * | e0 e4 e8 e12 |
229 * | e1 e5 e9 e13 |
230 * | e2 e6 e10 e14 |
231 * | e3 e7 e11 e15 |
232 **/
233 float e[16];
234
235}; // Matrix4
236
237class Matrix3
238{
239public:
240
241 Matrix3();
242
243 /**
244 * Constructs a 3x3 matrix from the upper left section of a 4x4 matrix.
245 **/
246 Matrix3(const Matrix4 &mat4);
247
248 /**
249 * Creates a new matrix set to a transformation.
250 **/
251 Matrix3(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
252
253 ~Matrix3();
254
255 /**
256 * Resets this matrix to the identity matrix.
257 **/
258 void setIdentity();
259
260 Matrix3 operator * (const Matrix3 &m) const;
261 void operator *= (const Matrix3 &m);
262
263 /**
264 * Gets a pointer to the 9 array elements.
265 **/
266 const float *getElements() const;
267
268 /**
269 * Calculates the inverse of the transpose of this matrix.
270 **/
271 Matrix3 transposedInverse() const;
272
273 /**
274 * Creates a transformation with a certain position, orientation, scale
275 * and offset.
276 *
277 * @param x The translation along the x-axis.
278 * @param y The translation along the y-axis.
279 * @param angle The rotation (rad) around the center with offset (ox,oy).
280 * @param sx Scale along x-axis.
281 * @param sy Scale along y-axis.
282 * @param ox The offset for rotation along the x-axis.
283 * @param oy The offset for rotation along the y-axis.
284 * @param kx Shear along x-axis
285 * @param ky Shear along y-axis
286 **/
287 void setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
288
289 /**
290 * Transforms an array of vertices by this matrix.
291 **/
292 template <typename Vdst, typename Vsrc>
293 void transformXY(Vdst *dst, const Vsrc *src, int size) const;
294
295private:
296
297 /**
298 * | e0 e3 e6
299 * | e1 e4 e7
300 * | e2 e5 e8
301 **/
302 float e[9];
303
304}; // Matrix3
305
306// | x |
307// | y |
308// | 0 |
309// | 1 |
310// | e0 e4 e8 e12 |
311// | e1 e5 e9 e13 |
312// | e2 e6 e10 e14 |
313// | e3 e7 e11 e15 |
314
315template <typename Vdst, typename Vsrc>
316void Matrix4::transformXY(Vdst *dst, const Vsrc *src, int size) const
317{
318 for (int i = 0; i < size; i++)
319 {
320 // Store in temp variables in case src = dst
321 float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (0) + (e[12]);
322 float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (0) + (e[13]);
323
324 dst[i].x = x;
325 dst[i].y = y;
326 }
327}
328
329template <typename Vdst, typename Vsrc>
330void Matrix4::transformXY0(Vdst *dst, const Vsrc *src, int size) const
331{
332 for (int i = 0; i < size; i++)
333 {
334 // Store in temp variables in case src = dst
335 float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (0) + (e[12]);
336 float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (0) + (e[13]);
337 float z = (e[2]*src[i].x) + (e[6]*src[i].y) + (0) + (e[14]);
338
339 dst[i].x = x;
340 dst[i].y = y;
341 dst[i].z = z;
342 }
343}
344
345// | x |
346// | y |
347// | z |
348// | 1 |
349// | e0 e4 e8 e12 |
350// | e1 e5 e9 e13 |
351// | e2 e6 e10 e14 |
352// | e3 e7 e11 e15 |
353
354template <typename Vdst, typename Vsrc>
355void Matrix4::transformXYZ(Vdst *dst, const Vsrc *src, int size) const
356{
357 for (int i = 0; i < size; i++)
358 {
359 // Store in temp variables in case src = dst
360 float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (e[ 8]*src[i].z) + (e[12]);
361 float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (e[ 9]*src[i].z) + (e[13]);
362 float z = (e[2]*src[i].x) + (e[6]*src[i].y) + (e[10]*src[i].z) + (e[14]);
363
364 dst[i].x = x;
365 dst[i].y = y;
366 dst[i].z = z;
367 }
368}
369
370// | x |
371// | y |
372// | 1 |
373// | e0 e3 e6 |
374// | e1 e4 e7 |
375// | e2 e5 e8 |
376template <typename Vdst, typename Vsrc>
377void Matrix3::transformXY(Vdst *dst, const Vsrc *src, int size) const
378{
379 for (int i = 0; i < size; i++)
380 {
381 float x = (e[0]*src[i].x) + (e[3]*src[i].y) + (e[6]);
382 float y = (e[1]*src[i].x) + (e[4]*src[i].y) + (e[7]);
383
384 dst[i].x = x;
385 dst[i].y = y;
386 }
387}
388
389} //love
390
391#endif// LOVE_MATRIX_H
392