| /* |
| * Copyright 2020 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SkottieKeyframeAnimator_DEFINED |
| #define SkottieKeyframeAnimator_DEFINED |
| |
| #include "include/core/SkCubicMap.h" |
| #include "include/core/SkPoint.h" |
| #include "include/private/SkNoncopyable.h" |
| #include "modules/skottie/include/Skottie.h" |
| #include "modules/skottie/src/animator/Animator.h" |
| |
| #include <vector> |
| |
| namespace skjson { |
| class ArrayValue; |
| class ObjectValue; |
| class Value; |
| } // namespace skjson |
| |
| namespace skottie::internal { |
| |
| class AnimationBuilder; |
| |
| struct Keyframe { |
| // We can store scalar values inline; other types are stored externally, |
| // and we track them by index. |
| struct Value { |
| enum class Type { |
| kIndex, |
| kScalar, |
| }; |
| |
| union { |
| uint32_t idx; |
| float flt; |
| }; |
| |
| bool equals(const Value& other, Type ty) const { |
| return ty == Type::kIndex |
| ? idx == other.idx |
| : flt == other.flt; |
| } |
| }; |
| |
| float t; |
| Value v; |
| uint32_t mapping; // Encodes the value interpolation in [KFRec_n .. KFRec_n+1): |
| // 0 -> constant |
| // 1 -> linear |
| // n -> cubic: cubic_mappers[n-2] |
| |
| inline static constexpr uint32_t kConstantMapping = 0; |
| inline static constexpr uint32_t kLinearMapping = 1; |
| inline static constexpr uint32_t kCubicIndexOffset = 2; |
| }; |
| |
| class KeyframeAnimator : public Animator { |
| public: |
| ~KeyframeAnimator() override; |
| |
| bool isConstant() const { |
| SkASSERT(!fKFs.empty()); |
| |
| // parseKeyFrames() ensures we only keep a single frame for constant properties. |
| return fKFs.size() == 1; |
| } |
| |
| protected: |
| KeyframeAnimator(std::vector<Keyframe> kfs, std::vector<SkCubicMap> cms) |
| : fKFs(std::move(kfs)) |
| , fCMs(std::move(cms)) {} |
| |
| struct LERPInfo { |
| float weight; // vrec0/vrec1 weight [0..1] |
| Keyframe::Value vrec0, vrec1; |
| }; |
| |
| // Main entry point: |t| -> LERPInfo |
| LERPInfo getLERPInfo(float t) const; |
| |
| private: |
| // Two sequential KFRecs determine how the value varies within [kf0 .. kf1) |
| struct KFSegment { |
| const Keyframe* kf0; |
| const Keyframe* kf1; |
| |
| bool contains(float t) const { |
| SkASSERT(!!kf0 == !!kf1); |
| SkASSERT(!kf0 || kf1 == kf0 + 1); |
| |
| return kf0 && kf0->t <= t && t < kf1->t; |
| } |
| }; |
| |
| // Find the KFSegment containing |t|. |
| KFSegment find_segment(float t) const; |
| |
| // Given a |t| and a containing KFSegment, compute the local interpolation weight. |
| float compute_weight(const KFSegment& seg, float t) const; |
| |
| const std::vector<Keyframe> fKFs; // Keyframe records, one per AE/Lottie keyframe. |
| const std::vector<SkCubicMap> fCMs; // Optional cubic mappers (Bezier interpolation). |
| mutable KFSegment fCurrentSegment = { nullptr, nullptr }; // Cached segment. |
| }; |
| |
| class AnimatorBuilder : public SkNoncopyable { |
| public: |
| virtual ~AnimatorBuilder(); |
| |
| virtual sk_sp<KeyframeAnimator> makeFromKeyframes(const AnimationBuilder&, |
| const skjson::ArrayValue&) = 0; |
| |
| virtual sk_sp<Animator> makeFromExpression(ExpressionManager&, const char*) = 0; |
| |
| virtual bool parseValue(const AnimationBuilder&, const skjson::Value&) const = 0; |
| |
| protected: |
| explicit AnimatorBuilder(Keyframe::Value::Type ty) |
| : keyframe_type(ty) {} |
| |
| virtual bool parseKFValue(const AnimationBuilder&, |
| const skjson::ObjectValue&, |
| const skjson::Value&, |
| Keyframe::Value*) = 0; |
| |
| bool parseKeyframes(const AnimationBuilder&, const skjson::ArrayValue&); |
| |
| std::vector<Keyframe> fKFs; // Keyframe records, one per AE/Lottie keyframe. |
| std::vector<SkCubicMap> fCMs; // Optional cubic mappers (Bezier interpolation). |
| |
| private: |
| uint32_t parseMapping(const skjson::ObjectValue&); |
| |
| const Keyframe::Value::Type keyframe_type; |
| |
| // Track previous cubic map parameters (for deduping). |
| SkPoint prev_c0 = { 0, 0 }, |
| prev_c1 = { 0, 0 }; |
| }; |
| |
| template <typename T> |
| T Lerp(const T& a, const T& b, float t) { return a + (b - a) * t; } |
| |
| } // namespace skottie::internal |
| |
| #endif // SkottieKeyframeAnimator_DEFINED |