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