| Index: third_party/WebKit/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
|
| ===================================================================
|
| --- third_party/WebKit/WebCore/platform/graphics/transforms/TransformationMatrix.cpp (revision 9391)
|
| +++ third_party/WebKit/WebCore/platform/graphics/transforms/TransformationMatrix.cpp (working copy)
|
| @@ -1,205 +1,1025 @@
|
| -/*
|
| - * Copyright (C) 2005, 2006 Apple Computer, 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 "TransformationMatrix.h"
|
| -
|
| -#include "FloatRect.h"
|
| -#include "FloatQuad.h"
|
| -#include "IntRect.h"
|
| -
|
| -#include <wtf/MathExtras.h>
|
| -
|
| -namespace WebCore {
|
| -
|
| -static void affineTransformDecompose(const TransformationMatrix& matrix, double sr[9])
|
| -{
|
| - TransformationMatrix m(matrix);
|
| -
|
| - // Compute scaling factors
|
| - double sx = sqrt(m.a() * m.a() + m.b() * m.b());
|
| - double sy = sqrt(m.c() * m.c() + m.d() * m.d());
|
| -
|
| - /* Compute cross product of transformed unit vectors. If negative,
|
| - one axis was flipped. */
|
| -
|
| - if (m.a() * m.d() - m.c() * m.b() < 0.0) {
|
| - // Flip axis with minimum unit vector dot product
|
| -
|
| - if (m.a() < m.d())
|
| - sx = -sx;
|
| - else
|
| - sy = -sy;
|
| - }
|
| -
|
| - // Remove scale from matrix
|
| -
|
| - m.scale(1.0 / sx, 1.0 / sy);
|
| -
|
| - // Compute rotation
|
| -
|
| - double angle = atan2(m.b(), m.a());
|
| -
|
| - // Remove rotation from matrix
|
| -
|
| - m.rotate(rad2deg(-angle));
|
| -
|
| - // Return results
|
| -
|
| - sr[0] = sx; sr[1] = sy; sr[2] = angle;
|
| - sr[3] = m.a(); sr[4] = m.b();
|
| - sr[5] = m.c(); sr[6] = m.d();
|
| - sr[7] = m.e(); sr[8] = m.f();
|
| -}
|
| -
|
| -static void affineTransformCompose(TransformationMatrix& m, const double sr[9])
|
| -{
|
| - m.setA(sr[3]);
|
| - m.setB(sr[4]);
|
| - m.setC(sr[5]);
|
| - m.setD(sr[6]);
|
| - m.setE(sr[7]);
|
| - m.setF(sr[8]);
|
| - m.rotate(rad2deg(sr[2]));
|
| - m.scale(sr[0], sr[1]);
|
| -}
|
| -
|
| -bool TransformationMatrix::isInvertible() const
|
| -{
|
| - return det() != 0.0;
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& other)
|
| -{
|
| - return (*this) *= other;
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::scale(double s)
|
| -{
|
| - return scale(s, s);
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
|
| -{
|
| - return scale(sx, sy);
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
|
| -{
|
| - return rotate(rad2deg(atan2(y, x)));
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::flipX()
|
| -{
|
| - return scale(-1.0f, 1.0f);
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::flipY()
|
| -{
|
| - return scale(1.0f, -1.0f);
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::skew(double angleX, double angleY)
|
| -{
|
| - return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::skewX(double angle)
|
| -{
|
| - return shear(tan(deg2rad(angle)), 0.0f);
|
| -}
|
| -
|
| -TransformationMatrix& TransformationMatrix::skewY(double angle)
|
| -{
|
| - return shear(0.0f, tan(deg2rad(angle)));
|
| -}
|
| -
|
| -TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
|
| -{
|
| - TransformationMatrix transform;
|
| - transform.translate(dest.x() - source.x(), dest.y() - source.y());
|
| - transform.scale(dest.width() / source.width(), dest.height() / source.height());
|
| - return transform;
|
| -}
|
| -
|
| -IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const
|
| -{
|
| - double x2, y2;
|
| - map(point.x(), point.y(), &x2, &y2);
|
| -
|
| - // Round the point.
|
| - return IntPoint(lround(x2), lround(y2));
|
| -}
|
| -
|
| -FloatPoint TransformationMatrix::mapPoint(const FloatPoint& point) const
|
| -{
|
| - double x2, y2;
|
| - map(point.x(), point.y(), &x2, &y2);
|
| -
|
| - return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
|
| -}
|
| -
|
| -FloatQuad TransformationMatrix::mapQuad(const FloatQuad& quad) const
|
| -{
|
| - // FIXME: avoid 4 seperate library calls. Point mapping really needs
|
| - // to be platform-independent code.
|
| - return FloatQuad(mapPoint(quad.p1()),
|
| - mapPoint(quad.p2()),
|
| - mapPoint(quad.p3()),
|
| - mapPoint(quad.p4()));
|
| -}
|
| -
|
| -void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
|
| -{
|
| - double srA[9], srB[9];
|
| -
|
| - affineTransformDecompose(from, srA);
|
| - affineTransformDecompose(*this, srB);
|
| -
|
| - // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
|
| - if ((srA[0] < 0.0 && srB[1] < 0.0) || (srA[1] < 0.0 && srB[0] < 0.0)) {
|
| - srA[0] = -srA[0];
|
| - srA[1] = -srA[1];
|
| - srA[2] += srA[2] < 0 ? piDouble : -piDouble;
|
| - }
|
| -
|
| - // Don't rotate the long way around.
|
| - srA[2] = fmod(srA[2], 2.0 * piDouble);
|
| - srB[2] = fmod(srB[2], 2.0 * piDouble);
|
| -
|
| - if (fabs(srA[2] - srB[2]) > piDouble) {
|
| - if (srA[2] > srB[2])
|
| - srA[2] -= piDouble * 2.0;
|
| - else
|
| - srB[2] -= piDouble * 2.0;
|
| - }
|
| -
|
| - for (int i = 0; i < 9; i++)
|
| - srA[i] = srA[i] + progress * (srB[i] - srA[i]);
|
| -
|
| - affineTransformCompose(*this, srA);
|
| -}
|
| -
|
| -}
|
| +/*
|
| + * Copyright (C) 2005, 2006 Apple Computer, 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 "TransformationMatrix.h"
|
| +
|
| +#include "FloatPoint3D.h"
|
| +#include "FloatRect.h"
|
| +#include "FloatQuad.h"
|
| +#include "IntRect.h"
|
| +
|
| +#include <wtf/MathExtras.h>
|
| +
|
| +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.
|
| +
|
| +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) {
|
| + for (i = 0; i < 3; i++) {
|
| + result.scaleX *= -1;
|
| + 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::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.0f, 1.0f);
|
| +}
|
| +
|
| +TransformationMatrix& TransformationMatrix::flipY()
|
| +{
|
| + return scaleNonUniform(1.0f, -1.0f);
|
| +}
|
| +
|
| +TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
|
| +{
|
| + TransformationMatrix transform;
|
| + transform.translate(dest.x() - source.x(), dest.y() - source.y());
|
| + transform.scaleNonUniform(dest.width() / source.width(), dest.height() / source.height());
|
| + return transform;
|
| +}
|
| +
|
| +FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) 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)
|
| +
|
| + double x = p.x();
|
| + double y = p.y();
|
| + double z = -(m13() * x + m23() * y + m43()) / m33();
|
| +
|
| + 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 != 1 && w != 0) {
|
| + outX /= w;
|
| + outY /= w;
|
| + }
|
| +
|
| + return FloatPoint(static_cast<float>(outX), static_cast<float>(outY));
|
| +}
|
| +
|
| +FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
|
| +{
|
| + double x, y;
|
| + multVecMatrix(p.x(), p.y(), x, y);
|
| + return FloatPoint(static_cast<float>(x), static_cast<float>(y));
|
| +}
|
| +
|
| +FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const
|
| +{
|
| + double x, y, z;
|
| + multVecMatrix(p.x(), p.y(), p.z(), x, y, z);
|
| + return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
| +}
|
| +
|
| +IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const
|
| +{
|
| + double x, y;
|
| + multVecMatrix(point.x(), point.y(), x, y);
|
| +
|
| + // Round the point.
|
| + return IntPoint(lround(x), lround(y));
|
| +}
|
| +
|
| +IntRect TransformationMatrix::mapRect(const IntRect &rect) const
|
| +{
|
| + return enclosingIntRect(mapRect(FloatRect(rect)));
|
| +}
|
| +
|
| +FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
|
| +{
|
| + FloatQuad resultQuad = mapQuad(FloatQuad(r));
|
| + return resultQuad.boundingBox();
|
| +}
|
| +
|
| +FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const
|
| +{
|
| + FloatQuad result;
|
| + result.setP1(mapPoint(q.p1()));
|
| + result.setP2(mapPoint(q.p2()));
|
| + result.setP3(mapPoint(q.p3()));
|
| + result.setP4(mapPoint(q.p4()));
|
| + return result;
|
| +}
|
| +
|
| +TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
|
| +{
|
| + TransformationMatrix mat;
|
| + mat.m_matrix[0][0] = sx;
|
| + mat.m_matrix[1][1] = sy;
|
| +
|
| + multLeft(mat);
|
| + return *this;
|
| +}
|
| +
|
| +TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz)
|
| +{
|
| + TransformationMatrix mat;
|
| + mat.m_matrix[0][0] = sx;
|
| + mat.m_matrix[1][1] = sy;
|
| + mat.m_matrix[2][2] = sz;
|
| +
|
| + multLeft(mat);
|
| + return *this;
|
| +}
|
| +
|
| +TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle)
|
| +{
|
| + // angles are in degrees. Switch to radians
|
| + angle = deg2rad(angle);
|
| +
|
| + angle /= 2.0f;
|
| + double sinA = sin(angle);
|
| + double cosA = cos(angle);
|
| + double sinA2 = sinA * sinA;
|
| +
|
| + // normalize
|
| + double length = sqrt(x * x + y * y + z * z);
|
| + if (length == 0) {
|
| + // bad vector, just use something reasonable
|
| + x = 0;
|
| + y = 0;
|
| + z = 1;
|
| + } else if (length != 1) {
|
| + x /= length;
|
| + y /= length;
|
| + z /= length;
|
| + }
|
| +
|
| + TransformationMatrix mat;
|
| +
|
| + // optimize case where axis is along major axis
|
| + if (x == 1.0f && y == 0.0f && z == 0.0f) {
|
| + mat.m_matrix[0][0] = 1.0f;
|
| + mat.m_matrix[0][1] = 0.0f;
|
| + mat.m_matrix[0][2] = 0.0f;
|
| + mat.m_matrix[1][0] = 0.0f;
|
| + mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[1][2] = 2.0f * sinA * cosA;
|
| + mat.m_matrix[2][0] = 0.0f;
|
| + mat.m_matrix[2][1] = -2.0f * sinA * cosA;
|
| + mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
|
| + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
|
| + mat.m_matrix[3][3] = 1.0f;
|
| + } else if (x == 0.0f && y == 1.0f && z == 0.0f) {
|
| + mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[0][1] = 0.0f;
|
| + mat.m_matrix[0][2] = -2.0f * sinA * cosA;
|
| + mat.m_matrix[1][0] = 0.0f;
|
| + mat.m_matrix[1][1] = 1.0f;
|
| + mat.m_matrix[1][2] = 0.0f;
|
| + mat.m_matrix[2][0] = 2.0f * sinA * cosA;
|
| + mat.m_matrix[2][1] = 0.0f;
|
| + mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
|
| + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
|
| + mat.m_matrix[3][3] = 1.0f;
|
| + } else if (x == 0.0f && y == 0.0f && z == 1.0f) {
|
| + mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[0][1] = 2.0f * sinA * cosA;
|
| + mat.m_matrix[0][2] = 0.0f;
|
| + mat.m_matrix[1][0] = -2.0f * sinA * cosA;
|
| + mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[1][2] = 0.0f;
|
| + mat.m_matrix[2][0] = 0.0f;
|
| + mat.m_matrix[2][1] = 0.0f;
|
| + mat.m_matrix[2][2] = 1.0f;
|
| + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
|
| + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
|
| + mat.m_matrix[3][3] = 1.0f;
|
| + } else {
|
| + double x2 = x*x;
|
| + double y2 = y*y;
|
| + double z2 = z*z;
|
| +
|
| + mat.m_matrix[0][0] = 1.0f - 2.0f * (y2 + z2) * sinA2;
|
| + mat.m_matrix[0][1] = 2.0f * (x * y * sinA2 + z * sinA * cosA);
|
| + mat.m_matrix[0][2] = 2.0f * (x * z * sinA2 - y * sinA * cosA);
|
| + mat.m_matrix[1][0] = 2.0f * (y * x * sinA2 - z * sinA * cosA);
|
| + mat.m_matrix[1][1] = 1.0f - 2.0f * (z2 + x2) * sinA2;
|
| + mat.m_matrix[1][2] = 2.0f * (y * z * sinA2 + x * sinA * cosA);
|
| + mat.m_matrix[2][0] = 2.0f * (z * x * sinA2 + y * sinA * cosA);
|
| + mat.m_matrix[2][1] = 2.0f * (z * y * sinA2 - x * sinA * cosA);
|
| + mat.m_matrix[2][2] = 1.0f - 2.0f * (x2 + y2) * sinA2;
|
| + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
|
| + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
|
| + mat.m_matrix[3][3] = 1.0f;
|
| + }
|
| + multLeft(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;
|
| +
|
| + rz /= 2.0f;
|
| + double sinA = sin(rz);
|
| + double cosA = cos(rz);
|
| + double sinA2 = sinA * sinA;
|
| +
|
| + mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[0][1] = 2.0f * sinA * cosA;
|
| + mat.m_matrix[0][2] = 0.0f;
|
| + mat.m_matrix[1][0] = -2.0f * sinA * cosA;
|
| + mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[1][2] = 0.0f;
|
| + mat.m_matrix[2][0] = 0.0f;
|
| + mat.m_matrix[2][1] = 0.0f;
|
| + mat.m_matrix[2][2] = 1.0f;
|
| + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
|
| + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
|
| + mat.m_matrix[3][3] = 1.0f;
|
| +
|
| + TransformationMatrix rmat(mat);
|
| +
|
| + ry /= 2.0f;
|
| + sinA = sin(ry);
|
| + cosA = cos(ry);
|
| + sinA2 = sinA * sinA;
|
| +
|
| + mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[0][1] = 0.0f;
|
| + mat.m_matrix[0][2] = -2.0f * sinA * cosA;
|
| + mat.m_matrix[1][0] = 0.0f;
|
| + mat.m_matrix[1][1] = 1.0f;
|
| + mat.m_matrix[1][2] = 0.0f;
|
| + mat.m_matrix[2][0] = 2.0f * sinA * cosA;
|
| + mat.m_matrix[2][1] = 0.0f;
|
| + mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
|
| + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
|
| + mat.m_matrix[3][3] = 1.0f;
|
| +
|
| + rmat.multLeft(mat);
|
| +
|
| + rx /= 2.0f;
|
| + sinA = sin(rx);
|
| + cosA = cos(rx);
|
| + sinA2 = sinA * sinA;
|
| +
|
| + mat.m_matrix[0][0] = 1.0f;
|
| + mat.m_matrix[0][1] = 0.0f;
|
| + mat.m_matrix[0][2] = 0.0f;
|
| + mat.m_matrix[1][0] = 0.0f;
|
| + mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[1][2] = 2.0f * sinA * cosA;
|
| + mat.m_matrix[2][0] = 0.0f;
|
| + mat.m_matrix[2][1] = -2.0f * sinA * cosA;
|
| + mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
|
| + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
|
| + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
|
| + mat.m_matrix[3][3] = 1.0f;
|
| +
|
| + rmat.multLeft(mat);
|
| +
|
| + multLeft(rmat);
|
| + return *this;
|
| +}
|
| +
|
| +TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
|
| +{
|
| + TransformationMatrix mat;
|
| + mat.m_matrix[3][0] = tx;
|
| + mat.m_matrix[3][1] = ty;
|
| +
|
| + multLeft(mat);
|
| + return *this;
|
| +}
|
| +
|
| +TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz)
|
| +{
|
| + TransformationMatrix mat;
|
| + mat.m_matrix[3][0] = tx;
|
| + mat.m_matrix[3][1] = ty;
|
| + mat.m_matrix[3][2] = tz;
|
| +
|
| + multLeft(mat);
|
| + 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
|
| +
|
| + multLeft(mat);
|
| + return *this;
|
| +}
|
| +
|
| +TransformationMatrix& TransformationMatrix::applyPerspective(double p)
|
| +{
|
| + TransformationMatrix mat;
|
| + if (p != 0)
|
| + mat.m_matrix[2][3] = -1/p;
|
| +
|
| + multLeft(mat);
|
| + return *this;
|
| +}
|
| +
|
| +//
|
| +// *this = mat * *this
|
| +//
|
| +TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix& mat)
|
| +{
|
| + 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);
|
| + 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
|
| +{
|
| + double det = WebCore::determinant4x4(m_matrix);
|
| +
|
| + if (fabs(det) < SMALL_NUMBER)
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +TransformationMatrix TransformationMatrix::inverse() const
|
| +{
|
| + TransformationMatrix invMat;
|
| +
|
| + bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix);
|
| + if (!inverted)
|
| + return TransformationMatrix();
|
| +
|
| + return invMat;
|
| +}
|
| +
|
| +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] = (float) decomp.perspectiveX;
|
| + m_matrix[1][3] = (float) decomp.perspectiveY;
|
| + m_matrix[2][3] = (float) decomp.perspectiveZ;
|
| + m_matrix[3][3] = (float) decomp.perspectiveW;
|
| +
|
| + // now translate
|
| + translate3d((float) decomp.translateX, (float) decomp.translateY, (float) 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);
|
| +
|
| + multLeft(rotationMatrix);
|
| +
|
| + // now apply skew
|
| + if (decomp.skewYZ) {
|
| + TransformationMatrix tmp;
|
| + tmp.setM32((float) decomp.skewYZ);
|
| + multLeft(tmp);
|
| + }
|
| +
|
| + if (decomp.skewXZ) {
|
| + TransformationMatrix tmp;
|
| + tmp.setM31((float) decomp.skewXZ);
|
| + multLeft(tmp);
|
| + }
|
| +
|
| + if (decomp.skewXY) {
|
| + TransformationMatrix tmp;
|
| + tmp.setM21((float) decomp.skewXY);
|
| + multLeft(tmp);
|
| + }
|
| +
|
| + // finally, apply scale
|
| + scale3d((float) decomp.scaleX, (float) decomp.scaleY, (float) decomp.scaleZ);
|
| +}
|
| +
|
| +}
|
|
|