15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2009 Torch Mobile, Inc.
453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * Copyright (C) 2013 Google Inc. All rights reserved.
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer.
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer in the
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    documentation and/or other materials provided with the distribution.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
291e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/transforms/TransformationMatrix.h"
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3176c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)#include "platform/geometry/FloatBox.h"
321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/geometry/FloatQuad.h"
331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/geometry/FloatRect.h"
341e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/geometry/IntRect.h"
351e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/geometry/LayoutRect.h"
361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/transforms/AffineTransform.h"
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/Assertions.h"
397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/MathExtras.h"
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
41926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#if CPU(X86_64)
42926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <emmintrin.h>
43926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#endif
44926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
45c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Supporting Math Functions
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// This is a set of function from various places (attributed inline) to do things like
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// inversion and decomposition of a 4x4 matrix. They are used throughout the code
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch// EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
5802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch// as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
5902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch// or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
6002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch// are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
6102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch// webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// with no guarantee.
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// A clarification about the storage of matrix elements
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
6602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch// This class uses a 2 dimensional array internally to store the elements of the matrix.  The first index into
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// the array refers to the column that the element lies in; the second index refers to the row.
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// In other words, this is the layout of the matrix:
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// | m_matrix[0][0] m_matrix[1][0] m_matrix[2][0] m_matrix[3][0] |
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// | m_matrix[0][1] m_matrix[1][1] m_matrix[2][1] m_matrix[3][1] |
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// | m_matrix[0][2] m_matrix[1][2] m_matrix[2][2] m_matrix[3][2] |
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// | m_matrix[0][3] m_matrix[1][3] m_matrix[2][3] m_matrix[3][3] |
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)typedef double Vector4[4];
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)typedef double Vector3[3];
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const double SMALL_NUMBER = 1.e-8;
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// inverse(original_matrix, inverse_matrix)
8202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch//
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// calculate the inverse of a 4x4 matrix
8402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch//
8502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch// -1
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// A  = ___1__ adjoint A
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//       det A
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  double = determinant2x2(double a, double b, double c, double d)
9002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch//
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  calculate the determinant of a 2x2 matrix.
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static double determinant2x2(double a, double b, double c, double d)
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return a * d - b * c;
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
9902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch//
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  Calculate the determinant of a 3x3 matrix
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  in the form
10202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch//
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//      | a1,  b1,  c1 |
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//      | a2,  b2,  c2 |
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//      | a3,  b3,  c3 |
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return a1 * determinant2x2(b2, b3, c2, c3)
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         - b1 * determinant2x2(a2, a3, c2, c3)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         + c1 * determinant2x2(a2, a3, b2, b3);
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  double = determinant4x4(matrix)
11502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch//
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  calculate the determinant of a 4x4 matrix.
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static double determinant4x4(const TransformationMatrix::Matrix4& m)
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Assign to individual variable names to aid selecting
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // correct elements
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a1 = m[0][0];
12402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    double b1 = m[0][1];
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double c1 = m[0][2];
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double d1 = m[0][3];
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a2 = m[1][0];
12902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    double b2 = m[1][1];
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double c2 = m[1][2];
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double d2 = m[1][3];
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    double a3 = m[2][0];
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double b3 = m[2][1];
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double c3 = m[2][2];
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double d3 = m[2][3];
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a4 = m[3][0];
13902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    double b4 = m[3][1];
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double c4 = m[3][2];
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double d4 = m[3][3];
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// adjoint( original_matrix, inverse_matrix )
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//   calculate the adjoint of a 4x4 matrix
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//    Let  a   denote the minor determinant of matrix A obtained by
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//         ij
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//    deleting the ith row and jth column from A.
15702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch//
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//                  i+j
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//   Let  b   = (-1)    a
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//        ij            ji
16102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch//
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  The matrix B = (b  ) is the adjoint of A
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//                   ij
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Assign to individual variable names to aid
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // selecting correct values
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a1 = matrix[0][0];
17002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    double b1 = matrix[0][1];
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double c1 = matrix[0][2];
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double d1 = matrix[0][3];
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a2 = matrix[1][0];
17502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    double b2 = matrix[1][1];
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double c2 = matrix[1][2];
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double d2 = matrix[1][3];
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a3 = matrix[2][0];
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double b3 = matrix[2][1];
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double c3 = matrix[2][2];
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double d3 = matrix[2][3];
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a4 = matrix[3][0];
18502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    double b4 = matrix[3][1];
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double c4 = matrix[3][2];
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double d4 = matrix[3][3];
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Row column labeling reversed since we transpose rows & columns
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[0][0]  =   determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[1][0]  = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[2][0]  =   determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[3][0]  = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
19402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[0][1]  = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[1][1]  =   determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[2][1]  = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[3][1]  =   determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
19902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[0][2]  =   determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[1][2]  = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[2][2]  =   determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[3][2]  = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
20402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[0][3]  = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[1][3]  =   determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[2][3]  = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[3][3]  =   determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Returns false if the matrix is not invertible
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Calculate the adjoint matrix
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    adjoint(matrix, result);
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Calculate the 4x4 determinant
21802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    // If the determinant is zero,
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // then the inverse matrix is not unique.
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double det = determinant4x4(matrix);
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (fabs(det) < SMALL_NUMBER)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Scale the adjoint matrix to get the inverse
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int i = 0; i < 4; i++)
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (int j = 0; j < 4; j++)
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result[i][j] = result[i][j] / det;
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// End of code adapted from Matrix Inversion by Richard Carling
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Perform a decomposition on the passed matrix, return false if unsuccessful
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// From Graphics Gems: unmatrix.c
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Transpose rotation portion of matrix a, return b
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b)
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int i = 0; i < 4; i++)
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (int j = 0; j < 4; j++)
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            b[i][j] = a[j][i];
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Multiply a homogeneous point by a matrix and return the transformed point
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result)
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) +
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                (p[2] * m[2][0]) + (p[3] * m[3][0]);
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) +
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                (p[2] * m[2][1]) + (p[3] * m[3][1]);
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) +
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                (p[2] * m[2][2]) + (p[3] * m[3][2]);
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) +
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                (p[2] * m[2][3]) + (p[3] * m[3][3]);
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static double v3Length(Vector3 a)
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    return std::sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
26502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdochstatic void v3Scale(Vector3 v, double desiredLength)
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double len = v3Length(v);
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (len != 0) {
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        double l = desiredLength / len;
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        v[0] *= l;
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        v[1] *= l;
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        v[2] *= l;
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
27602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdochstatic double v3Dot(const Vector3 a, const Vector3 b)
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Make a linear combination of two vectors and return the result.
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// result = (a * ascl) + (b * bscl)
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl)
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[0] = (ascl * a[0]) + (bscl * b[0]);
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[1] = (ascl * a[1]) + (bscl * b[1]);
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[2] = (ascl * a[2]) + (bscl * b[2]);
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Return the cross product result = a cross b */
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[0] = (a[1] * b[2]) - (a[2] * b[1]);
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[1] = (a[2] * b[0]) - (a[0] * b[2]);
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[2] = (a[0] * b[1]) - (a[1] * b[0]);
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result)
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TransformationMatrix::Matrix4 localMatrix;
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4));
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Normalize the matrix.
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (localMatrix[3][3] == 0)
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int i, j;
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (i = 0; i < 4; i++)
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (j = 0; j < 4; j++)
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            localMatrix[i][j] /= localMatrix[3][3];
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // perspectiveMatrix is used to solve for perspective, but it also provides
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // an easy way to test for singularity of the upper 3x3 component.
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TransformationMatrix::Matrix4 perspectiveMatrix;
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4));
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (i = 0; i < 3; i++)
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        perspectiveMatrix[i][3] = 0;
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    perspectiveMatrix[3][3] = 1;
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (determinant4x4(perspectiveMatrix) == 0)
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // First, isolate perspective.  This is the messiest.
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) {
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // rightHandSide is the right hand side of the equation.
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Vector4 rightHandSide;
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rightHandSide[0] = localMatrix[0][3];
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rightHandSide[1] = localMatrix[1][3];
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rightHandSide[2] = localMatrix[2][3];
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rightHandSide[3] = localMatrix[3][3];
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Solve the equation by inverting perspectiveMatrix and multiplying
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // rightHandSide by the inverse.  (This is the easiest way, not
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // necessarily the best.)
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix;
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        inverse(perspectiveMatrix, inversePerspectiveMatrix);
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Vector4 perspectivePoint;
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
34102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.perspectiveX = perspectivePoint[0];
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.perspectiveY = perspectivePoint[1];
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.perspectiveZ = perspectivePoint[2];
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.perspectiveW = perspectivePoint[3];
34602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Clear the perspective partition
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0;
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        localMatrix[3][3] = 1;
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // No perspective.
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0;
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.perspectiveW = 1;
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
35502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Next take care of translation (easy).
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.translateX = localMatrix[3][0];
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    localMatrix[3][0] = 0;
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.translateY = localMatrix[3][1];
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    localMatrix[3][1] = 0;
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.translateZ = localMatrix[3][2];
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    localMatrix[3][2] = 0;
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Vector4 type and functions need to be added to the common set.
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector3 row[3], pdum3;
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Now get scale and shear.
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (i = 0; i < 3; i++) {
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        row[i][0] = localMatrix[i][0];
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        row[i][1] = localMatrix[i][1];
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        row[i][2] = localMatrix[i][2];
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Compute X scale factor and normalize first row.
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.scaleX = v3Length(row[0]);
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v3Scale(row[0], 1.0);
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Compute XY shear factor and make 2nd row orthogonal to 1st.
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.skewXY = v3Dot(row[0], row[1]);
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY);
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Now, compute Y scale and normalize 2nd row.
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.scaleY = v3Length(row[1]);
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v3Scale(row[1], 1.0);
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.skewXY /= result.scaleY;
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Compute XZ and YZ shears, orthogonalize 3rd row.
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.skewXZ = v3Dot(row[0], row[2]);
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ);
3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.skewYZ = v3Dot(row[1], row[2]);
3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ);
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Next, get Z scale and normalize 3rd row.
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.scaleZ = v3Length(row[2]);
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v3Scale(row[2], 1.0);
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.skewXZ /= result.scaleZ;
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.skewYZ /= result.scaleZ;
39802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // At this point, the matrix (in rows[]) is orthonormal.
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Check for a coordinate system flip.  If the determinant
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // is -1, then negate the matrix and the scaling factors.
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v3Cross(row[1], row[2], pdum3);
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (v3Dot(row[0], pdum3) < 0) {
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.scaleX *= -1;
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.scaleY *= -1;
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.scaleZ *= -1;
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (i = 0; i < 3; i++) {
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            row[i][0] *= -1;
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            row[i][1] *= -1;
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            row[i][2] *= -1;
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
41502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Now, get the rotations out, as described in the gem.
41702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME - Add the ability to return either quaternions (which are
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // easier to recompose with) or Euler angles (rx, ry, rz), which
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // are easier for authors to deal with. The latter will only be useful
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // will leave the Euler angle code here for now.
4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // ret.rotateY = asin(-row[0][2]);
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // if (cos(ret.rotateY) != 0) {
4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //     ret.rotateX = atan2(row[1][2], row[2][2]);
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //     ret.rotateZ = atan2(row[0][1], row[0][0]);
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // } else {
4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //     ret.rotateX = atan2(-row[2][0], row[1][1]);
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //     ret.rotateZ = 0;
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // }
43202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double s, t, x, y, z, w;
4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    t = row[0][0] + row[1][1] + row[2][2] + 1.0;
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (t > 1e-4) {
4387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        s = 0.5 / std::sqrt(t);
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        w = 0.25 / s;
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        x = (row[2][1] - row[1][2]) * s;
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        y = (row[0][2] - row[2][0]) * s;
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        z = (row[1][0] - row[0][1]) * s;
44302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
4447242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        s = std::sqrt(1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        x = 0.25 * s;
44602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        y = (row[0][1] + row[1][0]) / s;
44702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        z = (row[0][2] + row[2][0]) / s;
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        w = (row[2][1] - row[1][2]) / s;
44902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    } else if (row[1][1] > row[2][2]) {
4507242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        s = std::sqrt(1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy
45102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        x = (row[0][1] + row[1][0]) / s;
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        y = 0.25 * s;
45302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        z = (row[1][2] + row[2][1]) / s;
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        w = (row[0][2] - row[2][0]) / s;
45502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    } else {
4567242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        s = std::sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        x = (row[0][2] + row[2][0]) / s;
45802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        y = (row[1][2] + row[2][1]) / s;
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        z = 0.25 * s;
4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        w = (row[1][0] - row[0][1]) / s;
4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.quaternionX = x;
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.quaternionY = y;
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.quaternionZ = z;
4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.quaternionW = w;
46702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Perform a spherical linear interpolation between the two
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// passed quaternions with 0 <= t <= 1
4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void slerp(double qa[4], const double qb[4], double t)
4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double ax, ay, az, aw;
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double bx, by, bz, bw;
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double cx, cy, cz, cw;
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double angle;
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double th, invth, scale, invscale;
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3];
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3];
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    angle = ax * bx + ay * by + az * bz + aw * bw;
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (angle < 0.0) {
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ax = -ax; ay = -ay;
4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        az = -az; aw = -aw;
4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        angle = -angle;
4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (angle + 1.0 > .05) {
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (1.0 - angle >= .05) {
4947242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            th = std::acos(angle);
4957242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            invth = 1.0 / std::sin(th);
4967242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            scale = std::sin(th * (1.0 - t)) * invth;
4977242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            invscale = std::sin(th * t) * invth;
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else {
4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            scale = 1.0 - t;
5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            invscale = t;
5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bx = -ay;
5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        by = ax;
5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bz = -aw;
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bw = az;
5077242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        scale = std::sin(piDouble * (.5 - t));
5087242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        invscale = std::sin(piDouble * t);
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    cx = ax * scale + bx * invscale;
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    cy = ay * scale + by * invscale;
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    cz = az * scale + bz * invscale;
5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    cw = aw * scale + bw * invscale;
5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw;
5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// End of Supporting Math Functions
5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix::TransformationMatrix(const AffineTransform& t)
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    setMatrix(t.a(), t.b(), t.c(), t.d(), t.e(), t.f());
5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::scale(double s)
5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return scaleNonUniform(s, s);
5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return rotate(rad2deg(atan2(y, x)));
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::flipX()
5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
538926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return scaleNonUniform(-1.0, 1.0);
5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::flipY()
5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
543926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return scaleNonUniform(1.0, -1.0);
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p, bool* clamped) const
5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // This is basically raytracing. We have a point in the destination
5495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // plane with z=0, and we cast a ray parallel to the z-axis from that
5505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // point to find the z-position at which it intersects the z=0 plane
5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // with the transform applied. Once we have that point we apply the
5525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // inverse transform to find the corresponding point in the source
5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // space.
55402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    //
5555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Given a plane with normal Pn, and a ray starting at point R0 and
5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // with direction defined by the vector Rd, we can find the
5575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // intersection point as a distance d from R0 in units of Rd by:
55802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    //
5595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // d = -dot (Pn', R0) / dot (Pn', Rd)
5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (clamped)
5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        *clamped = false;
5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m33() == 0) {
5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // In this case, the projection plane is parallel to the ray we are trying to
5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // trace, and there is no well-defined value for the projection.
5665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return FloatPoint();
5675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
56802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double x = p.x();
5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double y = p.y();
5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double z = -(m13() * x + m23() * y + m43()) / m33();
5725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: use multVecMatrix()
5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double outX = x * m11() + y * m21() + z * m31() + m41();
5755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double outY = x * m12() + y * m22() + z * m32() + m42();
5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double w = x * m14() + y * m24() + z * m34() + m44();
5785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (w <= 0) {
5795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Using int max causes overflow when other code uses the projected point. To
5805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // represent infinity yet reduce the risk of overflow, we use a large but
5815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // not-too-large number here when clamping.
5825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const int largeNumber = 100000000 / kFixedPointDenominator;
5835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        outX = copysign(largeNumber, outX);
5845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        outY = copysign(largeNumber, outY);
5855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (clamped)
5865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            *clamped = true;
5875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else if (w != 1) {
5885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        outX /= w;
5895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        outY /= w;
5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return FloatPoint(static_cast<float>(outX), static_cast<float>(outY));
5935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q, bool* clamped) const
5965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatQuad projectedQuad;
5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool clamped1 = false;
6005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool clamped2 = false;
6015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool clamped3 = false;
6025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool clamped4 = false;
6035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    projectedQuad.setP1(projectPoint(q.p1(), &clamped1));
6055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    projectedQuad.setP2(projectPoint(q.p2(), &clamped2));
6065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    projectedQuad.setP3(projectPoint(q.p3(), &clamped3));
6075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    projectedQuad.setP4(projectPoint(q.p4(), &clamped4));
6085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (clamped)
6105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        *clamped = clamped1 || clamped2 || clamped3 || clamped4;
61102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If all points on the quad had w < 0, then the entire quad would not be visible to the projected surface.
6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool everythingWasClipped = clamped1 && clamped2 && clamped3 && clamped4;
6145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (everythingWasClipped)
6155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return FloatQuad();
6165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return projectedQuad;
6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static float clampEdgeValue(float f)
6215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
622926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    ASSERT(!std::isnan(f));
6237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    return std::min<float>(std::max<float>(f, (-LayoutUnit::max() / 2).toFloat()), (LayoutUnit::max() / 2).toFloat());
6245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutRect TransformationMatrix::clampedBoundsOfProjectedQuad(const FloatQuad& q) const
6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatRect mappedQuadBounds = projectQuad(q).boundingBox();
6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float left = clampEdgeValue(floorf(mappedQuadBounds.x()));
6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float top = clampEdgeValue(floorf(mappedQuadBounds.y()));
6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float right;
634926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (std::isinf(mappedQuadBounds.x()) && std::isinf(mappedQuadBounds.width()))
635d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        right = (LayoutUnit::max() / 2).toFloat();
6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        right = clampEdgeValue(ceilf(mappedQuadBounds.maxX()));
6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float bottom;
640926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (std::isinf(mappedQuadBounds.y()) && std::isinf(mappedQuadBounds.height()))
641d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        bottom = (LayoutUnit::max() / 2).toFloat();
6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bottom = clampEdgeValue(ceilf(mappedQuadBounds.maxY()));
6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return LayoutRect(LayoutUnit::clamp(left), LayoutUnit::clamp(top),  LayoutUnit::clamp(right - left), LayoutUnit::clamp(bottom - top));
6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
64876c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)void TransformationMatrix::transformBox(FloatBox& box) const
64976c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles){
65076c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    FloatBox bounds;
65176c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    bool firstPoint = true;
65276c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    for (size_t i = 0; i < 2; ++i) {
65376c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)        for (size_t j = 0; j < 2; ++j) {
65476c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)            for (size_t k = 0; k < 2; ++k) {
65576c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                FloatPoint3D point(box.x(), box.y(), box.z());
65676c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                point += FloatPoint3D(i * box.width(), j * box.height(), k * box.depth());
65776c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                point = mapPoint(point);
65876c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                if (firstPoint) {
65976c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                    bounds.setOrigin(point);
66076c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                    firstPoint = false;
66176c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                } else {
66276c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                    bounds.expandTo(point);
66376c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)                }
66476c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)            }
66576c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)        }
66676c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    }
66776c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    box = bounds;
66876c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)}
66976c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)
6705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
6715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isIdentityOrTranslation())
6735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1]));
6745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
675926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return internalMapPoint(p);
6765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const
6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isIdentityOrTranslation())
6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]),
6825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            p.y() + static_cast<float>(m_matrix[3][1]),
6835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            p.z() + static_cast<float>(m_matrix[3][2]));
6845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
685926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return internalMapPoint(p);
6865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)IntRect TransformationMatrix::mapRect(const IntRect &rect) const
6895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return enclosingIntRect(mapRect(FloatRect(rect)));
6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutRect TransformationMatrix::mapRect(const LayoutRect& r) const
6945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return enclosingLayoutRect(mapRect(FloatRect(r)));
6965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
6995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isIdentityOrTranslation()) {
7015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        FloatRect mappedRect(r);
7025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
7035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return mappedRect;
7045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
706926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    FloatQuad result;
707926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
708926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    float maxX = r.maxX();
709926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    float maxY = r.maxY();
710926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    result.setP1(internalMapPoint(FloatPoint(r.x(), r.y())));
711926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    result.setP2(internalMapPoint(FloatPoint(maxX, r.y())));
712926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    result.setP3(internalMapPoint(FloatPoint(maxX, maxY)));
713926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    result.setP4(internalMapPoint(FloatPoint(r.x(), maxY)));
714926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
715926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return result.boundingBox();
7165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const
7195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isIdentityOrTranslation()) {
7215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        FloatQuad mappedQuad(q);
7225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
7235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return mappedQuad;
7245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatQuad result;
727926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    result.setP1(internalMapPoint(q.p1()));
728926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    result.setP2(internalMapPoint(q.p2()));
729926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    result.setP3(internalMapPoint(q.p3()));
730926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    result.setP4(internalMapPoint(q.p4()));
7315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
7325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
7355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[0][0] *= sx;
7375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[0][1] *= sx;
7385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[0][2] *= sx;
7395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[0][3] *= sx;
74002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
7415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[1][0] *= sy;
7425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[1][1] *= sy;
7435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[1][2] *= sy;
7445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[1][3] *= sy;
7455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
7465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz)
7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    scaleNonUniform(sx, sy);
75102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
7525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[2][0] *= sz;
7535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[2][1] *= sz;
7545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[2][2] *= sz;
7555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[2][3] *= sz;
7565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
7575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle)
7605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Normalize the axis of rotation
7627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    double length = std::sqrt(x * x + y * y + z * z);
7635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (length == 0) {
76402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied.
7655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return *this;
7665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else if (length != 1) {
7675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        x /= length;
7685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        y /= length;
7695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        z /= length;
7705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Angles are in degrees. Switch to radians.
7735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    angle = deg2rad(angle);
7745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7757242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    double sinTheta = std::sin(angle);
7767242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    double cosTheta = std::cos(angle);
77702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
7785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TransformationMatrix mat;
7795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Optimize cases where the axis is along a major axis
781926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (x == 1.0 && y == 0.0 && z == 0.0) {
782926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][0] = 1.0;
783926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][1] = 0.0;
784926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][2] = 0.0;
785926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[1][0] = 0.0;
7865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[1][1] = cosTheta;
7875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[1][2] = sinTheta;
788926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[2][0] = 0.0;
7895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[2][1] = -sinTheta;
7905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[2][2] = cosTheta;
791926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
792926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
793926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[3][3] = 1.0;
794926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    } else if (x == 0.0 && y == 1.0 && z == 0.0) {
7955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[0][0] = cosTheta;
796926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][1] = 0.0;
7975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[0][2] = -sinTheta;
798926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[1][0] = 0.0;
799926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[1][1] = 1.0;
800926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[1][2] = 0.0;
8015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[2][0] = sinTheta;
802926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[2][1] = 0.0;
8035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[2][2] = cosTheta;
804926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
805926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
806926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[3][3] = 1.0;
807926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    } else if (x == 0.0 && y == 0.0 && z == 1.0) {
8085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[0][0] = cosTheta;
8095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[0][1] = sinTheta;
810926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][2] = 0.0;
8115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[1][0] = -sinTheta;
8125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[1][1] = cosTheta;
813926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[1][2] = 0.0;
814926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[2][0] = 0.0;
815926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[2][1] = 0.0;
816926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[2][2] = 1.0;
817926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
818926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
819926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[3][3] = 1.0;
8205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
8215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // This case is the rotation about an arbitrary unit vector.
8225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        //
8235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Formula is adapted from Wikipedia article on Rotation matrix,
8245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
8255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        //
8265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // An alternate resource with the same matrix: http://www.fastgraph.com/makegames/3drotation/
8275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        //
8285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        double oneMinusCosTheta = 1 - cosTheta;
8295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[0][0] = cosTheta + x * x * oneMinusCosTheta;
8305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[0][1] = y * x * oneMinusCosTheta + z * sinTheta;
8315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[0][2] = z * x * oneMinusCosTheta - y * sinTheta;
8325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[1][0] = x * y * oneMinusCosTheta - z * sinTheta;
8335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[1][1] = cosTheta + y * y * oneMinusCosTheta;
8345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[1][2] = z * y * oneMinusCosTheta + x * sinTheta;
8355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[2][0] = x * z * oneMinusCosTheta + y * sinTheta;
8365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[2][1] = y * z * oneMinusCosTheta - x * sinTheta;
8375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[2][2] = cosTheta + z * z * oneMinusCosTheta;
838926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
839926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
840926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        mat.m_matrix[3][3] = 1.0;
8415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
8425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    multiply(mat);
8435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
8445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz)
8475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
8485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Angles are in degrees. Switch to radians.
8495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rx = deg2rad(rx);
8505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ry = deg2rad(ry);
8515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rz = deg2rad(rz);
85202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
8535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TransformationMatrix mat;
85402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
8557242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    double sinTheta = std::sin(rz);
8567242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    double cosTheta = std::cos(rz);
85702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
8585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[0][0] = cosTheta;
8595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[0][1] = sinTheta;
860926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[0][2] = 0.0;
8615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[1][0] = -sinTheta;
8625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[1][1] = cosTheta;
863926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[1][2] = 0.0;
864926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[2][0] = 0.0;
865926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[2][1] = 0.0;
866926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[2][2] = 1.0;
867926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
868926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
869926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[3][3] = 1.0;
87002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
8715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TransformationMatrix rmat(mat);
87202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
8737242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    sinTheta = std::sin(ry);
8747242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    cosTheta = std::cos(ry);
87502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
8765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[0][0] = cosTheta;
877926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[0][1] = 0.0;
8785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[0][2] = -sinTheta;
879926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[1][0] = 0.0;
880926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[1][1] = 1.0;
881926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[1][2] = 0.0;
8825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[2][0] = sinTheta;
883926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[2][1] = 0.0;
8845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[2][2] = cosTheta;
885926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
886926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
887926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[3][3] = 1.0;
8885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rmat.multiply(mat);
8905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8917242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    sinTheta = std::sin(rx);
8927242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    cosTheta = std::cos(rx);
89302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
894926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[0][0] = 1.0;
895926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[0][1] = 0.0;
896926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[0][2] = 0.0;
897926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[1][0] = 0.0;
8985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[1][1] = cosTheta;
8995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[1][2] = sinTheta;
900926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[2][0] = 0.0;
9015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[2][1] = -sinTheta;
9025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mat.m_matrix[2][2] = cosTheta;
903926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
904926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
905926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    mat.m_matrix[3][3] = 1.0;
9065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rmat.multiply(mat);
9085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    multiply(rmat);
9105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
9115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
9145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
9155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0];
9165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1];
9175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2];
9185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3];
9195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
9205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz)
9235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
9245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0];
9255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1];
9265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2];
9275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3];
9285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
9295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty)
9325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
9335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (tx != 0) {
9345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[0][0] +=  m_matrix[0][3] * tx;
9355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[1][0] +=  m_matrix[1][3] * tx;
9365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[2][0] +=  m_matrix[2][3] * tx;
9375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[3][0] +=  m_matrix[3][3] * tx;
9385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (ty != 0) {
9415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[0][1] +=  m_matrix[0][3] * ty;
9425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[1][1] +=  m_matrix[1][3] * ty;
9435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[2][1] +=  m_matrix[2][3] * ty;
9445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[3][1] +=  m_matrix[3][3] * ty;
9455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
9485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz)
9515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
9525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    translateRight(tx, ty);
9535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (tz != 0) {
9545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[0][2] +=  m_matrix[0][3] * tz;
9555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[1][2] +=  m_matrix[1][3] * tz;
9565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[2][2] +=  m_matrix[2][3] * tz;
9575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_matrix[3][2] +=  m_matrix[3][3] * tz;
9585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
9615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::skew(double sx, double sy)
9645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
9655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // angles are in degrees. Switch to radians
9665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    sx = deg2rad(sx);
9675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    sy = deg2rad(sy);
96802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
9695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TransformationMatrix mat;
9707242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    mat.m_matrix[0][1] = std::tan(sy); // note that the y shear goes in the first row
9717242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    mat.m_matrix[1][0] = std::tan(sx); // and the x shear in the second row
9725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    multiply(mat);
9745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
9755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::applyPerspective(double p)
9785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
9795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TransformationMatrix mat;
9805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (p != 0)
9815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mat.m_matrix[2][3] = -1/p;
9825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    multiply(mat);
9845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
9855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to)
9885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
9895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(!from.isEmpty());
9905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return TransformationMatrix(to.width() / from.width(),
9915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                0, 0,
9925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                to.height() / from.height(),
9935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                to.x() - from.x(),
9945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                to.y() - from.y());
9955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
997926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)// this = mat * this.
9985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& mat)
9995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
10007242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#if CPU(ARM64)
10017242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    double* rightMatrix = &(m_matrix[0][0]);
10027242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    const double* leftMatrix = &(mat.m_matrix[0][0]);
10037242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    asm volatile(
10047242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // Load mat.m_matrix to v16 - v23.
10057242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // Load this.m_matrix to v24 - v31.
10067242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // Result: this = mat * this
10077242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // | v0, v1 |   | v16, v17 |   | v24, v25 |
10087242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // | v2, v3 | = | v18, v19 | * | v26, v27 |
10097242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // | v4, v5 |   | v20, v21 |   | v28, v29 |
10107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // | v6, v7 |   | v22, v23 |   | v30, v31 |
10117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "mov x9, %[rightMatrix]   \t\n"
10127242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "ld1 {v16.2d - v19.2d}, [%[leftMatrix]], 64  \t\n"
10137242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "ld1 {v20.2d - v23.2d}, [%[leftMatrix]]      \t\n"
10147242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "ld1 {v24.2d - v27.2d}, [%[rightMatrix]], 64 \t\n"
10157242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "ld1 {v28.2d - v31.2d}, [%[rightMatrix]]     \t\n"
10167242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
10177242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmul v0.2d, v24.2d, v16.d[0]  \t\n"
10187242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmul v1.2d, v25.2d, v16.d[0]  \t\n"
10197242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmul v2.2d, v24.2d, v18.d[0]  \t\n"
10207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmul v3.2d, v25.2d, v18.d[0]  \t\n"
10217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmul v4.2d, v24.2d, v20.d[0]  \t\n"
10227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmul v5.2d, v25.2d, v20.d[0]  \t\n"
10237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmul v6.2d, v24.2d, v22.d[0]  \t\n"
10247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmul v7.2d, v25.2d, v22.d[0]  \t\n"
10257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
10267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v0.2d, v26.2d, v16.d[1]  \t\n"
10277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v1.2d, v27.2d, v16.d[1]  \t\n"
10287242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v2.2d, v26.2d, v18.d[1]  \t\n"
10297242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v3.2d, v27.2d, v18.d[1]  \t\n"
10307242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v4.2d, v26.2d, v20.d[1]  \t\n"
10317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v5.2d, v27.2d, v20.d[1]  \t\n"
10327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v6.2d, v26.2d, v22.d[1]  \t\n"
10337242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v7.2d, v27.2d, v22.d[1]  \t\n"
10347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
10357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v0.2d, v28.2d, v17.d[0]  \t\n"
10367242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v1.2d, v29.2d, v17.d[0]  \t\n"
10377242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v2.2d, v28.2d, v19.d[0]  \t\n"
10387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v3.2d, v29.2d, v19.d[0]  \t\n"
10397242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v4.2d, v28.2d, v21.d[0]  \t\n"
10407242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v5.2d, v29.2d, v21.d[0]  \t\n"
10417242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v6.2d, v28.2d, v23.d[0]  \t\n"
10427242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v7.2d, v29.2d, v23.d[0]  \t\n"
10437242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
10447242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v0.2d, v30.2d, v17.d[1]  \t\n"
10457242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v1.2d, v31.2d, v17.d[1]  \t\n"
10467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v2.2d, v30.2d, v19.d[1]  \t\n"
10477242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v3.2d, v31.2d, v19.d[1]  \t\n"
10487242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v4.2d, v30.2d, v21.d[1]  \t\n"
10497242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v5.2d, v31.2d, v21.d[1]  \t\n"
10507242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v6.2d, v30.2d, v23.d[1]  \t\n"
10517242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "fmla v7.2d, v31.2d, v23.d[1]  \t\n"
10527242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
10537242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "st1 {v0.2d - v3.2d}, [x9], 64 \t\n"
10547242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        "st1 {v4.2d - v7.2d}, [x9]     \t\n"
10557242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        : [leftMatrix]"+r"(leftMatrix), [rightMatrix]"+r"(rightMatrix)
10567242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        :
10577242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        : "memory", "x9", "v16", "v17", "v18", "v19", "v20", "v21", "v22",
10587242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
10597242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7"
10607242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    );
10617242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#elif CPU(APPLE_ARMV7S)
10625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double* leftMatrix = &(m_matrix[0][0]);
10635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const double* rightMatrix = &(mat.m_matrix[0][0]);
10645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    asm volatile (// First row of leftMatrix.
10655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "mov        r3, %[leftMatrix]\n\t"
10665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vld1.64    { d16-d19 }, [%[leftMatrix], :128]!\n\t"
10675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vld1.64    { d0-d3}, [%[rightMatrix], :128]!\n\t"
10685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d4, d0, d16\n\t"
10695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vld1.64    { d20-d23 }, [%[leftMatrix], :128]!\n\t"
10705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d1, d20\n\t"
10715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vld1.64    { d24-d27 }, [%[leftMatrix], :128]!\n\t"
10725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d2, d24\n\t"
10735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vld1.64    { d28-d31 }, [%[leftMatrix], :128]!\n\t"
10745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d3, d28\n\t"
10755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d5, d0, d17\n\t"
10775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d1, d21\n\t"
10785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d2, d25\n\t"
10795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d3, d29\n\t"
10805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d6, d0, d18\n\t"
10825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d1, d22\n\t"
10835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d2, d26\n\t"
10845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d3, d30\n\t"
10855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d7, d0, d19\n\t"
10875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d1, d23\n\t"
10885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d2, d27\n\t"
10895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d3, d31\n\t"
10905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vld1.64    { d0-d3}, [%[rightMatrix], :128]!\n\t"
10915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vst1.64    { d4-d7 }, [r3, :128]!\n\t"
10925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Second row of leftMatrix.
10945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d4, d0, d16\n\t"
10955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d1, d20\n\t"
10965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d2, d24\n\t"
10975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d3, d28\n\t"
10985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d5, d0, d17\n\t"
11005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d1, d21\n\t"
11015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d2, d25\n\t"
11025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d3, d29\n\t"
11035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d6, d0, d18\n\t"
11055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d1, d22\n\t"
11065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d2, d26\n\t"
11075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d3, d30\n\t"
11085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d7, d0, d19\n\t"
11105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d1, d23\n\t"
11115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d2, d27\n\t"
11125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d3, d31\n\t"
11135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vld1.64    { d0-d3}, [%[rightMatrix], :128]!\n\t"
11145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vst1.64    { d4-d7 }, [r3, :128]!\n\t"
11155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Third row of leftMatrix.
11175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d4, d0, d16\n\t"
11185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d1, d20\n\t"
11195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d2, d24\n\t"
11205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d3, d28\n\t"
11215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d5, d0, d17\n\t"
11235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d1, d21\n\t"
11245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d2, d25\n\t"
11255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d3, d29\n\t"
11265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d6, d0, d18\n\t"
11285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d1, d22\n\t"
11295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d2, d26\n\t"
11305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d3, d30\n\t"
11315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d7, d0, d19\n\t"
11335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d1, d23\n\t"
11345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d2, d27\n\t"
11355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d3, d31\n\t"
11365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vld1.64    { d0-d3}, [%[rightMatrix], :128]\n\t"
11375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vst1.64    { d4-d7 }, [r3, :128]!\n\t"
11385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Fourth and last row of leftMatrix.
11405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d4, d0, d16\n\t"
11415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d1, d20\n\t"
11425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d2, d24\n\t"
11435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d4, d3, d28\n\t"
11445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d5, d0, d17\n\t"
11465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d1, d21\n\t"
11475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d2, d25\n\t"
11485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d5, d3, d29\n\t"
11495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d6, d0, d18\n\t"
11515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d1, d22\n\t"
11525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d2, d26\n\t"
11535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d6, d3, d30\n\t"
11545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmul.f64   d7, d0, d19\n\t"
11565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d1, d23\n\t"
11575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d2, d27\n\t"
11585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vmla.f64   d7, d3, d31\n\t"
11595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "vst1.64    { d4-d7 }, [r3, :128]\n\t"
11605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        : [leftMatrix]"+r"(leftMatrix), [rightMatrix]"+r"(rightMatrix)
11615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        :
11625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        : "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");
1163926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#elif defined(TRANSFORMATION_MATRIX_USE_X86_64_SSE2)
1164926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // x86_64 has 16 XMM registers which is enough to do the multiplication fully in registers.
1165926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d matrixBlockA = _mm_load_pd(&(m_matrix[0][0]));
1166926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d matrixBlockC = _mm_load_pd(&(m_matrix[1][0]));
1167926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d matrixBlockE = _mm_load_pd(&(m_matrix[2][0]));
1168926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d matrixBlockG = _mm_load_pd(&(m_matrix[3][0]));
1169926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1170926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // First row.
1171926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[0][0]);
1172926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[0][1]);
1173926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[0][2]);
1174926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[0][3]);
1175926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1176926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // output00 and output01.
1177926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1178926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1179926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1180926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1181926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1182926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d matrixBlockB = _mm_load_pd(&(m_matrix[0][2]));
1183926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d matrixBlockD = _mm_load_pd(&(m_matrix[1][2]));
1184926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d matrixBlockF = _mm_load_pd(&(m_matrix[2][2]));
1185926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    __m128d matrixBlockH = _mm_load_pd(&(m_matrix[3][2]));
1186926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1187926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp1);
1188926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp2);
1189926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp3);
1190926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    _mm_store_pd(&m_matrix[0][0], accumulator);
1191926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1192926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // output02 and output03.
1193926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1194926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1195926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1196926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1197926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1198926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp1);
1199926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp2);
1200926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp3);
1201926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    _mm_store_pd(&m_matrix[0][2], accumulator);
1202926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1203926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Second row.
1204926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[1][0]);
1205926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[1][1]);
1206926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[1][2]);
1207926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[1][3]);
1208926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1209926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // output10 and output11.
1210926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1211926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1212926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1213926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1214926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1215926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp1);
1216926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp2);
1217926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp3);
1218926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    _mm_store_pd(&m_matrix[1][0], accumulator);
1219926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1220926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // output12 and output13.
1221926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1222926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1223926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1224926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1225926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1226926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp1);
1227926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp2);
1228926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp3);
1229926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    _mm_store_pd(&m_matrix[1][2], accumulator);
1230926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1231926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Third row.
1232926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[2][0]);
1233926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[2][1]);
1234926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[2][2]);
1235926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[2][3]);
1236926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1237926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // output20 and output21.
1238926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1239926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1240926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1241926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1242926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1243926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp1);
1244926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp2);
1245926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp3);
1246926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    _mm_store_pd(&m_matrix[2][0], accumulator);
1247926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1248926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // output22 and output23.
1249926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1250926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1251926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1252926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1253926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1254926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp1);
1255926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp2);
1256926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp3);
1257926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    _mm_store_pd(&m_matrix[2][2], accumulator);
1258926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1259926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Fourth row.
1260926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[3][0]);
1261926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[3][1]);
1262926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[3][2]);
1263926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[3][3]);
1264926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1265926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // output30 and output31.
1266926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1267926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1268926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1269926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1270926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1271926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp1);
1272926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp2);
1273926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp3);
1274926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    _mm_store_pd(&m_matrix[3][0], accumulator);
1275926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1276926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // output32 and output33.
1277926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1278926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1279926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1280926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1281926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1282926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp1);
1283926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp2);
1284926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    accumulator = _mm_add_pd(accumulator, temp3);
1285926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    _mm_store_pd(&m_matrix[3][2], accumulator);
12865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#else
12875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Matrix4 tmp;
128802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
12895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0]
12905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]);
12915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1]
12925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]);
12935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2]
12945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]);
12955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3]
12965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]);
12975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0]
12995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]);
13005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1]
13015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]);
13025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2]
13035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]);
13045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3]
13055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]);
13065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0]
13085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]);
13095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1]
13105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]);
13115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2]
13125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]);
13135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3]
13145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]);
13155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0]
13175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]);
13185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1]
13195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]);
13205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2]
13215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]);
13225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3]
13235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]);
132402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    setMatrix(tmp);
13265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
13275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return *this;
13285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const
13315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0];
13335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1];
13345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3];
13355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (w != 1 && w != 0) {
13365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        resultX /= w;
13375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        resultY /= w;
13385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const
13425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
13445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
13455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2];
13465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3];
13475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (w != 1 && w != 0) {
13485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        resultX /= w;
13495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        resultY /= w;
13505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        resultZ /= w;
13515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool TransformationMatrix::isInvertible() const
13555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isIdentityOrTranslation())
13575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
13585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1359c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    double det = blink::determinant4x4(m_matrix);
13605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (fabs(det) < SMALL_NUMBER)
13625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
13635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
13655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
136702772c6a72f1ee0b226341a4f4439970c29fc861Ben MurdochTransformationMatrix TransformationMatrix::inverse() const
13685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isIdentityOrTranslation()) {
13705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // identity matrix
13715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0)
13725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return TransformationMatrix();
137302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // translation
13755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return TransformationMatrix(1, 0, 0, 0,
13765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                    0, 1, 0, 0,
13775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                    0, 0, 1, 0,
13785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                    -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1);
13795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
138002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TransformationMatrix invMat;
1382c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    bool inverted = blink::inverse(m_matrix, invMat.m_matrix);
13835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!inverted)
13845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return TransformationMatrix();
138502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return invMat;
13875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void TransformationMatrix::makeAffine()
13905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[0][2] = 0;
13925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[0][3] = 0;
139302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[1][2] = 0;
13955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[1][3] = 0;
139602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[2][0] = 0;
13985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[2][1] = 0;
13995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[2][2] = 1;
14005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[2][3] = 0;
140102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][2] = 0;
14035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_matrix[3][3] = 1;
14045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)AffineTransform TransformationMatrix::toAffineTransform() const
14075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return AffineTransform(m_matrix[0][0], m_matrix[0][1], m_matrix[1][0],
14095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                           m_matrix[1][1], m_matrix[3][0], m_matrix[3][1]);
14105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline void blendFloat(double& from, double to, double progress)
14135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (from != to)
14155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        from = from + (to - from) * progress;
14165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
14195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (from.isIdentity() && isIdentity())
14215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
142202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // decompose
14245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DecomposedType fromDecomp;
14255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DecomposedType toDecomp;
1426197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    if (!from.decompose(fromDecomp) || !decompose(toDecomp)) {
1427197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        if (progress < 0.5)
1428197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            *this = from;
1429197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        return;
1430197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    }
14315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // interpolate
14335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
14345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
14355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress);
14365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress);
14375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress);
14385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress);
14395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.translateX, toDecomp.translateX, progress);
14405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.translateY, toDecomp.translateY, progress);
14415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress);
14425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress);
14435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress);
14445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress);
14455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress);
144602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress);
144802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // recompose
14505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    recompose(fromDecomp);
14515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool TransformationMatrix::decompose(DecomposedType& decomp) const
14545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isIdentity()) {
14565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        memset(&decomp, 0, sizeof(decomp));
14575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        decomp.perspectiveW = 1;
14585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        decomp.scaleX = 1;
14595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        decomp.scaleY = 1;
14605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        decomp.scaleZ = 1;
14615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
146202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1463c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (!blink::decompose(m_matrix, decomp))
14645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
14655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
14665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void TransformationMatrix::recompose(const DecomposedType& decomp)
14695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    makeIdentity();
147102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // first apply perspective
1473926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    m_matrix[0][3] = decomp.perspectiveX;
1474926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    m_matrix[1][3] = decomp.perspectiveY;
1475926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    m_matrix[2][3] = decomp.perspectiveZ;
1476926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    m_matrix[3][3] = decomp.perspectiveW;
147702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // now translate
1479926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    translate3d(decomp.translateX, decomp.translateY, decomp.translateZ);
148002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // apply rotation
14825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double xx = decomp.quaternionX * decomp.quaternionX;
14835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double xy = decomp.quaternionX * decomp.quaternionY;
14845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double xz = decomp.quaternionX * decomp.quaternionZ;
14855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double xw = decomp.quaternionX * decomp.quaternionW;
14865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double yy = decomp.quaternionY * decomp.quaternionY;
14875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double yz = decomp.quaternionY * decomp.quaternionZ;
14885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double yw = decomp.quaternionY * decomp.quaternionW;
14895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double zz = decomp.quaternionZ * decomp.quaternionZ;
14905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double zw = decomp.quaternionZ * decomp.quaternionW;
149102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Construct a composite rotation matrix from the quaternion values
149302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0,
14945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                           2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
14955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                           2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
14965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                           0, 0, 0, 1);
149702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
14985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    multiply(rotationMatrix);
149902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
15005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // now apply skew
15015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (decomp.skewYZ) {
15025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        TransformationMatrix tmp;
1503926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        tmp.setM32(decomp.skewYZ);
15045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        multiply(tmp);
15055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
150602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
15075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (decomp.skewXZ) {
15085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        TransformationMatrix tmp;
1509926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        tmp.setM31(decomp.skewXZ);
15105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        multiply(tmp);
15115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
151202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
15135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (decomp.skewXY) {
15145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        TransformationMatrix tmp;
1515926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        tmp.setM21(decomp.skewXY);
15165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        multiply(tmp);
15175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
151802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
15195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // finally, apply scale
1520926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    scale3d(decomp.scaleX, decomp.scaleY, decomp.scaleZ);
15215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool TransformationMatrix::isIntegerTranslation() const
15245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
15255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!isIdentityOrTranslation())
15265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
15275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Check for translate Z.
15295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_matrix[3][2])
15305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
15315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Check for non-integer translate X/Y.
15335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (static_cast<int>(m_matrix[3][0]) != m_matrix[3][0] || static_cast<int>(m_matrix[3][1]) != m_matrix[3][1])
15345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
15355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
15375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TransformationMatrix TransformationMatrix::to2dTransform() const
15405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
15415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return TransformationMatrix(m_matrix[0][0], m_matrix[0][1], 0, m_matrix[0][3],
15425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                m_matrix[1][0], m_matrix[1][1], 0, m_matrix[1][3],
15435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                0, 0, 1, 0,
15445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                m_matrix[3][0], m_matrix[3][1], 0, m_matrix[3][3]);
15455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void TransformationMatrix::toColumnMajorFloatArray(FloatMatrix4& result) const
15485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
15495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[0] = m11();
15505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[1] = m12();
15515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[2] = m13();
15525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[3] = m14();
15535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[4] = m21();
15545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[5] = m22();
15555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[6] = m23();
15565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[7] = m24();
15575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[8] = m31();
15585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[9] = m32();
15595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[10] = m33();
15605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[11] = m34();
15615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[12] = m41();
15625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[13] = m42();
15635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[14] = m43();
15645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result[15] = m44();
15655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1567bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)SkMatrix44 TransformationMatrix::toSkMatrix44(const TransformationMatrix& matrix)
1568bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles){
1569bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    SkMatrix44 ret(SkMatrix44::kUninitialized_Constructor);
1570bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(0, 0, matrix.m11());
1571bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(0, 1, matrix.m21());
1572bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(0, 2, matrix.m31());
1573bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(0, 3, matrix.m41());
1574bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(1, 0, matrix.m12());
1575bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(1, 1, matrix.m22());
1576bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(1, 2, matrix.m32());
1577bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(1, 3, matrix.m42());
1578bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(2, 0, matrix.m13());
1579bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(2, 1, matrix.m23());
1580bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(2, 2, matrix.m33());
1581bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(2, 3, matrix.m43());
1582bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(3, 0, matrix.m14());
1583bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(3, 1, matrix.m24());
1584bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(3, 2, matrix.m34());
1585bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ret.setDouble(3, 3, matrix.m44());
1586bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    return ret;
1587bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)}
1588bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)
15895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1590