1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/flow/matrix_decomposition.h"
6
7 namespace flutter {
8
SkVector3Combine(const SkVector3 & a,float a_scale,const SkVector3 & b,float b_scale)9 static inline SkVector3 SkVector3Combine(const SkVector3& a,
10 float a_scale,
11 const SkVector3& b,
12 float b_scale) {
13 return {
14 a_scale * a.fX + b_scale * b.fX, //
15 a_scale * a.fY + b_scale * b.fY, //
16 a_scale * a.fZ + b_scale * b.fZ, //
17 };
18 }
19
SkVector3Cross(const SkVector3 & a,const SkVector3 & b)20 static inline SkVector3 SkVector3Cross(const SkVector3& a, const SkVector3& b) {
21 return {
22 (a.fY * b.fZ) - (a.fZ * b.fY), //
23 (a.fZ * b.fX) - (a.fX * b.fZ), //
24 (a.fX * b.fY) - (a.fY * b.fX) //
25 };
26 }
27
MatrixDecomposition(const SkMatrix & matrix)28 MatrixDecomposition::MatrixDecomposition(const SkMatrix& matrix)
29 : MatrixDecomposition(SkMatrix44{matrix}) {}
30
31 // Use custom normalize to avoid skia precision loss/normalize() privatization.
SkVector3Normalize(SkVector3 & v)32 static inline void SkVector3Normalize(SkVector3& v) {
33 double mag = sqrt(v.fX * v.fX + v.fY * v.fY + v.fZ * v.fZ);
34 double scale = 1.0 / mag;
35 v.fX *= scale;
36 v.fY *= scale;
37 v.fZ *= scale;
38 }
39
MatrixDecomposition(SkMatrix44 matrix)40 MatrixDecomposition::MatrixDecomposition(SkMatrix44 matrix) : valid_(false) {
41 if (matrix.get(3, 3) == 0) {
42 return;
43 }
44
45 for (int i = 0; i < 4; i++) {
46 for (int j = 0; j < 4; j++) {
47 matrix.set(j, i, matrix.get(j, i) / matrix.get(3, 3));
48 }
49 }
50
51 SkMatrix44 perpective_matrix = matrix;
52 for (int i = 0; i < 3; i++) {
53 perpective_matrix.set(3, i, 0.0);
54 }
55
56 perpective_matrix.set(3, 3, 1.0);
57
58 if (perpective_matrix.determinant() == 0.0) {
59 return;
60 }
61
62 if (matrix.get(3, 0) != 0.0 || matrix.get(3, 1) != 0.0 ||
63 matrix.get(3, 2) != 0.0) {
64 const SkVector4 right_hand_side(matrix.get(3, 0), matrix.get(3, 1),
65 matrix.get(3, 2), matrix.get(3, 3));
66
67 SkMatrix44 inverted_transposed(
68 SkMatrix44::Uninitialized_Constructor::kUninitialized_Constructor);
69 if (!perpective_matrix.invert(&inverted_transposed)) {
70 return;
71 }
72 inverted_transposed.transpose();
73
74 perspective_ = inverted_transposed * right_hand_side;
75
76 matrix.set(3, 0, 0);
77 matrix.set(3, 1, 0);
78 matrix.set(3, 2, 0);
79 matrix.set(3, 3, 1);
80 }
81
82 translation_ = {matrix.get(0, 3), matrix.get(1, 3), matrix.get(2, 3)};
83
84 matrix.set(0, 3, 0.0);
85 matrix.set(1, 3, 0.0);
86 matrix.set(2, 3, 0.0);
87
88 SkVector3 row[3];
89 for (int i = 0; i < 3; i++) {
90 row[i].set(matrix.get(0, i), matrix.get(1, i), matrix.get(2, i));
91 }
92
93 scale_.fX = row[0].length();
94
95 SkVector3Normalize(row[0]);
96
97 shear_.fX = row[0].dot(row[1]);
98 row[1] = SkVector3Combine(row[1], 1.0, row[0], -shear_.fX);
99
100 scale_.fY = row[1].length();
101
102 SkVector3Normalize(row[1]);
103
104 shear_.fX /= scale_.fY;
105
106 shear_.fY = row[0].dot(row[2]);
107 row[2] = SkVector3Combine(row[2], 1.0, row[0], -shear_.fY);
108 shear_.fZ = row[1].dot(row[2]);
109 row[2] = SkVector3Combine(row[2], 1.0, row[1], -shear_.fZ);
110
111 scale_.fZ = row[2].length();
112
113 SkVector3Normalize(row[2]);
114
115 shear_.fY /= scale_.fZ;
116 shear_.fZ /= scale_.fZ;
117
118 if (row[0].dot(SkVector3Cross(row[1], row[2])) < 0) {
119 scale_.fX *= -1;
120 scale_.fY *= -1;
121 scale_.fZ *= -1;
122
123 for (int i = 0; i < 3; i++) {
124 row[i].fX *= -1;
125 row[i].fY *= -1;
126 row[i].fZ *= -1;
127 }
128 }
129
130 rotation_.set(0.5 * sqrt(fmax(1.0 + row[0].fX - row[1].fY - row[2].fZ, 0.0)),
131 0.5 * sqrt(fmax(1.0 - row[0].fX + row[1].fY - row[2].fZ, 0.0)),
132 0.5 * sqrt(fmax(1.0 - row[0].fX - row[1].fY + row[2].fZ, 0.0)),
133 0.5 * sqrt(fmax(1.0 + row[0].fX + row[1].fY + row[2].fZ, 0.0)));
134
135 if (row[2].fY > row[1].fZ) {
136 rotation_.fData[0] = -rotation_.fData[0];
137 }
138 if (row[0].fZ > row[2].fX) {
139 rotation_.fData[1] = -rotation_.fData[1];
140 }
141 if (row[1].fX > row[0].fY) {
142 rotation_.fData[2] = -rotation_.fData[2];
143 }
144
145 valid_ = true;
146 }
147
148 MatrixDecomposition::~MatrixDecomposition() = default;
149
IsValid() const150 bool MatrixDecomposition::IsValid() const {
151 return valid_;
152 }
153
154 } // namespace flutter
155