Convert MatrixDecomposition from SkMatrix44 to SkM44 (#17760)

* Convert MatrixDecomposition from SkMatrix44 to SkM44

SkMatrix44 is deprecated and being removed.
This commit is contained in:
Brian Osman 2020-04-16 15:27:41 -04:00 committed by GitHub
parent e368377ce8
commit ef161fb5c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 140 additions and 167 deletions

View File

@ -6,140 +6,114 @@
namespace flutter {
static inline SkVector3 SkVector3Combine(const SkVector3& a,
float a_scale,
const SkVector3& b,
float b_scale) {
return {
a_scale * a.fX + b_scale * b.fX, //
a_scale * a.fY + b_scale * b.fY, //
a_scale * a.fZ + b_scale * b.fZ, //
};
}
static inline SkVector3 SkVector3Cross(const SkVector3& a, const SkVector3& b) {
return {
(a.fY * b.fZ) - (a.fZ * b.fY), //
(a.fZ * b.fX) - (a.fX * b.fZ), //
(a.fX * b.fY) - (a.fY * b.fX) //
};
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(SkMatrix44{matrix}) {}
: MatrixDecomposition(SkM44{matrix}) {}
// Use custom normalize to avoid skia precision loss/normalize() privatization.
static inline void SkVector3Normalize(SkVector3& v) {
double mag = sqrt(v.fX * v.fX + v.fY * v.fY + v.fZ * v.fZ);
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.fX *= scale;
v.fY *= scale;
v.fZ *= scale;
v.x *= scale;
v.y *= scale;
v.z *= scale;
}
MatrixDecomposition::MatrixDecomposition(SkMatrix44 matrix) : valid_(false) {
if (matrix.get(3, 3) == 0) {
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.set(j, i, matrix.get(j, i) / matrix.get(3, 3));
matrix.setRC(j, i, matrix.rc(j, i) / matrix.rc(3, 3));
}
}
SkMatrix44 perpective_matrix = matrix;
SkM44 perpective_matrix = matrix;
for (int i = 0; i < 3; i++) {
perpective_matrix.set(3, i, 0.0);
perpective_matrix.setRC(3, i, 0.0);
}
perpective_matrix.set(3, 3, 1.0);
perpective_matrix.setRC(3, 3, 1.0);
if (perpective_matrix.determinant() == 0.0) {
SkM44 inverted(SkM44::Uninitialized_Constructor::kUninitialized_Constructor);
if (!perpective_matrix.invert(&inverted)) {
return;
}
if (matrix.get(3, 0) != 0.0 || matrix.get(3, 1) != 0.0 ||
matrix.get(3, 2) != 0.0) {
const SkVector4 right_hand_side(matrix.get(3, 0), matrix.get(3, 1),
matrix.get(3, 2), matrix.get(3, 3));
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);
SkMatrix44 inverted_transposed(
SkMatrix44::Uninitialized_Constructor::kUninitialized_Constructor);
if (!perpective_matrix.invert(&inverted_transposed)) {
return;
}
inverted_transposed.transpose();
perspective_ = inverted.transpose() * right_hand_side;
perspective_ = inverted_transposed * right_hand_side;
matrix.set(3, 0, 0);
matrix.set(3, 1, 0);
matrix.set(3, 2, 0);
matrix.set(3, 3, 1);
matrix.setRow(3, {0, 0, 0, 1});
}
translation_ = {matrix.get(0, 3), matrix.get(1, 3), matrix.get(2, 3)};
translation_ = {matrix.rc(0, 3), matrix.rc(1, 3), matrix.rc(2, 3)};
matrix.set(0, 3, 0.0);
matrix.set(1, 3, 0.0);
matrix.set(2, 3, 0.0);
matrix.setRC(0, 3, 0.0);
matrix.setRC(1, 3, 0.0);
matrix.setRC(2, 3, 0.0);
SkVector3 row[3];
SkV3 row[3];
for (int i = 0; i < 3; i++) {
row[i].set(matrix.get(0, i), matrix.get(1, i), matrix.get(2, i));
row[i] = {matrix.rc(0, i), matrix.rc(1, i), matrix.rc(2, i)};
}
scale_.fX = row[0].length();
scale_.x = row[0].length();
SkVector3Normalize(row[0]);
SkV3Normalize(row[0]);
shear_.fX = row[0].dot(row[1]);
row[1] = SkVector3Combine(row[1], 1.0, row[0], -shear_.fX);
shear_.x = row[0].dot(row[1]);
row[1] = SkV3Combine(row[1], 1.0, row[0], -shear_.x);
scale_.fY = row[1].length();
scale_.y = row[1].length();
SkVector3Normalize(row[1]);
SkV3Normalize(row[1]);
shear_.fX /= scale_.fY;
shear_.x /= scale_.y;
shear_.fY = row[0].dot(row[2]);
row[2] = SkVector3Combine(row[2], 1.0, row[0], -shear_.fY);
shear_.fZ = row[1].dot(row[2]);
row[2] = SkVector3Combine(row[2], 1.0, row[1], -shear_.fZ);
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_.fZ = row[2].length();
scale_.z = row[2].length();
SkVector3Normalize(row[2]);
SkV3Normalize(row[2]);
shear_.fY /= scale_.fZ;
shear_.fZ /= scale_.fZ;
shear_.y /= scale_.z;
shear_.z /= scale_.z;
if (row[0].dot(SkVector3Cross(row[1], row[2])) < 0) {
scale_.fX *= -1;
scale_.fY *= -1;
scale_.fZ *= -1;
if (row[0].dot(row[1].cross(row[2])) < 0) {
scale_ *= -1;
for (int i = 0; i < 3; i++) {
row[i].fX *= -1;
row[i].fY *= -1;
row[i].fZ *= -1;
row[i] *= -1;
}
}
rotation_.set(0.5 * sqrt(fmax(1.0 + row[0].fX - row[1].fY - row[2].fZ, 0.0)),
0.5 * sqrt(fmax(1.0 - row[0].fX + row[1].fY - row[2].fZ, 0.0)),
0.5 * sqrt(fmax(1.0 - row[0].fX - row[1].fY + row[2].fZ, 0.0)),
0.5 * sqrt(fmax(1.0 + row[0].fX + row[1].fY + row[2].fZ, 0.0)));
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].fY > row[1].fZ) {
rotation_.fData[0] = -rotation_.fData[0];
if (row[2].y > row[1].z) {
rotation_.x = -rotation_.x;
}
if (row[0].fZ > row[2].fX) {
rotation_.fData[1] = -rotation_.fData[1];
if (row[0].z > row[2].x) {
rotation_.y = -rotation_.y;
}
if (row[1].fX > row[0].fY) {
rotation_.fData[2] = -rotation_.fData[2];
if (row[1].x > row[0].y) {
rotation_.z = -rotation_.z;
}
valid_ = true;

View File

@ -6,9 +6,8 @@
#define FLUTTER_FLOW_MATRIX_DECOMPOSITION_H_
#include "flutter/fml/macros.h"
#include "third_party/skia/include/core/SkM44.h"
#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "third_party/skia/include/core/SkPoint3.h"
namespace flutter {
@ -19,29 +18,29 @@ class MatrixDecomposition {
public:
MatrixDecomposition(const SkMatrix& matrix);
MatrixDecomposition(SkMatrix44 matrix);
MatrixDecomposition(SkM44 matrix);
~MatrixDecomposition();
bool IsValid() const;
const SkVector3& translation() const { return translation_; }
const SkV3& translation() const { return translation_; }
const SkVector3& scale() const { return scale_; }
const SkV3& scale() const { return scale_; }
const SkVector3& shear() const { return shear_; }
const SkV3& shear() const { return shear_; }
const SkVector4& perspective() const { return perspective_; }
const SkV4& perspective() const { return perspective_; }
const SkVector4& rotation() const { return rotation_; }
const SkV4& rotation() const { return rotation_; }
private:
bool valid_;
SkVector3 translation_;
SkVector3 scale_;
SkVector3 shear_;
SkVector4 perspective_;
SkVector4 rotation_;
SkV3 translation_;
SkV3 scale_;
SkV3 shear_;
SkV4 perspective_;
SkV4 rotation_;
FML_DISALLOW_COPY_AND_ASSIGN(MatrixDecomposition);
};

View File

@ -16,24 +16,24 @@ namespace flutter {
namespace testing {
TEST(MatrixDecomposition, Rotation) {
SkMatrix44 matrix = SkMatrix44::I();
SkM44 matrix;
const auto angle = M_PI_4;
matrix.setRotateAbout(0.0, 0.0, 1.0, angle);
matrix.setRotate({0.0, 0.0, 1.0}, angle);
flutter::MatrixDecomposition decomposition(matrix);
ASSERT_TRUE(decomposition.IsValid());
const auto sine = sin(angle * 0.5);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[1]);
ASSERT_FLOAT_EQ(sine, decomposition.rotation().fData[2]);
ASSERT_FLOAT_EQ(cos(angle * 0.5), decomposition.rotation().fData[3]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().x);
ASSERT_FLOAT_EQ(0, decomposition.rotation().y);
ASSERT_FLOAT_EQ(sine, decomposition.rotation().z);
ASSERT_FLOAT_EQ(cos(angle * 0.5), decomposition.rotation().w);
}
TEST(MatrixDecomposition, Scale) {
SkMatrix44 matrix = SkMatrix44::I();
SkM44 matrix;
const auto scale = 5.0;
matrix.setScale(scale + 0, scale + 1, scale + 2);
@ -41,13 +41,13 @@ TEST(MatrixDecomposition, Scale) {
flutter::MatrixDecomposition decomposition(matrix);
ASSERT_TRUE(decomposition.IsValid());
ASSERT_FLOAT_EQ(scale + 0, decomposition.scale().fX);
ASSERT_FLOAT_EQ(scale + 1, decomposition.scale().fY);
ASSERT_FLOAT_EQ(scale + 2, decomposition.scale().fZ);
ASSERT_FLOAT_EQ(scale + 0, decomposition.scale().x);
ASSERT_FLOAT_EQ(scale + 1, decomposition.scale().y);
ASSERT_FLOAT_EQ(scale + 2, decomposition.scale().z);
}
TEST(MatrixDecomposition, Translate) {
SkMatrix44 matrix = SkMatrix44::I();
SkM44 matrix;
const auto translate = 125.0;
matrix.setTranslate(translate + 0, translate + 1, translate + 2);
@ -55,9 +55,9 @@ TEST(MatrixDecomposition, Translate) {
flutter::MatrixDecomposition decomposition(matrix);
ASSERT_TRUE(decomposition.IsValid());
ASSERT_FLOAT_EQ(translate + 0, decomposition.translation().fX);
ASSERT_FLOAT_EQ(translate + 1, decomposition.translation().fY);
ASSERT_FLOAT_EQ(translate + 2, decomposition.translation().fZ);
ASSERT_FLOAT_EQ(translate + 0, decomposition.translation().x);
ASSERT_FLOAT_EQ(translate + 1, decomposition.translation().y);
ASSERT_FLOAT_EQ(translate + 2, decomposition.translation().z);
}
TEST(MatrixDecomposition, Combination) {
@ -65,65 +65,65 @@ TEST(MatrixDecomposition, Combination) {
const auto scale = 5;
const auto translate = 125.0;
SkMatrix44 m1 = SkMatrix44::I();
m1.setRotateAbout(0, 0, 1, rotation);
SkM44 m1;
m1.setRotate({0, 0, 1}, rotation);
SkMatrix44 m2 = SkMatrix44::I();
m2.setScale(scale);
SkM44 m2;
m2.setScale(scale, scale, scale);
SkMatrix44 m3 = SkMatrix44::I();
SkM44 m3;
m3.setTranslate(translate, translate, translate);
SkMatrix44 combined = m3 * m2 * m1;
SkM44 combined = m3 * m2 * m1;
flutter::MatrixDecomposition decomposition(combined);
ASSERT_TRUE(decomposition.IsValid());
ASSERT_FLOAT_EQ(translate, decomposition.translation().fX);
ASSERT_FLOAT_EQ(translate, decomposition.translation().fY);
ASSERT_FLOAT_EQ(translate, decomposition.translation().fZ);
ASSERT_FLOAT_EQ(translate, decomposition.translation().x);
ASSERT_FLOAT_EQ(translate, decomposition.translation().y);
ASSERT_FLOAT_EQ(translate, decomposition.translation().z);
ASSERT_FLOAT_EQ(scale, decomposition.scale().fX);
ASSERT_FLOAT_EQ(scale, decomposition.scale().fY);
ASSERT_FLOAT_EQ(scale, decomposition.scale().fZ);
ASSERT_FLOAT_EQ(scale, decomposition.scale().x);
ASSERT_FLOAT_EQ(scale, decomposition.scale().y);
ASSERT_FLOAT_EQ(scale, decomposition.scale().z);
const auto sine = sin(rotation * 0.5);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[1]);
ASSERT_FLOAT_EQ(sine, decomposition.rotation().fData[2]);
ASSERT_FLOAT_EQ(cos(rotation * 0.5), decomposition.rotation().fData[3]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().x);
ASSERT_FLOAT_EQ(0, decomposition.rotation().y);
ASSERT_FLOAT_EQ(sine, decomposition.rotation().z);
ASSERT_FLOAT_EQ(cos(rotation * 0.5), decomposition.rotation().w);
}
TEST(MatrixDecomposition, ScaleFloatError) {
constexpr float scale_increment = 0.00001f;
for (float scale = 0.0001f; scale < 2.0f; scale += scale_increment) {
SkMatrix44 matrix = SkMatrix44::I();
SkM44 matrix;
matrix.setScale(scale, scale, 1.0f);
flutter::MatrixDecomposition decomposition3(matrix);
ASSERT_TRUE(decomposition3.IsValid());
ASSERT_FLOAT_EQ(scale, decomposition3.scale().fX);
ASSERT_FLOAT_EQ(scale, decomposition3.scale().fY);
ASSERT_FLOAT_EQ(1.f, decomposition3.scale().fZ);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[1]);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[2]);
ASSERT_FLOAT_EQ(scale, decomposition3.scale().x);
ASSERT_FLOAT_EQ(scale, decomposition3.scale().y);
ASSERT_FLOAT_EQ(1.f, decomposition3.scale().z);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().x);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().y);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().z);
}
SkMatrix44 matrix = SkMatrix44::I();
SkM44 matrix;
const auto scale = 1.7734375f;
matrix.setScale(scale, scale, 1.f);
// Bug upper bound (empirical)
const auto scale2 = 1.773437559603f;
SkMatrix44 matrix2 = SkMatrix44::I();
SkM44 matrix2;
matrix2.setScale(scale2, scale2, 1.f);
// Bug lower bound (empirical)
const auto scale3 = 1.7734374403954f;
SkMatrix44 matrix3 = SkMatrix44::I();
SkM44 matrix3;
matrix3.setScale(scale3, scale3, 1.f);
flutter::MatrixDecomposition decomposition(matrix);
@ -135,26 +135,26 @@ TEST(MatrixDecomposition, ScaleFloatError) {
flutter::MatrixDecomposition decomposition3(matrix3);
ASSERT_TRUE(decomposition3.IsValid());
ASSERT_FLOAT_EQ(scale, decomposition.scale().fX);
ASSERT_FLOAT_EQ(scale, decomposition.scale().fY);
ASSERT_FLOAT_EQ(1.f, decomposition.scale().fZ);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[1]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[2]);
ASSERT_FLOAT_EQ(scale, decomposition.scale().x);
ASSERT_FLOAT_EQ(scale, decomposition.scale().y);
ASSERT_FLOAT_EQ(1.f, decomposition.scale().z);
ASSERT_FLOAT_EQ(0, decomposition.rotation().x);
ASSERT_FLOAT_EQ(0, decomposition.rotation().y);
ASSERT_FLOAT_EQ(0, decomposition.rotation().z);
ASSERT_FLOAT_EQ(scale2, decomposition2.scale().fX);
ASSERT_FLOAT_EQ(scale2, decomposition2.scale().fY);
ASSERT_FLOAT_EQ(1.f, decomposition2.scale().fZ);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().fData[1]);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().fData[2]);
ASSERT_FLOAT_EQ(scale2, decomposition2.scale().x);
ASSERT_FLOAT_EQ(scale2, decomposition2.scale().y);
ASSERT_FLOAT_EQ(1.f, decomposition2.scale().z);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().x);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().y);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().z);
ASSERT_FLOAT_EQ(scale3, decomposition3.scale().fX);
ASSERT_FLOAT_EQ(scale3, decomposition3.scale().fY);
ASSERT_FLOAT_EQ(1.f, decomposition3.scale().fZ);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[1]);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[2]);
ASSERT_FLOAT_EQ(scale3, decomposition3.scale().x);
ASSERT_FLOAT_EQ(scale3, decomposition3.scale().y);
ASSERT_FLOAT_EQ(1.f, decomposition3.scale().z);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().x);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().y);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().z);
}
} // namespace testing

View File

@ -250,22 +250,22 @@ SceneUpdateContext::Transform::Transform(SceneUpdateContext& context,
if (decomposition.IsValid()) {
// Don't allow clients to control the z dimension; we control that
// instead to make sure layers appear in proper order.
entity_node().SetTranslation(decomposition.translation().x(), //
decomposition.translation().y(), //
0.f //
entity_node().SetTranslation(decomposition.translation().x, //
decomposition.translation().y, //
0.f //
);
entity_node().SetScale(decomposition.scale().x(), //
decomposition.scale().y(), //
1.f //
entity_node().SetScale(decomposition.scale().x, //
decomposition.scale().y, //
1.f //
);
context.top_scale_x_ *= decomposition.scale().x();
context.top_scale_y_ *= decomposition.scale().y();
context.top_scale_x_ *= decomposition.scale().x;
context.top_scale_y_ *= decomposition.scale().y;
entity_node().SetRotation(decomposition.rotation().fData[0], //
decomposition.rotation().fData[1], //
decomposition.rotation().fData[2], //
decomposition.rotation().fData[3] //
entity_node().SetRotation(decomposition.rotation().x, //
decomposition.rotation().y, //
decomposition.rotation().z, //
decomposition.rotation().w //
);
}
}