[skottie] Make AnimationBuilder available for value parsing
Plumb AnimationBuilder throught a bazillion layers to make it reachable when parsing animatable values. This is in preparation of keyframed text, which will require access to the font set when parsing. Refactor only, no functional changes. TBR= Change-Id: Ide2ef2ba66fbcc75fdcc785f987b364d45dff5b6 Reviewed-on: https://skia-review.googlesource.com/149264 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
3054989426
commit
471a946cf1
@ -14,7 +14,6 @@ skia_skottie_sources = [
|
||||
"$_src/SkottieAdapter.cpp",
|
||||
"$_src/SkottieAdapter.h",
|
||||
"$_src/SkottieAnimator.cpp",
|
||||
"$_src/SkottieAnimator.h",
|
||||
"$_src/SkottieJson.cpp",
|
||||
"$_src/SkottieJson.h",
|
||||
"$_src/SkottieLayer.cpp",
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "SkTime.h"
|
||||
#include "SkTo.h"
|
||||
#include "SkottieAdapter.h"
|
||||
#include "SkottieAnimator.h"
|
||||
#include "SkottieJson.h"
|
||||
#include "SkottiePriv.h"
|
||||
#include "SkottieValue.h"
|
||||
@ -43,23 +42,24 @@ void LogJSON(const skjson::Value& json, const char msg[]) {
|
||||
LOG("%s: %s\n", msg, dump.c_str());
|
||||
}
|
||||
|
||||
sk_sp<sksg::Matrix> AttachMatrix(const skjson::ObjectValue& t, AnimatorScope* ascope,
|
||||
sk_sp<sksg::Matrix> parentMatrix) {
|
||||
sk_sp<sksg::Matrix> AnimationBuilder::attachMatrix(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 bound = BindProperty<VectorValue>(t["a"], ascope,
|
||||
auto bound = this->bindProperty<VectorValue>(t["a"], ascope,
|
||||
[adapter](const VectorValue& a) {
|
||||
adapter->setAnchorPoint(ValueTraits<VectorValue>::As<SkPoint>(a));
|
||||
}, g_default_vec_0);
|
||||
bound |= BindProperty<VectorValue>(t["p"], ascope,
|
||||
bound |= this->bindProperty<VectorValue>(t["p"], ascope,
|
||||
[adapter](const VectorValue& p) {
|
||||
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
|
||||
}, g_default_vec_0);
|
||||
bound |= BindProperty<VectorValue>(t["s"], ascope,
|
||||
bound |= this->bindProperty<VectorValue>(t["s"], ascope,
|
||||
[adapter](const VectorValue& s) {
|
||||
adapter->setScale(ValueTraits<VectorValue>::As<SkVector>(s));
|
||||
}, g_default_vec_100);
|
||||
@ -70,15 +70,15 @@ sk_sp<sksg::Matrix> AttachMatrix(const skjson::ObjectValue& t, AnimatorScope* as
|
||||
// we can still make use of rz.
|
||||
jrotation = &t["rz"];
|
||||
}
|
||||
bound |= BindProperty<ScalarValue>(*jrotation, ascope,
|
||||
bound |= this->bindProperty<ScalarValue>(*jrotation, ascope,
|
||||
[adapter](const ScalarValue& r) {
|
||||
adapter->setRotation(r);
|
||||
}, 0.0f);
|
||||
bound |= BindProperty<ScalarValue>(t["sk"], ascope,
|
||||
bound |= this->bindProperty<ScalarValue>(t["sk"], ascope,
|
||||
[adapter](const ScalarValue& sk) {
|
||||
adapter->setSkew(sk);
|
||||
}, 0.0f);
|
||||
bound |= BindProperty<ScalarValue>(t["sa"], ascope,
|
||||
bound |= this->bindProperty<ScalarValue>(t["sa"], ascope,
|
||||
[adapter](const ScalarValue& sa) {
|
||||
adapter->setSkewAxis(sa);
|
||||
}, 0.0f);
|
||||
@ -86,14 +86,15 @@ sk_sp<sksg::Matrix> AttachMatrix(const skjson::ObjectValue& t, AnimatorScope* as
|
||||
return bound ? matrix : parentMatrix;
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AttachOpacity(const skjson::ObjectValue& jtransform, AnimatorScope* ascope,
|
||||
sk_sp<sksg::RenderNode> childNode) {
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachOpacity(const skjson::ObjectValue& jtransform,
|
||||
AnimatorScope* ascope,
|
||||
sk_sp<sksg::RenderNode> childNode) const {
|
||||
if (!childNode)
|
||||
return nullptr;
|
||||
|
||||
auto opacityNode = sksg::OpacityEffect::Make(childNode);
|
||||
|
||||
if (!BindProperty<ScalarValue>(jtransform["o"], ascope,
|
||||
if (!this->bindProperty<ScalarValue>(jtransform["o"], ascope,
|
||||
[opacityNode](const ScalarValue& o) {
|
||||
// BM opacity is [0..100]
|
||||
opacityNode->setOpacity(o * 0.01f);
|
||||
@ -105,9 +106,10 @@ sk_sp<sksg::RenderNode> AttachOpacity(const skjson::ObjectValue& jtransform, Ani
|
||||
return std::move(opacityNode);
|
||||
}
|
||||
|
||||
sk_sp<sksg::Path> AttachPath(const skjson::Value& jpath, AnimatorScope* ascope) {
|
||||
sk_sp<sksg::Path> AnimationBuilder::attachPath(const skjson::Value& jpath,
|
||||
AnimatorScope* ascope) const {
|
||||
auto path_node = sksg::Path::Make();
|
||||
return BindProperty<ShapeValue>(jpath, ascope,
|
||||
return this->bindProperty<ShapeValue>(jpath, ascope,
|
||||
[path_node](const ShapeValue& p) {
|
||||
// FillType is tracked in the SG node, not in keyframes -- make sure we preserve it.
|
||||
auto path = ValueTraits<ShapeValue>::As<SkPath>(p);
|
||||
@ -118,10 +120,11 @@ sk_sp<sksg::Path> AttachPath(const skjson::Value& jpath, AnimatorScope* ascope)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
sk_sp<sksg::Color> AttachColor(const skjson::ObjectValue& jcolor, AnimatorScope* ascope,
|
||||
const char prop_name[]) {
|
||||
sk_sp<sksg::Color> AnimationBuilder::attachColor(const skjson::ObjectValue& jcolor,
|
||||
AnimatorScope* ascope,
|
||||
const char prop_name[]) const {
|
||||
auto color_node = sksg::Color::Make(SK_ColorBLACK);
|
||||
BindProperty<VectorValue>(jcolor[prop_name], ascope,
|
||||
this->bindProperty<VectorValue>(jcolor[prop_name], ascope,
|
||||
[color_node](const VectorValue& c) {
|
||||
color_node->setColor(ValueTraits<VectorValue>::As<SkColor>(c));
|
||||
});
|
||||
|
@ -5,11 +5,11 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkottieAnimator.h"
|
||||
|
||||
#include "SkCubicMap.h"
|
||||
#include "SkottieJson.h"
|
||||
#include "SkottiePriv.h"
|
||||
#include "SkottieValue.h"
|
||||
#include "SkSGScene.h"
|
||||
#include "SkString.h"
|
||||
#include "SkTArray.h"
|
||||
|
||||
@ -68,9 +68,9 @@ protected:
|
||||
: SkTPin(fCubicMaps[rec.cmidx].computeYFromX(lt), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
virtual int parseValue(const skjson::Value&) = 0;
|
||||
virtual int parseValue(const skjson::Value&, const AnimationBuilder* abuilder) = 0;
|
||||
|
||||
void parseKeyFrames(const skjson::ArrayValue& jframes) {
|
||||
void parseKeyFrames(const skjson::ArrayValue& jframes, const AnimationBuilder* abuilder) {
|
||||
for (const skjson::ObjectValue* jframe : jframes) {
|
||||
if (!jframe) continue;
|
||||
|
||||
@ -88,7 +88,7 @@ protected:
|
||||
fRecs.back().t1 = t0;
|
||||
}
|
||||
|
||||
const auto vidx0 = this->parseValue((*jframe)["s"]);
|
||||
const auto vidx0 = this->parseValue((*jframe)["s"], abuilder);
|
||||
if (vidx0 < 0)
|
||||
continue;
|
||||
|
||||
@ -97,7 +97,7 @@ protected:
|
||||
|
||||
if (!ParseDefault<bool>((*jframe)["h"], false)) {
|
||||
// Regular frame, requires an end value.
|
||||
vidx1 = this->parseValue((*jframe)["e"]);
|
||||
vidx1 = this->parseValue((*jframe)["e"], abuilder);
|
||||
if (vidx1 < 0)
|
||||
continue;
|
||||
|
||||
@ -176,10 +176,12 @@ template <typename T>
|
||||
class KeyframeAnimator final : public KeyframeAnimatorBase {
|
||||
public:
|
||||
static std::unique_ptr<KeyframeAnimator> Make(const skjson::ArrayValue* jv,
|
||||
const AnimationBuilder* abuilder,
|
||||
std::function<void(const T&)>&& apply) {
|
||||
if (!jv) return nullptr;
|
||||
|
||||
std::unique_ptr<KeyframeAnimator> animator(new KeyframeAnimator(*jv, std::move(apply)));
|
||||
std::unique_ptr<KeyframeAnimator> animator(
|
||||
new KeyframeAnimator(*jv, abuilder, std::move(apply)));
|
||||
if (!animator->count())
|
||||
return nullptr;
|
||||
|
||||
@ -193,14 +195,16 @@ protected:
|
||||
|
||||
private:
|
||||
KeyframeAnimator(const skjson::ArrayValue& jframes,
|
||||
const AnimationBuilder* abuilder,
|
||||
std::function<void(const T&)>&& apply)
|
||||
: fApplyFunc(std::move(apply)) {
|
||||
this->parseKeyFrames(jframes);
|
||||
this->parseKeyFrames(jframes, abuilder);
|
||||
}
|
||||
|
||||
int parseValue(const skjson::Value& jv) override {
|
||||
int parseValue(const skjson::Value& jv, const AnimationBuilder* abuilder) override {
|
||||
T val;
|
||||
if (!Parse<T>(jv, &val) || (!fVs.empty() && !ValueTraits<T>::CanLerp(val, fVs.back()))) {
|
||||
if (!ValueTraits<T>::FromJSON(jv, abuilder, &val) ||
|
||||
(!fVs.empty() && !ValueTraits<T>::CanLerp(val, fVs.back()))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -241,7 +245,8 @@ private:
|
||||
|
||||
template <typename T>
|
||||
static inline bool BindPropertyImpl(const skjson::ObjectValue* jprop,
|
||||
sksg::AnimatorList* animators,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope,
|
||||
std::function<void(const T&)>&& apply,
|
||||
const T* noop = nullptr) {
|
||||
if (!jprop) return false;
|
||||
@ -257,7 +262,7 @@ static inline bool BindPropertyImpl(const skjson::ObjectValue* jprop,
|
||||
// For those, we attempt to parse both ways.
|
||||
if (!ParseDefault<bool>(jpropA, false)) {
|
||||
T val;
|
||||
if (Parse<T>(jpropK, &val)) {
|
||||
if (ValueTraits<T>::FromJSON(jpropK, abuilder, &val)) {
|
||||
// Static property.
|
||||
if (noop && val == *noop)
|
||||
return false;
|
||||
@ -272,13 +277,13 @@ static inline bool BindPropertyImpl(const skjson::ObjectValue* jprop,
|
||||
}
|
||||
|
||||
// Keyframe property.
|
||||
auto animator = KeyframeAnimator<T>::Make(jpropK, std::move(apply));
|
||||
auto animator = KeyframeAnimator<T>::Make(jpropK, abuilder, std::move(apply));
|
||||
|
||||
if (!animator) {
|
||||
return LogFail(*jprop, "Could not parse keyframed property");
|
||||
}
|
||||
|
||||
animators->push_back(std::move(animator));
|
||||
ascope->push_back(std::move(animator));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -286,6 +291,7 @@ static inline bool BindPropertyImpl(const skjson::ObjectValue* jprop,
|
||||
class SplitPointAnimator final : public sksg::Animator {
|
||||
public:
|
||||
static std::unique_ptr<SplitPointAnimator> Make(const skjson::ObjectValue* jprop,
|
||||
const AnimationBuilder* abuilder,
|
||||
std::function<void(const VectorValue&)>&& apply,
|
||||
const VectorValue*) {
|
||||
if (!jprop) return nullptr;
|
||||
@ -297,9 +303,9 @@ public:
|
||||
// the object itself, so the scope is bound to the life time of the object.
|
||||
auto* split_animator_ptr = split_animator.get();
|
||||
|
||||
if (!BindPropertyImpl<ScalarValue>((*jprop)["x"], &split_animator->fAnimators,
|
||||
if (!BindPropertyImpl<ScalarValue>((*jprop)["x"], abuilder, &split_animator->fAnimators,
|
||||
[split_animator_ptr](const ScalarValue& x) { split_animator_ptr->setX(x); }) ||
|
||||
!BindPropertyImpl<ScalarValue>((*jprop)["y"], &split_animator->fAnimators,
|
||||
!BindPropertyImpl<ScalarValue>((*jprop)["y"], abuilder, &split_animator->fAnimators,
|
||||
[split_animator_ptr](const ScalarValue& y) { split_animator_ptr->setY(y); })) {
|
||||
LogFail(*jprop, "Could not parse split property");
|
||||
return nullptr;
|
||||
@ -340,11 +346,12 @@ private:
|
||||
};
|
||||
|
||||
bool BindSplitPositionProperty(const skjson::Value& jv,
|
||||
sksg::AnimatorList* animators,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope,
|
||||
std::function<void(const VectorValue&)>&& apply,
|
||||
const VectorValue* noop) {
|
||||
if (auto split_animator = SplitPointAnimator::Make(jv, std::move(apply), noop)) {
|
||||
animators->push_back(std::unique_ptr<sksg::Animator>(split_animator.release()));
|
||||
if (auto split_animator = SplitPointAnimator::Make(jv, abuilder, std::move(apply), noop)) {
|
||||
ascope->push_back(std::unique_ptr<sksg::Animator>(split_animator.release()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -354,32 +361,32 @@ bool BindSplitPositionProperty(const skjson::Value& jv,
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
bool BindProperty(const skjson::Value& jv,
|
||||
bool AnimationBuilder::bindProperty(const skjson::Value& jv,
|
||||
AnimatorScope* ascope,
|
||||
std::function<void(const ScalarValue&)>&& apply,
|
||||
const ScalarValue* noop) {
|
||||
return BindPropertyImpl(jv, ascope, std::move(apply), noop);
|
||||
const ScalarValue* noop) const {
|
||||
return BindPropertyImpl(jv, this, ascope, std::move(apply), noop);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool BindProperty(const skjson::Value& jv,
|
||||
bool AnimationBuilder::bindProperty(const skjson::Value& jv,
|
||||
AnimatorScope* ascope,
|
||||
std::function<void(const VectorValue&)>&& apply,
|
||||
const VectorValue* noop) {
|
||||
const VectorValue* noop) const {
|
||||
if (!jv.is<skjson::ObjectValue>())
|
||||
return false;
|
||||
|
||||
return ParseDefault<bool>(jv.as<skjson::ObjectValue>()["s"], false)
|
||||
? BindSplitPositionProperty(jv, ascope, std::move(apply), noop)
|
||||
: BindPropertyImpl(jv, ascope, std::move(apply), noop);
|
||||
? BindSplitPositionProperty(jv, this, ascope, std::move(apply), noop)
|
||||
: BindPropertyImpl(jv, this, ascope, std::move(apply), noop);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool BindProperty(const skjson::Value& jv,
|
||||
bool AnimationBuilder::bindProperty(const skjson::Value& jv,
|
||||
AnimatorScope* ascope,
|
||||
std::function<void(const ShapeValue&)>&& apply,
|
||||
const ShapeValue* noop) {
|
||||
return BindPropertyImpl(jv, ascope, std::move(apply), noop);
|
||||
const ShapeValue* noop) const {
|
||||
return BindPropertyImpl(jv, this, ascope, std::move(apply), noop);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkottieAnimator_DEFINED
|
||||
#define SkottieAnimator_DEFINED
|
||||
|
||||
#include "SkottiePriv.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace skjson { class Value; }
|
||||
|
||||
namespace skottie {
|
||||
namespace internal {
|
||||
|
||||
// This is the workhorse for property binding: depending on whether the property is animated,
|
||||
// it will either apply immediately or instantiate and attach a keyframe animator.
|
||||
template <typename T>
|
||||
bool BindProperty(const skjson::Value&,
|
||||
AnimatorScope*,
|
||||
std::function<void(const T&)>&&,
|
||||
const T* default_igore = nullptr);
|
||||
|
||||
template <typename T>
|
||||
bool BindProperty(const skjson::Value& jv,
|
||||
AnimatorScope* animators,
|
||||
std::function<void(const T&)>&& apply,
|
||||
const T& default_ignore) {
|
||||
return BindProperty(jv, animators, std::move(apply), &default_ignore);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace skottie
|
||||
|
||||
#endif // SkottieAnimator_DEFINED
|
@ -110,63 +110,4 @@ bool Parse<std::vector<float>>(const Value& v, std::vector<float>* vec) {
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool ParsePointVec(const Value& v, std::vector<SkPoint>* pts) {
|
||||
if (!v.is<ArrayValue>())
|
||||
return false;
|
||||
const auto& av = v.as<ArrayValue>();
|
||||
|
||||
pts->clear();
|
||||
pts->reserve(av.size());
|
||||
|
||||
std::vector<float> vec;
|
||||
for (size_t i = 0; i < av.size(); ++i) {
|
||||
if (!Parse(av[i], &vec) || vec.size() != 2)
|
||||
return false;
|
||||
pts->push_back(SkPoint::Make(vec[0], vec[1]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
bool Parse<ShapeValue>(const Value& v, ShapeValue* sh) {
|
||||
SkASSERT(sh->fVertices.empty());
|
||||
|
||||
// Some versions wrap values as single-element arrays.
|
||||
if (const skjson::ArrayValue* av = v) {
|
||||
if (av->size() == 1) {
|
||||
return Parse((*av)[0], sh);
|
||||
}
|
||||
}
|
||||
|
||||
if (!v.is<skjson::ObjectValue>())
|
||||
return false;
|
||||
const auto& ov = v.as<ObjectValue>();
|
||||
|
||||
std::vector<SkPoint> inPts, // Cubic Bezier "in" control points, relative to vertices.
|
||||
outPts, // Cubic Bezier "out" control points, relative to vertices.
|
||||
verts; // Cubic Bezier vertices.
|
||||
|
||||
if (!ParsePointVec(ov["i"], &inPts) ||
|
||||
!ParsePointVec(ov["o"], &outPts) ||
|
||||
!ParsePointVec(ov["v"], &verts) ||
|
||||
inPts.size() != outPts.size() ||
|
||||
inPts.size() != verts.size()) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
sh->fVertices.reserve(inPts.size());
|
||||
for (size_t i = 0; i < inPts.size(); ++i) {
|
||||
sh->fVertices.push_back(BezierVertex({inPts[i], outPts[i], verts[i]}));
|
||||
}
|
||||
sh->fClosed = ParseDefault<bool>(ov["c"], false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace skottie
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "SkImage.h"
|
||||
#include "SkJSON.h"
|
||||
#include "SkMakeUnique.h"
|
||||
#include "SkottieAnimator.h"
|
||||
#include "SkottieJson.h"
|
||||
#include "SkottieValue.h"
|
||||
#include "SkParse.h"
|
||||
@ -65,6 +64,7 @@ const MaskInfo* GetMaskInfo(char mode) {
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope,
|
||||
sk_sp<sksg::RenderNode> childNode) {
|
||||
if (!jmask) return childNode;
|
||||
@ -100,7 +100,7 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
|
||||
continue;
|
||||
}
|
||||
|
||||
auto mask_path = AttachPath((*m)["pt"], ascope);
|
||||
auto mask_path = abuilder->attachPath((*m)["pt"], ascope);
|
||||
if (!mask_path) {
|
||||
LogJSON(*m, "!! Could not parse mask path");
|
||||
continue;
|
||||
@ -118,7 +118,7 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
|
||||
mask_paint->setBlendMode(mask_stack.empty() ? SkBlendMode::kSrc
|
||||
: mask_info->fBlendMode);
|
||||
|
||||
has_opacity |= BindProperty<ScalarValue>((*m)["o"], ascope,
|
||||
has_opacity |= abuilder->bindProperty<ScalarValue>((*m)["o"], ascope,
|
||||
[mask_paint](const ScalarValue& o) {
|
||||
mask_paint->setOpacity(o * 0.01f);
|
||||
}, 100.0f);
|
||||
@ -164,7 +164,7 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
|
||||
} // namespace
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachNestedAnimation(const char* name,
|
||||
AnimatorScope* ascope) {
|
||||
AnimatorScope* ascope) const {
|
||||
class SkottieSGAdapter final : public sksg::RenderNode {
|
||||
public:
|
||||
explicit SkottieSGAdapter(sk_sp<Animation> animation)
|
||||
@ -230,7 +230,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachNestedAnimation(const char* name
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachAssetRef(
|
||||
const skjson::ObjectValue& jlayer, AnimatorScope* ascope,
|
||||
sk_sp<sksg::RenderNode>(AnimationBuilder::* attach_proc)(const skjson::ObjectValue& comp,
|
||||
AnimatorScope* ascope)) {
|
||||
AnimatorScope* ascope) const) const {
|
||||
|
||||
const auto refId = ParseDefault<SkString>(jlayer["refId"], SkString());
|
||||
if (refId.isEmpty()) {
|
||||
@ -261,7 +261,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachAssetRef(
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachSolidLayer(const skjson::ObjectValue& jlayer,
|
||||
AnimatorScope*) {
|
||||
AnimatorScope*) const {
|
||||
const auto size = SkSize::Make(ParseDefault<float>(jlayer["sw"], 0.0f),
|
||||
ParseDefault<float>(jlayer["sh"], 0.0f));
|
||||
const skjson::StringValue* hex_str = jlayer["sc"];
|
||||
@ -281,7 +281,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachSolidLayer(const skjson::ObjectV
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachImageAsset(const skjson::ObjectValue& jimage,
|
||||
AnimatorScope*) {
|
||||
AnimatorScope*) const {
|
||||
const skjson::StringValue* name = jimage["p"];
|
||||
const skjson::StringValue* path = jimage["u"];
|
||||
if (!name) {
|
||||
@ -306,12 +306,12 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachImageAsset(const skjson::ObjectV
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachImageLayer(const skjson::ObjectValue& jlayer,
|
||||
AnimatorScope* ascope) {
|
||||
AnimatorScope* ascope) const {
|
||||
return this->attachAssetRef(jlayer, ascope, &AnimationBuilder::attachImageAsset);
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachNullLayer(const skjson::ObjectValue& layer,
|
||||
AnimatorScope*) {
|
||||
AnimatorScope*) const {
|
||||
// Null layers are used solely to drive dependent transforms,
|
||||
// but we use free-floating sksg::Matrices for that purpose.
|
||||
return nullptr;
|
||||
@ -326,7 +326,8 @@ struct AnimationBuilder::AttachLayerContext {
|
||||
SkTHashMap<int, sk_sp<sksg::Matrix>> fLayerMatrixMap;
|
||||
sk_sp<sksg::RenderNode> fCurrentMatte;
|
||||
|
||||
sk_sp<sksg::Matrix> AttachLayerMatrix(const skjson::ObjectValue& jlayer) {
|
||||
sk_sp<sksg::Matrix> AttachLayerMatrix(const skjson::ObjectValue& jlayer,
|
||||
const AnimationBuilder* abuilder) {
|
||||
const auto layer_index = ParseDefault<int>(jlayer["ind"], -1);
|
||||
if (layer_index < 0)
|
||||
return nullptr;
|
||||
@ -334,11 +335,12 @@ struct AnimationBuilder::AttachLayerContext {
|
||||
if (auto* m = fLayerMatrixMap.find(layer_index))
|
||||
return *m;
|
||||
|
||||
return this->AttachLayerMatrixImpl(jlayer, layer_index);
|
||||
return this->AttachLayerMatrixImpl(jlayer, abuilder, layer_index);
|
||||
}
|
||||
|
||||
private:
|
||||
sk_sp<sksg::Matrix> AttachParentLayerMatrix(const skjson::ObjectValue& jlayer,
|
||||
const AnimationBuilder* abuilder,
|
||||
int layer_index) {
|
||||
const auto parent_index = ParseDefault<int>(jlayer["parent"], -1);
|
||||
if (parent_index < 0 || parent_index == layer_index)
|
||||
@ -351,24 +353,27 @@ private:
|
||||
if (!l) continue;
|
||||
|
||||
if (ParseDefault<int>((*l)["ind"], -1) == parent_index) {
|
||||
return this->AttachLayerMatrixImpl(*l, parent_index);
|
||||
return this->AttachLayerMatrixImpl(*l, abuilder, parent_index);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<sksg::Matrix> AttachLayerMatrixImpl(const skjson::ObjectValue& jlayer, int layer_index) {
|
||||
sk_sp<sksg::Matrix> AttachLayerMatrixImpl(const skjson::ObjectValue& jlayer,
|
||||
const AnimationBuilder* abuilder,
|
||||
int layer_index) {
|
||||
SkASSERT(!fLayerMatrixMap.find(layer_index));
|
||||
|
||||
// Add a stub entry to break recursion cycles.
|
||||
fLayerMatrixMap.set(layer_index, nullptr);
|
||||
|
||||
auto parent_matrix = this->AttachParentLayerMatrix(jlayer, layer_index);
|
||||
auto parent_matrix = this->AttachParentLayerMatrix(jlayer, abuilder, layer_index);
|
||||
|
||||
if (const skjson::ObjectValue* jtransform = jlayer["ks"]) {
|
||||
return *fLayerMatrixMap.set(layer_index, AttachMatrix(*jtransform, fScope,
|
||||
std::move(parent_matrix)));
|
||||
return *fLayerMatrixMap.set(layer_index,
|
||||
abuilder->attachMatrix(*jtransform, fScope,
|
||||
std::move(parent_matrix)));
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
@ -376,11 +381,11 @@ private:
|
||||
};
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachLayer(const skjson::ObjectValue* jlayer,
|
||||
AttachLayerContext* layerCtx) {
|
||||
AttachLayerContext* layerCtx) const {
|
||||
if (!jlayer) return nullptr;
|
||||
|
||||
using LayerAttacher = sk_sp<sksg::RenderNode> (AnimationBuilder::*)(const skjson::ObjectValue&,
|
||||
AnimatorScope*);
|
||||
AnimatorScope*) const;
|
||||
static constexpr LayerAttacher gLayerAttachers[] = {
|
||||
&AnimationBuilder::attachPrecompLayer, // 'ty': 0
|
||||
&AnimationBuilder::attachSolidLayer, // 'ty': 1
|
||||
@ -409,17 +414,17 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachLayer(const skjson::ObjectValue*
|
||||
}
|
||||
|
||||
// Optional layer mask.
|
||||
layer = AttachMask((*jlayer)["masksProperties"], &layer_animators, std::move(layer));
|
||||
layer = AttachMask((*jlayer)["masksProperties"], this, &layer_animators, std::move(layer));
|
||||
|
||||
// Optional layer transform.
|
||||
if (auto layerMatrix = layerCtx->AttachLayerMatrix(*jlayer)) {
|
||||
if (auto layerMatrix = layerCtx->AttachLayerMatrix(*jlayer, this)) {
|
||||
layer = sksg::Transform::Make(std::move(layer), std::move(layerMatrix));
|
||||
}
|
||||
|
||||
// Optional layer opacity.
|
||||
// TODO: de-dupe this "ks" lookup with matrix above.
|
||||
if (const skjson::ObjectValue* jtransform = (*jlayer)["ks"]) {
|
||||
layer = AttachOpacity(*jtransform, &layer_animators, std::move(layer));
|
||||
layer = this->attachOpacity(*jtransform, &layer_animators, std::move(layer));
|
||||
}
|
||||
|
||||
// Optional layer effects.
|
||||
@ -492,7 +497,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachLayer(const skjson::ObjectValue*
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachComposition(const skjson::ObjectValue& comp,
|
||||
AnimatorScope* scope) {
|
||||
AnimatorScope* scope) const {
|
||||
const skjson::ArrayValue* jlayers = comp["layers"];
|
||||
if (!jlayers) return nullptr;
|
||||
|
||||
|
@ -18,6 +18,7 @@ namespace internal {
|
||||
namespace {
|
||||
|
||||
sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_props,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope,
|
||||
sk_sp<sksg::RenderNode> layer) {
|
||||
if (!jeffect_props) return layer;
|
||||
@ -29,7 +30,7 @@ sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_
|
||||
|
||||
switch (const auto ty = ParseDefault<int>((*jprop)["ty"], -1)) {
|
||||
case 2: // color
|
||||
color_node = AttachColor(*jprop, ascope, "v");
|
||||
color_node = abuilder->attachColor(*jprop, ascope, "v");
|
||||
break;
|
||||
default:
|
||||
LOG("?? Ignoring unsupported fill effect poperty type: %d\n", ty);
|
||||
@ -46,13 +47,13 @@ sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachLayerEffects(const skjson::ArrayValue& jeffects,
|
||||
AnimatorScope* ascope,
|
||||
sk_sp<sksg::RenderNode> layer) {
|
||||
sk_sp<sksg::RenderNode> layer) const {
|
||||
for (const skjson::ObjectValue* jeffect : jeffects) {
|
||||
if (!jeffect) continue;
|
||||
|
||||
switch (const auto ty = ParseDefault<int>((*jeffect)["ty"], -1)) {
|
||||
case 21: // Fill
|
||||
layer = AttachFillLayerEffect((*jeffect)["ef"], ascope, std::move(layer));
|
||||
layer = AttachFillLayerEffect((*jeffect)["ef"], this, ascope, std::move(layer));
|
||||
break;
|
||||
default:
|
||||
LOG("?? Unsupported layer effect type: %d\n", ty);
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "SkottiePriv.h"
|
||||
|
||||
#include "SkJSON.h"
|
||||
#include "SkottieAnimator.h"
|
||||
#include "SkottieJson.h"
|
||||
#include "SkottieValue.h"
|
||||
#include "SkMakeUnique.h"
|
||||
@ -20,7 +19,7 @@ namespace skottie {
|
||||
namespace internal {
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachPrecompLayer(const skjson::ObjectValue& jlayer,
|
||||
AnimatorScope* ascope) {
|
||||
AnimatorScope* ascope) const {
|
||||
const skjson::ObjectValue* time_remap = jlayer["tm"];
|
||||
const auto start_time = ParseDefault<float>(jlayer["st"], 0.0f),
|
||||
stretch_time = ParseDefault<float>(jlayer["sr"], 1.0f);
|
||||
@ -70,7 +69,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachPrecompLayer(const skjson::Objec
|
||||
// because both the lambda and the mapper are scoped/owned by ctx->fAnimators.
|
||||
auto* raw_mapper = time_mapper.get();
|
||||
auto frame_rate = fFrameRate;
|
||||
BindProperty<ScalarValue>(*time_remap, ascope,
|
||||
this->bindProperty<ScalarValue>(*time_remap, ascope,
|
||||
[raw_mapper, frame_rate](const ScalarValue& t) {
|
||||
raw_mapper->remapTime(t * frame_rate);
|
||||
});
|
||||
|
@ -49,6 +49,30 @@ public:
|
||||
|
||||
std::unique_ptr<sksg::Scene> parse(const skjson::ObjectValue&);
|
||||
|
||||
// This is the workhorse for property binding: depending on whether the property is animated,
|
||||
// it will either apply immediately or instantiate and attach a keyframe animator.
|
||||
template <typename T>
|
||||
bool bindProperty(const skjson::Value&,
|
||||
AnimatorScope*,
|
||||
std::function<void(const T&)>&&,
|
||||
const T* default_igore = nullptr) const;
|
||||
|
||||
template <typename T>
|
||||
bool bindProperty(const skjson::Value& jv,
|
||||
AnimatorScope* ascope,
|
||||
std::function<void(const T&)>&& apply,
|
||||
const T& default_ignore) const {
|
||||
return this->bindProperty(jv, ascope, std::move(apply), &default_ignore);
|
||||
}
|
||||
|
||||
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::RenderNode> attachOpacity(const skjson::ObjectValue&, AnimatorScope*,
|
||||
sk_sp<sksg::RenderNode>) const;
|
||||
sk_sp<sksg::Path> attachPath(const skjson::Value&, AnimatorScope*) const;
|
||||
|
||||
private:
|
||||
struct AttachLayerContext;
|
||||
|
||||
@ -56,24 +80,24 @@ private:
|
||||
void parseFonts (const skjson::ObjectValue* jfonts,
|
||||
const skjson::ArrayValue* jchars);
|
||||
|
||||
sk_sp<sksg::RenderNode> attachComposition(const skjson::ObjectValue&, AnimatorScope*);
|
||||
sk_sp<sksg::RenderNode> attachLayer(const skjson::ObjectValue*, AttachLayerContext*);
|
||||
sk_sp<sksg::RenderNode> attachComposition(const skjson::ObjectValue&, AnimatorScope*) const;
|
||||
sk_sp<sksg::RenderNode> attachLayer(const skjson::ObjectValue*, AttachLayerContext*) const;
|
||||
sk_sp<sksg::RenderNode> attachLayerEffects(const skjson::ArrayValue& jeffects, AnimatorScope*,
|
||||
sk_sp<sksg::RenderNode>);
|
||||
sk_sp<sksg::RenderNode>) const;
|
||||
|
||||
sk_sp<sksg::RenderNode> attachAssetRef(const skjson::ObjectValue&, AnimatorScope*,
|
||||
sk_sp<sksg::RenderNode>(AnimationBuilder::*)(const skjson::ObjectValue&,
|
||||
AnimatorScope* ctx));
|
||||
sk_sp<sksg::RenderNode> attachImageAsset(const skjson::ObjectValue&, AnimatorScope*);
|
||||
AnimatorScope* ctx) const) const;
|
||||
sk_sp<sksg::RenderNode> attachImageAsset(const skjson::ObjectValue&, AnimatorScope*) const;
|
||||
|
||||
sk_sp<sksg::RenderNode> attachNestedAnimation(const char* name, AnimatorScope* ascope);
|
||||
sk_sp<sksg::RenderNode> attachNestedAnimation(const char* name, AnimatorScope* ascope) const;
|
||||
|
||||
sk_sp<sksg::RenderNode> attachImageLayer (const skjson::ObjectValue&, AnimatorScope*);
|
||||
sk_sp<sksg::RenderNode> attachNullLayer (const skjson::ObjectValue&, AnimatorScope*);
|
||||
sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, AnimatorScope*);
|
||||
sk_sp<sksg::RenderNode> attachShapeLayer (const skjson::ObjectValue&, AnimatorScope*);
|
||||
sk_sp<sksg::RenderNode> attachSolidLayer (const skjson::ObjectValue&, AnimatorScope*);
|
||||
sk_sp<sksg::RenderNode> attachTextLayer (const skjson::ObjectValue&, AnimatorScope*);
|
||||
sk_sp<sksg::RenderNode> attachImageLayer (const skjson::ObjectValue&, AnimatorScope*) const;
|
||||
sk_sp<sksg::RenderNode> attachNullLayer (const skjson::ObjectValue&, AnimatorScope*) const;
|
||||
sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, AnimatorScope*) const;
|
||||
sk_sp<sksg::RenderNode> attachShapeLayer (const skjson::ObjectValue&, AnimatorScope*) const;
|
||||
sk_sp<sksg::RenderNode> attachSolidLayer (const skjson::ObjectValue&, AnimatorScope*) const;
|
||||
sk_sp<sksg::RenderNode> attachTextLayer (const skjson::ObjectValue&, AnimatorScope*) const;
|
||||
|
||||
sk_sp<ResourceProvider> fResourceProvider;
|
||||
sk_sp<SkFontMgr> fFontMgr;
|
||||
@ -100,20 +124,13 @@ private:
|
||||
using AssetCache = SkTHashMap<SkString, sk_sp<sksg::RenderNode>>;
|
||||
using FontMap = SkTHashMap<SkString, FontInfo>;
|
||||
|
||||
AssetMap fAssets;
|
||||
AssetCache fAssetCache;
|
||||
FontMap fFonts;
|
||||
AssetMap fAssets;
|
||||
FontMap fFonts;
|
||||
mutable AssetCache fAssetCache;
|
||||
|
||||
using INHERITED = SkNoncopyable;
|
||||
};
|
||||
|
||||
// Shared helpers
|
||||
sk_sp<sksg::Color> AttachColor(const skjson::ObjectValue&, AnimatorScope*, const char prop_name[]);
|
||||
sk_sp<sksg::Path> AttachPath(const skjson::Value&, AnimatorScope*);
|
||||
sk_sp<sksg::Matrix> AttachMatrix(const skjson::ObjectValue&, AnimatorScope*, sk_sp<sksg::Matrix>);
|
||||
sk_sp<sksg::RenderNode> AttachOpacity(const skjson::ObjectValue&, AnimatorScope*,
|
||||
sk_sp<sksg::RenderNode>);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace skottie
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "SkJSON.h"
|
||||
#include "SkottieAdapter.h"
|
||||
#include "SkottieAnimator.h"
|
||||
#include "SkottieJson.h"
|
||||
#include "SkottieValue.h"
|
||||
#include "SkPath.h"
|
||||
@ -31,24 +30,26 @@ namespace internal {
|
||||
namespace {
|
||||
|
||||
sk_sp<sksg::GeometryNode> AttachPathGeometry(const skjson::ObjectValue& jpath,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope) {
|
||||
return AttachPath(jpath["ks"], ascope);
|
||||
return abuilder->attachPath(jpath["ks"], ascope);
|
||||
}
|
||||
|
||||
sk_sp<sksg::GeometryNode> AttachRRectGeometry(const skjson::ObjectValue& jrect,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope) {
|
||||
auto rect_node = sksg::RRect::Make();
|
||||
auto adapter = sk_make_sp<RRectAdapter>(rect_node);
|
||||
|
||||
auto p_attached = BindProperty<VectorValue>(jrect["p"], ascope,
|
||||
auto p_attached = abuilder->bindProperty<VectorValue>(jrect["p"], ascope,
|
||||
[adapter](const VectorValue& p) {
|
||||
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
|
||||
});
|
||||
auto s_attached = BindProperty<VectorValue>(jrect["s"], ascope,
|
||||
auto s_attached = abuilder->bindProperty<VectorValue>(jrect["s"], ascope,
|
||||
[adapter](const VectorValue& s) {
|
||||
adapter->setSize(ValueTraits<VectorValue>::As<SkSize>(s));
|
||||
});
|
||||
auto r_attached = BindProperty<ScalarValue>(jrect["r"], ascope,
|
||||
auto r_attached = abuilder->bindProperty<ScalarValue>(jrect["r"], ascope,
|
||||
[adapter](const ScalarValue& r) {
|
||||
adapter->setRadius(SkSize::Make(r, r));
|
||||
});
|
||||
@ -61,15 +62,16 @@ sk_sp<sksg::GeometryNode> AttachRRectGeometry(const skjson::ObjectValue& jrect,
|
||||
}
|
||||
|
||||
sk_sp<sksg::GeometryNode> AttachEllipseGeometry(const skjson::ObjectValue& jellipse,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope) {
|
||||
auto rect_node = sksg::RRect::Make();
|
||||
auto adapter = sk_make_sp<RRectAdapter>(rect_node);
|
||||
|
||||
auto p_attached = BindProperty<VectorValue>(jellipse["p"], ascope,
|
||||
auto p_attached = abuilder->bindProperty<VectorValue>(jellipse["p"], ascope,
|
||||
[adapter](const VectorValue& p) {
|
||||
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
|
||||
});
|
||||
auto s_attached = BindProperty<VectorValue>(jellipse["s"], ascope,
|
||||
auto s_attached = abuilder->bindProperty<VectorValue>(jellipse["s"], ascope,
|
||||
[adapter](const VectorValue& s) {
|
||||
const auto sz = ValueTraits<VectorValue>::As<SkSize>(s);
|
||||
adapter->setSize(sz);
|
||||
@ -84,6 +86,7 @@ sk_sp<sksg::GeometryNode> AttachEllipseGeometry(const skjson::ObjectValue& jelli
|
||||
}
|
||||
|
||||
sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const skjson::ObjectValue& jstar,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope) {
|
||||
static constexpr PolyStarAdapter::Type gTypes[] = {
|
||||
PolyStarAdapter::Type::kStar, // "sy": 1
|
||||
@ -99,31 +102,31 @@ sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const skjson::ObjectValue& jsta
|
||||
auto path_node = sksg::Path::Make();
|
||||
auto adapter = sk_make_sp<PolyStarAdapter>(path_node, gTypes[type]);
|
||||
|
||||
BindProperty<VectorValue>(jstar["p"], ascope,
|
||||
abuilder->bindProperty<VectorValue>(jstar["p"], ascope,
|
||||
[adapter](const VectorValue& p) {
|
||||
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
|
||||
});
|
||||
BindProperty<ScalarValue>(jstar["pt"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jstar["pt"], ascope,
|
||||
[adapter](const ScalarValue& pt) {
|
||||
adapter->setPointCount(pt);
|
||||
});
|
||||
BindProperty<ScalarValue>(jstar["ir"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jstar["ir"], ascope,
|
||||
[adapter](const ScalarValue& ir) {
|
||||
adapter->setInnerRadius(ir);
|
||||
});
|
||||
BindProperty<ScalarValue>(jstar["or"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jstar["or"], ascope,
|
||||
[adapter](const ScalarValue& otr) {
|
||||
adapter->setOuterRadius(otr);
|
||||
});
|
||||
BindProperty<ScalarValue>(jstar["is"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jstar["is"], ascope,
|
||||
[adapter](const ScalarValue& is) {
|
||||
adapter->setInnerRoundness(is);
|
||||
});
|
||||
BindProperty<ScalarValue>(jstar["os"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jstar["os"], ascope,
|
||||
[adapter](const ScalarValue& os) {
|
||||
adapter->setOuterRoundness(os);
|
||||
});
|
||||
BindProperty<ScalarValue>(jstar["r"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jstar["r"], ascope,
|
||||
[adapter](const ScalarValue& r) {
|
||||
adapter->setRotation(r);
|
||||
});
|
||||
@ -131,7 +134,8 @@ sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const skjson::ObjectValue& jsta
|
||||
return std::move(path_node);
|
||||
}
|
||||
|
||||
sk_sp<sksg::Gradient> AttachGradient(const skjson::ObjectValue& jgrad, AnimatorScope* ascope) {
|
||||
sk_sp<sksg::Gradient> AttachGradient(const skjson::ObjectValue& jgrad,
|
||||
const AnimationBuilder* abuilder, AnimatorScope* ascope) {
|
||||
const skjson::ObjectValue* stops = jgrad["g"];
|
||||
if (!stops)
|
||||
return nullptr;
|
||||
@ -155,15 +159,15 @@ sk_sp<sksg::Gradient> AttachGradient(const skjson::ObjectValue& jgrad, AnimatorS
|
||||
gradient_node = std::move(radial_node);
|
||||
}
|
||||
|
||||
BindProperty<VectorValue>((*stops)["k"], ascope,
|
||||
abuilder->bindProperty<VectorValue>((*stops)["k"], ascope,
|
||||
[adapter](const VectorValue& stops) {
|
||||
adapter->setColorStops(stops);
|
||||
});
|
||||
BindProperty<VectorValue>(jgrad["s"], ascope,
|
||||
abuilder->bindProperty<VectorValue>(jgrad["s"], ascope,
|
||||
[adapter](const VectorValue& s) {
|
||||
adapter->setStartPoint(ValueTraits<VectorValue>::As<SkPoint>(s));
|
||||
});
|
||||
BindProperty<VectorValue>(jgrad["e"], ascope,
|
||||
abuilder->bindProperty<VectorValue>(jgrad["e"], ascope,
|
||||
[adapter](const VectorValue& e) {
|
||||
adapter->setEndPoint(ValueTraits<VectorValue>::As<SkPoint>(e));
|
||||
});
|
||||
@ -171,12 +175,13 @@ sk_sp<sksg::Gradient> AttachGradient(const skjson::ObjectValue& jgrad, AnimatorS
|
||||
return gradient_node;
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachPaint(const skjson::ObjectValue& jpaint, AnimatorScope* ascope,
|
||||
sk_sp<sksg::PaintNode> AttachPaint(const skjson::ObjectValue& jpaint,
|
||||
const AnimationBuilder* abuilder, AnimatorScope* ascope,
|
||||
sk_sp<sksg::PaintNode> paint_node) {
|
||||
if (paint_node) {
|
||||
paint_node->setAntiAlias(true);
|
||||
|
||||
BindProperty<ScalarValue>(jpaint["o"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jpaint["o"], ascope,
|
||||
[paint_node](const ScalarValue& o) {
|
||||
// BM opacity is [0..100]
|
||||
paint_node->setOpacity(o * 0.01f);
|
||||
@ -186,14 +191,15 @@ sk_sp<sksg::PaintNode> AttachPaint(const skjson::ObjectValue& jpaint, AnimatorSc
|
||||
return paint_node;
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachStroke(const skjson::ObjectValue& jstroke, AnimatorScope* ascope,
|
||||
sk_sp<sksg::PaintNode> AttachStroke(const skjson::ObjectValue& jstroke,
|
||||
const AnimationBuilder* abuilder, AnimatorScope* ascope,
|
||||
sk_sp<sksg::PaintNode> stroke_node) {
|
||||
if (!stroke_node)
|
||||
return nullptr;
|
||||
|
||||
stroke_node->setStyle(SkPaint::kStroke_Style);
|
||||
|
||||
BindProperty<ScalarValue>(jstroke["w"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jstroke["w"], ascope,
|
||||
[stroke_node](const ScalarValue& w) {
|
||||
stroke_node->setStrokeWidth(w);
|
||||
});
|
||||
@ -219,24 +225,30 @@ sk_sp<sksg::PaintNode> AttachStroke(const skjson::ObjectValue& jstroke, Animator
|
||||
return stroke_node;
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachColorFill(const skjson::ObjectValue& jfill, AnimatorScope* ascope) {
|
||||
return AttachPaint(jfill, ascope, AttachColor(jfill, ascope, "c"));
|
||||
sk_sp<sksg::PaintNode> AttachColorFill(const skjson::ObjectValue& jfill,
|
||||
const AnimationBuilder* abuilder, AnimatorScope* ascope) {
|
||||
return AttachPaint(jfill, abuilder, ascope, abuilder->attachColor(jfill, ascope, "c"));
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachGradientFill(const skjson::ObjectValue& jfill, AnimatorScope* ascope) {
|
||||
return AttachPaint(jfill, ascope, AttachGradient(jfill, ascope));
|
||||
sk_sp<sksg::PaintNode> AttachGradientFill(const skjson::ObjectValue& jfill,
|
||||
const AnimationBuilder* abuilder, AnimatorScope* ascope) {
|
||||
return AttachPaint(jfill, abuilder, ascope, AttachGradient(jfill, abuilder, ascope));
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachColorStroke(const skjson::ObjectValue& jstroke,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope) {
|
||||
return AttachStroke(jstroke, ascope, AttachPaint(jstroke, ascope,
|
||||
AttachColor(jstroke, ascope, "c")));
|
||||
return AttachStroke(jstroke, abuilder, ascope,
|
||||
AttachPaint(jstroke, abuilder, ascope,
|
||||
abuilder->attachColor(jstroke, ascope, "c")));
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachGradientStroke(const skjson::ObjectValue& jstroke,
|
||||
const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope) {
|
||||
return AttachStroke(jstroke, ascope, AttachPaint(jstroke, ascope,
|
||||
AttachGradient(jstroke, ascope)));
|
||||
return AttachStroke(jstroke, abuilder, ascope,
|
||||
AttachPaint(jstroke, abuilder, ascope,
|
||||
AttachGradient(jstroke, abuilder, ascope)));
|
||||
}
|
||||
|
||||
sk_sp<sksg::Merge> Merge(std::vector<sk_sp<sksg::GeometryNode>>&& geos, sksg::Merge::Mode mode) {
|
||||
@ -252,7 +264,7 @@ sk_sp<sksg::Merge> Merge(std::vector<sk_sp<sksg::GeometryNode>>&& geos, sksg::Me
|
||||
}
|
||||
|
||||
std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
|
||||
const skjson::ObjectValue& jmerge, AnimatorScope*,
|
||||
const skjson::ObjectValue& jmerge, const AnimationBuilder*, AnimatorScope*,
|
||||
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
|
||||
static constexpr sksg::Merge::Mode gModes[] = {
|
||||
sksg::Merge::Mode::kMerge, // "mm": 1
|
||||
@ -272,7 +284,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
|
||||
}
|
||||
|
||||
std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
|
||||
const skjson::ObjectValue& jtrim, AnimatorScope* ascope,
|
||||
const skjson::ObjectValue& jtrim, const AnimationBuilder* abuilder, AnimatorScope* ascope,
|
||||
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
|
||||
|
||||
enum class Mode {
|
||||
@ -297,15 +309,15 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
|
||||
trimmed.push_back(trimEffect);
|
||||
|
||||
const auto adapter = sk_make_sp<TrimEffectAdapter>(std::move(trimEffect));
|
||||
BindProperty<ScalarValue>(jtrim["s"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jtrim["s"], ascope,
|
||||
[adapter](const ScalarValue& s) {
|
||||
adapter->setStart(s);
|
||||
});
|
||||
BindProperty<ScalarValue>(jtrim["e"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jtrim["e"], ascope,
|
||||
[adapter](const ScalarValue& e) {
|
||||
adapter->setEnd(e);
|
||||
});
|
||||
BindProperty<ScalarValue>(jtrim["o"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jtrim["o"], ascope,
|
||||
[adapter](const ScalarValue& o) {
|
||||
adapter->setOffset(o);
|
||||
});
|
||||
@ -315,7 +327,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
|
||||
}
|
||||
|
||||
std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
|
||||
const skjson::ObjectValue& jtrim, AnimatorScope* ascope,
|
||||
const skjson::ObjectValue& jtrim, const AnimationBuilder* abuilder, AnimatorScope* ascope,
|
||||
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
|
||||
|
||||
std::vector<sk_sp<sksg::GeometryNode>> rounded;
|
||||
@ -325,7 +337,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
|
||||
const auto roundEffect = sksg::RoundEffect::Make(std::move(g));
|
||||
rounded.push_back(roundEffect);
|
||||
|
||||
BindProperty<ScalarValue>(jtrim["r"], ascope,
|
||||
abuilder->bindProperty<ScalarValue>(jtrim["r"], ascope,
|
||||
[roundEffect](const ScalarValue& r) {
|
||||
roundEffect->setRadius(r);
|
||||
});
|
||||
@ -334,7 +346,8 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
|
||||
return rounded;
|
||||
}
|
||||
|
||||
using GeometryAttacherT = sk_sp<sksg::GeometryNode> (*)(const skjson::ObjectValue&, AnimatorScope*);
|
||||
using GeometryAttacherT = sk_sp<sksg::GeometryNode> (*)(const skjson::ObjectValue&,
|
||||
const AnimationBuilder*, AnimatorScope*);
|
||||
static constexpr GeometryAttacherT gGeometryAttachers[] = {
|
||||
AttachPathGeometry,
|
||||
AttachRRectGeometry,
|
||||
@ -342,7 +355,8 @@ static constexpr GeometryAttacherT gGeometryAttachers[] = {
|
||||
AttachPolystarGeometry,
|
||||
};
|
||||
|
||||
using PaintAttacherT = sk_sp<sksg::PaintNode> (*)(const skjson::ObjectValue&, AnimatorScope*);
|
||||
using PaintAttacherT = sk_sp<sksg::PaintNode> (*)(const skjson::ObjectValue&,
|
||||
const AnimationBuilder*, AnimatorScope*);
|
||||
static constexpr PaintAttacherT gPaintAttachers[] = {
|
||||
AttachColorFill,
|
||||
AttachColorStroke,
|
||||
@ -352,7 +366,7 @@ static constexpr PaintAttacherT gPaintAttachers[] = {
|
||||
|
||||
using GeometryEffectAttacherT =
|
||||
std::vector<sk_sp<sksg::GeometryNode>> (*)(const skjson::ObjectValue&,
|
||||
AnimatorScope*,
|
||||
const AnimationBuilder*, AnimatorScope*,
|
||||
std::vector<sk_sp<sksg::GeometryNode>>&&);
|
||||
static constexpr GeometryEffectAttacherT gGeometryEffectAttachers[] = {
|
||||
AttachMergeGeometryEffect,
|
||||
@ -414,27 +428,29 @@ struct GeometryEffectRec {
|
||||
};
|
||||
|
||||
struct AttachShapeContext {
|
||||
AttachShapeContext(AnimatorScope* ascope,
|
||||
AttachShapeContext(const AnimationBuilder* abuilder,
|
||||
AnimatorScope* ascope,
|
||||
std::vector<sk_sp<sksg::GeometryNode>>* geos,
|
||||
std::vector<GeometryEffectRec>* effects,
|
||||
size_t committedAnimators)
|
||||
: fScope(ascope)
|
||||
: fBuilder(abuilder)
|
||||
, fScope(ascope)
|
||||
, fGeometryStack(geos)
|
||||
, fGeometryEffectStack(effects)
|
||||
, fCommittedAnimators(committedAnimators) {}
|
||||
|
||||
const AnimationBuilder* fBuilder;
|
||||
AnimatorScope* fScope;
|
||||
std::vector<sk_sp<sksg::GeometryNode>>* fGeometryStack;
|
||||
std::vector<GeometryEffectRec>* fGeometryEffectStack;
|
||||
size_t fCommittedAnimators;
|
||||
};
|
||||
|
||||
sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
|
||||
AttachShapeContext* shapeCtx) {
|
||||
sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape, AttachShapeContext* ctx) {
|
||||
if (!jshape)
|
||||
return nullptr;
|
||||
|
||||
SkDEBUGCODE(const auto initialGeometryEffects = shapeCtx->fGeometryEffectStack->size();)
|
||||
SkDEBUGCODE(const auto initialGeometryEffects = ctx->fGeometryEffectStack->size();)
|
||||
|
||||
sk_sp<sksg::Group> shape_group = sksg::Group::Make();
|
||||
sk_sp<sksg::RenderNode> shape_wrapper = shape_group;
|
||||
@ -466,14 +482,15 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
|
||||
|
||||
switch (info->fShapeType) {
|
||||
case ShapeType::kTransform:
|
||||
if ((shape_matrix = AttachMatrix(*shape, shapeCtx->fScope, nullptr))) {
|
||||
if ((shape_matrix = ctx->fBuilder->attachMatrix(*shape, ctx->fScope, nullptr))) {
|
||||
shape_wrapper = sksg::Transform::Make(std::move(shape_wrapper), shape_matrix);
|
||||
}
|
||||
shape_wrapper = AttachOpacity(*shape, shapeCtx->fScope, std::move(shape_wrapper));
|
||||
shape_wrapper = ctx->fBuilder->attachOpacity(*shape, ctx->fScope,
|
||||
std::move(shape_wrapper));
|
||||
break;
|
||||
case ShapeType::kGeometryEffect:
|
||||
SkASSERT(info->fAttacherIndex < SK_ARRAY_COUNT(gGeometryEffectAttachers));
|
||||
shapeCtx->fGeometryEffectStack->push_back(
|
||||
ctx->fGeometryEffectStack->push_back(
|
||||
{ *shape, gGeometryEffectAttachers[info->fAttacherIndex] });
|
||||
break;
|
||||
default:
|
||||
@ -493,7 +510,8 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
|
||||
case ShapeType::kGeometry: {
|
||||
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gGeometryAttachers));
|
||||
if (auto geo = gGeometryAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
|
||||
shapeCtx->fScope)) {
|
||||
ctx->fBuilder,
|
||||
ctx->fScope)) {
|
||||
geos.push_back(std::move(geo));
|
||||
}
|
||||
} break;
|
||||
@ -502,38 +520,42 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
|
||||
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gGeometryEffectAttachers));
|
||||
if (!geos.empty()) {
|
||||
geos = gGeometryEffectAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
|
||||
shapeCtx->fScope,
|
||||
ctx->fBuilder,
|
||||
ctx->fScope,
|
||||
std::move(geos));
|
||||
}
|
||||
|
||||
SkASSERT(&shapeCtx->fGeometryEffectStack->back().fJson == &rec->fJson);
|
||||
SkASSERT(shapeCtx->fGeometryEffectStack->back().fAttach ==
|
||||
SkASSERT(&ctx->fGeometryEffectStack->back().fJson == &rec->fJson);
|
||||
SkASSERT(ctx->fGeometryEffectStack->back().fAttach ==
|
||||
gGeometryEffectAttachers[rec->fInfo.fAttacherIndex]);
|
||||
shapeCtx->fGeometryEffectStack->pop_back();
|
||||
ctx->fGeometryEffectStack->pop_back();
|
||||
} break;
|
||||
case ShapeType::kGroup: {
|
||||
AttachShapeContext groupShapeCtx(shapeCtx->fScope,
|
||||
AttachShapeContext groupShapeCtx(ctx->fBuilder,
|
||||
ctx->fScope,
|
||||
&geos,
|
||||
shapeCtx->fGeometryEffectStack,
|
||||
shapeCtx->fCommittedAnimators);
|
||||
ctx->fGeometryEffectStack,
|
||||
ctx->fCommittedAnimators);
|
||||
if (auto subgroup = AttachShape(rec->fJson["it"], &groupShapeCtx)) {
|
||||
draws.push_back(std::move(subgroup));
|
||||
SkASSERT(groupShapeCtx.fCommittedAnimators >= shapeCtx->fCommittedAnimators);
|
||||
shapeCtx->fCommittedAnimators = groupShapeCtx.fCommittedAnimators;
|
||||
SkASSERT(groupShapeCtx.fCommittedAnimators >= ctx->fCommittedAnimators);
|
||||
ctx->fCommittedAnimators = groupShapeCtx.fCommittedAnimators;
|
||||
}
|
||||
} break;
|
||||
case ShapeType::kPaint: {
|
||||
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gPaintAttachers));
|
||||
auto paint = gPaintAttachers[rec->fInfo.fAttacherIndex](rec->fJson, shapeCtx->fScope);
|
||||
auto paint = gPaintAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
|
||||
ctx->fBuilder,
|
||||
ctx->fScope);
|
||||
if (!paint || geos.empty())
|
||||
break;
|
||||
|
||||
auto drawGeos = geos;
|
||||
|
||||
// Apply all pending effects from the stack.
|
||||
for (auto it = shapeCtx->fGeometryEffectStack->rbegin();
|
||||
it != shapeCtx->fGeometryEffectStack->rend(); ++it) {
|
||||
drawGeos = it->fAttach(it->fJson, shapeCtx->fScope, std::move(drawGeos));
|
||||
for (auto it = ctx->fGeometryEffectStack->rbegin();
|
||||
it != ctx->fGeometryEffectStack->rend(); ++it) {
|
||||
drawGeos = it->fAttach(it->fJson, ctx->fBuilder, ctx->fScope, std::move(drawGeos));
|
||||
}
|
||||
|
||||
// If we still have multiple geos, reduce using 'merge'.
|
||||
@ -543,7 +565,7 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
|
||||
|
||||
SkASSERT(geo);
|
||||
draws.push_back(sksg::Draw::Make(std::move(geo), std::move(paint)));
|
||||
shapeCtx->fCommittedAnimators = shapeCtx->fScope->size();
|
||||
ctx->fCommittedAnimators = ctx->fScope->size();
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
@ -551,11 +573,11 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
|
||||
}
|
||||
|
||||
// By now we should have popped all local geometry effects.
|
||||
SkASSERT(shapeCtx->fGeometryEffectStack->size() == initialGeometryEffects);
|
||||
SkASSERT(ctx->fGeometryEffectStack->size() == initialGeometryEffects);
|
||||
|
||||
// Push transformed local geometries to parent list, for subsequent paints.
|
||||
for (const auto& geo : geos) {
|
||||
shapeCtx->fGeometryStack->push_back(shape_matrix
|
||||
ctx->fGeometryStack->push_back(shape_matrix
|
||||
? sksg::GeometryTransform::Make(std::move(geo), shape_matrix)
|
||||
: std::move(geo));
|
||||
}
|
||||
@ -571,10 +593,10 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
|
||||
} // namespace
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachShapeLayer(const skjson::ObjectValue& layer,
|
||||
AnimatorScope* ascope) {
|
||||
AnimatorScope* ascope) const {
|
||||
std::vector<sk_sp<sksg::GeometryNode>> geometryStack;
|
||||
std::vector<GeometryEffectRec> geometryEffectStack;
|
||||
AttachShapeContext shapeCtx(ascope, &geometryStack, &geometryEffectStack, ascope->size());
|
||||
AttachShapeContext shapeCtx(this, ascope, &geometryStack, &geometryEffectStack, ascope->size());
|
||||
auto shapeNode = AttachShape(layer["shapes"], &shapeCtx);
|
||||
|
||||
// Trim uncommitted animators: AttachShape consumes effects on the fly, and greedily attaches
|
||||
|
@ -206,7 +206,7 @@ void AnimationBuilder::parseFonts(const skjson::ObjectValue* jfonts,
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachTextLayer(const skjson::ObjectValue& layer,
|
||||
AnimatorScope* ascope) {
|
||||
AnimatorScope* ascope) const {
|
||||
// General text node format:
|
||||
// "t": {
|
||||
// "a": [], // animators (TODO)
|
||||
|
@ -8,12 +8,20 @@
|
||||
#include "SkottieValue.h"
|
||||
|
||||
#include "SkColor.h"
|
||||
#include "SkottieJson.h"
|
||||
#include "SkottiePriv.h"
|
||||
#include "SkNx.h"
|
||||
#include "SkPoint.h"
|
||||
#include "SkSize.h"
|
||||
|
||||
namespace skottie {
|
||||
|
||||
template <>
|
||||
bool ValueTraits<ScalarValue>::FromJSON(const skjson::Value& jv, const internal::AnimationBuilder*,
|
||||
ScalarValue* v) {
|
||||
return Parse(jv, v);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ValueTraits<ScalarValue>::CanLerp(const ScalarValue&, const ScalarValue&) {
|
||||
return true;
|
||||
@ -32,6 +40,12 @@ SkScalar ValueTraits<ScalarValue>::As<SkScalar>(const ScalarValue& v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ValueTraits<VectorValue>::FromJSON(const skjson::Value& jv, const internal::AnimationBuilder*,
|
||||
VectorValue* v) {
|
||||
return Parse(jv, v);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ValueTraits<VectorValue>::CanLerp(const VectorValue& v1, const VectorValue& v2) {
|
||||
return v1.size() == v2.size();
|
||||
@ -80,6 +94,67 @@ SkSize ValueTraits<VectorValue>::As<SkSize>(const VectorValue& vec) {
|
||||
return SkSize::Make(pt.x(), pt.y());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool ParsePointVec(const skjson::Value& jv, std::vector<SkPoint>* pts) {
|
||||
if (!jv.is<skjson::ArrayValue>())
|
||||
return false;
|
||||
const auto& av = jv.as<skjson::ArrayValue>();
|
||||
|
||||
pts->clear();
|
||||
pts->reserve(av.size());
|
||||
|
||||
std::vector<float> vec;
|
||||
for (size_t i = 0; i < av.size(); ++i) {
|
||||
if (!Parse(av[i], &vec) || vec.size() != 2)
|
||||
return false;
|
||||
pts->push_back(SkPoint::Make(vec[0], vec[1]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
bool ValueTraits<ShapeValue>::FromJSON(const skjson::Value& jv,
|
||||
const internal::AnimationBuilder* abuilder,
|
||||
ShapeValue* v) {
|
||||
SkASSERT(v->fVertices.empty());
|
||||
|
||||
// Some versions wrap values as single-element arrays.
|
||||
if (const skjson::ArrayValue* av = jv) {
|
||||
if (av->size() == 1) {
|
||||
return FromJSON((*av)[0], abuilder, v);
|
||||
}
|
||||
}
|
||||
|
||||
if (!jv.is<skjson::ObjectValue>())
|
||||
return false;
|
||||
const auto& ov = jv.as<skjson::ObjectValue>();
|
||||
|
||||
std::vector<SkPoint> inPts, // Cubic Bezier "in" control points, relative to vertices.
|
||||
outPts, // Cubic Bezier "out" control points, relative to vertices.
|
||||
verts; // Cubic Bezier vertices.
|
||||
|
||||
if (!ParsePointVec(ov["i"], &inPts) ||
|
||||
!ParsePointVec(ov["o"], &outPts) ||
|
||||
!ParsePointVec(ov["v"], &verts) ||
|
||||
inPts.size() != outPts.size() ||
|
||||
inPts.size() != verts.size()) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
v->fVertices.reserve(inPts.size());
|
||||
for (size_t i = 0; i < inPts.size(); ++i) {
|
||||
v->fVertices.push_back(BezierVertex({inPts[i], outPts[i], verts[i]}));
|
||||
}
|
||||
v->fClosed = ParseDefault<bool>(ov["c"], false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ValueTraits<ShapeValue>::CanLerp(const ShapeValue& v1, const ShapeValue& v2) {
|
||||
return v1.fVertices.size() == v2.fVertices.size()
|
||||
|
@ -13,10 +13,17 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace skottie {
|
||||
namespace skjson { class Value; }
|
||||
|
||||
namespace skottie {
|
||||
namespace internal {
|
||||
class AnimationBuilder;
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
struct ValueTraits {
|
||||
static bool FromJSON(const skjson::Value&, const internal::AnimationBuilder*, T*);
|
||||
|
||||
template <typename U>
|
||||
static U As(const T&);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user