From cca86f386cfd050cd03a25b305fc6fda48a8d6cd Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Mon, 29 Jan 2018 10:49:49 -0500 Subject: [skottie] Hierarchical animators Instead of a flat animator space, introduce animator groups. This allows us to encapsulate layer animators and only dispatch ticks when their owning layer is active. TBR= Change-Id: I1fc8a55abf68a712b71969bb1a11275dbe54c236 Reviewed-on: https://skia-review.googlesource.com/101201 Reviewed-by: Florin Malita Commit-Queue: Florin Malita --- experimental/skottie/Skottie.cpp | 55 ++++++++++++++++++++------------ experimental/skottie/SkottieAnimator.cpp | 8 ++--- experimental/skottie/SkottieAnimator.h | 2 +- experimental/sksg/SkSGScene.cpp | 9 ++++++ experimental/sksg/SkSGScene.h | 16 ++++++++-- 5 files changed, 62 insertions(+), 28 deletions(-) (limited to 'experimental') diff --git a/experimental/skottie/Skottie.cpp b/experimental/skottie/Skottie.cpp index 1ec461423d..66b84b5750 100644 --- a/experimental/skottie/Skottie.cpp +++ b/experimental/skottie/Skottie.cpp @@ -18,7 +18,6 @@ #include "SkOSPath.h" #include "SkPaint.h" #include "SkParse.h" -#include "SkPath.h" #include "SkPoint.h" #include "SkSGColor.h" #include "SkSGDraw.h" @@ -53,9 +52,9 @@ namespace { using AssetMap = SkTHashMap; struct AttachContext { - const ResourceProvider& fResources; - const AssetMap& fAssets; - sksg::Scene::AnimatorList& fAnimators; + const ResourceProvider& fResources; + const AssetMap& fAssets; + sksg::AnimatorList& fAnimators; }; bool LogFail(const Json::Value& json, const char* msg) { @@ -921,58 +920,72 @@ sk_sp AttachLayer(const Json::Value& jlayer, return nullptr; } + sksg::AnimatorList layer_animators; + AttachContext local_ctx = + { layerCtx->fCtx->fResources, layerCtx->fCtx->fAssets, layer_animators}; + // Layer content. - auto layer = gLayerAttachers[type](jlayer, layerCtx->fCtx); + auto layer = gLayerAttachers[type](jlayer, &local_ctx); // Optional layer mask. - layer = AttachMask(jlayer["masksProperties"], layerCtx->fCtx, std::move(layer)); + layer = AttachMask(jlayer["masksProperties"], &local_ctx, std::move(layer)); // Optional layer transform. if (auto layerMatrix = layerCtx->AttachLayerMatrix(jlayer)) { layer = sksg::Transform::Make(std::move(layer), std::move(layerMatrix)); } // Optional layer opacity. - layer = AttachOpacity(jlayer["ks"], layerCtx->fCtx, std::move(layer)); + layer = AttachOpacity(jlayer["ks"], &local_ctx, std::move(layer)); - // TODO: we should also disable related/inactive animators. - class Activator final : public sksg::Animator { + class Activator final : public sksg::GroupAnimator { public: - Activator(sk_sp controlNode, float in, float out) - : fControlNode(std::move(controlNode)) + Activator(sksg::AnimatorList&& layer_animators, + sk_sp controlNode, float in, float out) + : INHERITED(std::move(layer_animators)) + , fControlNode(std::move(controlNode)) , fIn(in) , fOut(out) {} void onTick(float t) override { + const auto active = (t >= fIn && t <= fOut); + // Keep the layer fully transparent except for its [in..out] lifespan. // (note: opacity == 0 disables rendering, while opacity == 1 is a noop) - fControlNode->setOpacity(t >= fIn && t <= fOut ? 1 : 0); + fControlNode->setOpacity(active ? 1 : 0); + + // Dispatch ticks only while active. + if (active) + this->INHERITED::onTick(t); } private: const sk_sp fControlNode; const float fIn, fOut; + + using INHERITED = sksg::GroupAnimator; }; - auto layerControl = sksg::OpacityEffect::Make(std::move(layer)); - const auto in = ParseDefault(jlayer["ip"], 0.0f), - out = ParseDefault(jlayer["op"], in); + auto controller = sksg::OpacityEffect::Make(std::move(layer)); + const auto in = ParseDefault(jlayer["ip"], 0.0f), + out = ParseDefault(jlayer["op"], in); - if (in >= out || ! layerControl) + if (in >= out || !controller) return nullptr; - layerCtx->fCtx->fAnimators.push_back(skstd::make_unique(layerControl, in, out)); + layerCtx->fCtx->fAnimators.push_back( + skstd::make_unique(std::move(layer_animators), controller, in, out)); if (ParseDefault(jlayer["td"], false)) { // This layer is a matte. We apply it as a mask to the next layer. - layerCtx->fCurrentMatte = std::move(layerControl); + layerCtx->fCurrentMatte = std::move(controller); return nullptr; } if (layerCtx->fCurrentMatte) { // There is a pending matte. Apply and reset. - return sksg::MaskEffect::Make(std::move(layerControl), std::move(layerCtx->fCurrentMatte)); + return sksg::MaskEffect::Make(std::move(controller), std::move(layerCtx->fCurrentMatte)); } - return layerControl; + return controller; } sk_sp AttachComposition(const Json::Value& comp, AttachContext* ctx) { @@ -1091,7 +1104,7 @@ Animation::Animation(const ResourceProvider& resources, assets.set(ParseDefault(asset["id"], SkString()), &asset); } - sksg::Scene::AnimatorList animators; + sksg::AnimatorList animators; AttachContext ctx = { resources, assets, animators }; auto root = AttachComposition(json, &ctx); diff --git a/experimental/skottie/SkottieAnimator.cpp b/experimental/skottie/SkottieAnimator.cpp index b50e8ac442..c5cea588eb 100644 --- a/experimental/skottie/SkottieAnimator.cpp +++ b/experimental/skottie/SkottieAnimator.cpp @@ -275,7 +275,7 @@ private: template static inline bool BindPropertyImpl(const Json::Value& jprop, - sksg::Scene::AnimatorList* animators, + sksg::AnimatorList* animators, std::function&& apply, const T* noop) { if (!jprop.isObject()) @@ -318,7 +318,7 @@ static inline bool BindPropertyImpl(const Json::Value& jprop, template <> bool BindProperty(const Json::Value& jprop, - sksg::Scene::AnimatorList* animators, + sksg::AnimatorList* animators, std::function&& apply, const ScalarValue* noop) { return BindPropertyImpl(jprop, animators, std::move(apply), noop); @@ -326,7 +326,7 @@ bool BindProperty(const Json::Value& jprop, template <> bool BindProperty(const Json::Value& jprop, - sksg::Scene::AnimatorList* animators, + sksg::AnimatorList* animators, std::function&& apply, const VectorValue* noop) { return BindPropertyImpl(jprop, animators, std::move(apply), noop); @@ -334,7 +334,7 @@ bool BindProperty(const Json::Value& jprop, template <> bool BindProperty(const Json::Value& jprop, - sksg::Scene::AnimatorList* animators, + sksg::AnimatorList* animators, std::function&& apply, const ShapeValue* noop) { return BindPropertyImpl(jprop, animators, std::move(apply), noop); diff --git a/experimental/skottie/SkottieAnimator.h b/experimental/skottie/SkottieAnimator.h index c32b4f8207..77be06b809 100644 --- a/experimental/skottie/SkottieAnimator.h +++ b/experimental/skottie/SkottieAnimator.h @@ -20,7 +20,7 @@ namespace skottie { // it will either apply immediately or instantiate and attach a keyframe animator. template bool BindProperty(const Json::Value&, - sksg::Scene::AnimatorList*, + sksg::AnimatorList*, std::function&&, const T* noop = nullptr); diff --git a/experimental/sksg/SkSGScene.cpp b/experimental/sksg/SkSGScene.cpp index 85a1b43b1c..8d7e0b369b 100644 --- a/experimental/sksg/SkSGScene.cpp +++ b/experimental/sksg/SkSGScene.cpp @@ -22,6 +22,15 @@ void Animator::tick(float t) { this->onTick(t); } +GroupAnimator::GroupAnimator(AnimatorList&& animators) + : fAnimators(std::move(animators)) {} + +void GroupAnimator::onTick(float t) { + for (const auto& a : fAnimators) { + a->tick(t); + } +} + std::unique_ptr Scene::Make(sk_sp root, AnimatorList&& anims) { return root ? std::unique_ptr(new Scene(std::move(root), std::move(anims))) : nullptr; } diff --git a/experimental/sksg/SkSGScene.h b/experimental/sksg/SkSGScene.h index 32186498d2..2081c1d747 100644 --- a/experimental/sksg/SkSGScene.h +++ b/experimental/sksg/SkSGScene.h @@ -39,6 +39,20 @@ private: using INHERITED = SkNoncopyable; }; +using AnimatorList = std::vector>; + +class GroupAnimator : public Animator { +protected: + explicit GroupAnimator(AnimatorList&&); + + void onTick(float t) override; + +private: + const AnimatorList fAnimators; + + using INHERITED = Animator; +}; + /** * Holds a scene root and a list of animators. * @@ -47,8 +61,6 @@ private: */ class Scene final : SkNoncopyable { public: - using AnimatorList = std::vector>; - static std::unique_ptr Make(sk_sp root, AnimatorList&& animators); ~Scene(); -- cgit v1.2.3