• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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