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 | |
9 | static inline SkV3 SkV3Combine(const SkV3& a, |
10 | float a_scale, |
11 | const SkV3& b, |
12 | float b_scale) { |
13 | return (a * a_scale) + (b * b_scale); |
14 | } |
15 | |
16 | MatrixDecomposition::MatrixDecomposition(const SkMatrix& matrix) |
17 | : MatrixDecomposition(SkM44{matrix}) {} |
18 | |
19 | // Use custom normalize to avoid skia precision loss/normalize() privatization. |
20 | static inline void SkV3Normalize(SkV3* v) { |
21 | double mag = sqrt(v->x * v->x + v->y * v->y + v->z * v->z); |
22 | double scale = 1.0 / mag; |
23 | v->x *= scale; |
24 | v->y *= scale; |
25 | v->z *= scale; |
26 | } |
27 | |
28 | MatrixDecomposition::MatrixDecomposition(SkM44 matrix) : valid_(false) { |
29 | if (matrix.rc(3, 3) == 0) { |
30 | return; |
31 | } |
32 | |
33 | for (int i = 0; i < 4; i++) { |
34 | for (int j = 0; j < 4; j++) { |
35 | matrix.setRC(j, i, matrix.rc(j, i) / matrix.rc(3, 3)); |
36 | } |
37 | } |
38 | |
39 | SkM44 perpective_matrix = matrix; |
40 | for (int i = 0; i < 3; i++) { |
41 | perpective_matrix.setRC(3, i, 0.0); |
42 | } |
43 | |
44 | perpective_matrix.setRC(3, 3, 1.0); |
45 | |
46 | SkM44 inverted(SkM44::Uninitialized_Constructor::kUninitialized_Constructor); |
47 | if (!perpective_matrix.invert(&inverted)) { |
48 | return; |
49 | } |
50 | |
51 | if (matrix.rc(3, 0) != 0.0 || matrix.rc(3, 1) != 0.0 || |
52 | matrix.rc(3, 2) != 0.0) { |
53 | const SkV4 right_hand_side = matrix.row(3); |
54 | |
55 | perspective_ = inverted.transpose() * right_hand_side; |
56 | |
57 | matrix.setRow(3, {0, 0, 0, 1}); |
58 | } |
59 | |
60 | translation_ = {matrix.rc(0, 3), matrix.rc(1, 3), matrix.rc(2, 3)}; |
61 | |
62 | matrix.setRC(0, 3, 0.0); |
63 | matrix.setRC(1, 3, 0.0); |
64 | matrix.setRC(2, 3, 0.0); |
65 | |
66 | SkV3 row[3]; |
67 | for (int i = 0; i < 3; i++) { |
68 | row[i] = {matrix.rc(0, i), matrix.rc(1, i), matrix.rc(2, i)}; |
69 | } |
70 | |
71 | scale_.x = row[0].length(); |
72 | |
73 | SkV3Normalize(&row[0]); |
74 | |
75 | shear_.x = row[0].dot(row[1]); |
76 | row[1] = SkV3Combine(row[1], 1.0, row[0], -shear_.x); |
77 | |
78 | scale_.y = row[1].length(); |
79 | |
80 | SkV3Normalize(&row[1]); |
81 | |
82 | shear_.x /= scale_.y; |
83 | |
84 | shear_.y = row[0].dot(row[2]); |
85 | row[2] = SkV3Combine(row[2], 1.0, row[0], -shear_.y); |
86 | shear_.z = row[1].dot(row[2]); |
87 | row[2] = SkV3Combine(row[2], 1.0, row[1], -shear_.z); |
88 | |
89 | scale_.z = row[2].length(); |
90 | |
91 | SkV3Normalize(&row[2]); |
92 | |
93 | shear_.y /= scale_.z; |
94 | shear_.z /= scale_.z; |
95 | |
96 | if (row[0].dot(row[1].cross(row[2])) < 0) { |
97 | scale_ *= -1; |
98 | |
99 | for (int i = 0; i < 3; i++) { |
100 | row[i] *= -1; |
101 | } |
102 | } |
103 | |
104 | rotation_.x = 0.5 * sqrt(fmax(1.0 + row[0].x - row[1].y - row[2].z, 0.0)); |
105 | rotation_.y = 0.5 * sqrt(fmax(1.0 - row[0].x + row[1].y - row[2].z, 0.0)); |
106 | rotation_.z = 0.5 * sqrt(fmax(1.0 - row[0].x - row[1].y + row[2].z, 0.0)); |
107 | rotation_.w = 0.5 * sqrt(fmax(1.0 + row[0].x + row[1].y + row[2].z, 0.0)); |
108 | |
109 | if (row[2].y > row[1].z) { |
110 | rotation_.x = -rotation_.x; |
111 | } |
112 | if (row[0].z > row[2].x) { |
113 | rotation_.y = -rotation_.y; |
114 | } |
115 | if (row[1].x > row[0].y) { |
116 | rotation_.z = -rotation_.z; |
117 | } |
118 | |
119 | valid_ = true; |
120 | } |
121 | |
122 | MatrixDecomposition::~MatrixDecomposition() = default; |
123 | |
124 | bool MatrixDecomposition::IsValid() const { |
125 | return valid_; |
126 | } |
127 | |
128 | } // namespace flutter |
129 | |