2017-12-30 17:27:00 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2017 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2018-01-16 22:04:30 +00:00
|
|
|
#ifndef SkottieAnimator_DEFINED
|
|
|
|
#define SkottieAnimator_DEFINED
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-05 18:20:11 +00:00
|
|
|
#include "SkCubicMap.h"
|
|
|
|
#include "SkMakeUnique.h"
|
2018-01-16 22:04:30 +00:00
|
|
|
#include "SkottiePriv.h"
|
|
|
|
#include "SkottieProperties.h"
|
2018-01-22 17:57:06 +00:00
|
|
|
#include "SkSGScene.h"
|
2017-12-30 17:27:00 +00:00
|
|
|
#include "SkTypes.h"
|
|
|
|
|
|
|
|
#include <memory>
|
2018-01-09 16:56:09 +00:00
|
|
|
#include <vector>
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-16 22:04:30 +00:00
|
|
|
namespace skottie {
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
class KeyframeIntervalBase : public SkNoncopyable {
|
|
|
|
public:
|
|
|
|
KeyframeIntervalBase() = default;
|
|
|
|
KeyframeIntervalBase(KeyframeIntervalBase&&) = default;
|
|
|
|
KeyframeIntervalBase& operator=(KeyframeIntervalBase&&) = default;
|
2018-01-04 18:11:14 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
float t0() const { return fT0; }
|
|
|
|
float t1() const { return fT1; }
|
2018-01-04 18:11:14 +00:00
|
|
|
|
2018-01-24 16:17:42 +00:00
|
|
|
bool isValid() const { return fT0 < fT1 || fHold; }
|
2018-01-09 00:23:08 +00:00
|
|
|
bool contains(float t) const { return t >= fT0 && t <= fT1; }
|
2018-01-04 18:11:14 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
protected:
|
2018-01-04 18:11:14 +00:00
|
|
|
// Parse the current interval AND back-fill prev interval t1.
|
2018-01-09 00:23:08 +00:00
|
|
|
bool parse(const Json::Value&, KeyframeIntervalBase* prev);
|
2018-01-04 18:11:14 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
// Computes a "local" t (relative to [fT0..fT1]), and mapped
|
|
|
|
// through the cubic (if applicable).
|
|
|
|
float localT(float t) const;
|
2018-01-04 18:11:14 +00:00
|
|
|
|
2018-01-24 16:17:42 +00:00
|
|
|
bool isHold() const { return fHold; }
|
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
private:
|
|
|
|
// Initialized for non-linear interpolation.
|
|
|
|
std::unique_ptr<SkCubicMap> fCubicMap;
|
2018-01-04 18:11:14 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
// Start/end times.
|
|
|
|
float fT0 = 0,
|
|
|
|
fT1 = 0;
|
2018-01-24 16:17:42 +00:00
|
|
|
|
|
|
|
bool fHold = false;
|
2018-01-09 00:23:08 +00:00
|
|
|
};
|
2018-01-05 18:20:11 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
// Describes a keyframe interpolation interval (v0@t0) -> (v1@t1).
|
|
|
|
template <typename T>
|
|
|
|
class KeyframeInterval final : public KeyframeIntervalBase {
|
|
|
|
public:
|
|
|
|
bool parse(const Json::Value& k, KeyframeInterval* prev) {
|
|
|
|
SkASSERT(k.isObject());
|
2018-01-04 18:11:14 +00:00
|
|
|
|
2018-01-24 16:17:42 +00:00
|
|
|
if (!this->INHERITED::parse(k, prev) ||
|
|
|
|
!ValueTraits<T>::Parse(k["s"], &fV0)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-24 19:30:12 +00:00
|
|
|
if (!this->isHold() &&
|
|
|
|
(!ValueTraits<T>::Parse(k["e"], &fV1) ||
|
|
|
|
ValueTraits<T>::Cardinality(fV0) != ValueTraits<T>::Cardinality(fV1))) {
|
2018-01-24 16:17:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-24 19:30:12 +00:00
|
|
|
return !prev || ValueTraits<T>::Cardinality(fV0) == ValueTraits<T>::Cardinality(prev->fV0);
|
|
|
|
}
|
2018-01-24 16:17:42 +00:00
|
|
|
|
2018-01-24 19:30:12 +00:00
|
|
|
void eval(float t, T* v) const {
|
|
|
|
if (this->isHold() || t <= this->t0()) {
|
|
|
|
*v = fV0;
|
|
|
|
} else if (t >= this->t1()) {
|
|
|
|
*v = fV1;
|
|
|
|
} else {
|
|
|
|
this->lerp(t, v);
|
|
|
|
}
|
2018-01-04 18:11:14 +00:00
|
|
|
}
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-24 19:30:12 +00:00
|
|
|
private:
|
2017-12-30 17:27:00 +00:00
|
|
|
void lerp(float t, T*) const;
|
2018-01-09 00:23:08 +00:00
|
|
|
|
|
|
|
// Start/end values.
|
2018-01-09 16:56:09 +00:00
|
|
|
T fV0,
|
|
|
|
fV1;
|
2018-01-09 00:23:08 +00:00
|
|
|
|
|
|
|
using INHERITED = KeyframeIntervalBase;
|
2017-12-30 17:27:00 +00:00
|
|
|
};
|
|
|
|
|
2018-01-09 16:56:09 +00:00
|
|
|
template <typename T>
|
|
|
|
std::vector<KeyframeInterval<T>> ParseFrames(const Json::Value& jframes) {
|
|
|
|
std::vector<KeyframeInterval<T>> frames;
|
|
|
|
|
|
|
|
if (jframes.isArray()) {
|
|
|
|
frames.reserve(jframes.size());
|
|
|
|
|
|
|
|
KeyframeInterval<T>* prev_frame = nullptr;
|
|
|
|
for (const auto& jframe : jframes) {
|
|
|
|
if (!jframe.isObject())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
KeyframeInterval<T> frame;
|
|
|
|
if (frame.parse(jframe, prev_frame)) {
|
|
|
|
frames.push_back(std::move(frame));
|
|
|
|
prev_frame = &frames.back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we couldn't determine a t1 for the last frame, discard it.
|
|
|
|
if (!frames.empty() && !frames.back().isValid()) {
|
|
|
|
frames.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
return frames;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Binds an animated/keyframed property to a node attribute setter.
|
|
|
|
template <typename ValT, typename NodeT>
|
2018-01-22 17:57:06 +00:00
|
|
|
class Animator final : public sksg::Animator {
|
2017-12-30 17:27:00 +00:00
|
|
|
public:
|
2018-01-09 16:56:09 +00:00
|
|
|
using ApplyFuncT = void(*)(NodeT*, const ValT&);
|
|
|
|
static std::unique_ptr<Animator> Make(std::vector<KeyframeInterval<ValT>>&& frames,
|
|
|
|
sk_sp<NodeT> node,
|
|
|
|
ApplyFuncT&& applyFunc) {
|
|
|
|
return (node && !frames.empty())
|
|
|
|
? std::unique_ptr<Animator>(new Animator(std::move(frames),
|
|
|
|
std::move(node),
|
|
|
|
std::move(applyFunc)))
|
|
|
|
: nullptr;
|
|
|
|
}
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-22 17:57:06 +00:00
|
|
|
void onTick(float t) override {
|
2018-01-09 16:56:09 +00:00
|
|
|
const auto& frame = this->findFrame(t);
|
2017-12-30 17:27:00 +00:00
|
|
|
|
|
|
|
ValT val;
|
2018-01-24 19:30:12 +00:00
|
|
|
frame.eval(t, &val);
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-09 16:56:09 +00:00
|
|
|
fFunc(fTarget.get(), val);
|
2017-12-30 17:27:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-01-09 16:56:09 +00:00
|
|
|
Animator(std::vector<KeyframeInterval<ValT>>&& frames, sk_sp<NodeT> node,
|
2018-01-06 19:25:49 +00:00
|
|
|
ApplyFuncT&& applyFunc)
|
2018-01-09 16:56:09 +00:00
|
|
|
: fFrames(std::move(frames))
|
2017-12-30 17:27:00 +00:00
|
|
|
, fTarget(std::move(node))
|
|
|
|
, fFunc(std::move(applyFunc)) {}
|
|
|
|
|
2018-01-09 16:56:09 +00:00
|
|
|
const KeyframeInterval<ValT>& findFrame(float t) const;
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-09 16:56:09 +00:00
|
|
|
const std::vector<KeyframeInterval<ValT>> fFrames;
|
|
|
|
sk_sp<NodeT> fTarget;
|
|
|
|
ApplyFuncT fFunc;
|
2017-12-30 17:27:00 +00:00
|
|
|
};
|
|
|
|
|
2018-01-09 16:56:09 +00:00
|
|
|
template <typename ValT, typename NodeT>
|
|
|
|
const KeyframeInterval<ValT>& Animator<ValT, NodeT>::findFrame(float t) const {
|
|
|
|
SkASSERT(!fFrames.empty());
|
2017-12-30 17:27:00 +00:00
|
|
|
|
|
|
|
// TODO: cache last/current frame?
|
|
|
|
|
2018-01-09 16:56:09 +00:00
|
|
|
auto f0 = fFrames.begin(),
|
|
|
|
f1 = fFrames.end() - 1;
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
SkASSERT(f0->isValid());
|
|
|
|
SkASSERT(f1->isValid());
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
if (t < f0->t0()) {
|
2017-12-30 17:27:00 +00:00
|
|
|
return *f0;
|
|
|
|
}
|
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
if (t > f1->t1()) {
|
2017-12-30 17:27:00 +00:00
|
|
|
return *f1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (f0 != f1) {
|
|
|
|
SkASSERT(f0 < f1);
|
2018-01-09 00:23:08 +00:00
|
|
|
SkASSERT(t >= f0->t0() && t <= f1->t1());
|
2017-12-30 17:27:00 +00:00
|
|
|
|
|
|
|
const auto f = f0 + (f1 - f0) / 2;
|
2018-01-09 00:23:08 +00:00
|
|
|
SkASSERT(f->isValid());
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-09 00:23:08 +00:00
|
|
|
if (t > f->t1()) {
|
2017-12-30 17:27:00 +00:00
|
|
|
f0 = f + 1;
|
|
|
|
} else {
|
|
|
|
f1 = f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SkASSERT(f0 == f1);
|
2018-01-09 00:23:08 +00:00
|
|
|
SkASSERT(f0->contains(t));
|
|
|
|
|
2017-12-30 17:27:00 +00:00
|
|
|
return *f0;
|
|
|
|
}
|
|
|
|
|
2018-01-16 22:04:30 +00:00
|
|
|
} // namespace skottie
|
2017-12-30 17:27:00 +00:00
|
|
|
|
2018-01-16 22:04:30 +00:00
|
|
|
#endif // SkottieAnimator_DEFINED
|