1 /*
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 "modules/skottie/src/SkottiePriv.h"
9
10 #include "modules/skottie/src/SkottieJson.h"
11 #include "modules/skottie/src/SkottieValue.h"
12 #include "modules/sksg/include/SkSGRenderNode.h"
13 #include "modules/sksg/include/SkSGScene.h"
14 #include "src/core/SkTLazy.h"
15 #include "src/utils/SkJSON.h"
16
17 namespace skottie {
18 namespace internal {
19
attachPrecompLayer(const skjson::ObjectValue & jlayer,LayerInfo * layer_info) const20 sk_sp<sksg::RenderNode> AnimationBuilder::attachPrecompLayer(const skjson::ObjectValue& jlayer,
21 LayerInfo* layer_info) const {
22 const skjson::ObjectValue* time_remap = jlayer["tm"];
23 // Empirically, a time mapper supersedes start/stretch.
24 const auto start_time = time_remap ? 0.0f : ParseDefault<float>(jlayer["st"], 0.0f),
25 stretch_time = time_remap ? 1.0f : ParseDefault<float>(jlayer["sr"], 1.0f);
26 const auto requires_time_mapping = !SkScalarNearlyEqual(start_time , 0) ||
27 !SkScalarNearlyEqual(stretch_time, 1) ||
28 time_remap;
29
30 // Precomp layers are sized explicitly.
31 layer_info->fSize = SkSize::Make(ParseDefault<float>(jlayer["w"], 0.0f),
32 ParseDefault<float>(jlayer["h"], 0.0f));
33
34 SkTLazy<AutoScope> local_scope;
35 if (requires_time_mapping) {
36 local_scope.init(this);
37 }
38
39 auto precomp_layer = this->attachAssetRef(jlayer,
40 [this] (const skjson::ObjectValue& jcomp) {
41 return this->attachComposition(jcomp);
42 });
43
44 // Applies a bias/scale/remap t-adjustment to child animators.
45 class CompTimeMapper final : public sksg::GroupAnimator {
46 public:
47 CompTimeMapper(sksg::AnimatorList&& layer_animators, float time_bias, float time_scale)
48 : INHERITED(std::move(layer_animators))
49 , fTimeBias(time_bias)
50 , fTimeScale(time_scale) {}
51
52 void onTick(float t) override {
53 // When time remapping is active, |t| is driven externally.
54 if (fRemappedTime.isValid()) {
55 t = *fRemappedTime.get();
56 }
57
58 this->INHERITED::onTick((t + fTimeBias) * fTimeScale);
59 }
60
61 void remapTime(float t) { fRemappedTime.set(t); }
62
63 private:
64 const float fTimeBias,
65 fTimeScale;
66 SkTLazy<float> fRemappedTime;
67
68 using INHERITED = sksg::GroupAnimator;
69 };
70
71 if (requires_time_mapping) {
72 const auto t_bias = -start_time,
73 t_scale = sk_ieee_float_divide(1, stretch_time);
74 auto time_mapper = sk_make_sp<CompTimeMapper>(local_scope->release(), t_bias,
75 sk_float_isfinite(t_scale) ? t_scale : 0);
76 if (time_remap) {
77 auto frame_rate = fFrameRate;
78 this->bindProperty<ScalarValue>(*time_remap,
79 [time_mapper, frame_rate](const ScalarValue& t) {
80 time_mapper->remapTime(t * frame_rate);
81 });
82 }
83 fCurrentAnimatorScope->push_back(std::move(time_mapper));
84 }
85
86 return precomp_layer;
87 }
88
89 } // namespace internal
90 } // namespace skottie
91