From 2518a0a328e06aca6c951987f48e6d583df1bc30 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Wed, 24 Jan 2018 18:29:00 -0500 Subject: [skottie] Animator scrubbing Use std::function and lambda closures to capture node type info. Reduces the template degree. TBR= Change-Id: Id81ff3e2e1fca5c8acaaf2d0fc67e608d6f3d606 Reviewed-on: https://skia-review.googlesource.com/99261 Reviewed-by: Florin Malita Commit-Queue: Florin Malita --- experimental/skottie/Skottie.cpp | 193 ++++++++++++++++----------------- experimental/skottie/SkottieAnimator.h | 63 +++++------ 2 files changed, 122 insertions(+), 134 deletions(-) (limited to 'experimental') diff --git a/experimental/skottie/Skottie.cpp b/experimental/skottie/Skottie.cpp index 2199f51f2a..c8144e446d 100644 --- a/experimental/skottie/Skottie.cpp +++ b/experimental/skottie/Skottie.cpp @@ -64,9 +64,9 @@ bool LogFail(const Json::Value& json, const char* msg) { // This is the workhorse for binding properties: depending on whether the property is animated, // it will either apply immediately or instantiate and attach a keyframe animator. -template -bool BindProperty(const Json::Value& jprop, AttachContext* ctx, const sk_sp& node, - typename Animator::ApplyFuncT&& apply) { +template +bool BindProperty(const Json::Value& jprop, AttachContext* ctx, + typename Animator::ApplyFuncT&& apply) { if (!jprop.isObject()) return false; @@ -76,10 +76,10 @@ bool BindProperty(const Json::Value& jprop, AttachContext* ctx, const sk_sp::Parse(jpropK, &val)) { + T val; + if (ValueTraits::Parse(jpropK, &val)) { // Static property. - apply(node.get(), val); + apply(val); return true; } @@ -89,8 +89,7 @@ bool BindProperty(const Json::Value& jprop, AttachContext* ctx, const sk_sp; - auto animator = AnimatorT::Make(ParseFrames(jpropK), node, std::move(apply)); + auto animator = Animator::Make(jpropK, std::move(apply)); if (!animator) { return LogFail(jprop, "Could not parse keyframed property"); @@ -108,29 +107,29 @@ sk_sp AttachMatrix(const Json::Value& t, AttachContext* ctx, auto matrix = sksg::Matrix::Make(SkMatrix::I(), std::move(parentMatrix)); auto composite = sk_make_sp(matrix); - auto anchor_attached = BindProperty(t["a"], ctx, composite, - [](CompositeTransform* node, const VectorValue& a) { - node->setAnchorPoint(ValueTraits::As(a)); + auto anchor_attached = BindProperty(t["a"], ctx, + [composite](const VectorValue& a) { + composite->setAnchorPoint(ValueTraits::As(a)); }); - auto position_attached = BindProperty(t["p"], ctx, composite, - [](CompositeTransform* node, const VectorValue& p) { - node->setPosition(ValueTraits::As(p)); + auto position_attached = BindProperty(t["p"], ctx, + [composite](const VectorValue& p) { + composite->setPosition(ValueTraits::As(p)); }); - auto scale_attached = BindProperty(t["s"], ctx, composite, - [](CompositeTransform* node, const VectorValue& s) { - node->setScale(ValueTraits::As(s)); + auto scale_attached = BindProperty(t["s"], ctx, + [composite](const VectorValue& s) { + composite->setScale(ValueTraits::As(s)); }); - auto rotation_attached = BindProperty(t["r"], ctx, composite, - [](CompositeTransform* node, const ScalarValue& r) { - node->setRotation(r); + auto rotation_attached = BindProperty(t["r"], ctx, + [composite](const ScalarValue& r) { + composite->setRotation(r); }); - auto skew_attached = BindProperty(t["sk"], ctx, composite, - [](CompositeTransform* node, const ScalarValue& sk) { - node->setSkew(sk); + auto skew_attached = BindProperty(t["sk"], ctx, + [composite](const ScalarValue& sk) { + composite->setSkew(sk); }); - auto skewaxis_attached = BindProperty(t["sa"], ctx, composite, - [](CompositeTransform* node, const ScalarValue& sa) { - node->setSkewAxis(sa); + auto skewaxis_attached = BindProperty(t["sa"], ctx, + [composite](const ScalarValue& sa) { + composite->setSkewAxis(sa); }); if (!anchor_attached && @@ -162,10 +161,10 @@ sk_sp AttachOpacity(const Json::Value& jtransform, AttachConte } auto opacityNode = sksg::OpacityEffect::Make(childNode); - BindProperty(opacity, ctx, opacityNode, - [](sksg::OpacityEffect* node, const ScalarValue& o) { + BindProperty(opacity, ctx, + [opacityNode](const ScalarValue& o) { // BM opacity is [0..100] - node->setOpacity(o * 0.01f); + opacityNode->setOpacity(o * 0.01f); }); return opacityNode; @@ -175,8 +174,8 @@ sk_sp AttachComposition(const Json::Value&, AttachContext* ctx sk_sp AttachPath(const Json::Value& jpath, AttachContext* ctx) { auto path_node = sksg::Path::Make(); - return BindProperty(jpath, ctx, path_node, - [](sksg::Path* node, const ShapeValue& p) { node->setPath(p); }) + return BindProperty(jpath, ctx, + [path_node](const ShapeValue& p) { path_node->setPath(p); }) ? path_node : nullptr; } @@ -193,17 +192,17 @@ sk_sp AttachRRectGeometry(const Json::Value& jrect, AttachCo auto rect_node = sksg::RRect::Make(); auto composite = sk_make_sp(rect_node); - auto p_attached = BindProperty(jrect["p"], ctx, composite, - [](CompositeRRect* node, const VectorValue& p) { - node->setPosition(ValueTraits::As(p)); + auto p_attached = BindProperty(jrect["p"], ctx, + [composite](const VectorValue& p) { + composite->setPosition(ValueTraits::As(p)); }); - auto s_attached = BindProperty(jrect["s"], ctx, composite, - [](CompositeRRect* node, const VectorValue& s) { - node->setSize(ValueTraits::As(s)); + auto s_attached = BindProperty(jrect["s"], ctx, + [composite](const VectorValue& s) { + composite->setSize(ValueTraits::As(s)); }); - auto r_attached = BindProperty(jrect["r"], ctx, composite, - [](CompositeRRect* node, const ScalarValue& r) { - node->setRadius(SkSize::Make(r, r)); + auto r_attached = BindProperty(jrect["r"], ctx, + [composite](const ScalarValue& r) { + composite->setRadius(SkSize::Make(r, r)); }); if (!p_attached && !s_attached && !r_attached) { @@ -221,15 +220,15 @@ sk_sp AttachEllipseGeometry(const Json::Value& jellipse, Att auto rect_node = sksg::RRect::Make(); auto composite = sk_make_sp(rect_node); - auto p_attached = BindProperty(jellipse["p"], ctx, composite, - [](CompositeRRect* node, const VectorValue& p) { - node->setPosition(ValueTraits::As(p)); + auto p_attached = BindProperty(jellipse["p"], ctx, + [composite](const VectorValue& p) { + composite->setPosition(ValueTraits::As(p)); }); - auto s_attached = BindProperty(jellipse["s"], ctx, composite, - [](CompositeRRect* node, const VectorValue& s) { + auto s_attached = BindProperty(jellipse["s"], ctx, + [composite](const VectorValue& s) { const auto sz = ValueTraits::As(s); - node->setSize(sz); - node->setRadius(SkSize::Make(sz.width() / 2, sz.height() / 2)); + composite->setSize(sz); + composite->setRadius(SkSize::Make(sz.width() / 2, sz.height() / 2)); }); if (!p_attached && !s_attached) { @@ -258,33 +257,33 @@ sk_sp AttachPolystarGeometry(const Json::Value& jstar, Attac auto path_node = sksg::Path::Make(); auto composite = sk_make_sp(path_node, gTypes[type]); - BindProperty(jstar["p"], ctx, composite, - [](CompositePolyStar* node, const VectorValue& p) { - node->setPosition(ValueTraits::As(p)); + BindProperty(jstar["p"], ctx, + [composite](const VectorValue& p) { + composite->setPosition(ValueTraits::As(p)); }); - BindProperty(jstar["pt"], ctx, composite, - [](CompositePolyStar* node, const ScalarValue& pt) { - node->setPointCount(pt); + BindProperty(jstar["pt"], ctx, + [composite](const ScalarValue& pt) { + composite->setPointCount(pt); }); - BindProperty(jstar["ir"], ctx, composite, - [](CompositePolyStar* node, const ScalarValue& ir) { - node->setInnerRadius(ir); + BindProperty(jstar["ir"], ctx, + [composite](const ScalarValue& ir) { + composite->setInnerRadius(ir); }); - BindProperty(jstar["or"], ctx, composite, - [](CompositePolyStar* node, const ScalarValue& otr) { - node->setOuterRadius(otr); + BindProperty(jstar["or"], ctx, + [composite](const ScalarValue& otr) { + composite->setOuterRadius(otr); }); - BindProperty(jstar["is"], ctx, composite, - [](CompositePolyStar* node, const ScalarValue& is) { - node->setInnerRoundness(is); + BindProperty(jstar["is"], ctx, + [composite](const ScalarValue& is) { + composite->setInnerRoundness(is); }); - BindProperty(jstar["os"], ctx, composite, - [](CompositePolyStar* node, const ScalarValue& os) { - node->setOuterRoundness(os); + BindProperty(jstar["os"], ctx, + [composite](const ScalarValue& os) { + composite->setOuterRoundness(os); }); - BindProperty(jstar["r"], ctx, composite, - [](CompositePolyStar* node, const ScalarValue& r) { - node->setRotation(r); + BindProperty(jstar["r"], ctx, + [composite](const ScalarValue& r) { + composite->setRotation(r); }); return path_node; @@ -294,9 +293,9 @@ sk_sp AttachColor(const Json::Value& obj, AttachContext* ctx) { SkASSERT(obj.isObject()); auto color_node = sksg::Color::Make(SK_ColorBLACK); - auto color_attached = BindProperty(obj["c"], ctx, color_node, - [](sksg::Color* node, const VectorValue& c) { - node->setColor(ValueTraits::As(c)); + auto color_attached = BindProperty(obj["c"], ctx, + [color_node](const VectorValue& c) { + color_node->setColor(ValueTraits::As(c)); }); return color_attached ? color_node : nullptr; @@ -328,17 +327,17 @@ sk_sp AttachGradient(const Json::Value& obj, AttachContext* ctx) gradient_node = std::move(radial_node); } - BindProperty(stops["k"], ctx, composite, - [](CompositeGradient* node, const VectorValue& stops) { - node->setColorStops(stops); + BindProperty(stops["k"], ctx, + [composite](const VectorValue& stops) { + composite->setColorStops(stops); }); - BindProperty(obj["s"], ctx, composite, - [](CompositeGradient* node, const VectorValue& s) { - node->setStartPoint(ValueTraits::As(s)); + BindProperty(obj["s"], ctx, + [composite](const VectorValue& s) { + composite->setStartPoint(ValueTraits::As(s)); }); - BindProperty(obj["e"], ctx, composite, - [](CompositeGradient* node, const VectorValue& e) { - node->setEndPoint(ValueTraits::As(e)); + BindProperty(obj["e"], ctx, + [composite](const VectorValue& e) { + composite->setEndPoint(ValueTraits::As(e)); }); return gradient_node; @@ -349,10 +348,10 @@ sk_sp AttachPaint(const Json::Value& jpaint, AttachContext* ctx if (paint_node) { paint_node->setAntiAlias(true); - BindProperty(jpaint["o"], ctx, paint_node, - [](sksg::PaintNode* node, const ScalarValue& o) { + BindProperty(jpaint["o"], ctx, + [paint_node](const ScalarValue& o) { // BM opacity is [0..100] - node->setOpacity(o * 0.01f); + paint_node->setOpacity(o * 0.01f); }); } @@ -368,9 +367,9 @@ sk_sp AttachStroke(const Json::Value& jstroke, AttachContext* c stroke_node->setStyle(SkPaint::kStroke_Style); - auto width_attached = BindProperty(jstroke["w"], ctx, stroke_node, - [](sksg::PaintNode* node, const ScalarValue& w) { - node->setStrokeWidth(w); + auto width_attached = BindProperty(jstroke["w"], ctx, + [stroke_node](const ScalarValue& w) { + stroke_node->setStrokeWidth(w); }); if (!width_attached) return nullptr; @@ -464,17 +463,17 @@ std::vector> AttachTrimGeometryEffect( for (const auto& i : inputs) { const auto trim = sksg::TrimEffect::Make(i); trimmed.push_back(trim); - BindProperty(jtrim["s"], ctx, trim, - [](sksg::TrimEffect* node, const ScalarValue& s) { - node->setStart(s * 0.01f); + BindProperty(jtrim["s"], ctx, + [trim](const ScalarValue& s) { + trim->setStart(s * 0.01f); }); - BindProperty(jtrim["e"], ctx, trim, - [](sksg::TrimEffect* node, const ScalarValue& e) { - node->setEnd(e * 0.01f); + BindProperty(jtrim["e"], ctx, + [trim](const ScalarValue& e) { + trim->setEnd(e * 0.01f); }); - BindProperty(jtrim["o"], ctx, trim, - [](sksg::TrimEffect* node, const ScalarValue& o) { - node->setOffset(o / 360); + BindProperty(jtrim["o"], ctx, + [trim](const ScalarValue& o) { + trim->setOffset(o / 360); }); } @@ -927,8 +926,8 @@ sk_sp AttachMask(const Json::Value& jmask, auto mask_paint = sksg::Color::Make(SK_ColorBLACK); mask_paint->setBlendMode(MaskBlendMode(mode.c_str()[0])); - BindProperty(m["o"], ctx, mask_paint, - [](sksg::Color* node, const ScalarValue& o) { node->setOpacity(o * 0.01f); }); + BindProperty(m["o"], ctx, + [mask_paint](const ScalarValue& o) { mask_paint->setOpacity(o * 0.01f); }); mask_group->addChild(sksg::Draw::Make(std::move(mask_path), std::move(mask_paint))); } diff --git a/experimental/skottie/SkottieAnimator.h b/experimental/skottie/SkottieAnimator.h index 062a4d8969..7ea4929280 100644 --- a/experimental/skottie/SkottieAnimator.h +++ b/experimental/skottie/SkottieAnimator.h @@ -13,10 +13,11 @@ #include "SkottiePriv.h" #include "SkottieProperties.h" #include "SkSGScene.h" +#include "SkTArray.h" #include "SkTypes.h" +#include #include -#include namespace skottie { @@ -94,12 +95,17 @@ private: using INHERITED = KeyframeIntervalBase; }; +// Binds an animated/keyframed property to a node attribute setter. template -std::vector> ParseFrames(const Json::Value& jframes) { - std::vector> frames; +class Animator final : public sksg::Animator { +public: + using ApplyFuncT = std::function; + + static std::unique_ptr Make(const Json::Value& jframes, ApplyFuncT&& applyFunc) { + if (!jframes.isArray()) + return nullptr; - if (jframes.isArray()) { - frames.reserve(jframes.size()); + SkTArray, true> frames(jframes.size()); KeyframeInterval* prev_frame = nullptr; for (const auto& jframe : jframes) { @@ -112,56 +118,39 @@ std::vector> ParseFrames(const Json::Value& jframes) { prev_frame = &frames.back(); } } - } - - // If we couldn't determine a t1 for the last frame, discard it. - if (!frames.empty() && !frames.back().isValid()) { - frames.pop_back(); - } - return frames; -} + // If we couldn't determine a t1 for the last frame, discard it. + if (!frames.empty() && !frames.back().isValid()) { + frames.pop_back(); + } -// Binds an animated/keyframed property to a node attribute setter. -template -class Animator final : public sksg::Animator { -public: - using ApplyFuncT = void(*)(NodeT*, const ValT&); - static std::unique_ptr Make(std::vector>&& frames, - sk_sp node, - ApplyFuncT&& applyFunc) { - return (node && !frames.empty()) - ? std::unique_ptr(new Animator(std::move(frames), - std::move(node), - std::move(applyFunc))) - : nullptr; + return frames.empty() + ? nullptr + : std::unique_ptr(new Animator(std::move(frames), std::move(applyFunc))); } void onTick(float t) override { const auto& frame = this->findFrame(t); - ValT val; + T val; frame.eval(t, &val); - fFunc(fTarget.get(), val); + fFunc(val); } private: - Animator(std::vector>&& frames, sk_sp node, - ApplyFuncT&& applyFunc) + Animator(SkTArray, true>&& frames, ApplyFuncT&& applyFunc) : fFrames(std::move(frames)) - , fTarget(std::move(node)) , fFunc(std::move(applyFunc)) {} - const KeyframeInterval& findFrame(float t) const; + const KeyframeInterval& findFrame(float t) const; - const std::vector> fFrames; - sk_sp fTarget; - ApplyFuncT fFunc; + const SkTArray, true> fFrames; + const ApplyFuncT fFunc; }; -template -const KeyframeInterval& Animator::findFrame(float t) const { +template +const KeyframeInterval& Animator::findFrame(float t) const { SkASSERT(!fFrames.empty()); // TODO: cache last/current frame? -- cgit v1.2.3