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     ~KeyframeAnimator() override;
59 
isConstant()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:
KeyframeAnimator(std::vector<Keyframe> kfs,std::vector<SkCubicMap> cms)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 
isConstantLERPInfo76         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 
containsKFSegment88         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&, const skjson::ArrayValue&) = 0;
112 
113     virtual bool parseValue(const AnimationBuilder&, const skjson::Value&) const = 0;
114 
115 protected:
116     virtual bool parseKFValue(const AnimationBuilder&,
117                               const skjson::ObjectValue&,
118                               const skjson::Value&,
119                               Keyframe::Value*) = 0;
120 
121     bool parseKeyframes(const AnimationBuilder&, const skjson::ArrayValue&);
122 
123     std::vector<Keyframe>   fKFs; // Keyframe records, one per AE/Lottie keyframe.
124     std::vector<SkCubicMap> fCMs; // Optional cubic mappers (Bezier interpolation).
125 
126 private:
127     uint32_t parseMapping(const skjson::ObjectValue&);
128 
129     // Track previous cubic map parameters (for deduping).
130     SkPoint prev_c0 = { 0, 0 },
131             prev_c1 = { 0, 0 };
132 };
133 
134 template <typename T>
Lerp(const T & a,const T & b,float t)135 T Lerp(const T& a, const T& b, float t) { return a + (b - a) * t; }
136 
137 } // namespace skottie::internal
138 
139 #endif // SkottieKeyframeAnimator_DEFINED
140