1 /* 2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. 3 * Copyright (C) 2009 Torch Mobile, Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "TransformationMatrix.h" 29 30 #include "FloatPoint3D.h" 31 #include "FloatRect.h" 32 #include "FloatQuad.h" 33 #include "IntRect.h" 34 35 #include <wtf/Assertions.h> 36 #include <wtf/MathExtras.h> 37 38 namespace WebCore { 39 40 // 41 // Supporting Math Functions 42 // 43 // This is a set of function from various places (attributed inline) to do things like 44 // inversion and decomposition of a 4x4 matrix. They are used throughout the code 45 // 46 47 // 48 // Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>. 49 50 // EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code 51 // as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial 52 // or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there 53 // are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or 54 // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes 55 // with no guarantee. 56 57 typedef double Vector4[4]; 58 typedef double Vector3[3]; 59 60 const double SMALL_NUMBER = 1.e-8; 61 62 // inverse(original_matrix, inverse_matrix) 63 // 64 // calculate the inverse of a 4x4 matrix 65 // 66 // -1 67 // A = ___1__ adjoint A 68 // det A 69 70 // double = determinant2x2(double a, double b, double c, double d) 71 // 72 // calculate the determinant of a 2x2 matrix. 73 74 static double determinant2x2(double a, double b, double c, double d) 75 { 76 return a * d - b * c; 77 } 78 79 // double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3) 80 // 81 // Calculate the determinant of a 3x3 matrix 82 // in the form 83 // 84 // | a1, b1, c1 | 85 // | a2, b2, c2 | 86 // | a3, b3, c3 | 87 88 static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3) 89 { 90 return a1 * determinant2x2(b2, b3, c2, c3) 91 - b1 * determinant2x2(a2, a3, c2, c3) 92 + c1 * determinant2x2(a2, a3, b2, b3); 93 } 94 95 // double = determinant4x4(matrix) 96 // 97 // calculate the determinant of a 4x4 matrix. 98 99 static double determinant4x4(const TransformationMatrix::Matrix4& m) 100 { 101 // Assign to individual variable names to aid selecting 102 // correct elements 103 104 double a1 = m[0][0]; 105 double b1 = m[0][1]; 106 double c1 = m[0][2]; 107 double d1 = m[0][3]; 108 109 double a2 = m[1][0]; 110 double b2 = m[1][1]; 111 double c2 = m[1][2]; 112 double d2 = m[1][3]; 113 114 double a3 = m[2][0]; 115 double b3 = m[2][1]; 116 double c3 = m[2][2]; 117 double d3 = m[2][3]; 118 119 double a4 = m[3][0]; 120 double b4 = m[3][1]; 121 double c4 = m[3][2]; 122 double d4 = m[3][3]; 123 124 return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) 125 - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) 126 + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) 127 - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); 128 } 129 130 // adjoint( original_matrix, inverse_matrix ) 131 // 132 // calculate the adjoint of a 4x4 matrix 133 // 134 // Let a denote the minor determinant of matrix A obtained by 135 // ij 136 // 137 // deleting the ith row and jth column from A. 138 // 139 // i+j 140 // Let b = (-1) a 141 // ij ji 142 // 143 // The matrix B = (b ) is the adjoint of A 144 // ij 145 146 static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result) 147 { 148 // Assign to individual variable names to aid 149 // selecting correct values 150 double a1 = matrix[0][0]; 151 double b1 = matrix[0][1]; 152 double c1 = matrix[0][2]; 153 double d1 = matrix[0][3]; 154 155 double a2 = matrix[1][0]; 156 double b2 = matrix[1][1]; 157 double c2 = matrix[1][2]; 158 double d2 = matrix[1][3]; 159 160 double a3 = matrix[2][0]; 161 double b3 = matrix[2][1]; 162 double c3 = matrix[2][2]; 163 double d3 = matrix[2][3]; 164 165 double a4 = matrix[3][0]; 166 double b4 = matrix[3][1]; 167 double c4 = matrix[3][2]; 168 double d4 = matrix[3][3]; 169 170 // Row column labeling reversed since we transpose rows & columns 171 result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); 172 result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); 173 result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); 174 result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); 175 176 result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); 177 result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); 178 result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); 179 result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); 180 181 result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); 182 result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); 183 result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); 184 result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); 185 186 result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); 187 result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); 188 result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); 189 result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); 190 } 191 192 // Returns false if the matrix is not invertible 193 static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result) 194 { 195 // Calculate the adjoint matrix 196 adjoint(matrix, result); 197 198 // Calculate the 4x4 determinant 199 // If the determinant is zero, 200 // then the inverse matrix is not unique. 201 double det = determinant4x4(matrix); 202 203 if (fabs(det) < SMALL_NUMBER) 204 return false; 205 206 // Scale the adjoint matrix to get the inverse 207 208 for (int i = 0; i < 4; i++) 209 for (int j = 0; j < 4; j++) 210 result[i][j] = result[i][j] / det; 211 212 return true; 213 } 214 215 // End of code adapted from Matrix Inversion by Richard Carling 216 217 // Perform a decomposition on the passed matrix, return false if unsuccessful 218 // From Graphics Gems: unmatrix.c 219 220 // Transpose rotation portion of matrix a, return b 221 static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b) 222 { 223 for (int i = 0; i < 4; i++) 224 for (int j = 0; j < 4; j++) 225 b[i][j] = a[j][i]; 226 } 227 228 // Multiply a homogeneous point by a matrix and return the transformed point 229 static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result) 230 { 231 result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) + 232 (p[2] * m[2][0]) + (p[3] * m[3][0]); 233 result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) + 234 (p[2] * m[2][1]) + (p[3] * m[3][1]); 235 result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) + 236 (p[2] * m[2][2]) + (p[3] * m[3][2]); 237 result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) + 238 (p[2] * m[2][3]) + (p[3] * m[3][3]); 239 } 240 241 static double v3Length(Vector3 a) 242 { 243 return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2])); 244 } 245 246 static void v3Scale(Vector3 v, double desiredLength) 247 { 248 double len = v3Length(v); 249 if (len != 0) { 250 double l = desiredLength / len; 251 v[0] *= l; 252 v[1] *= l; 253 v[2] *= l; 254 } 255 } 256 257 static double v3Dot(const Vector3 a, const Vector3 b) 258 { 259 return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); 260 } 261 262 // Make a linear combination of two vectors and return the result. 263 // result = (a * ascl) + (b * bscl) 264 static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl) 265 { 266 result[0] = (ascl * a[0]) + (bscl * b[0]); 267 result[1] = (ascl * a[1]) + (bscl * b[1]); 268 result[2] = (ascl * a[2]) + (bscl * b[2]); 269 } 270 271 // Return the cross product result = a cross b */ 272 static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result) 273 { 274 result[0] = (a[1] * b[2]) - (a[2] * b[1]); 275 result[1] = (a[2] * b[0]) - (a[0] * b[2]); 276 result[2] = (a[0] * b[1]) - (a[1] * b[0]); 277 } 278 279 static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result) 280 { 281 TransformationMatrix::Matrix4 localMatrix; 282 memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4)); 283 284 // Normalize the matrix. 285 if (localMatrix[3][3] == 0) 286 return false; 287 288 int i, j; 289 for (i = 0; i < 4; i++) 290 for (j = 0; j < 4; j++) 291 localMatrix[i][j] /= localMatrix[3][3]; 292 293 // perspectiveMatrix is used to solve for perspective, but it also provides 294 // an easy way to test for singularity of the upper 3x3 component. 295 TransformationMatrix::Matrix4 perspectiveMatrix; 296 memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4)); 297 for (i = 0; i < 3; i++) 298 perspectiveMatrix[i][3] = 0; 299 perspectiveMatrix[3][3] = 1; 300 301 if (determinant4x4(perspectiveMatrix) == 0) 302 return false; 303 304 // First, isolate perspective. This is the messiest. 305 if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) { 306 // rightHandSide is the right hand side of the equation. 307 Vector4 rightHandSide; 308 rightHandSide[0] = localMatrix[0][3]; 309 rightHandSide[1] = localMatrix[1][3]; 310 rightHandSide[2] = localMatrix[2][3]; 311 rightHandSide[3] = localMatrix[3][3]; 312 313 // Solve the equation by inverting perspectiveMatrix and multiplying 314 // rightHandSide by the inverse. (This is the easiest way, not 315 // necessarily the best.) 316 TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix; 317 inverse(perspectiveMatrix, inversePerspectiveMatrix); 318 transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); 319 320 Vector4 perspectivePoint; 321 v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); 322 323 result.perspectiveX = perspectivePoint[0]; 324 result.perspectiveY = perspectivePoint[1]; 325 result.perspectiveZ = perspectivePoint[2]; 326 result.perspectiveW = perspectivePoint[3]; 327 328 // Clear the perspective partition 329 localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0; 330 localMatrix[3][3] = 1; 331 } else { 332 // No perspective. 333 result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0; 334 result.perspectiveW = 1; 335 } 336 337 // Next take care of translation (easy). 338 result.translateX = localMatrix[3][0]; 339 localMatrix[3][0] = 0; 340 result.translateY = localMatrix[3][1]; 341 localMatrix[3][1] = 0; 342 result.translateZ = localMatrix[3][2]; 343 localMatrix[3][2] = 0; 344 345 // Vector4 type and functions need to be added to the common set. 346 Vector3 row[3], pdum3; 347 348 // Now get scale and shear. 349 for (i = 0; i < 3; i++) { 350 row[i][0] = localMatrix[i][0]; 351 row[i][1] = localMatrix[i][1]; 352 row[i][2] = localMatrix[i][2]; 353 } 354 355 // Compute X scale factor and normalize first row. 356 result.scaleX = v3Length(row[0]); 357 v3Scale(row[0], 1.0); 358 359 // Compute XY shear factor and make 2nd row orthogonal to 1st. 360 result.skewXY = v3Dot(row[0], row[1]); 361 v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY); 362 363 // Now, compute Y scale and normalize 2nd row. 364 result.scaleY = v3Length(row[1]); 365 v3Scale(row[1], 1.0); 366 result.skewXY /= result.scaleY; 367 368 // Compute XZ and YZ shears, orthogonalize 3rd row. 369 result.skewXZ = v3Dot(row[0], row[2]); 370 v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ); 371 result.skewYZ = v3Dot(row[1], row[2]); 372 v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ); 373 374 // Next, get Z scale and normalize 3rd row. 375 result.scaleZ = v3Length(row[2]); 376 v3Scale(row[2], 1.0); 377 result.skewXZ /= result.scaleZ; 378 result.skewYZ /= result.scaleZ; 379 380 // At this point, the matrix (in rows[]) is orthonormal. 381 // Check for a coordinate system flip. If the determinant 382 // is -1, then negate the matrix and the scaling factors. 383 v3Cross(row[1], row[2], pdum3); 384 if (v3Dot(row[0], pdum3) < 0) { 385 for (i = 0; i < 3; i++) { 386 result.scaleX *= -1; 387 row[i][0] *= -1; 388 row[i][1] *= -1; 389 row[i][2] *= -1; 390 } 391 } 392 393 // Now, get the rotations out, as described in the gem. 394 395 // FIXME - Add the ability to return either quaternions (which are 396 // easier to recompose with) or Euler angles (rx, ry, rz), which 397 // are easier for authors to deal with. The latter will only be useful 398 // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I 399 // will leave the Euler angle code here for now. 400 401 // ret.rotateY = asin(-row[0][2]); 402 // if (cos(ret.rotateY) != 0) { 403 // ret.rotateX = atan2(row[1][2], row[2][2]); 404 // ret.rotateZ = atan2(row[0][1], row[0][0]); 405 // } else { 406 // ret.rotateX = atan2(-row[2][0], row[1][1]); 407 // ret.rotateZ = 0; 408 // } 409 410 double s, t, x, y, z, w; 411 412 t = row[0][0] + row[1][1] + row[2][2] + 1.0; 413 414 if (t > 1e-4) { 415 s = 0.5 / sqrt(t); 416 w = 0.25 / s; 417 x = (row[2][1] - row[1][2]) * s; 418 y = (row[0][2] - row[2][0]) * s; 419 z = (row[1][0] - row[0][1]) * s; 420 } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) { 421 s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx 422 x = 0.25 * s; 423 y = (row[0][1] + row[1][0]) / s; 424 z = (row[0][2] + row[2][0]) / s; 425 w = (row[2][1] - row[1][2]) / s; 426 } else if (row[1][1] > row[2][2]) { 427 s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy 428 x = (row[0][1] + row[1][0]) / s; 429 y = 0.25 * s; 430 z = (row[1][2] + row[2][1]) / s; 431 w = (row[0][2] - row[2][0]) / s; 432 } else { 433 s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz 434 x = (row[0][2] + row[2][0]) / s; 435 y = (row[1][2] + row[2][1]) / s; 436 z = 0.25 * s; 437 w = (row[1][0] - row[0][1]) / s; 438 } 439 440 result.quaternionX = x; 441 result.quaternionY = y; 442 result.quaternionZ = z; 443 result.quaternionW = w; 444 445 return true; 446 } 447 448 // Perform a spherical linear interpolation between the two 449 // passed quaternions with 0 <= t <= 1 450 static void slerp(double qa[4], const double qb[4], double t) 451 { 452 double ax, ay, az, aw; 453 double bx, by, bz, bw; 454 double cx, cy, cz, cw; 455 double angle; 456 double th, invth, scale, invscale; 457 458 ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3]; 459 bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3]; 460 461 angle = ax * bx + ay * by + az * bz + aw * bw; 462 463 if (angle < 0.0) { 464 ax = -ax; ay = -ay; 465 az = -az; aw = -aw; 466 angle = -angle; 467 } 468 469 if (angle + 1.0 > .05) { 470 if (1.0 - angle >= .05) { 471 th = acos (angle); 472 invth = 1.0 / sin (th); 473 scale = sin (th * (1.0 - t)) * invth; 474 invscale = sin (th * t) * invth; 475 } else { 476 scale = 1.0 - t; 477 invscale = t; 478 } 479 } else { 480 bx = -ay; 481 by = ax; 482 bz = -aw; 483 bw = az; 484 scale = sin(piDouble * (.5 - t)); 485 invscale = sin (piDouble * t); 486 } 487 488 cx = ax * scale + bx * invscale; 489 cy = ay * scale + by * invscale; 490 cz = az * scale + bz * invscale; 491 cw = aw * scale + bw * invscale; 492 493 qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw; 494 } 495 496 // End of Supporting Math Functions 497 498 TransformationMatrix& TransformationMatrix::scale(double s) 499 { 500 return scaleNonUniform(s, s); 501 } 502 503 TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y) 504 { 505 return rotate(rad2deg(atan2(y, x))); 506 } 507 508 TransformationMatrix& TransformationMatrix::flipX() 509 { 510 return scaleNonUniform(-1.0f, 1.0f); 511 } 512 513 TransformationMatrix& TransformationMatrix::flipY() 514 { 515 return scaleNonUniform(1.0f, -1.0f); 516 } 517 518 FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) const 519 { 520 // This is basically raytracing. We have a point in the destination 521 // plane with z=0, and we cast a ray parallel to the z-axis from that 522 // point to find the z-position at which it intersects the z=0 plane 523 // with the transform applied. Once we have that point we apply the 524 // inverse transform to find the corresponding point in the source 525 // space. 526 // 527 // Given a plane with normal Pn, and a ray starting at point R0 and 528 // with direction defined by the vector Rd, we can find the 529 // intersection point as a distance d from R0 in units of Rd by: 530 // 531 // d = -dot (Pn', R0) / dot (Pn', Rd) 532 533 double x = p.x(); 534 double y = p.y(); 535 double z = -(m13() * x + m23() * y + m43()) / m33(); 536 537 double outX = x * m11() + y * m21() + z * m31() + m41(); 538 double outY = x * m12() + y * m22() + z * m32() + m42(); 539 540 double w = x * m14() + y * m24() + z * m34() + m44(); 541 if (w != 1 && w != 0) { 542 outX /= w; 543 outY /= w; 544 } 545 546 return FloatPoint(static_cast<float>(outX), static_cast<float>(outY)); 547 } 548 549 FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const 550 { 551 FloatQuad projectedQuad; 552 projectedQuad.setP1(projectPoint(q.p1())); 553 projectedQuad.setP2(projectPoint(q.p2())); 554 projectedQuad.setP3(projectPoint(q.p3())); 555 projectedQuad.setP4(projectPoint(q.p4())); 556 return projectedQuad; 557 } 558 559 FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const 560 { 561 if (isIdentityOrTranslation()) 562 return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1])); 563 564 double x, y; 565 multVecMatrix(p.x(), p.y(), x, y); 566 return FloatPoint(static_cast<float>(x), static_cast<float>(y)); 567 } 568 569 FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const 570 { 571 if (isIdentityOrTranslation()) 572 return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]), 573 p.y() + static_cast<float>(m_matrix[3][1]), 574 p.z() + static_cast<float>(m_matrix[3][2])); 575 576 double x, y, z; 577 multVecMatrix(p.x(), p.y(), p.z(), x, y, z); 578 return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); 579 } 580 581 IntRect TransformationMatrix::mapRect(const IntRect &rect) const 582 { 583 return enclosingIntRect(mapRect(FloatRect(rect))); 584 } 585 586 FloatRect TransformationMatrix::mapRect(const FloatRect& r) const 587 { 588 if (isIdentityOrTranslation()) { 589 FloatRect mappedRect(r); 590 mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); 591 return mappedRect; 592 } 593 594 FloatQuad resultQuad = mapQuad(FloatQuad(r)); 595 return resultQuad.boundingBox(); 596 } 597 598 FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const 599 { 600 if (isIdentityOrTranslation()) { 601 FloatQuad mappedQuad(q); 602 mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); 603 return mappedQuad; 604 } 605 606 FloatQuad result; 607 result.setP1(mapPoint(q.p1())); 608 result.setP2(mapPoint(q.p2())); 609 result.setP3(mapPoint(q.p3())); 610 result.setP4(mapPoint(q.p4())); 611 return result; 612 } 613 614 TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy) 615 { 616 TransformationMatrix mat; 617 mat.m_matrix[0][0] = sx; 618 mat.m_matrix[1][1] = sy; 619 620 multLeft(mat); 621 return *this; 622 } 623 624 TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz) 625 { 626 TransformationMatrix mat; 627 mat.m_matrix[0][0] = sx; 628 mat.m_matrix[1][1] = sy; 629 mat.m_matrix[2][2] = sz; 630 631 multLeft(mat); 632 return *this; 633 } 634 635 TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle) 636 { 637 // angles are in degrees. Switch to radians 638 angle = deg2rad(angle); 639 640 angle /= 2.0f; 641 double sinA = sin(angle); 642 double cosA = cos(angle); 643 double sinA2 = sinA * sinA; 644 645 // normalize 646 double length = sqrt(x * x + y * y + z * z); 647 if (length == 0) { 648 // bad vector, just use something reasonable 649 x = 0; 650 y = 0; 651 z = 1; 652 } else if (length != 1) { 653 x /= length; 654 y /= length; 655 z /= length; 656 } 657 658 TransformationMatrix mat; 659 660 // optimize case where axis is along major axis 661 if (x == 1.0f && y == 0.0f && z == 0.0f) { 662 mat.m_matrix[0][0] = 1.0f; 663 mat.m_matrix[0][1] = 0.0f; 664 mat.m_matrix[0][2] = 0.0f; 665 mat.m_matrix[1][0] = 0.0f; 666 mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; 667 mat.m_matrix[1][2] = 2.0f * sinA * cosA; 668 mat.m_matrix[2][0] = 0.0f; 669 mat.m_matrix[2][1] = -2.0f * sinA * cosA; 670 mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; 671 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; 672 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; 673 mat.m_matrix[3][3] = 1.0f; 674 } else if (x == 0.0f && y == 1.0f && z == 0.0f) { 675 mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; 676 mat.m_matrix[0][1] = 0.0f; 677 mat.m_matrix[0][2] = -2.0f * sinA * cosA; 678 mat.m_matrix[1][0] = 0.0f; 679 mat.m_matrix[1][1] = 1.0f; 680 mat.m_matrix[1][2] = 0.0f; 681 mat.m_matrix[2][0] = 2.0f * sinA * cosA; 682 mat.m_matrix[2][1] = 0.0f; 683 mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; 684 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; 685 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; 686 mat.m_matrix[3][3] = 1.0f; 687 } else if (x == 0.0f && y == 0.0f && z == 1.0f) { 688 mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; 689 mat.m_matrix[0][1] = 2.0f * sinA * cosA; 690 mat.m_matrix[0][2] = 0.0f; 691 mat.m_matrix[1][0] = -2.0f * sinA * cosA; 692 mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; 693 mat.m_matrix[1][2] = 0.0f; 694 mat.m_matrix[2][0] = 0.0f; 695 mat.m_matrix[2][1] = 0.0f; 696 mat.m_matrix[2][2] = 1.0f; 697 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; 698 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; 699 mat.m_matrix[3][3] = 1.0f; 700 } else { 701 double x2 = x*x; 702 double y2 = y*y; 703 double z2 = z*z; 704 705 mat.m_matrix[0][0] = 1.0f - 2.0f * (y2 + z2) * sinA2; 706 mat.m_matrix[0][1] = 2.0f * (x * y * sinA2 + z * sinA * cosA); 707 mat.m_matrix[0][2] = 2.0f * (x * z * sinA2 - y * sinA * cosA); 708 mat.m_matrix[1][0] = 2.0f * (y * x * sinA2 - z * sinA * cosA); 709 mat.m_matrix[1][1] = 1.0f - 2.0f * (z2 + x2) * sinA2; 710 mat.m_matrix[1][2] = 2.0f * (y * z * sinA2 + x * sinA * cosA); 711 mat.m_matrix[2][0] = 2.0f * (z * x * sinA2 + y * sinA * cosA); 712 mat.m_matrix[2][1] = 2.0f * (z * y * sinA2 - x * sinA * cosA); 713 mat.m_matrix[2][2] = 1.0f - 2.0f * (x2 + y2) * sinA2; 714 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; 715 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; 716 mat.m_matrix[3][3] = 1.0f; 717 } 718 multLeft(mat); 719 return *this; 720 } 721 722 TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz) 723 { 724 // angles are in degrees. Switch to radians 725 rx = deg2rad(rx); 726 ry = deg2rad(ry); 727 rz = deg2rad(rz); 728 729 TransformationMatrix mat; 730 731 rz /= 2.0f; 732 double sinA = sin(rz); 733 double cosA = cos(rz); 734 double sinA2 = sinA * sinA; 735 736 mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; 737 mat.m_matrix[0][1] = 2.0f * sinA * cosA; 738 mat.m_matrix[0][2] = 0.0f; 739 mat.m_matrix[1][0] = -2.0f * sinA * cosA; 740 mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; 741 mat.m_matrix[1][2] = 0.0f; 742 mat.m_matrix[2][0] = 0.0f; 743 mat.m_matrix[2][1] = 0.0f; 744 mat.m_matrix[2][2] = 1.0f; 745 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; 746 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; 747 mat.m_matrix[3][3] = 1.0f; 748 749 TransformationMatrix rmat(mat); 750 751 ry /= 2.0f; 752 sinA = sin(ry); 753 cosA = cos(ry); 754 sinA2 = sinA * sinA; 755 756 mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; 757 mat.m_matrix[0][1] = 0.0f; 758 mat.m_matrix[0][2] = -2.0f * sinA * cosA; 759 mat.m_matrix[1][0] = 0.0f; 760 mat.m_matrix[1][1] = 1.0f; 761 mat.m_matrix[1][2] = 0.0f; 762 mat.m_matrix[2][0] = 2.0f * sinA * cosA; 763 mat.m_matrix[2][1] = 0.0f; 764 mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; 765 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; 766 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; 767 mat.m_matrix[3][3] = 1.0f; 768 769 rmat.multLeft(mat); 770 771 rx /= 2.0f; 772 sinA = sin(rx); 773 cosA = cos(rx); 774 sinA2 = sinA * sinA; 775 776 mat.m_matrix[0][0] = 1.0f; 777 mat.m_matrix[0][1] = 0.0f; 778 mat.m_matrix[0][2] = 0.0f; 779 mat.m_matrix[1][0] = 0.0f; 780 mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; 781 mat.m_matrix[1][2] = 2.0f * sinA * cosA; 782 mat.m_matrix[2][0] = 0.0f; 783 mat.m_matrix[2][1] = -2.0f * sinA * cosA; 784 mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; 785 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; 786 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; 787 mat.m_matrix[3][3] = 1.0f; 788 789 rmat.multLeft(mat); 790 791 multLeft(rmat); 792 return *this; 793 } 794 795 TransformationMatrix& TransformationMatrix::translate(double tx, double ty) 796 { 797 m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0]; 798 m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1]; 799 m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2]; 800 m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3]; 801 return *this; 802 } 803 804 TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz) 805 { 806 m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0]; 807 m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1]; 808 m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2]; 809 m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3]; 810 return *this; 811 } 812 813 TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty) 814 { 815 if (tx != 0) { 816 m_matrix[0][0] += m_matrix[0][3] * tx; 817 m_matrix[1][0] += m_matrix[1][3] * tx; 818 m_matrix[2][0] += m_matrix[2][3] * tx; 819 m_matrix[3][0] += m_matrix[3][3] * tx; 820 } 821 822 if (ty != 0) { 823 m_matrix[0][1] += m_matrix[0][3] * ty; 824 m_matrix[1][1] += m_matrix[1][3] * ty; 825 m_matrix[2][1] += m_matrix[2][3] * ty; 826 m_matrix[3][1] += m_matrix[3][3] * ty; 827 } 828 829 return *this; 830 } 831 832 TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz) 833 { 834 translateRight(tx, ty); 835 if (tz != 0) { 836 m_matrix[0][2] += m_matrix[0][3] * tz; 837 m_matrix[1][2] += m_matrix[1][3] * tz; 838 m_matrix[2][2] += m_matrix[2][3] * tz; 839 m_matrix[3][2] += m_matrix[3][3] * tz; 840 } 841 842 return *this; 843 } 844 845 TransformationMatrix& TransformationMatrix::skew(double sx, double sy) 846 { 847 // angles are in degrees. Switch to radians 848 sx = deg2rad(sx); 849 sy = deg2rad(sy); 850 851 TransformationMatrix mat; 852 mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row 853 mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row 854 855 multLeft(mat); 856 return *this; 857 } 858 859 TransformationMatrix& TransformationMatrix::applyPerspective(double p) 860 { 861 TransformationMatrix mat; 862 if (p != 0) 863 mat.m_matrix[2][3] = -1/p; 864 865 multLeft(mat); 866 return *this; 867 } 868 869 TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to) 870 { 871 ASSERT(!from.isEmpty()); 872 return TransformationMatrix(to.width() / from.width(), 873 0, 0, 874 to.height() / from.height(), 875 to.x() - from.x(), 876 to.y() - from.y()); 877 } 878 879 // 880 // *this = mat * *this 881 // 882 TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix& mat) 883 { 884 Matrix4 tmp; 885 886 tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0] 887 + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]); 888 tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1] 889 + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]); 890 tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2] 891 + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]); 892 tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3] 893 + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]); 894 895 tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0] 896 + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]); 897 tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1] 898 + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]); 899 tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2] 900 + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]); 901 tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3] 902 + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]); 903 904 tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0] 905 + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]); 906 tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1] 907 + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]); 908 tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2] 909 + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]); 910 tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3] 911 + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]); 912 913 tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0] 914 + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]); 915 tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1] 916 + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]); 917 tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2] 918 + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]); 919 tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3] 920 + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]); 921 922 setMatrix(tmp); 923 return *this; 924 } 925 926 void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const 927 { 928 resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0]; 929 resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1]; 930 double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3]; 931 if (w != 1 && w != 0) { 932 resultX /= w; 933 resultY /= w; 934 } 935 } 936 937 void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const 938 { 939 resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; 940 resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; 941 resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2]; 942 double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3]; 943 if (w != 1 && w != 0) { 944 resultX /= w; 945 resultY /= w; 946 resultZ /= w; 947 } 948 } 949 950 bool TransformationMatrix::isInvertible() const 951 { 952 if (isIdentityOrTranslation()) 953 return true; 954 955 double det = WebCore::determinant4x4(m_matrix); 956 957 if (fabs(det) < SMALL_NUMBER) 958 return false; 959 960 return true; 961 } 962 963 TransformationMatrix TransformationMatrix::inverse() const 964 { 965 if (isIdentityOrTranslation()) { 966 // identity matrix 967 if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0) 968 return TransformationMatrix(); 969 970 // translation 971 return TransformationMatrix(1, 0, 0, 0, 972 0, 1, 0, 0, 973 0, 0, 1, 0, 974 -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1); 975 } 976 977 TransformationMatrix invMat; 978 bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix); 979 if (!inverted) 980 return TransformationMatrix(); 981 982 return invMat; 983 } 984 985 void TransformationMatrix::makeAffine() 986 { 987 m_matrix[0][2] = 0; 988 m_matrix[0][3] = 0; 989 990 m_matrix[1][2] = 0; 991 m_matrix[1][3] = 0; 992 993 m_matrix[2][0] = 0; 994 m_matrix[2][1] = 0; 995 m_matrix[2][2] = 1; 996 m_matrix[2][3] = 0; 997 998 m_matrix[3][2] = 0; 999 m_matrix[3][3] = 1; 1000 } 1001 1002 AffineTransform TransformationMatrix::toAffineTransform() const 1003 { 1004 return AffineTransform(m_matrix[0][0], m_matrix[0][1], m_matrix[1][0], 1005 m_matrix[1][1], m_matrix[3][0], m_matrix[3][1]); 1006 } 1007 1008 static inline void blendFloat(double& from, double to, double progress) 1009 { 1010 if (from != to) 1011 from = from + (to - from) * progress; 1012 } 1013 1014 void TransformationMatrix::blend(const TransformationMatrix& from, double progress) 1015 { 1016 if (from.isIdentity() && isIdentity()) 1017 return; 1018 1019 // decompose 1020 DecomposedType fromDecomp; 1021 DecomposedType toDecomp; 1022 from.decompose(fromDecomp); 1023 decompose(toDecomp); 1024 1025 // interpolate 1026 blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress); 1027 blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress); 1028 blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress); 1029 blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress); 1030 blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress); 1031 blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress); 1032 blendFloat(fromDecomp.translateX, toDecomp.translateX, progress); 1033 blendFloat(fromDecomp.translateY, toDecomp.translateY, progress); 1034 blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress); 1035 blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress); 1036 blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress); 1037 blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress); 1038 blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress); 1039 1040 slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress); 1041 1042 // recompose 1043 recompose(fromDecomp); 1044 } 1045 1046 bool TransformationMatrix::decompose(DecomposedType& decomp) const 1047 { 1048 if (isIdentity()) { 1049 memset(&decomp, 0, sizeof(decomp)); 1050 decomp.perspectiveW = 1; 1051 decomp.scaleX = 1; 1052 decomp.scaleY = 1; 1053 decomp.scaleZ = 1; 1054 } 1055 1056 if (!WebCore::decompose(m_matrix, decomp)) 1057 return false; 1058 return true; 1059 } 1060 1061 void TransformationMatrix::recompose(const DecomposedType& decomp) 1062 { 1063 makeIdentity(); 1064 1065 // first apply perspective 1066 m_matrix[0][3] = (float) decomp.perspectiveX; 1067 m_matrix[1][3] = (float) decomp.perspectiveY; 1068 m_matrix[2][3] = (float) decomp.perspectiveZ; 1069 m_matrix[3][3] = (float) decomp.perspectiveW; 1070 1071 // now translate 1072 translate3d((float) decomp.translateX, (float) decomp.translateY, (float) decomp.translateZ); 1073 1074 // apply rotation 1075 double xx = decomp.quaternionX * decomp.quaternionX; 1076 double xy = decomp.quaternionX * decomp.quaternionY; 1077 double xz = decomp.quaternionX * decomp.quaternionZ; 1078 double xw = decomp.quaternionX * decomp.quaternionW; 1079 double yy = decomp.quaternionY * decomp.quaternionY; 1080 double yz = decomp.quaternionY * decomp.quaternionZ; 1081 double yw = decomp.quaternionY * decomp.quaternionW; 1082 double zz = decomp.quaternionZ * decomp.quaternionZ; 1083 double zw = decomp.quaternionZ * decomp.quaternionW; 1084 1085 // Construct a composite rotation matrix from the quaternion values 1086 TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, 1087 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0, 1088 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0, 1089 0, 0, 0, 1); 1090 1091 multLeft(rotationMatrix); 1092 1093 // now apply skew 1094 if (decomp.skewYZ) { 1095 TransformationMatrix tmp; 1096 tmp.setM32((float) decomp.skewYZ); 1097 multLeft(tmp); 1098 } 1099 1100 if (decomp.skewXZ) { 1101 TransformationMatrix tmp; 1102 tmp.setM31((float) decomp.skewXZ); 1103 multLeft(tmp); 1104 } 1105 1106 if (decomp.skewXY) { 1107 TransformationMatrix tmp; 1108 tmp.setM21((float) decomp.skewXY); 1109 multLeft(tmp); 1110 } 1111 1112 // finally, apply scale 1113 scale3d((float) decomp.scaleX, (float) decomp.scaleY, (float) decomp.scaleZ); 1114 } 1115 1116 } 1117