blob: f2297958d9c6ed33105bf39792a406de47a7fba3 [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 Malita471a9462018-08-25 20:22:34 -040022 AnimatorScope* ascope) const {
Florin Malita1b1dead2018-08-21 14:34:02 -040023 const skjson::ObjectValue* time_remap = jlayer["tm"];
Florin Malitaa225a6b2018-08-27 15:28:04 -040024 // Empirically, a time mapper supersedes start/stretch.
25 const auto start_time = time_remap ? 0.0f : ParseDefault<float>(jlayer["st"], 0.0f),
26 stretch_time = time_remap ? 1.0f : ParseDefault<float>(jlayer["sr"], 1.0f);
Florin Malita1b1dead2018-08-21 14:34:02 -040027 const auto requires_time_mapping = !SkScalarNearlyEqual(start_time , 0) ||
28 !SkScalarNearlyEqual(stretch_time, 1) ||
29 time_remap;
30
31 AnimatorScope local_animators;
32 auto precomp_layer = this->attachAssetRef(jlayer,
33 requires_time_mapping ? &local_animators : ascope,
34 &AnimationBuilder::attachComposition);
35
36 // Applies a bias/scale/remap t-adjustment to child animators.
37 class CompTimeMapper final : public sksg::GroupAnimator {
38 public:
39 CompTimeMapper(sksg::AnimatorList&& layer_animators, float time_bias, float time_scale)
40 : INHERITED(std::move(layer_animators))
41 , fTimeBias(time_bias)
42 , fTimeScale(time_scale) {}
43
44 void onTick(float t) override {
45 // When time remapping is active, |t| is driven externally.
46 if (fRemappedTime.isValid()) {
47 t = *fRemappedTime.get();
48 }
49
50 this->INHERITED::onTick((t + fTimeBias) * fTimeScale);
51 }
52
53 void remapTime(float t) { fRemappedTime.set(t); }
54
55 private:
56 const float fTimeBias,
57 fTimeScale;
58 SkTLazy<float> fRemappedTime;
59
60 using INHERITED = sksg::GroupAnimator;
61 };
62
63 if (requires_time_mapping) {
64 const auto t_bias = -start_time,
65 t_scale = sk_ieee_float_divide(1, stretch_time);
Florin Malitabeb83002018-09-18 10:38:51 -040066 auto time_mapper =
67 skstd::make_unique<CompTimeMapper>(std::move(local_animators), t_bias,
68 sk_float_isfinite(t_scale) ? t_scale : 0);
Florin Malita1b1dead2018-08-21 14:34:02 -040069 if (time_remap) {
70 // The lambda below captures a raw pointer to the mapper object. That should be safe,
71 // because both the lambda and the mapper are scoped/owned by ctx->fAnimators.
72 auto* raw_mapper = time_mapper.get();
73 auto frame_rate = fFrameRate;
Florin Malita471a9462018-08-25 20:22:34 -040074 this->bindProperty<ScalarValue>(*time_remap, ascope,
Florin Malita1b1dead2018-08-21 14:34:02 -040075 [raw_mapper, frame_rate](const ScalarValue& t) {
76 raw_mapper->remapTime(t * frame_rate);
77 });
78 }
79 ascope->push_back(std::move(time_mapper));
80 }
81
82 return precomp_layer;
83}
84
85} // namespace internal
86} // namespace skottie