2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (C) 2009 Torch Mobile, Inc.
4 * Copyright (C) 2013 Google Inc. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "platform/transforms/TransformationMatrix.h"
31 #include "platform/geometry/FloatBox.h"
32 #include "platform/geometry/FloatQuad.h"
33 #include "platform/geometry/FloatRect.h"
34 #include "platform/geometry/IntRect.h"
35 #include "platform/geometry/LayoutRect.h"
36 #include "platform/transforms/AffineTransform.h"
38 #include "wtf/Assertions.h"
39 #include "wtf/MathExtras.h"
42 #include <emmintrin.h>
48 // Supporting Math Functions
50 // This is a set of function from various places (attributed inline) to do things like
51 // inversion and decomposition of a 4x4 matrix. They are used throughout the code
55 // Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
57 // EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
58 // as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
59 // or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
60 // are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
61 // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
64 // A clarification about the storage of matrix elements
66 // This class uses a 2 dimensional array internally to store the elements of the matrix. The first index into
67 // the array refers to the column that the element lies in; the second index refers to the row.
69 // In other words, this is the layout of the matrix:
71 // | m_matrix[0][0] m_matrix[1][0] m_matrix[2][0] m_matrix[3][0] |
72 // | m_matrix[0][1] m_matrix[1][1] m_matrix[2][1] m_matrix[3][1] |
73 // | m_matrix[0][2] m_matrix[1][2] m_matrix[2][2] m_matrix[3][2] |
74 // | m_matrix[0][3] m_matrix[1][3] m_matrix[2][3] m_matrix[3][3] |
76 typedef double Vector4
[4];
77 typedef double Vector3
[3];
79 const double SMALL_NUMBER
= 1.e
-8;
81 // inverse(original_matrix, inverse_matrix)
83 // calculate the inverse of a 4x4 matrix
86 // A = ___1__ adjoint A
89 // double = determinant2x2(double a, double b, double c, double d)
91 // calculate the determinant of a 2x2 matrix.
93 static double determinant2x2(double a
, double b
, double c
, double d
)
98 // double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
100 // Calculate the determinant of a 3x3 matrix
107 static double determinant3x3(double a1
, double a2
, double a3
, double b1
, double b2
, double b3
, double c1
, double c2
, double c3
)
109 return a1
* determinant2x2(b2
, b3
, c2
, c3
)
110 - b1
* determinant2x2(a2
, a3
, c2
, c3
)
111 + c1
* determinant2x2(a2
, a3
, b2
, b3
);
114 // double = determinant4x4(matrix)
116 // calculate the determinant of a 4x4 matrix.
118 static double determinant4x4(const TransformationMatrix::Matrix4
& m
)
120 // Assign to individual variable names to aid selecting
143 return a1
* determinant3x3(b2
, b3
, b4
, c2
, c3
, c4
, d2
, d3
, d4
)
144 - b1
* determinant3x3(a2
, a3
, a4
, c2
, c3
, c4
, d2
, d3
, d4
)
145 + c1
* determinant3x3(a2
, a3
, a4
, b2
, b3
, b4
, d2
, d3
, d4
)
146 - d1
* determinant3x3(a2
, a3
, a4
, b2
, b3
, b4
, c2
, c3
, c4
);
149 // adjoint( original_matrix, inverse_matrix )
151 // calculate the adjoint of a 4x4 matrix
153 // Let a denote the minor determinant of matrix A obtained by
156 // deleting the ith row and jth column from A.
162 // The matrix B = (b ) is the adjoint of A
165 static inline void adjoint(const TransformationMatrix::Matrix4
& matrix
, TransformationMatrix::Matrix4
& result
)
167 // Assign to individual variable names to aid
168 // selecting correct values
169 double a1
= matrix
[0][0];
170 double b1
= matrix
[0][1];
171 double c1
= matrix
[0][2];
172 double d1
= matrix
[0][3];
174 double a2
= matrix
[1][0];
175 double b2
= matrix
[1][1];
176 double c2
= matrix
[1][2];
177 double d2
= matrix
[1][3];
179 double a3
= matrix
[2][0];
180 double b3
= matrix
[2][1];
181 double c3
= matrix
[2][2];
182 double d3
= matrix
[2][3];
184 double a4
= matrix
[3][0];
185 double b4
= matrix
[3][1];
186 double c4
= matrix
[3][2];
187 double d4
= matrix
[3][3];
189 // Row column labeling reversed since we transpose rows & columns
190 result
[0][0] = determinant3x3(b2
, b3
, b4
, c2
, c3
, c4
, d2
, d3
, d4
);
191 result
[1][0] = - determinant3x3(a2
, a3
, a4
, c2
, c3
, c4
, d2
, d3
, d4
);
192 result
[2][0] = determinant3x3(a2
, a3
, a4
, b2
, b3
, b4
, d2
, d3
, d4
);
193 result
[3][0] = - determinant3x3(a2
, a3
, a4
, b2
, b3
, b4
, c2
, c3
, c4
);
195 result
[0][1] = - determinant3x3(b1
, b3
, b4
, c1
, c3
, c4
, d1
, d3
, d4
);
196 result
[1][1] = determinant3x3(a1
, a3
, a4
, c1
, c3
, c4
, d1
, d3
, d4
);
197 result
[2][1] = - determinant3x3(a1
, a3
, a4
, b1
, b3
, b4
, d1
, d3
, d4
);
198 result
[3][1] = determinant3x3(a1
, a3
, a4
, b1
, b3
, b4
, c1
, c3
, c4
);
200 result
[0][2] = determinant3x3(b1
, b2
, b4
, c1
, c2
, c4
, d1
, d2
, d4
);
201 result
[1][2] = - determinant3x3(a1
, a2
, a4
, c1
, c2
, c4
, d1
, d2
, d4
);
202 result
[2][2] = determinant3x3(a1
, a2
, a4
, b1
, b2
, b4
, d1
, d2
, d4
);
203 result
[3][2] = - determinant3x3(a1
, a2
, a4
, b1
, b2
, b4
, c1
, c2
, c4
);
205 result
[0][3] = - determinant3x3(b1
, b2
, b3
, c1
, c2
, c3
, d1
, d2
, d3
);
206 result
[1][3] = determinant3x3(a1
, a2
, a3
, c1
, c2
, c3
, d1
, d2
, d3
);
207 result
[2][3] = - determinant3x3(a1
, a2
, a3
, b1
, b2
, b3
, d1
, d2
, d3
);
208 result
[3][3] = determinant3x3(a1
, a2
, a3
, b1
, b2
, b3
, c1
, c2
, c3
);
211 // Returns false if the matrix is not invertible
212 static bool inverse(const TransformationMatrix::Matrix4
& matrix
, TransformationMatrix::Matrix4
& result
)
214 // Calculate the 4x4 determinant
215 // If the determinant is zero,
216 // then the inverse matrix is not unique.
217 double det
= determinant4x4(matrix
);
219 if (fabs(det
) < SMALL_NUMBER
)
223 double rdet
= 1 / det
;
224 const double* mat
= &(matrix
[0][0]);
225 double* pr
= &(result
[0][0]);
228 // m11, m12, m13, m14
229 // m21, m22, m23, m24
230 // m31, m32, m33, m34
231 // m41, m42, m43, m44
232 "ld1 {v16.2d - v19.2d}, [%[mat]], 64 \n\t"
233 "ld1 {v20.2d - v23.2d}, [%[mat]] \n\t"
234 "ins v30.d[0], %[rdet] \n\t"
235 // Determinant: right mat2x2
236 "trn1 v0.2d, v17.2d, v21.2d \n\t"
237 "trn2 v1.2d, v19.2d, v23.2d \n\t"
238 "trn2 v2.2d, v17.2d, v21.2d \n\t"
239 "trn1 v3.2d, v19.2d, v23.2d \n\t"
240 "trn2 v5.2d, v21.2d, v23.2d \n\t"
241 "trn1 v4.2d, v17.2d, v19.2d \n\t"
242 "trn2 v6.2d, v17.2d, v19.2d \n\t"
243 "trn1 v7.2d, v21.2d, v23.2d \n\t"
244 "trn2 v25.2d, v23.2d, v21.2d \n\t"
245 "trn1 v27.2d, v23.2d, v21.2d \n\t"
246 "fmul v0.2d, v0.2d, v1.2d \n\t"
247 "fmul v1.2d, v4.2d, v5.2d \n\t"
248 "fmls v0.2d, v2.2d, v3.2d \n\t"
249 "fmul v2.2d, v4.2d, v25.2d \n\t"
250 "fmls v1.2d, v6.2d, v7.2d \n\t"
251 "fmls v2.2d, v6.2d, v27.2d \n\t"
253 // v24: A11A12, v25: A13A14
254 // v26: A21A22, v27: A23A24
255 "fmul v3.2d, v18.2d, v0.d[1] \n\t"
256 "fmul v4.2d, v16.2d, v0.d[1] \n\t"
257 "fmul v5.2d, v16.2d, v1.d[1] \n\t"
258 "fmul v6.2d, v16.2d, v2.d[1] \n\t"
259 "fmls v3.2d, v20.2d, v1.d[1] \n\t"
260 "fmls v4.2d, v20.2d, v2.d[0] \n\t"
261 "fmls v5.2d, v18.2d, v2.d[0] \n\t"
262 "fmls v6.2d, v18.2d, v1.d[0] \n\t"
263 "fmla v3.2d, v22.2d, v2.d[1] \n\t"
264 "fmla v4.2d, v22.2d, v1.d[0] \n\t"
265 "fmla v5.2d, v22.2d, v0.d[0] \n\t"
266 "fmla v6.2d, v20.2d, v0.d[0] \n\t"
267 "fneg v3.2d, v3.2d \n\t"
268 "fneg v5.2d, v5.2d \n\t"
269 "trn1 v26.2d, v3.2d, v4.2d \n\t"
270 "trn1 v27.2d, v5.2d, v6.2d \n\t"
271 "trn2 v24.2d, v3.2d, v4.2d \n\t"
272 "trn2 v25.2d, v5.2d, v6.2d \n\t"
273 "fneg v24.2d, v24.2d \n\t"
274 "fneg v25.2d, v25.2d \n\t"
276 // v24: I11I12, v25: I13I14
277 // v26: I21I22, v27: I23I24
278 "fmul v24.2d, v24.2d, v30.d[0] \n\t"
279 "fmul v25.2d, v25.2d, v30.d[0] \n\t"
280 "fmul v26.2d, v26.2d, v30.d[0] \n\t"
281 "fmul v27.2d, v27.2d, v30.d[0] \n\t"
282 "st1 {v24.2d - v27.2d}, [%[pr]], 64 \n\t"
283 // Determinant: left mat2x2
284 "trn1 v0.2d, v16.2d, v20.2d \n\t"
285 "trn2 v1.2d, v18.2d, v22.2d \n\t"
286 "trn2 v2.2d, v16.2d, v20.2d \n\t"
287 "trn1 v3.2d, v18.2d, v22.2d \n\t"
288 "trn2 v5.2d, v20.2d, v22.2d \n\t"
289 "trn1 v4.2d, v16.2d, v18.2d \n\t"
290 "trn2 v6.2d, v16.2d, v18.2d \n\t"
291 "trn1 v7.2d, v20.2d, v22.2d \n\t"
292 "trn2 v25.2d, v22.2d, v20.2d \n\t"
293 "trn1 v27.2d, v22.2d, v20.2d \n\t"
294 "fmul v0.2d, v0.2d, v1.2d \n\t"
295 "fmul v1.2d, v4.2d, v5.2d \n\t"
296 "fmls v0.2d, v2.2d, v3.2d \n\t"
297 "fmul v2.2d, v4.2d, v25.2d \n\t"
298 "fmls v1.2d, v6.2d, v7.2d \n\t"
299 "fmls v2.2d, v6.2d, v27.2d \n\t"
301 // v24: A31A32, v25: A33A34
302 // v26: A41A42, v27: A43A44
303 "fmul v3.2d, v19.2d, v0.d[1] \n\t"
304 "fmul v4.2d, v17.2d, v0.d[1] \n\t"
305 "fmul v5.2d, v17.2d, v1.d[1] \n\t"
306 "fmul v6.2d, v17.2d, v2.d[1] \n\t"
307 "fmls v3.2d, v21.2d, v1.d[1] \n\t"
308 "fmls v4.2d, v21.2d, v2.d[0] \n\t"
309 "fmls v5.2d, v19.2d, v2.d[0] \n\t"
310 "fmls v6.2d, v19.2d, v1.d[0] \n\t"
311 "fmla v3.2d, v23.2d, v2.d[1] \n\t"
312 "fmla v4.2d, v23.2d, v1.d[0] \n\t"
313 "fmla v5.2d, v23.2d, v0.d[0] \n\t"
314 "fmla v6.2d, v21.2d, v0.d[0] \n\t"
315 "fneg v3.2d, v3.2d \n\t"
316 "fneg v5.2d, v5.2d \n\t"
317 "trn1 v26.2d, v3.2d, v4.2d \n\t"
318 "trn1 v27.2d, v5.2d, v6.2d \n\t"
319 "trn2 v24.2d, v3.2d, v4.2d \n\t"
320 "trn2 v25.2d, v5.2d, v6.2d \n\t"
321 "fneg v24.2d, v24.2d \n\t"
322 "fneg v25.2d, v25.2d \n\t"
324 // v24: I31I32, v25: I33I34
325 // v26: I41I42, v27: I43I44
326 "fmul v24.2d, v24.2d, v30.d[0] \n\t"
327 "fmul v25.2d, v25.2d, v30.d[0] \n\t"
328 "fmul v26.2d, v26.2d, v30.d[0] \n\t"
329 "fmul v27.2d, v27.2d, v30.d[0] \n\t"
330 "st1 {v24.2d - v27.2d}, [%[pr]] \n\t"
331 : [mat
]"+r"(mat
), [pr
]"+r"(pr
)
333 : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18",
334 "v19", "v20", "v21", "v22", "v23", "24", "25", "v26", "v27", "v28", "v29", "v30"
337 // Calculate the adjoint matrix
338 adjoint(matrix
, result
);
340 // Scale the adjoint matrix to get the inverse
341 for (int i
= 0; i
< 4; i
++)
342 for (int j
= 0; j
< 4; j
++)
343 result
[i
][j
] = result
[i
][j
] / det
;
348 // End of code adapted from Matrix Inversion by Richard Carling
350 // Perform a decomposition on the passed matrix, return false if unsuccessful
351 // From Graphics Gems: unmatrix.c
353 // Transpose rotation portion of matrix a, return b
354 static void transposeMatrix4(const TransformationMatrix::Matrix4
& a
, TransformationMatrix::Matrix4
& b
)
356 for (int i
= 0; i
< 4; i
++)
357 for (int j
= 0; j
< 4; j
++)
361 // Multiply a homogeneous point by a matrix and return the transformed point
362 static void v4MulPointByMatrix(const Vector4 p
, const TransformationMatrix::Matrix4
& m
, Vector4 result
)
364 result
[0] = (p
[0] * m
[0][0]) + (p
[1] * m
[1][0]) +
365 (p
[2] * m
[2][0]) + (p
[3] * m
[3][0]);
366 result
[1] = (p
[0] * m
[0][1]) + (p
[1] * m
[1][1]) +
367 (p
[2] * m
[2][1]) + (p
[3] * m
[3][1]);
368 result
[2] = (p
[0] * m
[0][2]) + (p
[1] * m
[1][2]) +
369 (p
[2] * m
[2][2]) + (p
[3] * m
[3][2]);
370 result
[3] = (p
[0] * m
[0][3]) + (p
[1] * m
[1][3]) +
371 (p
[2] * m
[2][3]) + (p
[3] * m
[3][3]);
374 static double v3Length(Vector3 a
)
376 return std::sqrt((a
[0] * a
[0]) + (a
[1] * a
[1]) + (a
[2] * a
[2]));
379 static void v3Scale(Vector3 v
, double desiredLength
)
381 double len
= v3Length(v
);
383 double l
= desiredLength
/ len
;
390 static double v3Dot(const Vector3 a
, const Vector3 b
)
392 return (a
[0] * b
[0]) + (a
[1] * b
[1]) + (a
[2] * b
[2]);
395 // Make a linear combination of two vectors and return the result.
396 // result = (a * ascl) + (b * bscl)
397 static void v3Combine(const Vector3 a
, const Vector3 b
, Vector3 result
, double ascl
, double bscl
)
399 result
[0] = (ascl
* a
[0]) + (bscl
* b
[0]);
400 result
[1] = (ascl
* a
[1]) + (bscl
* b
[1]);
401 result
[2] = (ascl
* a
[2]) + (bscl
* b
[2]);
404 // Return the cross product result = a cross b */
405 static void v3Cross(const Vector3 a
, const Vector3 b
, Vector3 result
)
407 result
[0] = (a
[1] * b
[2]) - (a
[2] * b
[1]);
408 result
[1] = (a
[2] * b
[0]) - (a
[0] * b
[2]);
409 result
[2] = (a
[0] * b
[1]) - (a
[1] * b
[0]);
412 static bool decompose(const TransformationMatrix::Matrix4
& mat
, TransformationMatrix::DecomposedType
& result
)
414 TransformationMatrix::Matrix4 localMatrix
;
415 memcpy(localMatrix
, mat
, sizeof(TransformationMatrix::Matrix4
));
417 // Normalize the matrix.
418 if (localMatrix
[3][3] == 0)
422 for (i
= 0; i
< 4; i
++)
423 for (j
= 0; j
< 4; j
++)
424 localMatrix
[i
][j
] /= localMatrix
[3][3];
426 // perspectiveMatrix is used to solve for perspective, but it also provides
427 // an easy way to test for singularity of the upper 3x3 component.
428 TransformationMatrix::Matrix4 perspectiveMatrix
;
429 memcpy(perspectiveMatrix
, localMatrix
, sizeof(TransformationMatrix::Matrix4
));
430 for (i
= 0; i
< 3; i
++)
431 perspectiveMatrix
[i
][3] = 0;
432 perspectiveMatrix
[3][3] = 1;
434 if (determinant4x4(perspectiveMatrix
) == 0)
437 // First, isolate perspective. This is the messiest.
438 if (localMatrix
[0][3] != 0 || localMatrix
[1][3] != 0 || localMatrix
[2][3] != 0) {
439 // rightHandSide is the right hand side of the equation.
440 Vector4 rightHandSide
;
441 rightHandSide
[0] = localMatrix
[0][3];
442 rightHandSide
[1] = localMatrix
[1][3];
443 rightHandSide
[2] = localMatrix
[2][3];
444 rightHandSide
[3] = localMatrix
[3][3];
446 // Solve the equation by inverting perspectiveMatrix and multiplying
447 // rightHandSide by the inverse. (This is the easiest way, not
448 // necessarily the best.)
449 TransformationMatrix::Matrix4 inversePerspectiveMatrix
, transposedInversePerspectiveMatrix
;
450 if (!inverse(perspectiveMatrix
, inversePerspectiveMatrix
))
452 transposeMatrix4(inversePerspectiveMatrix
, transposedInversePerspectiveMatrix
);
454 Vector4 perspectivePoint
;
455 v4MulPointByMatrix(rightHandSide
, transposedInversePerspectiveMatrix
, perspectivePoint
);
457 result
.perspectiveX
= perspectivePoint
[0];
458 result
.perspectiveY
= perspectivePoint
[1];
459 result
.perspectiveZ
= perspectivePoint
[2];
460 result
.perspectiveW
= perspectivePoint
[3];
462 // Clear the perspective partition
463 localMatrix
[0][3] = localMatrix
[1][3] = localMatrix
[2][3] = 0;
464 localMatrix
[3][3] = 1;
467 result
.perspectiveX
= result
.perspectiveY
= result
.perspectiveZ
= 0;
468 result
.perspectiveW
= 1;
471 // Next take care of translation (easy).
472 result
.translateX
= localMatrix
[3][0];
473 localMatrix
[3][0] = 0;
474 result
.translateY
= localMatrix
[3][1];
475 localMatrix
[3][1] = 0;
476 result
.translateZ
= localMatrix
[3][2];
477 localMatrix
[3][2] = 0;
479 // Vector4 type and functions need to be added to the common set.
480 Vector3 row
[3], pdum3
;
482 // Now get scale and shear.
483 for (i
= 0; i
< 3; i
++) {
484 row
[i
][0] = localMatrix
[i
][0];
485 row
[i
][1] = localMatrix
[i
][1];
486 row
[i
][2] = localMatrix
[i
][2];
489 // Compute X scale factor and normalize first row.
490 result
.scaleX
= v3Length(row
[0]);
491 v3Scale(row
[0], 1.0);
493 // Compute XY shear factor and make 2nd row orthogonal to 1st.
494 result
.skewXY
= v3Dot(row
[0], row
[1]);
495 v3Combine(row
[1], row
[0], row
[1], 1.0, -result
.skewXY
);
497 // Now, compute Y scale and normalize 2nd row.
498 result
.scaleY
= v3Length(row
[1]);
499 v3Scale(row
[1], 1.0);
500 result
.skewXY
/= result
.scaleY
;
502 // Compute XZ and YZ shears, orthogonalize 3rd row.
503 result
.skewXZ
= v3Dot(row
[0], row
[2]);
504 v3Combine(row
[2], row
[0], row
[2], 1.0, -result
.skewXZ
);
505 result
.skewYZ
= v3Dot(row
[1], row
[2]);
506 v3Combine(row
[2], row
[1], row
[2], 1.0, -result
.skewYZ
);
508 // Next, get Z scale and normalize 3rd row.
509 result
.scaleZ
= v3Length(row
[2]);
510 v3Scale(row
[2], 1.0);
511 result
.skewXZ
/= result
.scaleZ
;
512 result
.skewYZ
/= result
.scaleZ
;
514 // At this point, the matrix (in rows[]) is orthonormal.
515 // Check for a coordinate system flip. If the determinant
516 // is -1, then negate the matrix and the scaling factors.
517 v3Cross(row
[1], row
[2], pdum3
);
518 if (v3Dot(row
[0], pdum3
) < 0) {
524 for (i
= 0; i
< 3; i
++) {
531 // Now, get the rotations out, as described in the gem.
533 // FIXME - Add the ability to return either quaternions (which are
534 // easier to recompose with) or Euler angles (rx, ry, rz), which
535 // are easier for authors to deal with. The latter will only be useful
536 // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
537 // will leave the Euler angle code here for now.
539 // ret.rotateY = asin(-row[0][2]);
540 // if (cos(ret.rotateY) != 0) {
541 // ret.rotateX = atan2(row[1][2], row[2][2]);
542 // ret.rotateZ = atan2(row[0][1], row[0][0]);
544 // ret.rotateX = atan2(-row[2][0], row[1][1]);
548 double s
, t
, x
, y
, z
, w
;
550 t
= row
[0][0] + row
[1][1] + row
[2][2] + 1.0;
553 s
= 0.5 / std::sqrt(t
);
555 x
= (row
[2][1] - row
[1][2]) * s
;
556 y
= (row
[0][2] - row
[2][0]) * s
;
557 z
= (row
[1][0] - row
[0][1]) * s
;
558 } else if (row
[0][0] > row
[1][1] && row
[0][0] > row
[2][2]) {
559 s
= std::sqrt(1.0 + row
[0][0] - row
[1][1] - row
[2][2]) * 2.0; // S=4*qx
561 y
= (row
[0][1] + row
[1][0]) / s
;
562 z
= (row
[0][2] + row
[2][0]) / s
;
563 w
= (row
[2][1] - row
[1][2]) / s
;
564 } else if (row
[1][1] > row
[2][2]) {
565 s
= std::sqrt(1.0 + row
[1][1] - row
[0][0] - row
[2][2]) * 2.0; // S=4*qy
566 x
= (row
[0][1] + row
[1][0]) / s
;
568 z
= (row
[1][2] + row
[2][1]) / s
;
569 w
= (row
[0][2] - row
[2][0]) / s
;
571 s
= std::sqrt(1.0 + row
[2][2] - row
[0][0] - row
[1][1]) * 2.0; // S=4*qz
572 x
= (row
[0][2] + row
[2][0]) / s
;
573 y
= (row
[1][2] + row
[2][1]) / s
;
575 w
= (row
[1][0] - row
[0][1]) / s
;
578 result
.quaternionX
= x
;
579 result
.quaternionY
= y
;
580 result
.quaternionZ
= z
;
581 result
.quaternionW
= w
;
586 // Perform a spherical linear interpolation between the two
587 // passed quaternions with 0 <= t <= 1
588 static void slerp(double qa
[4], const double qb
[4], double t
)
590 double ax
, ay
, az
, aw
;
591 double bx
, by
, bz
, bw
;
592 double cx
, cy
, cz
, cw
;
595 ax
= qa
[0]; ay
= qa
[1]; az
= qa
[2]; aw
= qa
[3];
596 bx
= qb
[0]; by
= qb
[1]; bz
= qb
[2]; bw
= qb
[3];
598 product
= ax
* bx
+ ay
* by
+ az
* bz
+ aw
* bw
;
600 // Clamp product to -1.0 <= product <= 1.0.
601 product
= std::min(std::max(product
, -1.0), 1.0);
603 const double epsilon
= 1e-5;
604 if (std::abs(product
- 1.0) < epsilon
) {
605 // Result is qa, so just return
609 double denom
= std::sqrt(1.0 - product
* product
);
610 double theta
= std::acos(product
);
611 double w
= std::sin(t
* theta
) * (1.0 / denom
);
613 double scale1
= std::cos(t
* theta
) - product
* w
;
616 cx
= ax
* scale1
+ bx
* scale2
;
617 cy
= ay
* scale1
+ by
* scale2
;
618 cz
= az
* scale1
+ bz
* scale2
;
619 cw
= aw
* scale1
+ bw
* scale2
;
621 qa
[0] = cx
; qa
[1] = cy
; qa
[2] = cz
; qa
[3] = cw
;
624 // End of Supporting Math Functions
626 TransformationMatrix::TransformationMatrix(const AffineTransform
& t
)
628 setMatrix(t
.a(), t
.b(), t
.c(), t
.d(), t
.e(), t
.f());
631 TransformationMatrix
& TransformationMatrix::scale(double s
)
633 return scaleNonUniform(s
, s
);
636 FloatPoint
TransformationMatrix::projectPoint(const FloatPoint
& p
, bool* clamped
) const
638 // This is basically raytracing. We have a point in the destination
639 // plane with z=0, and we cast a ray parallel to the z-axis from that
640 // point to find the z-position at which it intersects the z=0 plane
641 // with the transform applied. Once we have that point we apply the
642 // inverse transform to find the corresponding point in the source
645 // Given a plane with normal Pn, and a ray starting at point R0 and
646 // with direction defined by the vector Rd, we can find the
647 // intersection point as a distance d from R0 in units of Rd by:
649 // d = -dot (Pn', R0) / dot (Pn', Rd)
654 // In this case, the projection plane is parallel to the ray we are trying to
655 // trace, and there is no well-defined value for the projection.
661 double z
= -(m13() * x
+ m23() * y
+ m43()) / m33();
663 // FIXME: use multVecMatrix()
664 double outX
= x
* m11() + y
* m21() + z
* m31() + m41();
665 double outY
= x
* m12() + y
* m22() + z
* m32() + m42();
667 double w
= x
* m14() + y
* m24() + z
* m34() + m44();
669 // Using int max causes overflow when other code uses the projected point. To
670 // represent infinity yet reduce the risk of overflow, we use a large but
671 // not-too-large number here when clamping.
672 const int largeNumber
= 100000000 / kFixedPointDenominator
;
673 outX
= copysign(largeNumber
, outX
);
674 outY
= copysign(largeNumber
, outY
);
682 return FloatPoint(static_cast<float>(outX
), static_cast<float>(outY
));
685 FloatQuad
TransformationMatrix::projectQuad(const FloatQuad
& q
, bool* clamped
) const
687 FloatQuad projectedQuad
;
689 bool clamped1
= false;
690 bool clamped2
= false;
691 bool clamped3
= false;
692 bool clamped4
= false;
694 projectedQuad
.setP1(projectPoint(q
.p1(), &clamped1
));
695 projectedQuad
.setP2(projectPoint(q
.p2(), &clamped2
));
696 projectedQuad
.setP3(projectPoint(q
.p3(), &clamped3
));
697 projectedQuad
.setP4(projectPoint(q
.p4(), &clamped4
));
700 *clamped
= clamped1
|| clamped2
|| clamped3
|| clamped4
;
702 // If all points on the quad had w < 0, then the entire quad would not be visible to the projected surface.
703 bool everythingWasClipped
= clamped1
&& clamped2
&& clamped3
&& clamped4
;
704 if (everythingWasClipped
)
707 return projectedQuad
;
710 static float clampEdgeValue(float f
)
712 ASSERT(!std::isnan(f
));
713 return std::min
<float>(std::max
<float>(f
, (-LayoutUnit::max() / 2).toFloat()), (LayoutUnit::max() / 2).toFloat());
716 LayoutRect
TransformationMatrix::clampedBoundsOfProjectedQuad(const FloatQuad
& q
) const
718 FloatRect mappedQuadBounds
= projectQuad(q
).boundingBox();
720 float left
= clampEdgeValue(floorf(mappedQuadBounds
.x()));
721 float top
= clampEdgeValue(floorf(mappedQuadBounds
.y()));
724 if (std::isinf(mappedQuadBounds
.x()) && std::isinf(mappedQuadBounds
.width()))
725 right
= (LayoutUnit::max() / 2).toFloat();
727 right
= clampEdgeValue(ceilf(mappedQuadBounds
.maxX()));
730 if (std::isinf(mappedQuadBounds
.y()) && std::isinf(mappedQuadBounds
.height()))
731 bottom
= (LayoutUnit::max() / 2).toFloat();
733 bottom
= clampEdgeValue(ceilf(mappedQuadBounds
.maxY()));
735 return LayoutRect(LayoutUnit::clamp(left
), LayoutUnit::clamp(top
), LayoutUnit::clamp(right
- left
), LayoutUnit::clamp(bottom
- top
));
738 void TransformationMatrix::transformBox(FloatBox
& box
) const
741 bool firstPoint
= true;
742 for (size_t i
= 0; i
< 2; ++i
) {
743 for (size_t j
= 0; j
< 2; ++j
) {
744 for (size_t k
= 0; k
< 2; ++k
) {
745 FloatPoint3D
point(box
.x(), box
.y(), box
.z());
746 point
+= FloatPoint3D(i
* box
.width(), j
* box
.height(), k
* box
.depth());
747 point
= mapPoint(point
);
749 bounds
.setOrigin(point
);
752 bounds
.expandTo(point
);
760 FloatPoint
TransformationMatrix::mapPoint(const FloatPoint
& p
) const
762 if (isIdentityOrTranslation())
763 return FloatPoint(p
.x() + static_cast<float>(m_matrix
[3][0]), p
.y() + static_cast<float>(m_matrix
[3][1]));
765 return internalMapPoint(p
);
768 FloatPoint3D
TransformationMatrix::mapPoint(const FloatPoint3D
& p
) const
770 if (isIdentityOrTranslation())
771 return FloatPoint3D(p
.x() + static_cast<float>(m_matrix
[3][0]),
772 p
.y() + static_cast<float>(m_matrix
[3][1]),
773 p
.z() + static_cast<float>(m_matrix
[3][2]));
775 return internalMapPoint(p
);
778 IntRect
TransformationMatrix::mapRect(const IntRect
&rect
) const
780 return enclosingIntRect(mapRect(FloatRect(rect
)));
783 LayoutRect
TransformationMatrix::mapRect(const LayoutRect
& r
) const
785 return enclosingLayoutRect(mapRect(FloatRect(r
)));
788 FloatRect
TransformationMatrix::mapRect(const FloatRect
& r
) const
790 if (isIdentityOrTranslation()) {
791 FloatRect
mappedRect(r
);
792 mappedRect
.move(static_cast<float>(m_matrix
[3][0]), static_cast<float>(m_matrix
[3][1]));
798 float maxX
= r
.maxX();
799 float maxY
= r
.maxY();
800 result
.setP1(internalMapPoint(FloatPoint(r
.x(), r
.y())));
801 result
.setP2(internalMapPoint(FloatPoint(maxX
, r
.y())));
802 result
.setP3(internalMapPoint(FloatPoint(maxX
, maxY
)));
803 result
.setP4(internalMapPoint(FloatPoint(r
.x(), maxY
)));
805 return result
.boundingBox();
808 FloatQuad
TransformationMatrix::mapQuad(const FloatQuad
& q
) const
810 if (isIdentityOrTranslation()) {
811 FloatQuad
mappedQuad(q
);
812 mappedQuad
.move(static_cast<float>(m_matrix
[3][0]), static_cast<float>(m_matrix
[3][1]));
817 result
.setP1(internalMapPoint(q
.p1()));
818 result
.setP2(internalMapPoint(q
.p2()));
819 result
.setP3(internalMapPoint(q
.p3()));
820 result
.setP4(internalMapPoint(q
.p4()));
824 TransformationMatrix
& TransformationMatrix::scaleNonUniform(double sx
, double sy
)
826 m_matrix
[0][0] *= sx
;
827 m_matrix
[0][1] *= sx
;
828 m_matrix
[0][2] *= sx
;
829 m_matrix
[0][3] *= sx
;
831 m_matrix
[1][0] *= sy
;
832 m_matrix
[1][1] *= sy
;
833 m_matrix
[1][2] *= sy
;
834 m_matrix
[1][3] *= sy
;
838 TransformationMatrix
& TransformationMatrix::scale3d(double sx
, double sy
, double sz
)
840 scaleNonUniform(sx
, sy
);
842 m_matrix
[2][0] *= sz
;
843 m_matrix
[2][1] *= sz
;
844 m_matrix
[2][2] *= sz
;
845 m_matrix
[2][3] *= sz
;
849 TransformationMatrix
& TransformationMatrix::rotate3d(double x
, double y
, double z
, double angle
)
851 // Normalize the axis of rotation
852 double length
= std::sqrt(x
* x
+ y
* y
+ z
* z
);
854 // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied.
856 } else if (length
!= 1) {
862 // Angles are in degrees. Switch to radians.
863 angle
= deg2rad(angle
);
865 double sinTheta
= std::sin(angle
);
866 double cosTheta
= std::cos(angle
);
868 TransformationMatrix mat
;
870 // Optimize cases where the axis is along a major axis
871 if (x
== 1.0 && y
== 0.0 && z
== 0.0) {
872 mat
.m_matrix
[0][0] = 1.0;
873 mat
.m_matrix
[0][1] = 0.0;
874 mat
.m_matrix
[0][2] = 0.0;
875 mat
.m_matrix
[1][0] = 0.0;
876 mat
.m_matrix
[1][1] = cosTheta
;
877 mat
.m_matrix
[1][2] = sinTheta
;
878 mat
.m_matrix
[2][0] = 0.0;
879 mat
.m_matrix
[2][1] = -sinTheta
;
880 mat
.m_matrix
[2][2] = cosTheta
;
881 mat
.m_matrix
[0][3] = mat
.m_matrix
[1][3] = mat
.m_matrix
[2][3] = 0.0;
882 mat
.m_matrix
[3][0] = mat
.m_matrix
[3][1] = mat
.m_matrix
[3][2] = 0.0;
883 mat
.m_matrix
[3][3] = 1.0;
884 } else if (x
== 0.0 && y
== 1.0 && z
== 0.0) {
885 mat
.m_matrix
[0][0] = cosTheta
;
886 mat
.m_matrix
[0][1] = 0.0;
887 mat
.m_matrix
[0][2] = -sinTheta
;
888 mat
.m_matrix
[1][0] = 0.0;
889 mat
.m_matrix
[1][1] = 1.0;
890 mat
.m_matrix
[1][2] = 0.0;
891 mat
.m_matrix
[2][0] = sinTheta
;
892 mat
.m_matrix
[2][1] = 0.0;
893 mat
.m_matrix
[2][2] = cosTheta
;
894 mat
.m_matrix
[0][3] = mat
.m_matrix
[1][3] = mat
.m_matrix
[2][3] = 0.0;
895 mat
.m_matrix
[3][0] = mat
.m_matrix
[3][1] = mat
.m_matrix
[3][2] = 0.0;
896 mat
.m_matrix
[3][3] = 1.0;
897 } else if (x
== 0.0 && y
== 0.0 && z
== 1.0) {
898 mat
.m_matrix
[0][0] = cosTheta
;
899 mat
.m_matrix
[0][1] = sinTheta
;
900 mat
.m_matrix
[0][2] = 0.0;
901 mat
.m_matrix
[1][0] = -sinTheta
;
902 mat
.m_matrix
[1][1] = cosTheta
;
903 mat
.m_matrix
[1][2] = 0.0;
904 mat
.m_matrix
[2][0] = 0.0;
905 mat
.m_matrix
[2][1] = 0.0;
906 mat
.m_matrix
[2][2] = 1.0;
907 mat
.m_matrix
[0][3] = mat
.m_matrix
[1][3] = mat
.m_matrix
[2][3] = 0.0;
908 mat
.m_matrix
[3][0] = mat
.m_matrix
[3][1] = mat
.m_matrix
[3][2] = 0.0;
909 mat
.m_matrix
[3][3] = 1.0;
911 // This case is the rotation about an arbitrary unit vector.
913 // Formula is adapted from Wikipedia article on Rotation matrix,
914 // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
916 // An alternate resource with the same matrix: http://www.fastgraph.com/makegames/3drotation/
918 double oneMinusCosTheta
= 1 - cosTheta
;
919 mat
.m_matrix
[0][0] = cosTheta
+ x
* x
* oneMinusCosTheta
;
920 mat
.m_matrix
[0][1] = y
* x
* oneMinusCosTheta
+ z
* sinTheta
;
921 mat
.m_matrix
[0][2] = z
* x
* oneMinusCosTheta
- y
* sinTheta
;
922 mat
.m_matrix
[1][0] = x
* y
* oneMinusCosTheta
- z
* sinTheta
;
923 mat
.m_matrix
[1][1] = cosTheta
+ y
* y
* oneMinusCosTheta
;
924 mat
.m_matrix
[1][2] = z
* y
* oneMinusCosTheta
+ x
* sinTheta
;
925 mat
.m_matrix
[2][0] = x
* z
* oneMinusCosTheta
+ y
* sinTheta
;
926 mat
.m_matrix
[2][1] = y
* z
* oneMinusCosTheta
- x
* sinTheta
;
927 mat
.m_matrix
[2][2] = cosTheta
+ z
* z
* oneMinusCosTheta
;
928 mat
.m_matrix
[0][3] = mat
.m_matrix
[1][3] = mat
.m_matrix
[2][3] = 0.0;
929 mat
.m_matrix
[3][0] = mat
.m_matrix
[3][1] = mat
.m_matrix
[3][2] = 0.0;
930 mat
.m_matrix
[3][3] = 1.0;
936 TransformationMatrix
& TransformationMatrix::rotate3d(double rx
, double ry
, double rz
)
938 // Angles are in degrees. Switch to radians.
943 TransformationMatrix mat
;
945 double sinTheta
= std::sin(rz
);
946 double cosTheta
= std::cos(rz
);
948 mat
.m_matrix
[0][0] = cosTheta
;
949 mat
.m_matrix
[0][1] = sinTheta
;
950 mat
.m_matrix
[0][2] = 0.0;
951 mat
.m_matrix
[1][0] = -sinTheta
;
952 mat
.m_matrix
[1][1] = cosTheta
;
953 mat
.m_matrix
[1][2] = 0.0;
954 mat
.m_matrix
[2][0] = 0.0;
955 mat
.m_matrix
[2][1] = 0.0;
956 mat
.m_matrix
[2][2] = 1.0;
957 mat
.m_matrix
[0][3] = mat
.m_matrix
[1][3] = mat
.m_matrix
[2][3] = 0.0;
958 mat
.m_matrix
[3][0] = mat
.m_matrix
[3][1] = mat
.m_matrix
[3][2] = 0.0;
959 mat
.m_matrix
[3][3] = 1.0;
961 TransformationMatrix
rmat(mat
);
963 sinTheta
= std::sin(ry
);
964 cosTheta
= std::cos(ry
);
966 mat
.m_matrix
[0][0] = cosTheta
;
967 mat
.m_matrix
[0][1] = 0.0;
968 mat
.m_matrix
[0][2] = -sinTheta
;
969 mat
.m_matrix
[1][0] = 0.0;
970 mat
.m_matrix
[1][1] = 1.0;
971 mat
.m_matrix
[1][2] = 0.0;
972 mat
.m_matrix
[2][0] = sinTheta
;
973 mat
.m_matrix
[2][1] = 0.0;
974 mat
.m_matrix
[2][2] = cosTheta
;
975 mat
.m_matrix
[0][3] = mat
.m_matrix
[1][3] = mat
.m_matrix
[2][3] = 0.0;
976 mat
.m_matrix
[3][0] = mat
.m_matrix
[3][1] = mat
.m_matrix
[3][2] = 0.0;
977 mat
.m_matrix
[3][3] = 1.0;
981 sinTheta
= std::sin(rx
);
982 cosTheta
= std::cos(rx
);
984 mat
.m_matrix
[0][0] = 1.0;
985 mat
.m_matrix
[0][1] = 0.0;
986 mat
.m_matrix
[0][2] = 0.0;
987 mat
.m_matrix
[1][0] = 0.0;
988 mat
.m_matrix
[1][1] = cosTheta
;
989 mat
.m_matrix
[1][2] = sinTheta
;
990 mat
.m_matrix
[2][0] = 0.0;
991 mat
.m_matrix
[2][1] = -sinTheta
;
992 mat
.m_matrix
[2][2] = cosTheta
;
993 mat
.m_matrix
[0][3] = mat
.m_matrix
[1][3] = mat
.m_matrix
[2][3] = 0.0;
994 mat
.m_matrix
[3][0] = mat
.m_matrix
[3][1] = mat
.m_matrix
[3][2] = 0.0;
995 mat
.m_matrix
[3][3] = 1.0;
1003 TransformationMatrix
& TransformationMatrix::translate(double tx
, double ty
)
1005 m_matrix
[3][0] += tx
* m_matrix
[0][0] + ty
* m_matrix
[1][0];
1006 m_matrix
[3][1] += tx
* m_matrix
[0][1] + ty
* m_matrix
[1][1];
1007 m_matrix
[3][2] += tx
* m_matrix
[0][2] + ty
* m_matrix
[1][2];
1008 m_matrix
[3][3] += tx
* m_matrix
[0][3] + ty
* m_matrix
[1][3];
1012 TransformationMatrix
& TransformationMatrix::translate3d(double tx
, double ty
, double tz
)
1014 m_matrix
[3][0] += tx
* m_matrix
[0][0] + ty
* m_matrix
[1][0] + tz
* m_matrix
[2][0];
1015 m_matrix
[3][1] += tx
* m_matrix
[0][1] + ty
* m_matrix
[1][1] + tz
* m_matrix
[2][1];
1016 m_matrix
[3][2] += tx
* m_matrix
[0][2] + ty
* m_matrix
[1][2] + tz
* m_matrix
[2][2];
1017 m_matrix
[3][3] += tx
* m_matrix
[0][3] + ty
* m_matrix
[1][3] + tz
* m_matrix
[2][3];
1021 TransformationMatrix
& TransformationMatrix::translateRight(double tx
, double ty
)
1024 m_matrix
[0][0] += m_matrix
[0][3] * tx
;
1025 m_matrix
[1][0] += m_matrix
[1][3] * tx
;
1026 m_matrix
[2][0] += m_matrix
[2][3] * tx
;
1027 m_matrix
[3][0] += m_matrix
[3][3] * tx
;
1031 m_matrix
[0][1] += m_matrix
[0][3] * ty
;
1032 m_matrix
[1][1] += m_matrix
[1][3] * ty
;
1033 m_matrix
[2][1] += m_matrix
[2][3] * ty
;
1034 m_matrix
[3][1] += m_matrix
[3][3] * ty
;
1040 TransformationMatrix
& TransformationMatrix::translateRight3d(double tx
, double ty
, double tz
)
1042 translateRight(tx
, ty
);
1044 m_matrix
[0][2] += m_matrix
[0][3] * tz
;
1045 m_matrix
[1][2] += m_matrix
[1][3] * tz
;
1046 m_matrix
[2][2] += m_matrix
[2][3] * tz
;
1047 m_matrix
[3][2] += m_matrix
[3][3] * tz
;
1053 TransformationMatrix
& TransformationMatrix::skew(double sx
, double sy
)
1055 // angles are in degrees. Switch to radians
1059 TransformationMatrix mat
;
1060 mat
.m_matrix
[0][1] = std::tan(sy
); // note that the y shear goes in the first row
1061 mat
.m_matrix
[1][0] = std::tan(sx
); // and the x shear in the second row
1067 TransformationMatrix
& TransformationMatrix::applyPerspective(double p
)
1069 TransformationMatrix mat
;
1071 mat
.m_matrix
[2][3] = -1/p
;
1077 TransformationMatrix
& TransformationMatrix::applyTransformOrigin(double x
, double y
, double z
)
1079 translateRight3d(x
, y
, z
);
1080 translate3d(-x
, -y
, -z
);
1084 // this = mat * this.
1085 TransformationMatrix
& TransformationMatrix::multiply(const TransformationMatrix
& mat
)
1088 double* rightMatrix
= &(m_matrix
[0][0]);
1089 const double* leftMatrix
= &(mat
.m_matrix
[0][0]);
1091 // Load mat.m_matrix to v16 - v23.
1092 // Load this.m_matrix to v24 - v31.
1093 // Result: this = mat * this
1094 // | v0, v1 | | v16, v17 | | v24, v25 |
1095 // | v2, v3 | = | v18, v19 | * | v26, v27 |
1096 // | v4, v5 | | v20, v21 | | v28, v29 |
1097 // | v6, v7 | | v22, v23 | | v30, v31 |
1098 "mov x9, %[rightMatrix] \t\n"
1099 "ld1 {v16.2d - v19.2d}, [%[leftMatrix]], 64 \t\n"
1100 "ld1 {v20.2d - v23.2d}, [%[leftMatrix]] \t\n"
1101 "ld1 {v24.2d - v27.2d}, [%[rightMatrix]], 64 \t\n"
1102 "ld1 {v28.2d - v31.2d}, [%[rightMatrix]] \t\n"
1104 "fmul v0.2d, v24.2d, v16.d[0] \t\n"
1105 "fmul v1.2d, v25.2d, v16.d[0] \t\n"
1106 "fmul v2.2d, v24.2d, v18.d[0] \t\n"
1107 "fmul v3.2d, v25.2d, v18.d[0] \t\n"
1108 "fmul v4.2d, v24.2d, v20.d[0] \t\n"
1109 "fmul v5.2d, v25.2d, v20.d[0] \t\n"
1110 "fmul v6.2d, v24.2d, v22.d[0] \t\n"
1111 "fmul v7.2d, v25.2d, v22.d[0] \t\n"
1113 "fmla v0.2d, v26.2d, v16.d[1] \t\n"
1114 "fmla v1.2d, v27.2d, v16.d[1] \t\n"
1115 "fmla v2.2d, v26.2d, v18.d[1] \t\n"
1116 "fmla v3.2d, v27.2d, v18.d[1] \t\n"
1117 "fmla v4.2d, v26.2d, v20.d[1] \t\n"
1118 "fmla v5.2d, v27.2d, v20.d[1] \t\n"
1119 "fmla v6.2d, v26.2d, v22.d[1] \t\n"
1120 "fmla v7.2d, v27.2d, v22.d[1] \t\n"
1122 "fmla v0.2d, v28.2d, v17.d[0] \t\n"
1123 "fmla v1.2d, v29.2d, v17.d[0] \t\n"
1124 "fmla v2.2d, v28.2d, v19.d[0] \t\n"
1125 "fmla v3.2d, v29.2d, v19.d[0] \t\n"
1126 "fmla v4.2d, v28.2d, v21.d[0] \t\n"
1127 "fmla v5.2d, v29.2d, v21.d[0] \t\n"
1128 "fmla v6.2d, v28.2d, v23.d[0] \t\n"
1129 "fmla v7.2d, v29.2d, v23.d[0] \t\n"
1131 "fmla v0.2d, v30.2d, v17.d[1] \t\n"
1132 "fmla v1.2d, v31.2d, v17.d[1] \t\n"
1133 "fmla v2.2d, v30.2d, v19.d[1] \t\n"
1134 "fmla v3.2d, v31.2d, v19.d[1] \t\n"
1135 "fmla v4.2d, v30.2d, v21.d[1] \t\n"
1136 "fmla v5.2d, v31.2d, v21.d[1] \t\n"
1137 "fmla v6.2d, v30.2d, v23.d[1] \t\n"
1138 "fmla v7.2d, v31.2d, v23.d[1] \t\n"
1140 "st1 {v0.2d - v3.2d}, [x9], 64 \t\n"
1141 "st1 {v4.2d - v7.2d}, [x9] \t\n"
1142 : [leftMatrix
]"+r"(leftMatrix
), [rightMatrix
]"+r"(rightMatrix
)
1144 : "memory", "x9", "v16", "v17", "v18", "v19", "v20", "v21", "v22",
1145 "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
1146 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7"
1148 #elif CPU(APPLE_ARMV7S)
1149 double* leftMatrix
= &(m_matrix
[0][0]);
1150 const double* rightMatrix
= &(mat
.m_matrix
[0][0]);
1151 asm volatile (// First row of leftMatrix.
1152 "mov r3, %[leftMatrix]\n\t"
1153 "vld1.64 { d16-d19 }, [%[leftMatrix], :128]!\n\t"
1154 "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t"
1155 "vmul.f64 d4, d0, d16\n\t"
1156 "vld1.64 { d20-d23 }, [%[leftMatrix], :128]!\n\t"
1157 "vmla.f64 d4, d1, d20\n\t"
1158 "vld1.64 { d24-d27 }, [%[leftMatrix], :128]!\n\t"
1159 "vmla.f64 d4, d2, d24\n\t"
1160 "vld1.64 { d28-d31 }, [%[leftMatrix], :128]!\n\t"
1161 "vmla.f64 d4, d3, d28\n\t"
1163 "vmul.f64 d5, d0, d17\n\t"
1164 "vmla.f64 d5, d1, d21\n\t"
1165 "vmla.f64 d5, d2, d25\n\t"
1166 "vmla.f64 d5, d3, d29\n\t"
1168 "vmul.f64 d6, d0, d18\n\t"
1169 "vmla.f64 d6, d1, d22\n\t"
1170 "vmla.f64 d6, d2, d26\n\t"
1171 "vmla.f64 d6, d3, d30\n\t"
1173 "vmul.f64 d7, d0, d19\n\t"
1174 "vmla.f64 d7, d1, d23\n\t"
1175 "vmla.f64 d7, d2, d27\n\t"
1176 "vmla.f64 d7, d3, d31\n\t"
1177 "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t"
1178 "vst1.64 { d4-d7 }, [r3, :128]!\n\t"
1180 // Second row of leftMatrix.
1181 "vmul.f64 d4, d0, d16\n\t"
1182 "vmla.f64 d4, d1, d20\n\t"
1183 "vmla.f64 d4, d2, d24\n\t"
1184 "vmla.f64 d4, d3, d28\n\t"
1186 "vmul.f64 d5, d0, d17\n\t"
1187 "vmla.f64 d5, d1, d21\n\t"
1188 "vmla.f64 d5, d2, d25\n\t"
1189 "vmla.f64 d5, d3, d29\n\t"
1191 "vmul.f64 d6, d0, d18\n\t"
1192 "vmla.f64 d6, d1, d22\n\t"
1193 "vmla.f64 d6, d2, d26\n\t"
1194 "vmla.f64 d6, d3, d30\n\t"
1196 "vmul.f64 d7, d0, d19\n\t"
1197 "vmla.f64 d7, d1, d23\n\t"
1198 "vmla.f64 d7, d2, d27\n\t"
1199 "vmla.f64 d7, d3, d31\n\t"
1200 "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t"
1201 "vst1.64 { d4-d7 }, [r3, :128]!\n\t"
1203 // Third row of leftMatrix.
1204 "vmul.f64 d4, d0, d16\n\t"
1205 "vmla.f64 d4, d1, d20\n\t"
1206 "vmla.f64 d4, d2, d24\n\t"
1207 "vmla.f64 d4, d3, d28\n\t"
1209 "vmul.f64 d5, d0, d17\n\t"
1210 "vmla.f64 d5, d1, d21\n\t"
1211 "vmla.f64 d5, d2, d25\n\t"
1212 "vmla.f64 d5, d3, d29\n\t"
1214 "vmul.f64 d6, d0, d18\n\t"
1215 "vmla.f64 d6, d1, d22\n\t"
1216 "vmla.f64 d6, d2, d26\n\t"
1217 "vmla.f64 d6, d3, d30\n\t"
1219 "vmul.f64 d7, d0, d19\n\t"
1220 "vmla.f64 d7, d1, d23\n\t"
1221 "vmla.f64 d7, d2, d27\n\t"
1222 "vmla.f64 d7, d3, d31\n\t"
1223 "vld1.64 { d0-d3}, [%[rightMatrix], :128]\n\t"
1224 "vst1.64 { d4-d7 }, [r3, :128]!\n\t"
1226 // Fourth and last row of leftMatrix.
1227 "vmul.f64 d4, d0, d16\n\t"
1228 "vmla.f64 d4, d1, d20\n\t"
1229 "vmla.f64 d4, d2, d24\n\t"
1230 "vmla.f64 d4, d3, d28\n\t"
1232 "vmul.f64 d5, d0, d17\n\t"
1233 "vmla.f64 d5, d1, d21\n\t"
1234 "vmla.f64 d5, d2, d25\n\t"
1235 "vmla.f64 d5, d3, d29\n\t"
1237 "vmul.f64 d6, d0, d18\n\t"
1238 "vmla.f64 d6, d1, d22\n\t"
1239 "vmla.f64 d6, d2, d26\n\t"
1240 "vmla.f64 d6, d3, d30\n\t"
1242 "vmul.f64 d7, d0, d19\n\t"
1243 "vmla.f64 d7, d1, d23\n\t"
1244 "vmla.f64 d7, d2, d27\n\t"
1245 "vmla.f64 d7, d3, d31\n\t"
1246 "vst1.64 { d4-d7 }, [r3, :128]\n\t"
1247 : [leftMatrix
]"+r"(leftMatrix
), [rightMatrix
]"+r"(rightMatrix
)
1249 : "memory", "r3", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31");
1250 #elif defined(TRANSFORMATION_MATRIX_USE_X86_64_SSE2)
1251 // x86_64 has 16 XMM registers which is enough to do the multiplication fully in registers.
1252 __m128d matrixBlockA
= _mm_load_pd(&(m_matrix
[0][0]));
1253 __m128d matrixBlockC
= _mm_load_pd(&(m_matrix
[1][0]));
1254 __m128d matrixBlockE
= _mm_load_pd(&(m_matrix
[2][0]));
1255 __m128d matrixBlockG
= _mm_load_pd(&(m_matrix
[3][0]));
1258 __m128d otherMatrixFirstParam
= _mm_set1_pd(mat
.m_matrix
[0][0]);
1259 __m128d otherMatrixSecondParam
= _mm_set1_pd(mat
.m_matrix
[0][1]);
1260 __m128d otherMatrixThirdParam
= _mm_set1_pd(mat
.m_matrix
[0][2]);
1261 __m128d otherMatrixFourthParam
= _mm_set1_pd(mat
.m_matrix
[0][3]);
1263 // output00 and output01.
1264 __m128d accumulator
= _mm_mul_pd(matrixBlockA
, otherMatrixFirstParam
);
1265 __m128d temp1
= _mm_mul_pd(matrixBlockC
, otherMatrixSecondParam
);
1266 __m128d temp2
= _mm_mul_pd(matrixBlockE
, otherMatrixThirdParam
);
1267 __m128d temp3
= _mm_mul_pd(matrixBlockG
, otherMatrixFourthParam
);
1269 __m128d matrixBlockB
= _mm_load_pd(&(m_matrix
[0][2]));
1270 __m128d matrixBlockD
= _mm_load_pd(&(m_matrix
[1][2]));
1271 __m128d matrixBlockF
= _mm_load_pd(&(m_matrix
[2][2]));
1272 __m128d matrixBlockH
= _mm_load_pd(&(m_matrix
[3][2]));
1274 accumulator
= _mm_add_pd(accumulator
, temp1
);
1275 accumulator
= _mm_add_pd(accumulator
, temp2
);
1276 accumulator
= _mm_add_pd(accumulator
, temp3
);
1277 _mm_store_pd(&m_matrix
[0][0], accumulator
);
1279 // output02 and output03.
1280 accumulator
= _mm_mul_pd(matrixBlockB
, otherMatrixFirstParam
);
1281 temp1
= _mm_mul_pd(matrixBlockD
, otherMatrixSecondParam
);
1282 temp2
= _mm_mul_pd(matrixBlockF
, otherMatrixThirdParam
);
1283 temp3
= _mm_mul_pd(matrixBlockH
, otherMatrixFourthParam
);
1285 accumulator
= _mm_add_pd(accumulator
, temp1
);
1286 accumulator
= _mm_add_pd(accumulator
, temp2
);
1287 accumulator
= _mm_add_pd(accumulator
, temp3
);
1288 _mm_store_pd(&m_matrix
[0][2], accumulator
);
1291 otherMatrixFirstParam
= _mm_set1_pd(mat
.m_matrix
[1][0]);
1292 otherMatrixSecondParam
= _mm_set1_pd(mat
.m_matrix
[1][1]);
1293 otherMatrixThirdParam
= _mm_set1_pd(mat
.m_matrix
[1][2]);
1294 otherMatrixFourthParam
= _mm_set1_pd(mat
.m_matrix
[1][3]);
1296 // output10 and output11.
1297 accumulator
= _mm_mul_pd(matrixBlockA
, otherMatrixFirstParam
);
1298 temp1
= _mm_mul_pd(matrixBlockC
, otherMatrixSecondParam
);
1299 temp2
= _mm_mul_pd(matrixBlockE
, otherMatrixThirdParam
);
1300 temp3
= _mm_mul_pd(matrixBlockG
, otherMatrixFourthParam
);
1302 accumulator
= _mm_add_pd(accumulator
, temp1
);
1303 accumulator
= _mm_add_pd(accumulator
, temp2
);
1304 accumulator
= _mm_add_pd(accumulator
, temp3
);
1305 _mm_store_pd(&m_matrix
[1][0], accumulator
);
1307 // output12 and output13.
1308 accumulator
= _mm_mul_pd(matrixBlockB
, otherMatrixFirstParam
);
1309 temp1
= _mm_mul_pd(matrixBlockD
, otherMatrixSecondParam
);
1310 temp2
= _mm_mul_pd(matrixBlockF
, otherMatrixThirdParam
);
1311 temp3
= _mm_mul_pd(matrixBlockH
, otherMatrixFourthParam
);
1313 accumulator
= _mm_add_pd(accumulator
, temp1
);
1314 accumulator
= _mm_add_pd(accumulator
, temp2
);
1315 accumulator
= _mm_add_pd(accumulator
, temp3
);
1316 _mm_store_pd(&m_matrix
[1][2], accumulator
);
1319 otherMatrixFirstParam
= _mm_set1_pd(mat
.m_matrix
[2][0]);
1320 otherMatrixSecondParam
= _mm_set1_pd(mat
.m_matrix
[2][1]);
1321 otherMatrixThirdParam
= _mm_set1_pd(mat
.m_matrix
[2][2]);
1322 otherMatrixFourthParam
= _mm_set1_pd(mat
.m_matrix
[2][3]);
1324 // output20 and output21.
1325 accumulator
= _mm_mul_pd(matrixBlockA
, otherMatrixFirstParam
);
1326 temp1
= _mm_mul_pd(matrixBlockC
, otherMatrixSecondParam
);
1327 temp2
= _mm_mul_pd(matrixBlockE
, otherMatrixThirdParam
);
1328 temp3
= _mm_mul_pd(matrixBlockG
, otherMatrixFourthParam
);
1330 accumulator
= _mm_add_pd(accumulator
, temp1
);
1331 accumulator
= _mm_add_pd(accumulator
, temp2
);
1332 accumulator
= _mm_add_pd(accumulator
, temp3
);
1333 _mm_store_pd(&m_matrix
[2][0], accumulator
);
1335 // output22 and output23.
1336 accumulator
= _mm_mul_pd(matrixBlockB
, otherMatrixFirstParam
);
1337 temp1
= _mm_mul_pd(matrixBlockD
, otherMatrixSecondParam
);
1338 temp2
= _mm_mul_pd(matrixBlockF
, otherMatrixThirdParam
);
1339 temp3
= _mm_mul_pd(matrixBlockH
, otherMatrixFourthParam
);
1341 accumulator
= _mm_add_pd(accumulator
, temp1
);
1342 accumulator
= _mm_add_pd(accumulator
, temp2
);
1343 accumulator
= _mm_add_pd(accumulator
, temp3
);
1344 _mm_store_pd(&m_matrix
[2][2], accumulator
);
1347 otherMatrixFirstParam
= _mm_set1_pd(mat
.m_matrix
[3][0]);
1348 otherMatrixSecondParam
= _mm_set1_pd(mat
.m_matrix
[3][1]);
1349 otherMatrixThirdParam
= _mm_set1_pd(mat
.m_matrix
[3][2]);
1350 otherMatrixFourthParam
= _mm_set1_pd(mat
.m_matrix
[3][3]);
1352 // output30 and output31.
1353 accumulator
= _mm_mul_pd(matrixBlockA
, otherMatrixFirstParam
);
1354 temp1
= _mm_mul_pd(matrixBlockC
, otherMatrixSecondParam
);
1355 temp2
= _mm_mul_pd(matrixBlockE
, otherMatrixThirdParam
);
1356 temp3
= _mm_mul_pd(matrixBlockG
, otherMatrixFourthParam
);
1358 accumulator
= _mm_add_pd(accumulator
, temp1
);
1359 accumulator
= _mm_add_pd(accumulator
, temp2
);
1360 accumulator
= _mm_add_pd(accumulator
, temp3
);
1361 _mm_store_pd(&m_matrix
[3][0], accumulator
);
1363 // output32 and output33.
1364 accumulator
= _mm_mul_pd(matrixBlockB
, otherMatrixFirstParam
);
1365 temp1
= _mm_mul_pd(matrixBlockD
, otherMatrixSecondParam
);
1366 temp2
= _mm_mul_pd(matrixBlockF
, otherMatrixThirdParam
);
1367 temp3
= _mm_mul_pd(matrixBlockH
, otherMatrixFourthParam
);
1369 accumulator
= _mm_add_pd(accumulator
, temp1
);
1370 accumulator
= _mm_add_pd(accumulator
, temp2
);
1371 accumulator
= _mm_add_pd(accumulator
, temp3
);
1372 _mm_store_pd(&m_matrix
[3][2], accumulator
);
1376 tmp
[0][0] = (mat
.m_matrix
[0][0] * m_matrix
[0][0] + mat
.m_matrix
[0][1] * m_matrix
[1][0]
1377 + mat
.m_matrix
[0][2] * m_matrix
[2][0] + mat
.m_matrix
[0][3] * m_matrix
[3][0]);
1378 tmp
[0][1] = (mat
.m_matrix
[0][0] * m_matrix
[0][1] + mat
.m_matrix
[0][1] * m_matrix
[1][1]
1379 + mat
.m_matrix
[0][2] * m_matrix
[2][1] + mat
.m_matrix
[0][3] * m_matrix
[3][1]);
1380 tmp
[0][2] = (mat
.m_matrix
[0][0] * m_matrix
[0][2] + mat
.m_matrix
[0][1] * m_matrix
[1][2]
1381 + mat
.m_matrix
[0][2] * m_matrix
[2][2] + mat
.m_matrix
[0][3] * m_matrix
[3][2]);
1382 tmp
[0][3] = (mat
.m_matrix
[0][0] * m_matrix
[0][3] + mat
.m_matrix
[0][1] * m_matrix
[1][3]
1383 + mat
.m_matrix
[0][2] * m_matrix
[2][3] + mat
.m_matrix
[0][3] * m_matrix
[3][3]);
1385 tmp
[1][0] = (mat
.m_matrix
[1][0] * m_matrix
[0][0] + mat
.m_matrix
[1][1] * m_matrix
[1][0]
1386 + mat
.m_matrix
[1][2] * m_matrix
[2][0] + mat
.m_matrix
[1][3] * m_matrix
[3][0]);
1387 tmp
[1][1] = (mat
.m_matrix
[1][0] * m_matrix
[0][1] + mat
.m_matrix
[1][1] * m_matrix
[1][1]
1388 + mat
.m_matrix
[1][2] * m_matrix
[2][1] + mat
.m_matrix
[1][3] * m_matrix
[3][1]);
1389 tmp
[1][2] = (mat
.m_matrix
[1][0] * m_matrix
[0][2] + mat
.m_matrix
[1][1] * m_matrix
[1][2]
1390 + mat
.m_matrix
[1][2] * m_matrix
[2][2] + mat
.m_matrix
[1][3] * m_matrix
[3][2]);
1391 tmp
[1][3] = (mat
.m_matrix
[1][0] * m_matrix
[0][3] + mat
.m_matrix
[1][1] * m_matrix
[1][3]
1392 + mat
.m_matrix
[1][2] * m_matrix
[2][3] + mat
.m_matrix
[1][3] * m_matrix
[3][3]);
1394 tmp
[2][0] = (mat
.m_matrix
[2][0] * m_matrix
[0][0] + mat
.m_matrix
[2][1] * m_matrix
[1][0]
1395 + mat
.m_matrix
[2][2] * m_matrix
[2][0] + mat
.m_matrix
[2][3] * m_matrix
[3][0]);
1396 tmp
[2][1] = (mat
.m_matrix
[2][0] * m_matrix
[0][1] + mat
.m_matrix
[2][1] * m_matrix
[1][1]
1397 + mat
.m_matrix
[2][2] * m_matrix
[2][1] + mat
.m_matrix
[2][3] * m_matrix
[3][1]);
1398 tmp
[2][2] = (mat
.m_matrix
[2][0] * m_matrix
[0][2] + mat
.m_matrix
[2][1] * m_matrix
[1][2]
1399 + mat
.m_matrix
[2][2] * m_matrix
[2][2] + mat
.m_matrix
[2][3] * m_matrix
[3][2]);
1400 tmp
[2][3] = (mat
.m_matrix
[2][0] * m_matrix
[0][3] + mat
.m_matrix
[2][1] * m_matrix
[1][3]
1401 + mat
.m_matrix
[2][2] * m_matrix
[2][3] + mat
.m_matrix
[2][3] * m_matrix
[3][3]);
1403 tmp
[3][0] = (mat
.m_matrix
[3][0] * m_matrix
[0][0] + mat
.m_matrix
[3][1] * m_matrix
[1][0]
1404 + mat
.m_matrix
[3][2] * m_matrix
[2][0] + mat
.m_matrix
[3][3] * m_matrix
[3][0]);
1405 tmp
[3][1] = (mat
.m_matrix
[3][0] * m_matrix
[0][1] + mat
.m_matrix
[3][1] * m_matrix
[1][1]
1406 + mat
.m_matrix
[3][2] * m_matrix
[2][1] + mat
.m_matrix
[3][3] * m_matrix
[3][1]);
1407 tmp
[3][2] = (mat
.m_matrix
[3][0] * m_matrix
[0][2] + mat
.m_matrix
[3][1] * m_matrix
[1][2]
1408 + mat
.m_matrix
[3][2] * m_matrix
[2][2] + mat
.m_matrix
[3][3] * m_matrix
[3][2]);
1409 tmp
[3][3] = (mat
.m_matrix
[3][0] * m_matrix
[0][3] + mat
.m_matrix
[3][1] * m_matrix
[1][3]
1410 + mat
.m_matrix
[3][2] * m_matrix
[2][3] + mat
.m_matrix
[3][3] * m_matrix
[3][3]);
1417 void TransformationMatrix::multVecMatrix(double x
, double y
, double& resultX
, double& resultY
) const
1419 resultX
= m_matrix
[3][0] + x
* m_matrix
[0][0] + y
* m_matrix
[1][0];
1420 resultY
= m_matrix
[3][1] + x
* m_matrix
[0][1] + y
* m_matrix
[1][1];
1421 double w
= m_matrix
[3][3] + x
* m_matrix
[0][3] + y
* m_matrix
[1][3];
1422 if (w
!= 1 && w
!= 0) {
1428 void TransformationMatrix::multVecMatrix(double x
, double y
, double z
, double& resultX
, double& resultY
, double& resultZ
) const
1430 resultX
= m_matrix
[3][0] + x
* m_matrix
[0][0] + y
* m_matrix
[1][0] + z
* m_matrix
[2][0];
1431 resultY
= m_matrix
[3][1] + x
* m_matrix
[0][1] + y
* m_matrix
[1][1] + z
* m_matrix
[2][1];
1432 resultZ
= m_matrix
[3][2] + x
* m_matrix
[0][2] + y
* m_matrix
[1][2] + z
* m_matrix
[2][2];
1433 double w
= m_matrix
[3][3] + x
* m_matrix
[0][3] + y
* m_matrix
[1][3] + z
* m_matrix
[2][3];
1434 if (w
!= 1 && w
!= 0) {
1441 bool TransformationMatrix::isInvertible() const
1443 if (isIdentityOrTranslation())
1446 double det
= blink::determinant4x4(m_matrix
);
1448 if (fabs(det
) < SMALL_NUMBER
)
1454 TransformationMatrix
TransformationMatrix::inverse() const
1456 if (isIdentityOrTranslation()) {
1458 if (m_matrix
[3][0] == 0 && m_matrix
[3][1] == 0 && m_matrix
[3][2] == 0)
1459 return TransformationMatrix();
1462 return TransformationMatrix(1, 0, 0, 0,
1465 -m_matrix
[3][0], -m_matrix
[3][1], -m_matrix
[3][2], 1);
1468 TransformationMatrix invMat
;
1469 bool inverted
= blink::inverse(m_matrix
, invMat
.m_matrix
);
1471 return TransformationMatrix();
1476 void TransformationMatrix::makeAffine()
1493 AffineTransform
TransformationMatrix::toAffineTransform() const
1495 return AffineTransform(m_matrix
[0][0], m_matrix
[0][1], m_matrix
[1][0],
1496 m_matrix
[1][1], m_matrix
[3][0], m_matrix
[3][1]);
1499 static inline void blendFloat(double& from
, double to
, double progress
)
1502 from
= from
+ (to
- from
) * progress
;
1505 void TransformationMatrix::blend(const TransformationMatrix
& from
, double progress
)
1507 if (from
.isIdentity() && isIdentity())
1511 DecomposedType fromDecomp
;
1512 DecomposedType toDecomp
;
1513 if (!from
.decompose(fromDecomp
) || !decompose(toDecomp
)) {
1520 blendFloat(fromDecomp
.scaleX
, toDecomp
.scaleX
, progress
);
1521 blendFloat(fromDecomp
.scaleY
, toDecomp
.scaleY
, progress
);
1522 blendFloat(fromDecomp
.scaleZ
, toDecomp
.scaleZ
, progress
);
1523 blendFloat(fromDecomp
.skewXY
, toDecomp
.skewXY
, progress
);
1524 blendFloat(fromDecomp
.skewXZ
, toDecomp
.skewXZ
, progress
);
1525 blendFloat(fromDecomp
.skewYZ
, toDecomp
.skewYZ
, progress
);
1526 blendFloat(fromDecomp
.translateX
, toDecomp
.translateX
, progress
);
1527 blendFloat(fromDecomp
.translateY
, toDecomp
.translateY
, progress
);
1528 blendFloat(fromDecomp
.translateZ
, toDecomp
.translateZ
, progress
);
1529 blendFloat(fromDecomp
.perspectiveX
, toDecomp
.perspectiveX
, progress
);
1530 blendFloat(fromDecomp
.perspectiveY
, toDecomp
.perspectiveY
, progress
);
1531 blendFloat(fromDecomp
.perspectiveZ
, toDecomp
.perspectiveZ
, progress
);
1532 blendFloat(fromDecomp
.perspectiveW
, toDecomp
.perspectiveW
, progress
);
1534 slerp(&fromDecomp
.quaternionX
, &toDecomp
.quaternionX
, progress
);
1537 recompose(fromDecomp
);
1540 bool TransformationMatrix::decompose(DecomposedType
& decomp
) const
1543 memset(&decomp
, 0, sizeof(decomp
));
1544 decomp
.perspectiveW
= 1;
1550 if (!blink::decompose(m_matrix
, decomp
))
1555 void TransformationMatrix::recompose(const DecomposedType
& decomp
)
1559 // first apply perspective
1560 m_matrix
[0][3] = decomp
.perspectiveX
;
1561 m_matrix
[1][3] = decomp
.perspectiveY
;
1562 m_matrix
[2][3] = decomp
.perspectiveZ
;
1563 m_matrix
[3][3] = decomp
.perspectiveW
;
1566 translate3d(decomp
.translateX
, decomp
.translateY
, decomp
.translateZ
);
1569 double xx
= decomp
.quaternionX
* decomp
.quaternionX
;
1570 double xy
= decomp
.quaternionX
* decomp
.quaternionY
;
1571 double xz
= decomp
.quaternionX
* decomp
.quaternionZ
;
1572 double xw
= decomp
.quaternionX
* decomp
.quaternionW
;
1573 double yy
= decomp
.quaternionY
* decomp
.quaternionY
;
1574 double yz
= decomp
.quaternionY
* decomp
.quaternionZ
;
1575 double yw
= decomp
.quaternionY
* decomp
.quaternionW
;
1576 double zz
= decomp
.quaternionZ
* decomp
.quaternionZ
;
1577 double zw
= decomp
.quaternionZ
* decomp
.quaternionW
;
1579 // Construct a composite rotation matrix from the quaternion values
1580 TransformationMatrix
rotationMatrix(1 - 2 * (yy
+ zz
), 2 * (xy
- zw
), 2 * (xz
+ yw
), 0,
1581 2 * (xy
+ zw
), 1 - 2 * (xx
+ zz
), 2 * (yz
- xw
), 0,
1582 2 * (xz
- yw
), 2 * (yz
+ xw
), 1 - 2 * (xx
+ yy
), 0,
1585 multiply(rotationMatrix
);
1588 if (decomp
.skewYZ
) {
1589 TransformationMatrix tmp
;
1590 tmp
.setM32(decomp
.skewYZ
);
1594 if (decomp
.skewXZ
) {
1595 TransformationMatrix tmp
;
1596 tmp
.setM31(decomp
.skewXZ
);
1600 if (decomp
.skewXY
) {
1601 TransformationMatrix tmp
;
1602 tmp
.setM21(decomp
.skewXY
);
1606 // finally, apply scale
1607 scale3d(decomp
.scaleX
, decomp
.scaleY
, decomp
.scaleZ
);
1610 bool TransformationMatrix::isIntegerTranslation() const
1612 if (!isIdentityOrTranslation())
1615 // Check for translate Z.
1619 // Check for non-integer translate X/Y.
1620 if (static_cast<int>(m_matrix
[3][0]) != m_matrix
[3][0] || static_cast<int>(m_matrix
[3][1]) != m_matrix
[3][1])
1626 FloatSize
TransformationMatrix::to2DTranslation() const
1628 ASSERT(isIdentityOr2DTranslation());
1629 return FloatSize(m_matrix
[3][0], m_matrix
[3][1]);
1632 void TransformationMatrix::toColumnMajorFloatArray(FloatMatrix4
& result
) const
1652 SkMatrix44
TransformationMatrix::toSkMatrix44(const TransformationMatrix
& matrix
)
1654 SkMatrix44
ret(SkMatrix44::kUninitialized_Constructor
);
1655 ret
.setDouble(0, 0, matrix
.m11());
1656 ret
.setDouble(0, 1, matrix
.m21());
1657 ret
.setDouble(0, 2, matrix
.m31());
1658 ret
.setDouble(0, 3, matrix
.m41());
1659 ret
.setDouble(1, 0, matrix
.m12());
1660 ret
.setDouble(1, 1, matrix
.m22());
1661 ret
.setDouble(1, 2, matrix
.m32());
1662 ret
.setDouble(1, 3, matrix
.m42());
1663 ret
.setDouble(2, 0, matrix
.m13());
1664 ret
.setDouble(2, 1, matrix
.m23());
1665 ret
.setDouble(2, 2, matrix
.m33());
1666 ret
.setDouble(2, 3, matrix
.m43());
1667 ret
.setDouble(3, 0, matrix
.m14());
1668 ret
.setDouble(3, 1, matrix
.m24());
1669 ret
.setDouble(3, 2, matrix
.m34());
1670 ret
.setDouble(3, 3, matrix
.m44());