| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/flow/matrix_decomposition.h" |
| |
| namespace flutter { |
| |
| static inline SkV3 SkV3Combine(const SkV3& a, |
| float a_scale, |
| const SkV3& b, |
| float b_scale) { |
| return (a * a_scale) + (b * b_scale); |
| } |
| |
| MatrixDecomposition::MatrixDecomposition(const SkMatrix& matrix) |
| : MatrixDecomposition(SkM44{matrix}) {} |
| |
| // Use custom normalize to avoid skia precision loss/normalize() privatization. |
| static inline void SkV3Normalize(SkV3* v) { |
| double mag = sqrt(v->x * v->x + v->y * v->y + v->z * v->z); |
| double scale = 1.0 / mag; |
| v->x *= scale; |
| v->y *= scale; |
| v->z *= scale; |
| } |
| |
| MatrixDecomposition::MatrixDecomposition(SkM44 matrix) : valid_(false) { |
| if (matrix.rc(3, 3) == 0) { |
| return; |
| } |
| |
| for (int i = 0; i < 4; i++) { |
| for (int j = 0; j < 4; j++) { |
| matrix.setRC(j, i, matrix.rc(j, i) / matrix.rc(3, 3)); |
| } |
| } |
| |
| SkM44 perpective_matrix = matrix; |
| for (int i = 0; i < 3; i++) { |
| perpective_matrix.setRC(3, i, 0.0); |
| } |
| |
| perpective_matrix.setRC(3, 3, 1.0); |
| |
| SkM44 inverted(SkM44::Uninitialized_Constructor::kUninitialized_Constructor); |
| if (!perpective_matrix.invert(&inverted)) { |
| return; |
| } |
| |
| if (matrix.rc(3, 0) != 0.0 || matrix.rc(3, 1) != 0.0 || |
| matrix.rc(3, 2) != 0.0) { |
| const SkV4 right_hand_side = matrix.row(3); |
| |
| perspective_ = inverted.transpose() * right_hand_side; |
| |
| matrix.setRow(3, {0, 0, 0, 1}); |
| } |
| |
| translation_ = {matrix.rc(0, 3), matrix.rc(1, 3), matrix.rc(2, 3)}; |
| |
| matrix.setRC(0, 3, 0.0); |
| matrix.setRC(1, 3, 0.0); |
| matrix.setRC(2, 3, 0.0); |
| |
| SkV3 row[3]; |
| for (int i = 0; i < 3; i++) { |
| row[i] = {matrix.rc(0, i), matrix.rc(1, i), matrix.rc(2, i)}; |
| } |
| |
| scale_.x = row[0].length(); |
| |
| SkV3Normalize(&row[0]); |
| |
| shear_.x = row[0].dot(row[1]); |
| row[1] = SkV3Combine(row[1], 1.0, row[0], -shear_.x); |
| |
| scale_.y = row[1].length(); |
| |
| SkV3Normalize(&row[1]); |
| |
| shear_.x /= scale_.y; |
| |
| shear_.y = row[0].dot(row[2]); |
| row[2] = SkV3Combine(row[2], 1.0, row[0], -shear_.y); |
| shear_.z = row[1].dot(row[2]); |
| row[2] = SkV3Combine(row[2], 1.0, row[1], -shear_.z); |
| |
| scale_.z = row[2].length(); |
| |
| SkV3Normalize(&row[2]); |
| |
| shear_.y /= scale_.z; |
| shear_.z /= scale_.z; |
| |
| if (row[0].dot(row[1].cross(row[2])) < 0) { |
| scale_ *= -1; |
| |
| for (int i = 0; i < 3; i++) { |
| row[i] *= -1; |
| } |
| } |
| |
| rotation_.x = 0.5 * sqrt(fmax(1.0 + row[0].x - row[1].y - row[2].z, 0.0)); |
| rotation_.y = 0.5 * sqrt(fmax(1.0 - row[0].x + row[1].y - row[2].z, 0.0)); |
| rotation_.z = 0.5 * sqrt(fmax(1.0 - row[0].x - row[1].y + row[2].z, 0.0)); |
| rotation_.w = 0.5 * sqrt(fmax(1.0 + row[0].x + row[1].y + row[2].z, 0.0)); |
| |
| if (row[2].y > row[1].z) { |
| rotation_.x = -rotation_.x; |
| } |
| if (row[0].z > row[2].x) { |
| rotation_.y = -rotation_.y; |
| } |
| if (row[1].x > row[0].y) { |
| rotation_.z = -rotation_.z; |
| } |
| |
| valid_ = true; |
| } |
| |
| MatrixDecomposition::~MatrixDecomposition() = default; |
| |
| bool MatrixDecomposition::IsValid() const { |
| return valid_; |
| } |
| |
| } // namespace flutter |