1 /**
2  * Copyright (c) 2006-2019 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 
27 namespace 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  **/
35 class Matrix4
36 {
37 private:
38 
39 	static void multiply(const Matrix4 &a, const Matrix4 &b, float t[16]);
40 
41 public:
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 
225 private:
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 
237 class Matrix3
238 {
239 public:
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 
295 private:
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 
315 template <typename Vdst, typename Vsrc>
transformXY(Vdst * dst,const Vsrc * src,int size)316 void 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 
329 template <typename Vdst, typename Vsrc>
transformXY0(Vdst * dst,const Vsrc * src,int size)330 void 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 
354 template <typename Vdst, typename Vsrc>
transformXYZ(Vdst * dst,const Vsrc * src,int size)355 void 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 |
376 template <typename Vdst, typename Vsrc>
transformXY(Vdst * dst,const Vsrc * src,int size)377 void 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