| 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 | #include "Matrix.h" | 
| 22 | #include "common/config.h" | 
| 23 |  | 
| 24 | // STD | 
| 25 | #include <cstring> // memcpy | 
| 26 | #include <cmath> | 
| 27 |  | 
| 28 | #if defined(LOVE_SIMD_SSE) | 
| 29 | #include <xmmintrin.h> | 
| 30 | #endif | 
| 31 |  | 
| 32 | #if defined(LOVE_SIMD_NEON) | 
| 33 | #include <arm_neon.h> | 
| 34 | #endif | 
| 35 |  | 
| 36 | namespace love | 
| 37 | { | 
| 38 |  | 
| 39 | //                 | e0 e4 e8  e12 | | 
| 40 | //                 | e1 e5 e9  e13 | | 
| 41 | //                 | e2 e6 e10 e14 | | 
| 42 | //                 | e3 e7 e11 e15 | | 
| 43 | // | e0 e4 e8  e12 | | 
| 44 | // | e1 e5 e9  e13 | | 
| 45 | // | e2 e6 e10 e14 | | 
| 46 | // | e3 e7 e11 e15 | | 
| 47 |  | 
| 48 | void Matrix4::multiply(const Matrix4 &a, const Matrix4 &b, float t[16]) | 
| 49 | { | 
| 50 | #if defined(LOVE_SIMD_SSE) | 
| 51 |  | 
| 52 | 	// We can't guarantee 16-bit alignment (e.g. for heap-allocated Matrix4 | 
| 53 | 	// objects) so we use unaligned loads and stores. | 
| 54 | 	__m128 col1 = _mm_loadu_ps(&a.e[0]); | 
| 55 | 	__m128 col2 = _mm_loadu_ps(&a.e[4]); | 
| 56 | 	__m128 col3 = _mm_loadu_ps(&a.e[8]); | 
| 57 | 	__m128 col4 = _mm_loadu_ps(&a.e[12]); | 
| 58 |  | 
| 59 | 	for (int i = 0; i < 4; i++) | 
| 60 | 	{ | 
| 61 | 		__m128 brod1 = _mm_set1_ps(b.e[4*i + 0]); | 
| 62 | 		__m128 brod2 = _mm_set1_ps(b.e[4*i + 1]); | 
| 63 | 		__m128 brod3 = _mm_set1_ps(b.e[4*i + 2]); | 
| 64 | 		__m128 brod4 = _mm_set1_ps(b.e[4*i + 3]); | 
| 65 |  | 
| 66 | 		__m128 col = _mm_add_ps( | 
| 67 | 			_mm_add_ps(_mm_mul_ps(brod1, col1), _mm_mul_ps(brod2, col2)), | 
| 68 | 			_mm_add_ps(_mm_mul_ps(brod3, col3), _mm_mul_ps(brod4, col4)) | 
| 69 | 		); | 
| 70 |  | 
| 71 | 		_mm_storeu_ps(&t[4*i], col); | 
| 72 | 	} | 
| 73 |  | 
| 74 | #elif defined(LOVE_SIMD_NEON) | 
| 75 |  | 
| 76 | 	float32x4_t cola1 = vld1q_f32(&a.e[0]); | 
| 77 | 	float32x4_t cola2 = vld1q_f32(&a.e[4]); | 
| 78 | 	float32x4_t cola3 = vld1q_f32(&a.e[8]); | 
| 79 | 	float32x4_t cola4 = vld1q_f32(&a.e[12]); | 
| 80 |  | 
| 81 | 	float32x4_t col1 = vmulq_n_f32(cola1, b.e[0]); | 
| 82 | 	col1 = vmlaq_n_f32(col1, cola2, b.e[1]); | 
| 83 | 	col1 = vmlaq_n_f32(col1, cola3, b.e[2]); | 
| 84 | 	col1 = vmlaq_n_f32(col1, cola4, b.e[3]); | 
| 85 |  | 
| 86 | 	float32x4_t col2 = vmulq_n_f32(cola1, b.e[4]); | 
| 87 | 	col2 = vmlaq_n_f32(col2, cola2, b.e[5]); | 
| 88 | 	col2 = vmlaq_n_f32(col2, cola3, b.e[6]); | 
| 89 | 	col2 = vmlaq_n_f32(col2, cola4, b.e[7]); | 
| 90 |  | 
| 91 | 	float32x4_t col3 = vmulq_n_f32(cola1, b.e[8]); | 
| 92 | 	col3 = vmlaq_n_f32(col3, cola2, b.e[9]); | 
| 93 | 	col3 = vmlaq_n_f32(col3, cola3, b.e[10]); | 
| 94 | 	col3 = vmlaq_n_f32(col3, cola4, b.e[11]); | 
| 95 |  | 
| 96 | 	float32x4_t col4 = vmulq_n_f32(cola1, b.e[12]); | 
| 97 | 	col4 = vmlaq_n_f32(col4, cola2, b.e[13]); | 
| 98 | 	col4 = vmlaq_n_f32(col4, cola3, b.e[14]); | 
| 99 | 	col4 = vmlaq_n_f32(col4, cola4, b.e[15]); | 
| 100 |  | 
| 101 | 	vst1q_f32(&t[0], col1); | 
| 102 | 	vst1q_f32(&t[4], col2); | 
| 103 | 	vst1q_f32(&t[8], col3); | 
| 104 | 	vst1q_f32(&t[12], col4); | 
| 105 |  | 
| 106 | #else | 
| 107 |  | 
| 108 | 	t[0]  = (a.e[0]*b.e[0])  + (a.e[4]*b.e[1])  + (a.e[8]*b.e[2])  + (a.e[12]*b.e[3]); | 
| 109 | 	t[4]  = (a.e[0]*b.e[4])  + (a.e[4]*b.e[5])  + (a.e[8]*b.e[6])  + (a.e[12]*b.e[7]); | 
| 110 | 	t[8]  = (a.e[0]*b.e[8])  + (a.e[4]*b.e[9])  + (a.e[8]*b.e[10]) + (a.e[12]*b.e[11]); | 
| 111 | 	t[12] = (a.e[0]*b.e[12]) + (a.e[4]*b.e[13]) + (a.e[8]*b.e[14]) + (a.e[12]*b.e[15]); | 
| 112 |  | 
| 113 | 	t[1]  = (a.e[1]*b.e[0])  + (a.e[5]*b.e[1])  + (a.e[9]*b.e[2])  + (a.e[13]*b.e[3]); | 
| 114 | 	t[5]  = (a.e[1]*b.e[4])  + (a.e[5]*b.e[5])  + (a.e[9]*b.e[6])  + (a.e[13]*b.e[7]); | 
| 115 | 	t[9]  = (a.e[1]*b.e[8])  + (a.e[5]*b.e[9])  + (a.e[9]*b.e[10]) + (a.e[13]*b.e[11]); | 
| 116 | 	t[13] = (a.e[1]*b.e[12]) + (a.e[5]*b.e[13]) + (a.e[9]*b.e[14]) + (a.e[13]*b.e[15]); | 
| 117 |  | 
| 118 | 	t[2]  = (a.e[2]*b.e[0])  + (a.e[6]*b.e[1])  + (a.e[10]*b.e[2])  + (a.e[14]*b.e[3]); | 
| 119 | 	t[6]  = (a.e[2]*b.e[4])  + (a.e[6]*b.e[5])  + (a.e[10]*b.e[6])  + (a.e[14]*b.e[7]); | 
| 120 | 	t[10] = (a.e[2]*b.e[8])  + (a.e[6]*b.e[9])  + (a.e[10]*b.e[10]) + (a.e[14]*b.e[11]); | 
| 121 | 	t[14] = (a.e[2]*b.e[12]) + (a.e[6]*b.e[13]) + (a.e[10]*b.e[14]) + (a.e[14]*b.e[15]); | 
| 122 |  | 
| 123 | 	t[3]  = (a.e[3]*b.e[0])  + (a.e[7]*b.e[1])  + (a.e[11]*b.e[2])  + (a.e[15]*b.e[3]); | 
| 124 | 	t[7]  = (a.e[3]*b.e[4])  + (a.e[7]*b.e[5])  + (a.e[11]*b.e[6])  + (a.e[15]*b.e[7]); | 
| 125 | 	t[11] = (a.e[3]*b.e[8])  + (a.e[7]*b.e[9])  + (a.e[11]*b.e[10]) + (a.e[15]*b.e[11]); | 
| 126 | 	t[15] = (a.e[3]*b.e[12]) + (a.e[7]*b.e[13]) + (a.e[11]*b.e[14]) + (a.e[15]*b.e[15]); | 
| 127 |  | 
| 128 | #endif | 
| 129 | } | 
| 130 |  | 
| 131 | void Matrix4::multiply(const Matrix4 &a, const Matrix4 &b, Matrix4 &t) | 
| 132 | { | 
| 133 | 	multiply(a, b, t.e); | 
| 134 | } | 
| 135 |  | 
| 136 | // | e0 e4 e8  e12 | | 
| 137 | // | e1 e5 e9  e13 | | 
| 138 | // | e2 e6 e10 e14 | | 
| 139 | // | e3 e7 e11 e15 | | 
| 140 |  | 
| 141 | Matrix4::Matrix4() | 
| 142 | { | 
| 143 | 	setIdentity(); | 
| 144 | } | 
| 145 |  | 
| 146 |  | 
| 147 | Matrix4::Matrix4(const float elements[16]) | 
| 148 | { | 
| 149 | 	memcpy(e, elements, sizeof(float) * 16); | 
| 150 | } | 
| 151 | 	 | 
| 152 | Matrix4::Matrix4(float t00, float t10, float t01, float t11, float x, float y) | 
| 153 | { | 
| 154 | 	setRawTransformation(t00, t10, t01, t11, x, y); | 
| 155 | } | 
| 156 |  | 
| 157 | Matrix4::Matrix4(const Matrix4 &a, const Matrix4 &b) | 
| 158 | { | 
| 159 | 	multiply(a, b, e); | 
| 160 | } | 
| 161 |  | 
| 162 | Matrix4::Matrix4(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) | 
| 163 | { | 
| 164 | 	setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); | 
| 165 | } | 
| 166 |  | 
| 167 | Matrix4 Matrix4::operator * (const Matrix4 &m) const | 
| 168 | { | 
| 169 | 	return Matrix4(*this, m); | 
| 170 | } | 
| 171 |  | 
| 172 | void Matrix4::operator *= (const Matrix4 &m) | 
| 173 | { | 
| 174 | 	float t[16]; | 
| 175 | 	multiply(*this, m, t); | 
| 176 | 	memcpy(this->e, t, sizeof(float)*16); | 
| 177 | } | 
| 178 |  | 
| 179 | const float *Matrix4::getElements() const | 
| 180 | { | 
| 181 | 	return e; | 
| 182 | } | 
| 183 |  | 
| 184 | void Matrix4::setIdentity() | 
| 185 | { | 
| 186 | 	memset(e, 0, sizeof(float)*16); | 
| 187 | 	e[15] = e[10] = e[5] = e[0] = 1; | 
| 188 | } | 
| 189 |  | 
| 190 | void Matrix4::setTranslation(float x, float y) | 
| 191 | { | 
| 192 | 	setIdentity(); | 
| 193 | 	e[12] = x; | 
| 194 | 	e[13] = y; | 
| 195 | } | 
| 196 |  | 
| 197 | void Matrix4::setRotation(float rad) | 
| 198 | { | 
| 199 | 	setIdentity(); | 
| 200 | 	float c = cosf(rad), s = sinf(rad); | 
| 201 | 	e[0] = c; | 
| 202 | 	e[4] = -s; | 
| 203 | 	e[1] = s; | 
| 204 | 	e[5] = c; | 
| 205 | } | 
| 206 |  | 
| 207 | void Matrix4::setScale(float sx, float sy) | 
| 208 | { | 
| 209 | 	setIdentity(); | 
| 210 | 	e[0] = sx; | 
| 211 | 	e[5] = sy; | 
| 212 | } | 
| 213 |  | 
| 214 | void Matrix4::setShear(float kx, float ky) | 
| 215 | { | 
| 216 | 	setIdentity(); | 
| 217 | 	e[1] = ky; | 
| 218 | 	e[4] = kx; | 
| 219 | } | 
| 220 |  | 
| 221 | void Matrix4::getApproximateScale(float &sx, float &sy) const | 
| 222 | { | 
| 223 | 	sx = sqrtf(e[0] * e[0] + e[4] * e[4]); | 
| 224 | 	sy = sqrtf(e[1] * e[1] + e[5] * e[5]); | 
| 225 | } | 
| 226 | 	 | 
| 227 | void Matrix4::setRawTransformation(float t00, float t10, float t01, float t11, float x, float y) | 
| 228 | { | 
| 229 | 	memset(e, 0, sizeof(float)*16); // zero out matrix | 
| 230 | 	e[10] = e[15] = 1.0f; | 
| 231 | 	e[0] = t00; | 
| 232 | 	e[1] = t10; | 
| 233 | 	e[4] = t01; | 
| 234 | 	e[5] = t11; | 
| 235 | 	e[12] = x; | 
| 236 | 	e[13] = y; | 
| 237 | } | 
| 238 |  | 
| 239 | void Matrix4::setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) | 
| 240 | { | 
| 241 | 	memset(e, 0, sizeof(float)*16); // zero out matrix | 
| 242 | 	float c = cosf(angle), s = sinf(angle); | 
| 243 | 	// matrix multiplication carried out on paper: | 
| 244 | 	// |1     x| |c -s    | |sx       | | 1 ky    | |1     -ox| | 
| 245 | 	// |  1   y| |s  c    | |   sy    | |kx  1    | |  1   -oy| | 
| 246 | 	// |    1  | |     1  | |      1  | |      1  | |    1    | | 
| 247 | 	// |      1| |       1| |        1| |        1| |       1 | | 
| 248 | 	//   move      rotate      scale       skew       origin | 
| 249 | 	e[10] = e[15] = 1.0f; | 
| 250 | 	e[0]  = c * sx - ky * s * sy; // = a | 
| 251 | 	e[1]  = s * sx + ky * c * sy; // = b | 
| 252 | 	e[4]  = kx * c * sx - s * sy; // = c | 
| 253 | 	e[5]  = kx * s * sx + c * sy; // = d | 
| 254 | 	e[12] = x - ox * e[0] - oy * e[4]; | 
| 255 | 	e[13] = y - ox * e[1] - oy * e[5]; | 
| 256 | } | 
| 257 |  | 
| 258 | void Matrix4::translate(float x, float y) | 
| 259 | { | 
| 260 | 	Matrix4 t; | 
| 261 | 	t.setTranslation(x, y); | 
| 262 | 	this->operator *=(t); | 
| 263 | } | 
| 264 |  | 
| 265 | void Matrix4::rotate(float rad) | 
| 266 | { | 
| 267 | 	Matrix4 t; | 
| 268 | 	t.setRotation(rad); | 
| 269 | 	this->operator *=(t); | 
| 270 | } | 
| 271 |  | 
| 272 | void Matrix4::scale(float sx, float sy) | 
| 273 | { | 
| 274 | 	Matrix4 t; | 
| 275 | 	t.setScale(sx, sy); | 
| 276 | 	this->operator *=(t); | 
| 277 | } | 
| 278 |  | 
| 279 | void Matrix4::shear(float kx, float ky) | 
| 280 | { | 
| 281 | 	Matrix4 t; | 
| 282 | 	t.setShear(kx,ky); | 
| 283 | 	this->operator *=(t); | 
| 284 | } | 
| 285 |  | 
| 286 | bool Matrix4::isAffine2DTransform() const | 
| 287 | { | 
| 288 | 	return fabsf(e[2] + e[3] + e[6] + e[7] + e[8] + e[9] + e[11] + e[14]) < 0.00001f | 
| 289 | 		&& fabsf(e[10] + e[15] - 2.0f) < 0.00001f; | 
| 290 | } | 
| 291 |  | 
| 292 | Matrix4 Matrix4::inverse() const | 
| 293 | { | 
| 294 | 	Matrix4 inv; | 
| 295 |  | 
| 296 | 	inv.e[0] = e[5]  * e[10] * e[15] - | 
| 297 | 	           e[5]  * e[11] * e[14] - | 
| 298 | 	           e[9]  * e[6]  * e[15] + | 
| 299 | 	           e[9]  * e[7]  * e[14] + | 
| 300 | 	           e[13] * e[6]  * e[11] - | 
| 301 | 	           e[13] * e[7]  * e[10]; | 
| 302 |  | 
| 303 | 	inv.e[4] = -e[4]  * e[10] * e[15] + | 
| 304 | 	            e[4]  * e[11] * e[14] + | 
| 305 | 	            e[8]  * e[6]  * e[15] - | 
| 306 | 	            e[8]  * e[7]  * e[14] - | 
| 307 | 	            e[12] * e[6]  * e[11] + | 
| 308 | 	            e[12] * e[7]  * e[10]; | 
| 309 |  | 
| 310 | 	inv.e[8] = e[4]  * e[9]  * e[15] - | 
| 311 | 	           e[4]  * e[11] * e[13] - | 
| 312 | 	           e[8]  * e[5]  * e[15] + | 
| 313 | 	           e[8]  * e[7]  * e[13] + | 
| 314 | 	           e[12] * e[5]  * e[11] - | 
| 315 | 	           e[12] * e[7]  * e[9]; | 
| 316 |  | 
| 317 | 	inv.e[12] = -e[4]  * e[9]  * e[14] + | 
| 318 | 	             e[4]  * e[10] * e[13] + | 
| 319 | 	             e[8]  * e[5]  * e[14] - | 
| 320 | 	             e[8]  * e[6]  * e[13] - | 
| 321 | 	             e[12] * e[5]  * e[10] + | 
| 322 | 	             e[12] * e[6]  * e[9]; | 
| 323 |  | 
| 324 | 	inv.e[1] = -e[1]  * e[10] * e[15] + | 
| 325 | 	            e[1]  * e[11] * e[14] + | 
| 326 | 	            e[9]  * e[2]  * e[15] - | 
| 327 | 	            e[9]  * e[3]  * e[14] - | 
| 328 | 	            e[13] * e[2]  * e[11] + | 
| 329 | 	            e[13] * e[3]  * e[10]; | 
| 330 |  | 
| 331 | 	inv.e[5] = e[0]  * e[10] * e[15] - | 
| 332 | 	           e[0]  * e[11] * e[14] - | 
| 333 | 	           e[8]  * e[2]  * e[15] + | 
| 334 | 	           e[8]  * e[3]  * e[14] + | 
| 335 | 	           e[12] * e[2]  * e[11] - | 
| 336 | 	           e[12] * e[3]  * e[10]; | 
| 337 |  | 
| 338 | 	inv.e[9] = -e[0]  * e[9]  * e[15] + | 
| 339 | 	            e[0]  * e[11] * e[13] + | 
| 340 | 	            e[8]  * e[1]  * e[15] - | 
| 341 | 	            e[8]  * e[3]  * e[13] - | 
| 342 | 	            e[12] * e[1]  * e[11] + | 
| 343 | 	            e[12] * e[3]  * e[9]; | 
| 344 |  | 
| 345 | 	inv.e[13] = e[0]  * e[9]  * e[14] - | 
| 346 | 	            e[0]  * e[10] * e[13] - | 
| 347 | 	            e[8]  * e[1]  * e[14] + | 
| 348 | 	            e[8]  * e[2]  * e[13] + | 
| 349 | 	            e[12] * e[1]  * e[10] - | 
| 350 | 	            e[12] * e[2]  * e[9]; | 
| 351 |  | 
| 352 | 	inv.e[2] = e[1]  * e[6] * e[15] - | 
| 353 | 	           e[1]  * e[7] * e[14] - | 
| 354 | 	           e[5]  * e[2] * e[15] + | 
| 355 | 	           e[5]  * e[3] * e[14] + | 
| 356 | 	           e[13] * e[2] * e[7] - | 
| 357 | 	           e[13] * e[3] * e[6]; | 
| 358 |  | 
| 359 | 	inv.e[6] = -e[0]  * e[6] * e[15] + | 
| 360 | 	            e[0]  * e[7] * e[14] + | 
| 361 | 	            e[4]  * e[2] * e[15] - | 
| 362 | 	            e[4]  * e[3] * e[14] - | 
| 363 | 	            e[12] * e[2] * e[7] + | 
| 364 | 	            e[12] * e[3] * e[6]; | 
| 365 |  | 
| 366 | 	inv.e[10] = e[0]  * e[5] * e[15] - | 
| 367 | 	            e[0]  * e[7] * e[13] - | 
| 368 | 	            e[4]  * e[1] * e[15] + | 
| 369 | 	            e[4]  * e[3] * e[13] + | 
| 370 | 	            e[12] * e[1] * e[7] - | 
| 371 | 	            e[12] * e[3] * e[5]; | 
| 372 |  | 
| 373 | 	inv.e[14] = -e[0]  * e[5] * e[14] + | 
| 374 | 	             e[0]  * e[6] * e[13] + | 
| 375 | 	             e[4]  * e[1] * e[14] - | 
| 376 | 	             e[4]  * e[2] * e[13] - | 
| 377 | 	             e[12] * e[1] * e[6] + | 
| 378 | 	             e[12] * e[2] * e[5]; | 
| 379 |  | 
| 380 | 	inv.e[3] = -e[1] * e[6] * e[11] + | 
| 381 | 	            e[1] * e[7] * e[10] + | 
| 382 | 	            e[5] * e[2] * e[11] - | 
| 383 | 	            e[5] * e[3] * e[10] - | 
| 384 | 	            e[9] * e[2] * e[7] + | 
| 385 | 	            e[9] * e[3] * e[6]; | 
| 386 |  | 
| 387 | 	inv.e[7] = e[0] * e[6] * e[11] - | 
| 388 | 	           e[0] * e[7] * e[10] - | 
| 389 | 	           e[4] * e[2] * e[11] + | 
| 390 | 	           e[4] * e[3] * e[10] + | 
| 391 | 	           e[8] * e[2] * e[7] - | 
| 392 | 	           e[8] * e[3] * e[6]; | 
| 393 |  | 
| 394 | 	inv.e[11] = -e[0] * e[5] * e[11] + | 
| 395 | 	             e[0] * e[7] * e[9] + | 
| 396 | 	             e[4] * e[1] * e[11] - | 
| 397 | 	             e[4] * e[3] * e[9] - | 
| 398 | 	             e[8] * e[1] * e[7] + | 
| 399 | 	             e[8] * e[3] * e[5]; | 
| 400 |  | 
| 401 | 	inv.e[15] = e[0] * e[5] * e[10] - | 
| 402 | 	            e[0] * e[6] * e[9] - | 
| 403 | 	            e[4] * e[1] * e[10] + | 
| 404 | 	            e[4] * e[2] * e[9] + | 
| 405 | 	            e[8] * e[1] * e[6] - | 
| 406 | 	            e[8] * e[2] * e[5]; | 
| 407 |  | 
| 408 | 	float det = e[0] * inv.e[0] + e[1] * inv.e[4] + e[2] * inv.e[8] + e[3] * inv.e[12]; | 
| 409 |  | 
| 410 | 	float invdet = 1.0f / det; | 
| 411 |  | 
| 412 | 	for (int i = 0; i < 16; i++) | 
| 413 | 		inv.e[i] *= invdet; | 
| 414 |  | 
| 415 | 	return inv; | 
| 416 | } | 
| 417 |  | 
| 418 | Matrix4 Matrix4::ortho(float left, float right, float bottom, float top, float near, float far) | 
| 419 | { | 
| 420 | 	Matrix4 m; | 
| 421 |  | 
| 422 | 	m.e[0] = 2.0f / (right - left); | 
| 423 | 	m.e[5] = 2.0f / (top - bottom); | 
| 424 | 	m.e[10] = -2.0f / (far - near); | 
| 425 |  | 
| 426 | 	m.e[12] = -(right + left) / (right - left); | 
| 427 | 	m.e[13] = -(top + bottom) / (top - bottom); | 
| 428 | 	m.e[14] = -(far + near) / (far - near); | 
| 429 |  | 
| 430 | 	return m; | 
| 431 | } | 
| 432 |  | 
| 433 | /** | 
| 434 |  * | e0 e3 e6 | | 
| 435 |  * | e1 e4 e7 | | 
| 436 |  * | e2 e5 e8 | | 
| 437 |  **/ | 
| 438 | Matrix3::Matrix3() | 
| 439 | { | 
| 440 | 	setIdentity(); | 
| 441 | } | 
| 442 |  | 
| 443 | Matrix3::Matrix3(const Matrix4 &mat4) | 
| 444 | { | 
| 445 | 	const float *mat4elems = mat4.getElements(); | 
| 446 |  | 
| 447 | 	// Column 0. | 
| 448 | 	e[0] = mat4elems[0]; | 
| 449 | 	e[1] = mat4elems[1]; | 
| 450 | 	e[2] = mat4elems[2]; | 
| 451 |  | 
| 452 | 	// Column 1. | 
| 453 | 	e[3] = mat4elems[4]; | 
| 454 | 	e[4] = mat4elems[5]; | 
| 455 | 	e[5] = mat4elems[6]; | 
| 456 |  | 
| 457 | 	// Column 2. | 
| 458 | 	e[6] = mat4elems[8]; | 
| 459 | 	e[7] = mat4elems[9]; | 
| 460 | 	e[8] = mat4elems[10]; | 
| 461 | } | 
| 462 |  | 
| 463 | Matrix3::Matrix3(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) | 
| 464 | { | 
| 465 | 	setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); | 
| 466 | } | 
| 467 |  | 
| 468 | Matrix3::~Matrix3() | 
| 469 | { | 
| 470 | } | 
| 471 |  | 
| 472 | void Matrix3::setIdentity() | 
| 473 | { | 
| 474 | 	memset(e, 0, sizeof(float) * 9); | 
| 475 | 	e[8] = e[4] = e[0] = 1.0f; | 
| 476 | } | 
| 477 |  | 
| 478 | Matrix3 Matrix3::operator * (const love::Matrix3 &m) const | 
| 479 | { | 
| 480 | 	Matrix3 t; | 
| 481 |  | 
| 482 | 	t.e[0] = (e[0]*m.e[0]) + (e[3]*m.e[1]) + (e[6]*m.e[2]); | 
| 483 | 	t.e[3] = (e[0]*m.e[3]) + (e[3]*m.e[4]) + (e[6]*m.e[5]); | 
| 484 | 	t.e[6] = (e[0]*m.e[6]) + (e[3]*m.e[7]) + (e[6]*m.e[8]); | 
| 485 |  | 
| 486 | 	t.e[1] = (e[1]*m.e[0]) + (e[4]*m.e[1]) + (e[7]*m.e[2]); | 
| 487 | 	t.e[4] = (e[1]*m.e[3]) + (e[4]*m.e[4]) + (e[7]*m.e[5]); | 
| 488 | 	t.e[7] = (e[1]*m.e[6]) + (e[4]*m.e[7]) + (e[7]*m.e[8]); | 
| 489 |  | 
| 490 | 	t.e[2] = (e[2]*m.e[0]) + (e[5]*m.e[1]) + (e[8]*m.e[2]); | 
| 491 | 	t.e[5] = (e[2]*m.e[3]) + (e[5]*m.e[4]) + (e[8]*m.e[5]); | 
| 492 | 	t.e[8] = (e[2]*m.e[6]) + (e[5]*m.e[7]) + (e[8]*m.e[8]); | 
| 493 |  | 
| 494 | 	return t; | 
| 495 | } | 
| 496 |  | 
| 497 | void Matrix3::operator *= (const Matrix3 &m) | 
| 498 | { | 
| 499 | 	Matrix3 t = (*this) * m; | 
| 500 | 	memcpy(e, t.e, sizeof(float) * 9); | 
| 501 | } | 
| 502 |  | 
| 503 | const float *Matrix3::getElements() const | 
| 504 | { | 
| 505 | 	return e; | 
| 506 | } | 
| 507 |  | 
| 508 | Matrix3 Matrix3::transposedInverse() const | 
| 509 | { | 
| 510 | 	// e0 e3 e6 | 
| 511 | 	// e1 e4 e7 | 
| 512 | 	// e2 e5 e8 | 
| 513 |  | 
| 514 | 	float det = e[0] * (e[4]*e[8] - e[7]*e[5]) | 
| 515 | 	          - e[1] * (e[3]*e[8] - e[5]*e[6]) | 
| 516 | 	          + e[2] * (e[3]*e[7] - e[4]*e[6]); | 
| 517 |  | 
| 518 | 	float invdet = 1.0f / det; | 
| 519 |  | 
| 520 | 	Matrix3 m; | 
| 521 |  | 
| 522 | 	m.e[0] =  invdet * (e[4]*e[8] - e[7]*e[5]); | 
| 523 | 	m.e[3] = -invdet * (e[1]*e[8] - e[2]*e[7]); | 
| 524 | 	m.e[6] =  invdet * (e[1]*e[5] - e[2]*e[4]); | 
| 525 | 	m.e[1] = -invdet * (e[3]*e[8] - e[5]*e[6]); | 
| 526 | 	m.e[4] =  invdet * (e[0]*e[8] - e[2]*e[6]); | 
| 527 | 	m.e[7] = -invdet * (e[0]*e[5] - e[3]*e[2]); | 
| 528 | 	m.e[2] =  invdet * (e[3]*e[7] - e[6]*e[4]); | 
| 529 | 	m.e[5] = -invdet * (e[0]*e[7] - e[6]*e[1]); | 
| 530 | 	m.e[8] =  invdet * (e[0]*e[4] - e[3]*e[1]); | 
| 531 |  | 
| 532 | 	return m; | 
| 533 | } | 
| 534 |  | 
| 535 | void Matrix3::setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) | 
| 536 | { | 
| 537 | 	float c = cosf(angle), s = sinf(angle); | 
| 538 | 	// matrix multiplication carried out on paper: | 
| 539 | 	// |1    x| |c -s  | |sx     | | 1 ky  | |1   -ox| | 
| 540 | 	// |  1  y| |s  c  | |   sy  | |kx  1  | |  1 -oy| | 
| 541 | 	// |     1| |     1| |      1| |      1| |     1 | | 
| 542 | 	//   move    rotate    scale     skew      origin | 
| 543 | 	e[0] = c * sx - ky * s * sy; // = a | 
| 544 | 	e[1] = s * sx + ky * c * sy; // = b | 
| 545 | 	e[3] = kx * c * sx - s * sy; // = c | 
| 546 | 	e[4] = kx * s * sx + c * sy; // = d | 
| 547 | 	e[6] = x - ox * e[0] - oy * e[3]; | 
| 548 | 	e[7] = y - ox * e[1] - oy * e[4]; | 
| 549 |  | 
| 550 | 	e[2] = e[5] = 0.0f; | 
| 551 | 	e[8] = 1.0f; | 
| 552 | } | 
| 553 |  | 
| 554 | } // love | 
| 555 |  |