Index: Source/core/platform/graphics/transforms/TransformationMatrix.cpp |
diff --git a/Source/core/platform/graphics/transforms/TransformationMatrix.cpp b/Source/core/platform/graphics/transforms/TransformationMatrix.cpp |
deleted file mode 100644 |
index e95936b0da877536e3c278f16cdd642903973d57..0000000000000000000000000000000000000000 |
--- a/Source/core/platform/graphics/transforms/TransformationMatrix.cpp |
+++ /dev/null |
@@ -1,1531 +0,0 @@ |
-/* |
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. |
- * Copyright (C) 2009 Torch Mobile, Inc. |
- * Copyright (C) 2013 Google Inc. All rights reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions |
- * are met: |
- * 1. Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright |
- * notice, this list of conditions and the following disclaimer in the |
- * documentation and/or other materials provided with the distribution. |
- * |
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#include "config.h" |
-#include "core/platform/graphics/transforms/TransformationMatrix.h" |
- |
-#include "core/platform/graphics/FloatQuad.h" |
-#include "core/platform/graphics/FloatRect.h" |
-#include "core/platform/graphics/IntRect.h" |
-#include "core/platform/graphics/LayoutRect.h" |
-#include "core/platform/graphics/skia/SkiaUtils.h" |
-#include "core/platform/graphics/transforms/AffineTransform.h" |
- |
-#include "wtf/Assertions.h" |
-#include "wtf/MathExtras.h" |
- |
-#if CPU(X86_64) |
-#include <emmintrin.h> |
-#endif |
- |
-using namespace std; |
- |
-namespace WebCore { |
- |
-// |
-// Supporting Math Functions |
-// |
-// This is a set of function from various places (attributed inline) to do things like |
-// inversion and decomposition of a 4x4 matrix. They are used throughout the code |
-// |
- |
-// |
-// Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>. |
- |
-// EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code |
-// as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial |
-// or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there |
-// are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or |
-// webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes |
-// with no guarantee. |
- |
-// A clarification about the storage of matrix elements |
-// |
-// This class uses a 2 dimensional array internally to store the elements of the matrix. The first index into |
-// the array refers to the column that the element lies in; the second index refers to the row. |
-// |
-// In other words, this is the layout of the matrix: |
-// |
-// | m_matrix[0][0] m_matrix[1][0] m_matrix[2][0] m_matrix[3][0] | |
-// | m_matrix[0][1] m_matrix[1][1] m_matrix[2][1] m_matrix[3][1] | |
-// | m_matrix[0][2] m_matrix[1][2] m_matrix[2][2] m_matrix[3][2] | |
-// | m_matrix[0][3] m_matrix[1][3] m_matrix[2][3] m_matrix[3][3] | |
- |
-typedef double Vector4[4]; |
-typedef double Vector3[3]; |
- |
-const double SMALL_NUMBER = 1.e-8; |
- |
-// inverse(original_matrix, inverse_matrix) |
-// |
-// calculate the inverse of a 4x4 matrix |
-// |
-// -1 |
-// A = ___1__ adjoint A |
-// det A |
- |
-// double = determinant2x2(double a, double b, double c, double d) |
-// |
-// calculate the determinant of a 2x2 matrix. |
- |
-static double determinant2x2(double a, double b, double c, double d) |
-{ |
- return a * d - b * c; |
-} |
- |
-// double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3) |
-// |
-// Calculate the determinant of a 3x3 matrix |
-// in the form |
-// |
-// | a1, b1, c1 | |
-// | a2, b2, c2 | |
-// | a3, b3, c3 | |
- |
-static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3) |
-{ |
- return a1 * determinant2x2(b2, b3, c2, c3) |
- - b1 * determinant2x2(a2, a3, c2, c3) |
- + c1 * determinant2x2(a2, a3, b2, b3); |
-} |
- |
-// double = determinant4x4(matrix) |
-// |
-// calculate the determinant of a 4x4 matrix. |
- |
-static double determinant4x4(const TransformationMatrix::Matrix4& m) |
-{ |
- // Assign to individual variable names to aid selecting |
- // correct elements |
- |
- double a1 = m[0][0]; |
- double b1 = m[0][1]; |
- double c1 = m[0][2]; |
- double d1 = m[0][3]; |
- |
- double a2 = m[1][0]; |
- double b2 = m[1][1]; |
- double c2 = m[1][2]; |
- double d2 = m[1][3]; |
- |
- double a3 = m[2][0]; |
- double b3 = m[2][1]; |
- double c3 = m[2][2]; |
- double d3 = m[2][3]; |
- |
- double a4 = m[3][0]; |
- double b4 = m[3][1]; |
- double c4 = m[3][2]; |
- double d4 = m[3][3]; |
- |
- return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) |
- - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) |
- + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) |
- - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); |
-} |
- |
-// adjoint( original_matrix, inverse_matrix ) |
-// |
-// calculate the adjoint of a 4x4 matrix |
-// |
-// Let a denote the minor determinant of matrix A obtained by |
-// ij |
-// |
-// deleting the ith row and jth column from A. |
-// |
-// i+j |
-// Let b = (-1) a |
-// ij ji |
-// |
-// The matrix B = (b ) is the adjoint of A |
-// ij |
- |
-static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result) |
-{ |
- // Assign to individual variable names to aid |
- // selecting correct values |
- double a1 = matrix[0][0]; |
- double b1 = matrix[0][1]; |
- double c1 = matrix[0][2]; |
- double d1 = matrix[0][3]; |
- |
- double a2 = matrix[1][0]; |
- double b2 = matrix[1][1]; |
- double c2 = matrix[1][2]; |
- double d2 = matrix[1][3]; |
- |
- double a3 = matrix[2][0]; |
- double b3 = matrix[2][1]; |
- double c3 = matrix[2][2]; |
- double d3 = matrix[2][3]; |
- |
- double a4 = matrix[3][0]; |
- double b4 = matrix[3][1]; |
- double c4 = matrix[3][2]; |
- double d4 = matrix[3][3]; |
- |
- // Row column labeling reversed since we transpose rows & columns |
- result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); |
- result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); |
- result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); |
- result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); |
- |
- result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); |
- result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); |
- result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); |
- result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); |
- |
- result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); |
- result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); |
- result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); |
- result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); |
- |
- result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); |
- result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); |
- result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); |
- result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); |
-} |
- |
-// Returns false if the matrix is not invertible |
-static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result) |
-{ |
- // Calculate the adjoint matrix |
- adjoint(matrix, result); |
- |
- // Calculate the 4x4 determinant |
- // If the determinant is zero, |
- // then the inverse matrix is not unique. |
- double det = determinant4x4(matrix); |
- |
- if (fabs(det) < SMALL_NUMBER) |
- return false; |
- |
- // Scale the adjoint matrix to get the inverse |
- |
- for (int i = 0; i < 4; i++) |
- for (int j = 0; j < 4; j++) |
- result[i][j] = result[i][j] / det; |
- |
- return true; |
-} |
- |
-// End of code adapted from Matrix Inversion by Richard Carling |
- |
-// Perform a decomposition on the passed matrix, return false if unsuccessful |
-// From Graphics Gems: unmatrix.c |
- |
-// Transpose rotation portion of matrix a, return b |
-static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b) |
-{ |
- for (int i = 0; i < 4; i++) |
- for (int j = 0; j < 4; j++) |
- b[i][j] = a[j][i]; |
-} |
- |
-// Multiply a homogeneous point by a matrix and return the transformed point |
-static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result) |
-{ |
- result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) + |
- (p[2] * m[2][0]) + (p[3] * m[3][0]); |
- result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) + |
- (p[2] * m[2][1]) + (p[3] * m[3][1]); |
- result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) + |
- (p[2] * m[2][2]) + (p[3] * m[3][2]); |
- result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) + |
- (p[2] * m[2][3]) + (p[3] * m[3][3]); |
-} |
- |
-static double v3Length(Vector3 a) |
-{ |
- return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2])); |
-} |
- |
-static void v3Scale(Vector3 v, double desiredLength) |
-{ |
- double len = v3Length(v); |
- if (len != 0) { |
- double l = desiredLength / len; |
- v[0] *= l; |
- v[1] *= l; |
- v[2] *= l; |
- } |
-} |
- |
-static double v3Dot(const Vector3 a, const Vector3 b) |
-{ |
- return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); |
-} |
- |
-// Make a linear combination of two vectors and return the result. |
-// result = (a * ascl) + (b * bscl) |
-static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl) |
-{ |
- result[0] = (ascl * a[0]) + (bscl * b[0]); |
- result[1] = (ascl * a[1]) + (bscl * b[1]); |
- result[2] = (ascl * a[2]) + (bscl * b[2]); |
-} |
- |
-// Return the cross product result = a cross b */ |
-static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result) |
-{ |
- result[0] = (a[1] * b[2]) - (a[2] * b[1]); |
- result[1] = (a[2] * b[0]) - (a[0] * b[2]); |
- result[2] = (a[0] * b[1]) - (a[1] * b[0]); |
-} |
- |
-static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result) |
-{ |
- TransformationMatrix::Matrix4 localMatrix; |
- memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4)); |
- |
- // Normalize the matrix. |
- if (localMatrix[3][3] == 0) |
- return false; |
- |
- int i, j; |
- for (i = 0; i < 4; i++) |
- for (j = 0; j < 4; j++) |
- localMatrix[i][j] /= localMatrix[3][3]; |
- |
- // perspectiveMatrix is used to solve for perspective, but it also provides |
- // an easy way to test for singularity of the upper 3x3 component. |
- TransformationMatrix::Matrix4 perspectiveMatrix; |
- memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4)); |
- for (i = 0; i < 3; i++) |
- perspectiveMatrix[i][3] = 0; |
- perspectiveMatrix[3][3] = 1; |
- |
- if (determinant4x4(perspectiveMatrix) == 0) |
- return false; |
- |
- // First, isolate perspective. This is the messiest. |
- if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) { |
- // rightHandSide is the right hand side of the equation. |
- Vector4 rightHandSide; |
- rightHandSide[0] = localMatrix[0][3]; |
- rightHandSide[1] = localMatrix[1][3]; |
- rightHandSide[2] = localMatrix[2][3]; |
- rightHandSide[3] = localMatrix[3][3]; |
- |
- // Solve the equation by inverting perspectiveMatrix and multiplying |
- // rightHandSide by the inverse. (This is the easiest way, not |
- // necessarily the best.) |
- TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix; |
- inverse(perspectiveMatrix, inversePerspectiveMatrix); |
- transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); |
- |
- Vector4 perspectivePoint; |
- v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); |
- |
- result.perspectiveX = perspectivePoint[0]; |
- result.perspectiveY = perspectivePoint[1]; |
- result.perspectiveZ = perspectivePoint[2]; |
- result.perspectiveW = perspectivePoint[3]; |
- |
- // Clear the perspective partition |
- localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0; |
- localMatrix[3][3] = 1; |
- } else { |
- // No perspective. |
- result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0; |
- result.perspectiveW = 1; |
- } |
- |
- // Next take care of translation (easy). |
- result.translateX = localMatrix[3][0]; |
- localMatrix[3][0] = 0; |
- result.translateY = localMatrix[3][1]; |
- localMatrix[3][1] = 0; |
- result.translateZ = localMatrix[3][2]; |
- localMatrix[3][2] = 0; |
- |
- // Vector4 type and functions need to be added to the common set. |
- Vector3 row[3], pdum3; |
- |
- // Now get scale and shear. |
- for (i = 0; i < 3; i++) { |
- row[i][0] = localMatrix[i][0]; |
- row[i][1] = localMatrix[i][1]; |
- row[i][2] = localMatrix[i][2]; |
- } |
- |
- // Compute X scale factor and normalize first row. |
- result.scaleX = v3Length(row[0]); |
- v3Scale(row[0], 1.0); |
- |
- // Compute XY shear factor and make 2nd row orthogonal to 1st. |
- result.skewXY = v3Dot(row[0], row[1]); |
- v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY); |
- |
- // Now, compute Y scale and normalize 2nd row. |
- result.scaleY = v3Length(row[1]); |
- v3Scale(row[1], 1.0); |
- result.skewXY /= result.scaleY; |
- |
- // Compute XZ and YZ shears, orthogonalize 3rd row. |
- result.skewXZ = v3Dot(row[0], row[2]); |
- v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ); |
- result.skewYZ = v3Dot(row[1], row[2]); |
- v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ); |
- |
- // Next, get Z scale and normalize 3rd row. |
- result.scaleZ = v3Length(row[2]); |
- v3Scale(row[2], 1.0); |
- result.skewXZ /= result.scaleZ; |
- result.skewYZ /= result.scaleZ; |
- |
- // At this point, the matrix (in rows[]) is orthonormal. |
- // Check for a coordinate system flip. If the determinant |
- // is -1, then negate the matrix and the scaling factors. |
- v3Cross(row[1], row[2], pdum3); |
- if (v3Dot(row[0], pdum3) < 0) { |
- |
- result.scaleX *= -1; |
- result.scaleY *= -1; |
- result.scaleZ *= -1; |
- |
- for (i = 0; i < 3; i++) { |
- row[i][0] *= -1; |
- row[i][1] *= -1; |
- row[i][2] *= -1; |
- } |
- } |
- |
- // Now, get the rotations out, as described in the gem. |
- |
- // FIXME - Add the ability to return either quaternions (which are |
- // easier to recompose with) or Euler angles (rx, ry, rz), which |
- // are easier for authors to deal with. The latter will only be useful |
- // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I |
- // will leave the Euler angle code here for now. |
- |
- // ret.rotateY = asin(-row[0][2]); |
- // if (cos(ret.rotateY) != 0) { |
- // ret.rotateX = atan2(row[1][2], row[2][2]); |
- // ret.rotateZ = atan2(row[0][1], row[0][0]); |
- // } else { |
- // ret.rotateX = atan2(-row[2][0], row[1][1]); |
- // ret.rotateZ = 0; |
- // } |
- |
- double s, t, x, y, z, w; |
- |
- t = row[0][0] + row[1][1] + row[2][2] + 1.0; |
- |
- if (t > 1e-4) { |
- s = 0.5 / sqrt(t); |
- w = 0.25 / s; |
- x = (row[2][1] - row[1][2]) * s; |
- y = (row[0][2] - row[2][0]) * s; |
- z = (row[1][0] - row[0][1]) * s; |
- } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) { |
- s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx |
- x = 0.25 * s; |
- y = (row[0][1] + row[1][0]) / s; |
- z = (row[0][2] + row[2][0]) / s; |
- w = (row[2][1] - row[1][2]) / s; |
- } else if (row[1][1] > row[2][2]) { |
- s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy |
- x = (row[0][1] + row[1][0]) / s; |
- y = 0.25 * s; |
- z = (row[1][2] + row[2][1]) / s; |
- w = (row[0][2] - row[2][0]) / s; |
- } else { |
- s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz |
- x = (row[0][2] + row[2][0]) / s; |
- y = (row[1][2] + row[2][1]) / s; |
- z = 0.25 * s; |
- w = (row[1][0] - row[0][1]) / s; |
- } |
- |
- result.quaternionX = x; |
- result.quaternionY = y; |
- result.quaternionZ = z; |
- result.quaternionW = w; |
- |
- return true; |
-} |
- |
-// Perform a spherical linear interpolation between the two |
-// passed quaternions with 0 <= t <= 1 |
-static void slerp(double qa[4], const double qb[4], double t) |
-{ |
- double ax, ay, az, aw; |
- double bx, by, bz, bw; |
- double cx, cy, cz, cw; |
- double angle; |
- double th, invth, scale, invscale; |
- |
- ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3]; |
- bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3]; |
- |
- angle = ax * bx + ay * by + az * bz + aw * bw; |
- |
- if (angle < 0.0) { |
- ax = -ax; ay = -ay; |
- az = -az; aw = -aw; |
- angle = -angle; |
- } |
- |
- if (angle + 1.0 > .05) { |
- if (1.0 - angle >= .05) { |
- th = acos (angle); |
- invth = 1.0 / sin (th); |
- scale = sin (th * (1.0 - t)) * invth; |
- invscale = sin (th * t) * invth; |
- } else { |
- scale = 1.0 - t; |
- invscale = t; |
- } |
- } else { |
- bx = -ay; |
- by = ax; |
- bz = -aw; |
- bw = az; |
- scale = sin(piDouble * (.5 - t)); |
- invscale = sin (piDouble * t); |
- } |
- |
- cx = ax * scale + bx * invscale; |
- cy = ay * scale + by * invscale; |
- cz = az * scale + bz * invscale; |
- cw = aw * scale + bw * invscale; |
- |
- qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw; |
-} |
- |
-// End of Supporting Math Functions |
- |
-TransformationMatrix::TransformationMatrix(const AffineTransform& t) |
-{ |
- setMatrix(t.a(), t.b(), t.c(), t.d(), t.e(), t.f()); |
-} |
- |
-TransformationMatrix& TransformationMatrix::scale(double s) |
-{ |
- return scaleNonUniform(s, s); |
-} |
- |
-TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y) |
-{ |
- return rotate(rad2deg(atan2(y, x))); |
-} |
- |
-TransformationMatrix& TransformationMatrix::flipX() |
-{ |
- return scaleNonUniform(-1.0, 1.0); |
-} |
- |
-TransformationMatrix& TransformationMatrix::flipY() |
-{ |
- return scaleNonUniform(1.0, -1.0); |
-} |
- |
-FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p, bool* clamped) const |
-{ |
- // This is basically raytracing. We have a point in the destination |
- // plane with z=0, and we cast a ray parallel to the z-axis from that |
- // point to find the z-position at which it intersects the z=0 plane |
- // with the transform applied. Once we have that point we apply the |
- // inverse transform to find the corresponding point in the source |
- // space. |
- // |
- // Given a plane with normal Pn, and a ray starting at point R0 and |
- // with direction defined by the vector Rd, we can find the |
- // intersection point as a distance d from R0 in units of Rd by: |
- // |
- // d = -dot (Pn', R0) / dot (Pn', Rd) |
- if (clamped) |
- *clamped = false; |
- |
- if (m33() == 0) { |
- // In this case, the projection plane is parallel to the ray we are trying to |
- // trace, and there is no well-defined value for the projection. |
- return FloatPoint(); |
- } |
- |
- double x = p.x(); |
- double y = p.y(); |
- double z = -(m13() * x + m23() * y + m43()) / m33(); |
- |
- // FIXME: use multVecMatrix() |
- double outX = x * m11() + y * m21() + z * m31() + m41(); |
- double outY = x * m12() + y * m22() + z * m32() + m42(); |
- |
- double w = x * m14() + y * m24() + z * m34() + m44(); |
- if (w <= 0) { |
- // Using int max causes overflow when other code uses the projected point. To |
- // represent infinity yet reduce the risk of overflow, we use a large but |
- // not-too-large number here when clamping. |
- const int largeNumber = 100000000 / kFixedPointDenominator; |
- outX = copysign(largeNumber, outX); |
- outY = copysign(largeNumber, outY); |
- if (clamped) |
- *clamped = true; |
- } else if (w != 1) { |
- outX /= w; |
- outY /= w; |
- } |
- |
- return FloatPoint(static_cast<float>(outX), static_cast<float>(outY)); |
-} |
- |
-FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q, bool* clamped) const |
-{ |
- FloatQuad projectedQuad; |
- |
- bool clamped1 = false; |
- bool clamped2 = false; |
- bool clamped3 = false; |
- bool clamped4 = false; |
- |
- projectedQuad.setP1(projectPoint(q.p1(), &clamped1)); |
- projectedQuad.setP2(projectPoint(q.p2(), &clamped2)); |
- projectedQuad.setP3(projectPoint(q.p3(), &clamped3)); |
- projectedQuad.setP4(projectPoint(q.p4(), &clamped4)); |
- |
- if (clamped) |
- *clamped = clamped1 || clamped2 || clamped3 || clamped4; |
- |
- // If all points on the quad had w < 0, then the entire quad would not be visible to the projected surface. |
- bool everythingWasClipped = clamped1 && clamped2 && clamped3 && clamped4; |
- if (everythingWasClipped) |
- return FloatQuad(); |
- |
- return projectedQuad; |
-} |
- |
-static float clampEdgeValue(float f) |
-{ |
- ASSERT(!std::isnan(f)); |
- return min<float>(max<float>(f, -LayoutUnit::max() / 2), LayoutUnit::max() / 2); |
-} |
- |
-LayoutRect TransformationMatrix::clampedBoundsOfProjectedQuad(const FloatQuad& q) const |
-{ |
- FloatRect mappedQuadBounds = projectQuad(q).boundingBox(); |
- |
- float left = clampEdgeValue(floorf(mappedQuadBounds.x())); |
- float top = clampEdgeValue(floorf(mappedQuadBounds.y())); |
- |
- float right; |
- if (std::isinf(mappedQuadBounds.x()) && std::isinf(mappedQuadBounds.width())) |
- right = LayoutUnit::max() / 2; |
- else |
- right = clampEdgeValue(ceilf(mappedQuadBounds.maxX())); |
- |
- float bottom; |
- if (std::isinf(mappedQuadBounds.y()) && std::isinf(mappedQuadBounds.height())) |
- bottom = LayoutUnit::max() / 2; |
- else |
- bottom = clampEdgeValue(ceilf(mappedQuadBounds.maxY())); |
- |
- return LayoutRect(LayoutUnit::clamp(left), LayoutUnit::clamp(top), LayoutUnit::clamp(right - left), LayoutUnit::clamp(bottom - top)); |
-} |
- |
-FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const |
-{ |
- if (isIdentityOrTranslation()) |
- return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1])); |
- |
- return internalMapPoint(p); |
-} |
- |
-FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const |
-{ |
- if (isIdentityOrTranslation()) |
- return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]), |
- p.y() + static_cast<float>(m_matrix[3][1]), |
- p.z() + static_cast<float>(m_matrix[3][2])); |
- |
- return internalMapPoint(p); |
-} |
- |
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const |
-{ |
- return enclosingIntRect(mapRect(FloatRect(rect))); |
-} |
- |
-LayoutRect TransformationMatrix::mapRect(const LayoutRect& r) const |
-{ |
- return enclosingLayoutRect(mapRect(FloatRect(r))); |
-} |
- |
-FloatRect TransformationMatrix::mapRect(const FloatRect& r) const |
-{ |
- if (isIdentityOrTranslation()) { |
- FloatRect mappedRect(r); |
- mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); |
- return mappedRect; |
- } |
- |
- FloatQuad result; |
- |
- float maxX = r.maxX(); |
- float maxY = r.maxY(); |
- result.setP1(internalMapPoint(FloatPoint(r.x(), r.y()))); |
- result.setP2(internalMapPoint(FloatPoint(maxX, r.y()))); |
- result.setP3(internalMapPoint(FloatPoint(maxX, maxY))); |
- result.setP4(internalMapPoint(FloatPoint(r.x(), maxY))); |
- |
- return result.boundingBox(); |
-} |
- |
-FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const |
-{ |
- if (isIdentityOrTranslation()) { |
- FloatQuad mappedQuad(q); |
- mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); |
- return mappedQuad; |
- } |
- |
- FloatQuad result; |
- result.setP1(internalMapPoint(q.p1())); |
- result.setP2(internalMapPoint(q.p2())); |
- result.setP3(internalMapPoint(q.p3())); |
- result.setP4(internalMapPoint(q.p4())); |
- return result; |
-} |
- |
-TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy) |
-{ |
- m_matrix[0][0] *= sx; |
- m_matrix[0][1] *= sx; |
- m_matrix[0][2] *= sx; |
- m_matrix[0][3] *= sx; |
- |
- m_matrix[1][0] *= sy; |
- m_matrix[1][1] *= sy; |
- m_matrix[1][2] *= sy; |
- m_matrix[1][3] *= sy; |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz) |
-{ |
- scaleNonUniform(sx, sy); |
- |
- m_matrix[2][0] *= sz; |
- m_matrix[2][1] *= sz; |
- m_matrix[2][2] *= sz; |
- m_matrix[2][3] *= sz; |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle) |
-{ |
- // Normalize the axis of rotation |
- double length = sqrt(x * x + y * y + z * z); |
- if (length == 0) { |
- // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied. |
- return *this; |
- } else if (length != 1) { |
- x /= length; |
- y /= length; |
- z /= length; |
- } |
- |
- // Angles are in degrees. Switch to radians. |
- angle = deg2rad(angle); |
- |
- double sinTheta = sin(angle); |
- double cosTheta = cos(angle); |
- |
- TransformationMatrix mat; |
- |
- // Optimize cases where the axis is along a major axis |
- if (x == 1.0 && y == 0.0 && z == 0.0) { |
- mat.m_matrix[0][0] = 1.0; |
- mat.m_matrix[0][1] = 0.0; |
- mat.m_matrix[0][2] = 0.0; |
- mat.m_matrix[1][0] = 0.0; |
- mat.m_matrix[1][1] = cosTheta; |
- mat.m_matrix[1][2] = sinTheta; |
- mat.m_matrix[2][0] = 0.0; |
- mat.m_matrix[2][1] = -sinTheta; |
- mat.m_matrix[2][2] = cosTheta; |
- mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; |
- mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; |
- mat.m_matrix[3][3] = 1.0; |
- } else if (x == 0.0 && y == 1.0 && z == 0.0) { |
- mat.m_matrix[0][0] = cosTheta; |
- mat.m_matrix[0][1] = 0.0; |
- mat.m_matrix[0][2] = -sinTheta; |
- mat.m_matrix[1][0] = 0.0; |
- mat.m_matrix[1][1] = 1.0; |
- mat.m_matrix[1][2] = 0.0; |
- mat.m_matrix[2][0] = sinTheta; |
- mat.m_matrix[2][1] = 0.0; |
- mat.m_matrix[2][2] = cosTheta; |
- mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; |
- mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; |
- mat.m_matrix[3][3] = 1.0; |
- } else if (x == 0.0 && y == 0.0 && z == 1.0) { |
- mat.m_matrix[0][0] = cosTheta; |
- mat.m_matrix[0][1] = sinTheta; |
- mat.m_matrix[0][2] = 0.0; |
- mat.m_matrix[1][0] = -sinTheta; |
- mat.m_matrix[1][1] = cosTheta; |
- mat.m_matrix[1][2] = 0.0; |
- mat.m_matrix[2][0] = 0.0; |
- mat.m_matrix[2][1] = 0.0; |
- mat.m_matrix[2][2] = 1.0; |
- mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; |
- mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; |
- mat.m_matrix[3][3] = 1.0; |
- } else { |
- // This case is the rotation about an arbitrary unit vector. |
- // |
- // Formula is adapted from Wikipedia article on Rotation matrix, |
- // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle |
- // |
- // An alternate resource with the same matrix: http://www.fastgraph.com/makegames/3drotation/ |
- // |
- double oneMinusCosTheta = 1 - cosTheta; |
- mat.m_matrix[0][0] = cosTheta + x * x * oneMinusCosTheta; |
- mat.m_matrix[0][1] = y * x * oneMinusCosTheta + z * sinTheta; |
- mat.m_matrix[0][2] = z * x * oneMinusCosTheta - y * sinTheta; |
- mat.m_matrix[1][0] = x * y * oneMinusCosTheta - z * sinTheta; |
- mat.m_matrix[1][1] = cosTheta + y * y * oneMinusCosTheta; |
- mat.m_matrix[1][2] = z * y * oneMinusCosTheta + x * sinTheta; |
- mat.m_matrix[2][0] = x * z * oneMinusCosTheta + y * sinTheta; |
- mat.m_matrix[2][1] = y * z * oneMinusCosTheta - x * sinTheta; |
- mat.m_matrix[2][2] = cosTheta + z * z * oneMinusCosTheta; |
- mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; |
- mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; |
- mat.m_matrix[3][3] = 1.0; |
- } |
- multiply(mat); |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz) |
-{ |
- // Angles are in degrees. Switch to radians. |
- rx = deg2rad(rx); |
- ry = deg2rad(ry); |
- rz = deg2rad(rz); |
- |
- TransformationMatrix mat; |
- |
- double sinTheta = sin(rz); |
- double cosTheta = cos(rz); |
- |
- mat.m_matrix[0][0] = cosTheta; |
- mat.m_matrix[0][1] = sinTheta; |
- mat.m_matrix[0][2] = 0.0; |
- mat.m_matrix[1][0] = -sinTheta; |
- mat.m_matrix[1][1] = cosTheta; |
- mat.m_matrix[1][2] = 0.0; |
- mat.m_matrix[2][0] = 0.0; |
- mat.m_matrix[2][1] = 0.0; |
- mat.m_matrix[2][2] = 1.0; |
- mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; |
- mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; |
- mat.m_matrix[3][3] = 1.0; |
- |
- TransformationMatrix rmat(mat); |
- |
- sinTheta = sin(ry); |
- cosTheta = cos(ry); |
- |
- mat.m_matrix[0][0] = cosTheta; |
- mat.m_matrix[0][1] = 0.0; |
- mat.m_matrix[0][2] = -sinTheta; |
- mat.m_matrix[1][0] = 0.0; |
- mat.m_matrix[1][1] = 1.0; |
- mat.m_matrix[1][2] = 0.0; |
- mat.m_matrix[2][0] = sinTheta; |
- mat.m_matrix[2][1] = 0.0; |
- mat.m_matrix[2][2] = cosTheta; |
- mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; |
- mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; |
- mat.m_matrix[3][3] = 1.0; |
- |
- rmat.multiply(mat); |
- |
- sinTheta = sin(rx); |
- cosTheta = cos(rx); |
- |
- mat.m_matrix[0][0] = 1.0; |
- mat.m_matrix[0][1] = 0.0; |
- mat.m_matrix[0][2] = 0.0; |
- mat.m_matrix[1][0] = 0.0; |
- mat.m_matrix[1][1] = cosTheta; |
- mat.m_matrix[1][2] = sinTheta; |
- mat.m_matrix[2][0] = 0.0; |
- mat.m_matrix[2][1] = -sinTheta; |
- mat.m_matrix[2][2] = cosTheta; |
- mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; |
- mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; |
- mat.m_matrix[3][3] = 1.0; |
- |
- rmat.multiply(mat); |
- |
- multiply(rmat); |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::translate(double tx, double ty) |
-{ |
- m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0]; |
- m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1]; |
- m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2]; |
- m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3]; |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz) |
-{ |
- m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0]; |
- m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1]; |
- m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2]; |
- m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3]; |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty) |
-{ |
- if (tx != 0) { |
- m_matrix[0][0] += m_matrix[0][3] * tx; |
- m_matrix[1][0] += m_matrix[1][3] * tx; |
- m_matrix[2][0] += m_matrix[2][3] * tx; |
- m_matrix[3][0] += m_matrix[3][3] * tx; |
- } |
- |
- if (ty != 0) { |
- m_matrix[0][1] += m_matrix[0][3] * ty; |
- m_matrix[1][1] += m_matrix[1][3] * ty; |
- m_matrix[2][1] += m_matrix[2][3] * ty; |
- m_matrix[3][1] += m_matrix[3][3] * ty; |
- } |
- |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz) |
-{ |
- translateRight(tx, ty); |
- if (tz != 0) { |
- m_matrix[0][2] += m_matrix[0][3] * tz; |
- m_matrix[1][2] += m_matrix[1][3] * tz; |
- m_matrix[2][2] += m_matrix[2][3] * tz; |
- m_matrix[3][2] += m_matrix[3][3] * tz; |
- } |
- |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::skew(double sx, double sy) |
-{ |
- // angles are in degrees. Switch to radians |
- sx = deg2rad(sx); |
- sy = deg2rad(sy); |
- |
- TransformationMatrix mat; |
- mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row |
- mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row |
- |
- multiply(mat); |
- return *this; |
-} |
- |
-TransformationMatrix& TransformationMatrix::applyPerspective(double p) |
-{ |
- TransformationMatrix mat; |
- if (p != 0) |
- mat.m_matrix[2][3] = -1/p; |
- |
- multiply(mat); |
- return *this; |
-} |
- |
-TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to) |
-{ |
- ASSERT(!from.isEmpty()); |
- return TransformationMatrix(to.width() / from.width(), |
- 0, 0, |
- to.height() / from.height(), |
- to.x() - from.x(), |
- to.y() - from.y()); |
-} |
- |
-// this = mat * this. |
-TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& mat) |
-{ |
-#if CPU(APPLE_ARMV7S) |
- double* leftMatrix = &(m_matrix[0][0]); |
- const double* rightMatrix = &(mat.m_matrix[0][0]); |
- asm volatile (// First row of leftMatrix. |
- "mov r3, %[leftMatrix]\n\t" |
- "vld1.64 { d16-d19 }, [%[leftMatrix], :128]!\n\t" |
- "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t" |
- "vmul.f64 d4, d0, d16\n\t" |
- "vld1.64 { d20-d23 }, [%[leftMatrix], :128]!\n\t" |
- "vmla.f64 d4, d1, d20\n\t" |
- "vld1.64 { d24-d27 }, [%[leftMatrix], :128]!\n\t" |
- "vmla.f64 d4, d2, d24\n\t" |
- "vld1.64 { d28-d31 }, [%[leftMatrix], :128]!\n\t" |
- "vmla.f64 d4, d3, d28\n\t" |
- |
- "vmul.f64 d5, d0, d17\n\t" |
- "vmla.f64 d5, d1, d21\n\t" |
- "vmla.f64 d5, d2, d25\n\t" |
- "vmla.f64 d5, d3, d29\n\t" |
- |
- "vmul.f64 d6, d0, d18\n\t" |
- "vmla.f64 d6, d1, d22\n\t" |
- "vmla.f64 d6, d2, d26\n\t" |
- "vmla.f64 d6, d3, d30\n\t" |
- |
- "vmul.f64 d7, d0, d19\n\t" |
- "vmla.f64 d7, d1, d23\n\t" |
- "vmla.f64 d7, d2, d27\n\t" |
- "vmla.f64 d7, d3, d31\n\t" |
- "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t" |
- "vst1.64 { d4-d7 }, [r3, :128]!\n\t" |
- |
- // Second row of leftMatrix. |
- "vmul.f64 d4, d0, d16\n\t" |
- "vmla.f64 d4, d1, d20\n\t" |
- "vmla.f64 d4, d2, d24\n\t" |
- "vmla.f64 d4, d3, d28\n\t" |
- |
- "vmul.f64 d5, d0, d17\n\t" |
- "vmla.f64 d5, d1, d21\n\t" |
- "vmla.f64 d5, d2, d25\n\t" |
- "vmla.f64 d5, d3, d29\n\t" |
- |
- "vmul.f64 d6, d0, d18\n\t" |
- "vmla.f64 d6, d1, d22\n\t" |
- "vmla.f64 d6, d2, d26\n\t" |
- "vmla.f64 d6, d3, d30\n\t" |
- |
- "vmul.f64 d7, d0, d19\n\t" |
- "vmla.f64 d7, d1, d23\n\t" |
- "vmla.f64 d7, d2, d27\n\t" |
- "vmla.f64 d7, d3, d31\n\t" |
- "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t" |
- "vst1.64 { d4-d7 }, [r3, :128]!\n\t" |
- |
- // Third row of leftMatrix. |
- "vmul.f64 d4, d0, d16\n\t" |
- "vmla.f64 d4, d1, d20\n\t" |
- "vmla.f64 d4, d2, d24\n\t" |
- "vmla.f64 d4, d3, d28\n\t" |
- |
- "vmul.f64 d5, d0, d17\n\t" |
- "vmla.f64 d5, d1, d21\n\t" |
- "vmla.f64 d5, d2, d25\n\t" |
- "vmla.f64 d5, d3, d29\n\t" |
- |
- "vmul.f64 d6, d0, d18\n\t" |
- "vmla.f64 d6, d1, d22\n\t" |
- "vmla.f64 d6, d2, d26\n\t" |
- "vmla.f64 d6, d3, d30\n\t" |
- |
- "vmul.f64 d7, d0, d19\n\t" |
- "vmla.f64 d7, d1, d23\n\t" |
- "vmla.f64 d7, d2, d27\n\t" |
- "vmla.f64 d7, d3, d31\n\t" |
- "vld1.64 { d0-d3}, [%[rightMatrix], :128]\n\t" |
- "vst1.64 { d4-d7 }, [r3, :128]!\n\t" |
- |
- // Fourth and last row of leftMatrix. |
- "vmul.f64 d4, d0, d16\n\t" |
- "vmla.f64 d4, d1, d20\n\t" |
- "vmla.f64 d4, d2, d24\n\t" |
- "vmla.f64 d4, d3, d28\n\t" |
- |
- "vmul.f64 d5, d0, d17\n\t" |
- "vmla.f64 d5, d1, d21\n\t" |
- "vmla.f64 d5, d2, d25\n\t" |
- "vmla.f64 d5, d3, d29\n\t" |
- |
- "vmul.f64 d6, d0, d18\n\t" |
- "vmla.f64 d6, d1, d22\n\t" |
- "vmla.f64 d6, d2, d26\n\t" |
- "vmla.f64 d6, d3, d30\n\t" |
- |
- "vmul.f64 d7, d0, d19\n\t" |
- "vmla.f64 d7, d1, d23\n\t" |
- "vmla.f64 d7, d2, d27\n\t" |
- "vmla.f64 d7, d3, d31\n\t" |
- "vst1.64 { d4-d7 }, [r3, :128]\n\t" |
- : [leftMatrix]"+r"(leftMatrix), [rightMatrix]"+r"(rightMatrix) |
- : |
- : "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"); |
-#elif defined(TRANSFORMATION_MATRIX_USE_X86_64_SSE2) |
- // x86_64 has 16 XMM registers which is enough to do the multiplication fully in registers. |
- __m128d matrixBlockA = _mm_load_pd(&(m_matrix[0][0])); |
- __m128d matrixBlockC = _mm_load_pd(&(m_matrix[1][0])); |
- __m128d matrixBlockE = _mm_load_pd(&(m_matrix[2][0])); |
- __m128d matrixBlockG = _mm_load_pd(&(m_matrix[3][0])); |
- |
- // First row. |
- __m128d otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[0][0]); |
- __m128d otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[0][1]); |
- __m128d otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[0][2]); |
- __m128d otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[0][3]); |
- |
- // output00 and output01. |
- __m128d accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam); |
- __m128d temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam); |
- __m128d temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam); |
- __m128d temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam); |
- |
- __m128d matrixBlockB = _mm_load_pd(&(m_matrix[0][2])); |
- __m128d matrixBlockD = _mm_load_pd(&(m_matrix[1][2])); |
- __m128d matrixBlockF = _mm_load_pd(&(m_matrix[2][2])); |
- __m128d matrixBlockH = _mm_load_pd(&(m_matrix[3][2])); |
- |
- accumulator = _mm_add_pd(accumulator, temp1); |
- accumulator = _mm_add_pd(accumulator, temp2); |
- accumulator = _mm_add_pd(accumulator, temp3); |
- _mm_store_pd(&m_matrix[0][0], accumulator); |
- |
- // output02 and output03. |
- accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam); |
- temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam); |
- temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam); |
- temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam); |
- |
- accumulator = _mm_add_pd(accumulator, temp1); |
- accumulator = _mm_add_pd(accumulator, temp2); |
- accumulator = _mm_add_pd(accumulator, temp3); |
- _mm_store_pd(&m_matrix[0][2], accumulator); |
- |
- // Second row. |
- otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[1][0]); |
- otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[1][1]); |
- otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[1][2]); |
- otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[1][3]); |
- |
- // output10 and output11. |
- accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam); |
- temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam); |
- temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam); |
- temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam); |
- |
- accumulator = _mm_add_pd(accumulator, temp1); |
- accumulator = _mm_add_pd(accumulator, temp2); |
- accumulator = _mm_add_pd(accumulator, temp3); |
- _mm_store_pd(&m_matrix[1][0], accumulator); |
- |
- // output12 and output13. |
- accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam); |
- temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam); |
- temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam); |
- temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam); |
- |
- accumulator = _mm_add_pd(accumulator, temp1); |
- accumulator = _mm_add_pd(accumulator, temp2); |
- accumulator = _mm_add_pd(accumulator, temp3); |
- _mm_store_pd(&m_matrix[1][2], accumulator); |
- |
- // Third row. |
- otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[2][0]); |
- otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[2][1]); |
- otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[2][2]); |
- otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[2][3]); |
- |
- // output20 and output21. |
- accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam); |
- temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam); |
- temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam); |
- temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam); |
- |
- accumulator = _mm_add_pd(accumulator, temp1); |
- accumulator = _mm_add_pd(accumulator, temp2); |
- accumulator = _mm_add_pd(accumulator, temp3); |
- _mm_store_pd(&m_matrix[2][0], accumulator); |
- |
- // output22 and output23. |
- accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam); |
- temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam); |
- temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam); |
- temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam); |
- |
- accumulator = _mm_add_pd(accumulator, temp1); |
- accumulator = _mm_add_pd(accumulator, temp2); |
- accumulator = _mm_add_pd(accumulator, temp3); |
- _mm_store_pd(&m_matrix[2][2], accumulator); |
- |
- // Fourth row. |
- otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[3][0]); |
- otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[3][1]); |
- otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[3][2]); |
- otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[3][3]); |
- |
- // output30 and output31. |
- accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam); |
- temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam); |
- temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam); |
- temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam); |
- |
- accumulator = _mm_add_pd(accumulator, temp1); |
- accumulator = _mm_add_pd(accumulator, temp2); |
- accumulator = _mm_add_pd(accumulator, temp3); |
- _mm_store_pd(&m_matrix[3][0], accumulator); |
- |
- // output32 and output33. |
- accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam); |
- temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam); |
- temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam); |
- temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam); |
- |
- accumulator = _mm_add_pd(accumulator, temp1); |
- accumulator = _mm_add_pd(accumulator, temp2); |
- accumulator = _mm_add_pd(accumulator, temp3); |
- _mm_store_pd(&m_matrix[3][2], accumulator); |
-#else |
- Matrix4 tmp; |
- |
- tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0] |
- + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]); |
- tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1] |
- + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]); |
- tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2] |
- + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]); |
- tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3] |
- + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]); |
- |
- tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0] |
- + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]); |
- tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1] |
- + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]); |
- tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2] |
- + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]); |
- tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3] |
- + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]); |
- |
- tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0] |
- + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]); |
- tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1] |
- + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]); |
- tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2] |
- + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]); |
- tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3] |
- + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]); |
- |
- tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0] |
- + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]); |
- tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1] |
- + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]); |
- tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2] |
- + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]); |
- tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3] |
- + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]); |
- |
- setMatrix(tmp); |
-#endif |
- return *this; |
-} |
- |
-void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const |
-{ |
- resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0]; |
- resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1]; |
- double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3]; |
- if (w != 1 && w != 0) { |
- resultX /= w; |
- resultY /= w; |
- } |
-} |
- |
-void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const |
-{ |
- resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; |
- resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; |
- resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2]; |
- double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3]; |
- if (w != 1 && w != 0) { |
- resultX /= w; |
- resultY /= w; |
- resultZ /= w; |
- } |
-} |
- |
-bool TransformationMatrix::isInvertible() const |
-{ |
- if (isIdentityOrTranslation()) |
- return true; |
- |
- double det = WebCore::determinant4x4(m_matrix); |
- |
- if (fabs(det) < SMALL_NUMBER) |
- return false; |
- |
- return true; |
-} |
- |
-TransformationMatrix TransformationMatrix::inverse() const |
-{ |
- if (isIdentityOrTranslation()) { |
- // identity matrix |
- if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0) |
- return TransformationMatrix(); |
- |
- // translation |
- return TransformationMatrix(1, 0, 0, 0, |
- 0, 1, 0, 0, |
- 0, 0, 1, 0, |
- -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1); |
- } |
- |
- TransformationMatrix invMat; |
- bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix); |
- if (!inverted) |
- return TransformationMatrix(); |
- |
- return invMat; |
-} |
- |
-void TransformationMatrix::makeAffine() |
-{ |
- m_matrix[0][2] = 0; |
- m_matrix[0][3] = 0; |
- |
- m_matrix[1][2] = 0; |
- m_matrix[1][3] = 0; |
- |
- m_matrix[2][0] = 0; |
- m_matrix[2][1] = 0; |
- m_matrix[2][2] = 1; |
- m_matrix[2][3] = 0; |
- |
- m_matrix[3][2] = 0; |
- m_matrix[3][3] = 1; |
-} |
- |
-AffineTransform TransformationMatrix::toAffineTransform() const |
-{ |
- return AffineTransform(m_matrix[0][0], m_matrix[0][1], m_matrix[1][0], |
- m_matrix[1][1], m_matrix[3][0], m_matrix[3][1]); |
-} |
- |
-TransformationMatrix::operator SkMatrix() const |
-{ |
- SkMatrix result; |
- |
- result.setScaleX(WebCoreDoubleToSkScalar(a())); |
- result.setSkewX(WebCoreDoubleToSkScalar(c())); |
- result.setTranslateX(WebCoreDoubleToSkScalar(e())); |
- |
- result.setScaleY(WebCoreDoubleToSkScalar(d())); |
- result.setSkewY(WebCoreDoubleToSkScalar(b())); |
- result.setTranslateY(WebCoreDoubleToSkScalar(f())); |
- |
- // FIXME: Set perspective properly. |
- result.setPerspX(0); |
- result.setPerspY(0); |
- result.set(SkMatrix::kMPersp2, SK_Scalar1); |
- |
- return result; |
-} |
- |
-static inline void blendFloat(double& from, double to, double progress) |
-{ |
- if (from != to) |
- from = from + (to - from) * progress; |
-} |
- |
-void TransformationMatrix::blend(const TransformationMatrix& from, double progress) |
-{ |
- if (from.isIdentity() && isIdentity()) |
- return; |
- |
- // decompose |
- DecomposedType fromDecomp; |
- DecomposedType toDecomp; |
- from.decompose(fromDecomp); |
- decompose(toDecomp); |
- |
- // interpolate |
- blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress); |
- blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress); |
- blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress); |
- blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress); |
- blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress); |
- blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress); |
- blendFloat(fromDecomp.translateX, toDecomp.translateX, progress); |
- blendFloat(fromDecomp.translateY, toDecomp.translateY, progress); |
- blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress); |
- blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress); |
- blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress); |
- blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress); |
- blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress); |
- |
- slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress); |
- |
- // recompose |
- recompose(fromDecomp); |
-} |
- |
-bool TransformationMatrix::decompose(DecomposedType& decomp) const |
-{ |
- if (isIdentity()) { |
- memset(&decomp, 0, sizeof(decomp)); |
- decomp.perspectiveW = 1; |
- decomp.scaleX = 1; |
- decomp.scaleY = 1; |
- decomp.scaleZ = 1; |
- } |
- |
- if (!WebCore::decompose(m_matrix, decomp)) |
- return false; |
- return true; |
-} |
- |
-void TransformationMatrix::recompose(const DecomposedType& decomp) |
-{ |
- makeIdentity(); |
- |
- // first apply perspective |
- m_matrix[0][3] = decomp.perspectiveX; |
- m_matrix[1][3] = decomp.perspectiveY; |
- m_matrix[2][3] = decomp.perspectiveZ; |
- m_matrix[3][3] = decomp.perspectiveW; |
- |
- // now translate |
- translate3d(decomp.translateX, decomp.translateY, decomp.translateZ); |
- |
- // apply rotation |
- double xx = decomp.quaternionX * decomp.quaternionX; |
- double xy = decomp.quaternionX * decomp.quaternionY; |
- double xz = decomp.quaternionX * decomp.quaternionZ; |
- double xw = decomp.quaternionX * decomp.quaternionW; |
- double yy = decomp.quaternionY * decomp.quaternionY; |
- double yz = decomp.quaternionY * decomp.quaternionZ; |
- double yw = decomp.quaternionY * decomp.quaternionW; |
- double zz = decomp.quaternionZ * decomp.quaternionZ; |
- double zw = decomp.quaternionZ * decomp.quaternionW; |
- |
- // Construct a composite rotation matrix from the quaternion values |
- TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, |
- 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0, |
- 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0, |
- 0, 0, 0, 1); |
- |
- multiply(rotationMatrix); |
- |
- // now apply skew |
- if (decomp.skewYZ) { |
- TransformationMatrix tmp; |
- tmp.setM32(decomp.skewYZ); |
- multiply(tmp); |
- } |
- |
- if (decomp.skewXZ) { |
- TransformationMatrix tmp; |
- tmp.setM31(decomp.skewXZ); |
- multiply(tmp); |
- } |
- |
- if (decomp.skewXY) { |
- TransformationMatrix tmp; |
- tmp.setM21(decomp.skewXY); |
- multiply(tmp); |
- } |
- |
- // finally, apply scale |
- scale3d(decomp.scaleX, decomp.scaleY, decomp.scaleZ); |
-} |
- |
-bool TransformationMatrix::isIntegerTranslation() const |
-{ |
- if (!isIdentityOrTranslation()) |
- return false; |
- |
- // Check for translate Z. |
- if (m_matrix[3][2]) |
- return false; |
- |
- // Check for non-integer translate X/Y. |
- if (static_cast<int>(m_matrix[3][0]) != m_matrix[3][0] || static_cast<int>(m_matrix[3][1]) != m_matrix[3][1]) |
- return false; |
- |
- return true; |
-} |
- |
-TransformationMatrix TransformationMatrix::to2dTransform() const |
-{ |
- return TransformationMatrix(m_matrix[0][0], m_matrix[0][1], 0, m_matrix[0][3], |
- m_matrix[1][0], m_matrix[1][1], 0, m_matrix[1][3], |
- 0, 0, 1, 0, |
- m_matrix[3][0], m_matrix[3][1], 0, m_matrix[3][3]); |
-} |
- |
-void TransformationMatrix::toColumnMajorFloatArray(FloatMatrix4& result) const |
-{ |
- result[0] = m11(); |
- result[1] = m12(); |
- result[2] = m13(); |
- result[3] = m14(); |
- result[4] = m21(); |
- result[5] = m22(); |
- result[6] = m23(); |
- result[7] = m24(); |
- result[8] = m31(); |
- result[9] = m32(); |
- result[10] = m33(); |
- result[11] = m34(); |
- result[12] = m41(); |
- result[13] = m42(); |
- result[14] = m43(); |
- result[15] = m44(); |
-} |
- |
-bool TransformationMatrix::isBackFaceVisible() const |
-{ |
- // Back-face visibility is determined by transforming the normal vector (0, 0, 1) and |
- // checking the sign of the resulting z component. However, normals cannot be |
- // transformed by the original matrix, they require being transformed by the |
- // inverse-transpose. |
- // |
- // Since we know we will be using (0, 0, 1), and we only care about the z-component of |
- // the transformed normal, then we only need the m33() element of the |
- // inverse-transpose. Therefore we do not need the transpose. |
- // |
- // Additionally, if we only need the m33() element, we do not need to compute a full |
- // inverse. Instead, knowing the inverse of a matrix is adjoint(matrix) / determinant, |
- // we can simply compute the m33() of the adjoint (adjugate) matrix, without computing |
- // the full adjoint. |
- |
- double determinant = WebCore::determinant4x4(m_matrix); |
- |
- // If the matrix is not invertible, then we assume its backface is not visible. |
- if (fabs(determinant) < SMALL_NUMBER) |
- return false; |
- |
- double cofactor33 = determinant3x3(m11(), m12(), m14(), m21(), m22(), m24(), m41(), m42(), m44()); |
- double zComponentOfTransformedNormal = cofactor33 / determinant; |
- |
- return zComponentOfTransformedNormal < 0; |
-} |
- |
-} |