| 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 | |