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