1 /*
2 * Copyright 2020 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 #ifndef SkottieKeyframeAnimator_DEFINED
9 #define SkottieKeyframeAnimator_DEFINED
10
11 #include "include/core/SkCubicMap.h"
12 #include "include/core/SkPoint.h"
13 #include "include/private/SkNoncopyable.h"
14 #include "modules/skottie/include/Skottie.h"
15 #include "modules/skottie/src/animator/Animator.h"
16
17 #include <vector>
18
19 namespace skjson {
20 class ArrayValue;
21 class ObjectValue;
22 class Value;
23 } // namespace skjson
24
25 namespace skottie::internal {
26
27 class AnimationBuilder;
28
29 struct Keyframe {
30 // We can store scalar values inline; other types are stored externally,
31 // and we track them by index.
32 struct Value {
33 enum class Type {
34 kIndex,
35 kScalar,
36 };
37
38 union {
39 uint32_t idx;
40 float flt;
41 };
42
equalsKeyframe::Value43 bool equals(const Value& other, Type ty) const {
44 return ty == Type::kIndex
45 ? idx == other.idx
46 : flt == other.flt;
47 }
48 };
49
50 float t;
51 Value v;
52 uint32_t mapping; // Encodes the value interpolation in [KFRec_n .. KFRec_n+1):
53 // 0 -> constant
54 // 1 -> linear
55 // n -> cubic: cubic_mappers[n-2]
56
57 inline static constexpr uint32_t kConstantMapping = 0;
58 inline static constexpr uint32_t kLinearMapping = 1;
59 inline static constexpr uint32_t kCubicIndexOffset = 2;
60 };
61
62 class KeyframeAnimator : public Animator {
63 public:
64 ~KeyframeAnimator() override;
65
isConstant()66 bool isConstant() const {
67 SkASSERT(!fKFs.empty());
68
69 // parseKeyFrames() ensures we only keep a single frame for constant properties.
70 return fKFs.size() == 1;
71 }
72
73 protected:
KeyframeAnimator(std::vector<Keyframe> kfs,std::vector<SkCubicMap> cms)74 KeyframeAnimator(std::vector<Keyframe> kfs, std::vector<SkCubicMap> cms)
75 : fKFs(std::move(kfs))
76 , fCMs(std::move(cms)) {}
77
78 struct LERPInfo {
79 float weight; // vrec0/vrec1 weight [0..1]
80 Keyframe::Value vrec0, vrec1;
81 };
82
83 // Main entry point: |t| -> LERPInfo
84 LERPInfo getLERPInfo(float t) const;
85
86 private:
87 // Two sequential KFRecs determine how the value varies within [kf0 .. kf1)
88 struct KFSegment {
89 const Keyframe* kf0;
90 const Keyframe* kf1;
91
containsKFSegment92 bool contains(float t) const {
93 SkASSERT(!!kf0 == !!kf1);
94 SkASSERT(!kf0 || kf1 == kf0 + 1);
95
96 return kf0 && kf0->t <= t && t < kf1->t;
97 }
98 };
99
100 // Find the KFSegment containing |t|.
101 KFSegment find_segment(float t) const;
102
103 // Given a |t| and a containing KFSegment, compute the local interpolation weight.
104 float compute_weight(const KFSegment& seg, float t) const;
105
106 const std::vector<Keyframe> fKFs; // Keyframe records, one per AE/Lottie keyframe.
107 const std::vector<SkCubicMap> fCMs; // Optional cubic mappers (Bezier interpolation).
108 mutable KFSegment fCurrentSegment = { nullptr, nullptr }; // Cached segment.
109 };
110
111 class AnimatorBuilder : public SkNoncopyable {
112 public:
113 virtual ~AnimatorBuilder();
114
115 virtual sk_sp<KeyframeAnimator> makeFromKeyframes(const AnimationBuilder&,
116 const skjson::ArrayValue&) = 0;
117
118 virtual sk_sp<Animator> makeFromExpression(ExpressionManager&, const char*) = 0;
119
120 virtual bool parseValue(const AnimationBuilder&, const skjson::Value&) const = 0;
121
122 protected:
AnimatorBuilder(Keyframe::Value::Type ty)123 explicit AnimatorBuilder(Keyframe::Value::Type ty)
124 : keyframe_type(ty) {}
125
126 virtual bool parseKFValue(const AnimationBuilder&,
127 const skjson::ObjectValue&,
128 const skjson::Value&,
129 Keyframe::Value*) = 0;
130
131 bool parseKeyframes(const AnimationBuilder&, const skjson::ArrayValue&);
132
133 std::vector<Keyframe> fKFs; // Keyframe records, one per AE/Lottie keyframe.
134 std::vector<SkCubicMap> fCMs; // Optional cubic mappers (Bezier interpolation).
135
136 private:
137 uint32_t parseMapping(const skjson::ObjectValue&);
138
139 const Keyframe::Value::Type keyframe_type;
140
141 // Track previous cubic map parameters (for deduping).
142 SkPoint prev_c0 = { 0, 0 },
143 prev_c1 = { 0, 0 };
144 };
145
146 template <typename T>
Lerp(const T & a,const T & b,float t)147 T Lerp(const T& a, const T& b, float t) { return a + (b - a) * t; }
148
149 } // namespace skottie::internal
150
151 #endif // SkottieKeyframeAnimator_DEFINED
152