diff options
author | Florin Malita <fmalita@chromium.org> | 2018-01-29 15:28:24 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-29 21:12:13 +0000 |
commit | eb87d67a8300754b555f1408df67753649beecbc (patch) | |
tree | a597c106cadd54a16867612b4d209b74288feb3d /experimental | |
parent | b50e38562d1e1cab1773e3ee44c4b01113858ab4 (diff) |
[skottie] Time start, time stretch
Pre-compositions (only) can have their timelines adjusted via bias and
scale.
TBR=
Change-Id: I519fa1d7cf210f7f152dcabcbe004119a2cf08d9
Reviewed-on: https://skia-review.googlesource.com/101460
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'experimental')
-rw-r--r-- | experimental/skottie/Skottie.cpp | 82 |
1 files changed, 58 insertions, 24 deletions
diff --git a/experimental/skottie/Skottie.cpp b/experimental/skottie/Skottie.cpp index 66b84b5750..532cc8d36d 100644 --- a/experimental/skottie/Skottie.cpp +++ b/experimental/skottie/Skottie.cpp @@ -675,11 +675,12 @@ sk_sp<sksg::RenderNode> AttachShape(const Json::Value& jshape, AttachShapeContex return draws.empty() ? nullptr : shape_wrapper; } -sk_sp<sksg::RenderNode> AttachCompLayer(const Json::Value& layer, AttachContext* ctx) { - SkASSERT(layer.isObject()); +sk_sp<sksg::RenderNode> AttachCompLayer(const Json::Value& jlayer, AttachContext* ctx, + float* time_bias, float* time_scale) { + SkASSERT(jlayer.isObject()); SkString refId; - if (!Parse(layer["refId"], &refId) || refId.isEmpty()) { + if (!Parse(jlayer["refId"], &refId) || refId.isEmpty()) { LOG("!! Comp layer missing refId\n"); return nullptr; } @@ -690,11 +691,21 @@ sk_sp<sksg::RenderNode> AttachCompLayer(const Json::Value& layer, AttachContext* return nullptr; } + const auto start_time = ParseDefault(jlayer["st"], 0.0f), + stretch_time = ParseDefault(jlayer["sr"], 1.0f); + + *time_bias = -start_time; + *time_scale = 1 / stretch_time; + if (SkScalarIsNaN(*time_scale)) { + *time_scale = 1; + } + // TODO: cycle detection return AttachComposition(**comp, ctx); } -sk_sp<sksg::RenderNode> AttachSolidLayer(const Json::Value& jlayer, AttachContext*) { +sk_sp<sksg::RenderNode> AttachSolidLayer(const Json::Value& jlayer, AttachContext*, + float*, float*) { SkASSERT(jlayer.isObject()); const auto size = SkSize::Make(ParseDefault(jlayer["sw"], 0.0f), @@ -735,7 +746,8 @@ sk_sp<sksg::RenderNode> AttachImageAsset(const Json::Value& jimage, AttachContex SkImage::MakeFromEncoded(SkData::MakeFromStream(resStream.get(), resStream->getLength()))); } -sk_sp<sksg::RenderNode> AttachImageLayer(const Json::Value& layer, AttachContext* ctx) { +sk_sp<sksg::RenderNode> AttachImageLayer(const Json::Value& layer, AttachContext* ctx, + float*, float*) { SkASSERT(layer.isObject()); SkString refId; @@ -753,7 +765,7 @@ sk_sp<sksg::RenderNode> AttachImageLayer(const Json::Value& layer, AttachContext return AttachImageAsset(**jimage, ctx); } -sk_sp<sksg::RenderNode> AttachNullLayer(const Json::Value& layer, AttachContext*) { +sk_sp<sksg::RenderNode> AttachNullLayer(const Json::Value& layer, AttachContext*, float*, float*) { SkASSERT(layer.isObject()); // Null layers are used solely to drive dependent transforms, @@ -761,7 +773,8 @@ sk_sp<sksg::RenderNode> AttachNullLayer(const Json::Value& layer, AttachContext* return nullptr; } -sk_sp<sksg::RenderNode> AttachShapeLayer(const Json::Value& layer, AttachContext* ctx) { +sk_sp<sksg::RenderNode> AttachShapeLayer(const Json::Value& layer, AttachContext* ctx, + float*, float*) { SkASSERT(layer.isObject()); std::vector<sk_sp<sksg::GeometryNode>> geometryStack; @@ -779,7 +792,7 @@ sk_sp<sksg::RenderNode> AttachShapeLayer(const Json::Value& layer, AttachContext return shapeNode; } -sk_sp<sksg::RenderNode> AttachTextLayer(const Json::Value& layer, AttachContext*) { +sk_sp<sksg::RenderNode> AttachTextLayer(const Json::Value& layer, AttachContext*, float*, float*) { SkASSERT(layer.isObject()); LOG("?? Text layer stub\n"); @@ -905,7 +918,8 @@ sk_sp<sksg::RenderNode> AttachLayer(const Json::Value& jlayer, if (!jlayer.isObject()) return nullptr; - using LayerAttacher = sk_sp<sksg::RenderNode> (*)(const Json::Value&, AttachContext*); + using LayerAttacher = sk_sp<sksg::RenderNode> (*)(const Json::Value&, AttachContext*, + float* time_bias, float* time_scale); static constexpr LayerAttacher gLayerAttachers[] = { AttachCompLayer, // 'ty': 0 AttachSolidLayer, // 'ty': 1 @@ -924,8 +938,12 @@ sk_sp<sksg::RenderNode> AttachLayer(const Json::Value& jlayer, AttachContext local_ctx = { layerCtx->fCtx->fResources, layerCtx->fCtx->fAssets, layer_animators}; + // Layer attachers may adjust these. + float time_bias = 0, + time_scale = 1; + // Layer content. - auto layer = gLayerAttachers[type](jlayer, &local_ctx); + auto layer = gLayerAttachers[type](jlayer, &local_ctx, &time_bias, &time_scale); // Optional layer mask. layer = AttachMask(jlayer["masksProperties"], &local_ctx, std::move(layer)); // Optional layer transform. @@ -935,14 +953,18 @@ sk_sp<sksg::RenderNode> AttachLayer(const Json::Value& jlayer, // Optional layer opacity. layer = AttachOpacity(jlayer["ks"], &local_ctx, std::move(layer)); - class Activator final : public sksg::GroupAnimator { + class LayerController final : public sksg::GroupAnimator { public: - Activator(sksg::AnimatorList&& layer_animators, - sk_sp<sksg::OpacityEffect> controlNode, float in, float out) + LayerController(sksg::AnimatorList&& layer_animators, + sk_sp<sksg::OpacityEffect> controlNode, + float in, float out, + float time_bias, float time_scale) : INHERITED(std::move(layer_animators)) , fControlNode(std::move(controlNode)) , fIn(in) - , fOut(out) {} + , fOut(out) + , fTimeBias(time_bias) + , fTimeScale(time_scale) {} void onTick(float t) override { const auto active = (t >= fIn && t <= fOut); @@ -953,39 +975,51 @@ sk_sp<sksg::RenderNode> AttachLayer(const Json::Value& jlayer, // Dispatch ticks only while active. if (active) - this->INHERITED::onTick(t); + this->INHERITED::onTick((t + fTimeBias) * fTimeScale); } private: const sk_sp<sksg::OpacityEffect> fControlNode; const float fIn, - fOut; + fOut, + fTimeBias, + fTimeScale; using INHERITED = sksg::GroupAnimator; }; - auto controller = sksg::OpacityEffect::Make(std::move(layer)); - const auto in = ParseDefault(jlayer["ip"], 0.0f), - out = ParseDefault(jlayer["op"], in); + auto controller_node = sksg::OpacityEffect::Make(std::move(layer)); + const auto in = ParseDefault(jlayer["ip"], 0.0f), + out = ParseDefault(jlayer["op"], in); + + if (!jlayer["tm"].isNull()) { + LogFail(jlayer["tm"], "Unsupported time remapping"); + } - if (in >= out || !controller) + if (in >= out || !controller_node) return nullptr; layerCtx->fCtx->fAnimators.push_back( - skstd::make_unique<Activator>(std::move(layer_animators), controller, in, out)); + skstd::make_unique<LayerController>(std::move(layer_animators), + controller_node, + in, + out, + time_bias, + time_scale)); if (ParseDefault(jlayer["td"], false)) { // This layer is a matte. We apply it as a mask to the next layer. - layerCtx->fCurrentMatte = std::move(controller); + layerCtx->fCurrentMatte = std::move(controller_node); return nullptr; } if (layerCtx->fCurrentMatte) { // There is a pending matte. Apply and reset. - return sksg::MaskEffect::Make(std::move(controller), std::move(layerCtx->fCurrentMatte)); + return sksg::MaskEffect::Make(std::move(controller_node), + std::move(layerCtx->fCurrentMatte)); } - return controller; + return controller_node; } sk_sp<sksg::RenderNode> AttachComposition(const Json::Value& comp, AttachContext* ctx) { |