blob: f110c2d65c8793b7508598dca6a537f38c8d1963 [file] [log] [blame]
Florin Malita1b1dead2018-08-21 14:34:02 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkottiePriv.h"
9
10#include "SkJSON.h"
Florin Malita1b1dead2018-08-21 14:34:02 -040011#include "SkottieJson.h"
12#include "SkottieValue.h"
13#include "SkMakeUnique.h"
14#include "SkSGRenderNode.h"
15#include "SkSGScene.h"
16#include "SkTLazy.h"
17
18namespace skottie {
19namespace internal {
20
21sk_sp<sksg::RenderNode> AnimationBuilder::attachPrecompLayer(const skjson::ObjectValue& jlayer,
Florin Malita62c6bd92018-10-03 14:39:56 -040022 const LayerInfo&,
Florin Malita471a9462018-08-25 20:22:34 -040023 AnimatorScope* ascope) const {
Florin Malita1b1dead2018-08-21 14:34:02 -040024 const skjson::ObjectValue* time_remap = jlayer["tm"];
Florin Malitaa225a6b2018-08-27 15:28:04 -040025 // Empirically, a time mapper supersedes start/stretch.
26 const auto start_time = time_remap ? 0.0f : ParseDefault<float>(jlayer["st"], 0.0f),
27 stretch_time = time_remap ? 1.0f : ParseDefault<float>(jlayer["sr"], 1.0f);
Florin Malita1b1dead2018-08-21 14:34:02 -040028 const auto requires_time_mapping = !SkScalarNearlyEqual(start_time , 0) ||
29 !SkScalarNearlyEqual(stretch_time, 1) ||
30 time_remap;
31
32 AnimatorScope local_animators;
33 auto precomp_layer = this->attachAssetRef(jlayer,
34 requires_time_mapping ? &local_animators : ascope,
Florin Malita62c6bd92018-10-03 14:39:56 -040035 [this] (const skjson::ObjectValue& jcomp,
36 AnimatorScope* ascope) {
37 return this->attachComposition(jcomp, ascope);
38 });
Florin Malita1b1dead2018-08-21 14:34:02 -040039
40 // Applies a bias/scale/remap t-adjustment to child animators.
41 class CompTimeMapper final : public sksg::GroupAnimator {
42 public:
43 CompTimeMapper(sksg::AnimatorList&& layer_animators, float time_bias, float time_scale)
44 : INHERITED(std::move(layer_animators))
45 , fTimeBias(time_bias)
46 , fTimeScale(time_scale) {}
47
48 void onTick(float t) override {
49 // When time remapping is active, |t| is driven externally.
50 if (fRemappedTime.isValid()) {
51 t = *fRemappedTime.get();
52 }
53
54 this->INHERITED::onTick((t + fTimeBias) * fTimeScale);
55 }
56
57 void remapTime(float t) { fRemappedTime.set(t); }
58
59 private:
60 const float fTimeBias,
61 fTimeScale;
62 SkTLazy<float> fRemappedTime;
63
64 using INHERITED = sksg::GroupAnimator;
65 };
66
67 if (requires_time_mapping) {
68 const auto t_bias = -start_time,
69 t_scale = sk_ieee_float_divide(1, stretch_time);
Florin Malitabeb83002018-09-18 10:38:51 -040070 auto time_mapper =
71 skstd::make_unique<CompTimeMapper>(std::move(local_animators), t_bias,
72 sk_float_isfinite(t_scale) ? t_scale : 0);
Florin Malita1b1dead2018-08-21 14:34:02 -040073 if (time_remap) {
74 // The lambda below captures a raw pointer to the mapper object. That should be safe,
75 // because both the lambda and the mapper are scoped/owned by ctx->fAnimators.
76 auto* raw_mapper = time_mapper.get();
77 auto frame_rate = fFrameRate;
Florin Malita471a9462018-08-25 20:22:34 -040078 this->bindProperty<ScalarValue>(*time_remap, ascope,
Florin Malita1b1dead2018-08-21 14:34:02 -040079 [raw_mapper, frame_rate](const ScalarValue& t) {
80 raw_mapper->remapTime(t * frame_rate);
81 });
82 }
83 ascope->push_back(std::move(time_mapper));
84 }
85
86 return precomp_layer;
87}
88
89} // namespace internal
90} // namespace skottie