[skottie] Initial 3D layer transform support
TBR=
Change-Id: Ia849a0062a75863857edc66d8a5c1c62bfc6d00a
Reviewed-on: https://skia-review.googlesource.com/c/180362
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/modules/skottie/include/SkottieProperty.h b/modules/skottie/include/SkottieProperty.h
index a738697..a3dee71 100644
--- a/modules/skottie/include/SkottieProperty.h
+++ b/modules/skottie/include/SkottieProperty.h
@@ -62,11 +62,11 @@
const sk_sp<NodeT> fNode;
};
-class TransformAdapter;
+class TransformAdapter2D;
using ColorPropertyHandle = PropertyHandle<ColorPropertyValue , sksg::Color >;
using OpacityPropertyHandle = PropertyHandle<OpacityPropertyValue , sksg::OpacityEffect >;
-using TransformPropertyHandle = PropertyHandle<TransformPropertyValue, TransformAdapter >;
+using TransformPropertyHandle = PropertyHandle<TransformPropertyValue, TransformAdapter2D >;
/**
* A PropertyObserver can be used to track and manipulate certain properties of "interesting"
diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp
index a18ffc5..65fed85 100644
--- a/modules/skottie/src/Skottie.cpp
+++ b/modules/skottie/src/Skottie.cpp
@@ -61,14 +61,14 @@
fLogger->log(lvl, buff, jsonstr.c_str());
}
-sk_sp<sksg::Matrix> AnimationBuilder::attachMatrix(const skjson::ObjectValue& t,
- AnimatorScope* ascope,
- sk_sp<sksg::Matrix> parentMatrix) const {
+sk_sp<sksg::Matrix> AnimationBuilder::attachMatrix2D(const skjson::ObjectValue& t,
+ AnimatorScope* ascope,
+ sk_sp<sksg::Matrix> parentMatrix) const {
static const VectorValue g_default_vec_0 = { 0, 0},
g_default_vec_100 = {100, 100};
auto matrix = sksg::Matrix::Make(SkMatrix::I(), parentMatrix);
- auto adapter = sk_make_sp<TransformAdapter>(matrix);
+ auto adapter = sk_make_sp<TransformAdapter2D>(matrix);
auto bound = this->bindProperty<VectorValue>(t["a"], ascope,
[adapter](const VectorValue& a) {
@@ -107,6 +107,58 @@
return (bound || dispatched) ? matrix : parentMatrix;
}
+sk_sp<sksg::Matrix> AnimationBuilder::attachMatrix3D(const skjson::ObjectValue& t,
+ AnimatorScope* ascope,
+ sk_sp<sksg::Matrix> parentMatrix) const {
+ static const VectorValue g_default_vec_0 = { 0, 0, 0},
+ g_default_vec_100 = {100, 100, 100};
+
+ auto matrix = sksg::Matrix::Make(SkMatrix::I(), parentMatrix);
+ auto adapter = sk_make_sp<TransformAdapter3D>(matrix);
+
+ auto bound = this->bindProperty<VectorValue>(t["a"], ascope,
+ [adapter](const VectorValue& a) {
+ adapter->setAnchorPoint(TransformAdapter3D::Vec3(a));
+ }, g_default_vec_0);
+ bound |= this->bindProperty<VectorValue>(t["p"], ascope,
+ [adapter](const VectorValue& p) {
+ adapter->setPosition(TransformAdapter3D::Vec3(p));
+ }, g_default_vec_0);
+ bound |= this->bindProperty<VectorValue>(t["s"], ascope,
+ [adapter](const VectorValue& s) {
+ adapter->setScale(TransformAdapter3D::Vec3(s));
+ }, g_default_vec_100);
+
+ // Orientation and rx/ry/rz are mapped to the same rotation property -- the difference is
+ // in how they get interpolated (vector vs. scalar/decomposed interpolation).
+ bound |= this->bindProperty<VectorValue>(t["or"], ascope,
+ [adapter](const VectorValue& o) {
+ adapter->setRotation(TransformAdapter3D::Vec3(o));
+ }, g_default_vec_0);
+
+ bound |= this->bindProperty<ScalarValue>(t["rx"], ascope,
+ [adapter](const ScalarValue& rx) {
+ const auto& r = adapter->getRotation();
+ adapter->setRotation(TransformAdapter3D::Vec3({rx, r.fY, r.fZ}));
+ }, 0.0f);
+
+ bound |= this->bindProperty<ScalarValue>(t["ry"], ascope,
+ [adapter](const ScalarValue& ry) {
+ const auto& r = adapter->getRotation();
+ adapter->setRotation(TransformAdapter3D::Vec3({r.fX, ry, r.fZ}));
+ }, 0.0f);
+
+ bound |= this->bindProperty<ScalarValue>(t["rz"], ascope,
+ [adapter](const ScalarValue& rz) {
+ const auto& r = adapter->getRotation();
+ adapter->setRotation(TransformAdapter3D::Vec3({r.fX, r.fY, rz}));
+ }, 0.0f);
+
+ // TODO: dispatch 3D transform properties
+
+ return bound ? matrix : parentMatrix;
+}
+
sk_sp<sksg::RenderNode> AnimationBuilder::attachOpacity(const skjson::ObjectValue& jtransform,
AnimatorScope* ascope,
sk_sp<sksg::RenderNode> childNode) const {
@@ -251,7 +303,7 @@
return dispatched;
}
-bool AnimationBuilder::dispatchTransformProperty(const sk_sp<TransformAdapter>& t) const {
+bool AnimationBuilder::dispatchTransformProperty(const sk_sp<TransformAdapter2D>& t) const {
bool dispatched = false;
if (fPropertyObserver) {
diff --git a/modules/skottie/src/SkottieAdapter.cpp b/modules/skottie/src/SkottieAdapter.cpp
index 0dd51bb..0d53869 100644
--- a/modules/skottie/src/SkottieAdapter.cpp
+++ b/modules/skottie/src/SkottieAdapter.cpp
@@ -9,6 +9,7 @@
#include "SkFont.h"
#include "SkMatrix.h"
+#include "SkMatrix44.h"
#include "SkPath.h"
#include "SkRRect.h"
#include "SkSGColor.h"
@@ -46,12 +47,12 @@
fRRectNode->setRRect(rr);
}
-TransformAdapter::TransformAdapter(sk_sp<sksg::Matrix> matrix)
+TransformAdapter2D::TransformAdapter2D(sk_sp<sksg::Matrix> matrix)
: fMatrixNode(std::move(matrix)) {}
-TransformAdapter::~TransformAdapter() = default;
+TransformAdapter2D::~TransformAdapter2D() = default;
-SkMatrix TransformAdapter::totalMatrix() const {
+SkMatrix TransformAdapter2D::totalMatrix() const {
SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y());
t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based
@@ -62,7 +63,42 @@
return t;
}
-void TransformAdapter::apply() {
+void TransformAdapter2D::apply() {
+ fMatrixNode->setMatrix(this->totalMatrix());
+}
+
+TransformAdapter3D::Vec3::Vec3(const VectorValue& v) {
+ fX = v.size() > 0 ? v[0] : 0;
+ fY = v.size() > 1 ? v[1] : 0;
+ fZ = v.size() > 2 ? v[2] : 0;
+}
+
+TransformAdapter3D::TransformAdapter3D(sk_sp<sksg::Matrix> matrix)
+ : fMatrixNode(std::move(matrix)) {}
+
+TransformAdapter3D::~TransformAdapter3D() = default;
+
+SkMatrix TransformAdapter3D::totalMatrix() const {
+ SkMatrix44 t;
+
+ t.setTranslate(-fAnchorPoint.fX, -fAnchorPoint.fY, -fAnchorPoint.fZ);
+ t.postScale(fScale.fX / 100, fScale.fY / 100, fScale.fZ / 100);
+
+ // TODO: SkMatrix44:postRotate()?
+ SkMatrix44 r;
+ r.setRotateDegreesAbout(1, 0, 0, fRotation.fX);
+ t.postConcat(r);
+ r.setRotateDegreesAbout(0, 1, 0, fRotation.fY);
+ t.postConcat(r);
+ r.setRotateDegreesAbout(0, 0, 1, fRotation.fZ);
+ t.postConcat(r);
+
+ t.postTranslate(fPosition.fX, fPosition.fY, fPosition.fZ);
+
+ return t;
+}
+
+void TransformAdapter3D::apply() {
fMatrixNode->setMatrix(this->totalMatrix());
}
diff --git a/modules/skottie/src/SkottieAdapter.h b/modules/skottie/src/SkottieAdapter.h
index 13b74f2..1ab9a7b 100644
--- a/modules/skottie/src/SkottieAdapter.h
+++ b/modules/skottie/src/SkottieAdapter.h
@@ -83,10 +83,10 @@
Type fType;
};
-class TransformAdapter final : public SkNVRefCnt<TransformAdapter> {
+class TransformAdapter2D final : public SkNVRefCnt<TransformAdapter2D> {
public:
- explicit TransformAdapter(sk_sp<sksg::Matrix>);
- ~TransformAdapter();
+ explicit TransformAdapter2D(sk_sp<sksg::Matrix>);
+ ~TransformAdapter2D();
ADAPTER_PROPERTY(AnchorPoint, SkPoint , SkPoint::Make(0, 0))
ADAPTER_PROPERTY(Position , SkPoint , SkPoint::Make(0, 0))
@@ -103,6 +103,35 @@
sk_sp<sksg::Matrix> fMatrixNode;
};
+class TransformAdapter3D final : public SkNVRefCnt<TransformAdapter3D> {
+public:
+ explicit TransformAdapter3D(sk_sp<sksg::Matrix>);
+ ~TransformAdapter3D();
+
+ struct Vec3 {
+ float fX, fY, fZ;
+
+ explicit Vec3(const VectorValue&);
+
+ bool operator==(const Vec3& other) const {
+ return fX == other.fX && fY == other.fY && fZ == other.fZ;
+ }
+ bool operator!=(const Vec3& other) const { return !(*this == other); }
+ };
+
+ ADAPTER_PROPERTY(AnchorPoint, Vec3, Vec3({ 0, 0, 0}))
+ ADAPTER_PROPERTY(Position , Vec3, Vec3({ 0, 0, 0}))
+ ADAPTER_PROPERTY(Rotation , Vec3, Vec3({ 0, 0, 0}))
+ ADAPTER_PROPERTY(Scale , Vec3, Vec3({100, 100, 100}))
+
+ SkMatrix totalMatrix() const;
+
+private:
+ void apply();
+
+ sk_sp<sksg::Matrix> fMatrixNode;
+};
+
class GradientAdapter : public SkRefCnt {
public:
ADAPTER_PROPERTY(StartPoint, SkPoint , SkPoint::Make(0, 0) )
diff --git a/modules/skottie/src/SkottieLayer.cpp b/modules/skottie/src/SkottieLayer.cpp
index 2786ed5..2bb6264 100644
--- a/modules/skottie/src/SkottieLayer.cpp
+++ b/modules/skottie/src/SkottieLayer.cpp
@@ -449,10 +449,11 @@
auto parent_matrix = this->AttachParentLayerMatrix(jlayer, abuilder, layer_index);
if (const skjson::ObjectValue* jtransform = jlayer["ks"]) {
- return *fLayerMatrixMap.set(layer_index,
- abuilder->attachMatrix(*jtransform, fScope,
- std::move(parent_matrix)));
+ auto matrix_node = (ParseDefault<int>(jlayer["ddd"], 0) == 0)
+ ? abuilder->attachMatrix2D(*jtransform, fScope, std::move(parent_matrix))
+ : abuilder->attachMatrix3D(*jtransform, fScope, std::move(parent_matrix));
+ return *fLayerMatrixMap.set(layer_index, std::move(matrix_node));
}
return nullptr;
}
diff --git a/modules/skottie/src/SkottiePriv.h b/modules/skottie/src/SkottiePriv.h
index b3c15e5..ee41f37 100644
--- a/modules/skottie/src/SkottiePriv.h
+++ b/modules/skottie/src/SkottiePriv.h
@@ -71,8 +71,10 @@
sk_sp<sksg::Color> attachColor(const skjson::ObjectValue&, AnimatorScope*,
const char prop_name[]) const;
- sk_sp<sksg::Matrix> attachMatrix(const skjson::ObjectValue&, AnimatorScope*,
- sk_sp<sksg::Matrix>) const;
+ sk_sp<sksg::Matrix> attachMatrix2D(const skjson::ObjectValue&, AnimatorScope*,
+ sk_sp<sksg::Matrix>) const;
+ sk_sp<sksg::Matrix> attachMatrix3D(const skjson::ObjectValue&, AnimatorScope*,
+ sk_sp<sksg::Matrix>) const;
sk_sp<sksg::RenderNode> attachOpacity(const skjson::ObjectValue&, AnimatorScope*,
sk_sp<sksg::RenderNode>) const;
sk_sp<sksg::Path> attachPath(const skjson::Value&, AnimatorScope*) const;
@@ -119,7 +121,7 @@
bool dispatchColorProperty(const sk_sp<sksg::Color>&) const;
bool dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>&) const;
- bool dispatchTransformProperty(const sk_sp<TransformAdapter>&) const;
+ bool dispatchTransformProperty(const sk_sp<TransformAdapter2D>&) const;
// Delay resolving the fontmgr until it is actually needed.
struct LazyResolveFontMgr {
diff --git a/modules/skottie/src/SkottieProperty.cpp b/modules/skottie/src/SkottieProperty.cpp
index 0d27017..143b97a 100644
--- a/modules/skottie/src/SkottieProperty.cpp
+++ b/modules/skottie/src/SkottieProperty.cpp
@@ -52,10 +52,10 @@
}
template <>
-PropertyHandle<TransformPropertyValue, TransformAdapter>::~PropertyHandle() {}
+PropertyHandle<TransformPropertyValue, TransformAdapter2D>::~PropertyHandle() {}
template <>
-TransformPropertyValue PropertyHandle<TransformPropertyValue, TransformAdapter>::get() const {
+TransformPropertyValue PropertyHandle<TransformPropertyValue, TransformAdapter2D>::get() const {
return {
fNode->getAnchorPoint(),
fNode->getPosition(),
@@ -67,7 +67,7 @@
}
template <>
-void PropertyHandle<TransformPropertyValue, TransformAdapter>::set(
+void PropertyHandle<TransformPropertyValue, TransformAdapter2D>::set(
const TransformPropertyValue& t) {
fNode->setAnchorPoint(t.fAnchorPoint);
fNode->setPosition(t.fPosition);
diff --git a/modules/skottie/src/SkottieShapeLayer.cpp b/modules/skottie/src/SkottieShapeLayer.cpp
index 197faec..76b5658 100644
--- a/modules/skottie/src/SkottieShapeLayer.cpp
+++ b/modules/skottie/src/SkottieShapeLayer.cpp
@@ -596,7 +596,7 @@
// of the dangling/uncommitted ones.
AnimatorScope local_scope;
- if ((shape_matrix = this->attachMatrix(*jtransform, &local_scope, nullptr))) {
+ if ((shape_matrix = this->attachMatrix2D(*jtransform, &local_scope, nullptr))) {
shape_wrapper = sksg::Transform::Make(std::move(shape_wrapper), shape_matrix);
}
shape_wrapper = this->attachOpacity(*jtransform, &local_scope, std::move(shape_wrapper));