aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2018-01-04 13:11:14 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-01-04 21:46:14 +0000
commitd6c4f8f608d431fcc11dab1f7c9858b6cdfb3d8a (patch)
treee7a2687a628d25b37325070e0d2cbfb1b51e47ba /experimental
parentd2d7bf99c85d38d9cc6ca8cc5957624f3cd6a335 (diff)
[skotty] Add cubic Bezier lerp stubs
... and refactor some of the keyframe parsing. TBR= Change-Id: If45922eab36412908036401cee693202f5c3e281 Reviewed-on: https://skia-review.googlesource.com/91100 Reviewed-by: Florin Malita <fmalita@chromium.org> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'experimental')
-rw-r--r--experimental/skotty/SkottyAnimator.cpp12
-rw-r--r--experimental/skotty/SkottyAnimator.h82
-rw-r--r--experimental/skotty/SkottyPriv.h8
3 files changed, 74 insertions, 28 deletions
diff --git a/experimental/skotty/SkottyAnimator.cpp b/experimental/skotty/SkottyAnimator.cpp
index 451f146888..d4c5c96c1a 100644
--- a/experimental/skotty/SkottyAnimator.cpp
+++ b/experimental/skotty/SkottyAnimator.cpp
@@ -42,4 +42,16 @@ void KeyframeInterval<ShapeValue>::lerp(float t, ShapeValue* v) const {
SkAssertResult(fV1.fPath.interpolate(fV0.fPath, t, &v->fPath));
}
+float AnimatorBase::ComputeLocalT(float t, float t0, float t1,
+ const SkPoint& c0, const SkPoint& c1) {
+ SkASSERT(t1 > t0);
+ auto lt = (t - t0) / (t1 - t0);
+
+ if (c0 != SkPoint({0, 0}) || c1 != SkPoint({1, 1})) {
+ // TODO: lt = CubicBezier(lt, c0, c1);
+ }
+
+ return SkTPin<float>(lt, 0, 1);
+}
+
} // namespace skotty
diff --git a/experimental/skotty/SkottyAnimator.h b/experimental/skotty/SkottyAnimator.h
index 833390e744..f8d1c3abb6 100644
--- a/experimental/skotty/SkottyAnimator.h
+++ b/experimental/skotty/SkottyAnimator.h
@@ -25,17 +25,61 @@ public:
virtual void tick(SkMSec) = 0;
protected:
- AnimatorBase() = default;
+ AnimatorBase() = default;
+
+ // Compute a cubic-Bezier-interpolated t relative to [t0..t1].
+ static float ComputeLocalT(float t, float t0, float t1,
+ const SkPoint& c0, const SkPoint& c1);
};
// Describes a keyframe interpolation interval (v0@t0) -> (v1@t1).
// TODO: add interpolation params.
template <typename T>
struct KeyframeInterval {
- T fV0,
- fV1;
- float fT0 = 0,
- fT1 = 0;
+ // Start/end values.
+ T fV0,
+ fV1;
+
+ // Start/end times.
+ float fT0 = 0,
+ fT1 = 0;
+
+ // Cubic Bezier interpolation control pts.
+ SkPoint fC0,
+ fC1;
+
+ // Parse the current interval AND back-fill prev interval t1.
+ bool parse(const Json::Value& k, KeyframeInterval* prev) {
+ SkASSERT(k.isObject());
+
+ fT0 = fT1 = ParseScalar(k["t"], SK_ScalarMin);
+ if (fT0 == SK_ScalarMin) {
+ return false;
+ }
+
+ if (prev) {
+ if (prev->fT1 >= fT0) {
+ LOG("!! Dropping out-of-order key frame (t: %f < t: %f)\n", fT0, prev->fT1);
+ return false;
+ }
+ // Back-fill t1 in prev interval. Note: we do this even if we end up discarding
+ // the current interval (to support "t"-only final frames).
+ prev->fT1 = fT0;
+ }
+
+ if (!T::Parse(k["s"], &fV0) ||
+ !T::Parse(k["e"], &fV1) ||
+ fV0.cardinality() != fV1.cardinality() ||
+ (prev && fV0.cardinality() != prev->fV0.cardinality())) {
+ return false;
+ }
+
+ // default is linear lerp
+ fC0 = ParsePoint(k["i"], SkPoint::Make(0, 0));
+ fC1 = ParsePoint(k["o"], SkPoint::Make(1, 1));
+
+ return true;
+ }
void lerp(float t, T*) const;
};
@@ -49,10 +93,9 @@ public:
void tick(SkMSec t) override {
const auto& frame = this->findInterval(t);
- const auto rel_t = (t - frame.fT0) / (frame.fT1 - frame.fT0);
ValT val;
- frame.lerp(SkTPin<float>(rel_t, 0, 1), &val);
+ frame.lerp(ComputeLocalT(t, frame.fT0, frame.fT1, frame.fC0, frame.fC1), &val);
fFunc(fTarget, val.template as<AttrT>());
}
@@ -80,36 +123,19 @@ Animator<ValT, AttrT, NodeT>::Make(const Json::Value& frames,
return nullptr;
SkTArray<KeyframeInterval<ValT>> intervals;
+ intervals.reserve(frames.size());
+
for (const auto& frame : frames) {
if (!frame.isObject())
return nullptr;
- const auto t = ParseScalar(frame["t"], SK_ScalarMin);
- if (t == SK_ScalarMin)
- break;
-
- auto* prev_interval = intervals.empty() ? nullptr : &intervals.back();
- if (prev_interval) {
- if (prev_interval->fT0 >= t) {
- LOG("!! Ignoring out-of-order key frame (t: %f < t: %f)\n", t, prev_interval->fT0);
- continue;
- }
- // Back-fill the prev interval t1.
- prev_interval->fT1 = t;
- }
-
auto& curr_interval = intervals.push_back();
- if (!ValT::Parse(frame["s"], &curr_interval.fV0) ||
- !ValT::Parse(frame["e"], &curr_interval.fV1) ||
- curr_interval.fV0.cardinality() != curr_interval.fV1.cardinality() ||
- (prev_interval &&
- curr_interval.fV0.cardinality() != prev_interval->fV0.cardinality())) {
+ auto* prev_interval = intervals.count() > 1 ? &intervals.fromBack(1) : nullptr;
+ if (!curr_interval.parse(frame, prev_interval)) {
// Invalid frame, or "t"-only frame.
intervals.pop_back();
continue;
}
-
- curr_interval.fT0 = curr_interval.fT1 = t;
}
// If we couldn't determine a t1 for the last interval, discard it.
diff --git a/experimental/skotty/SkottyPriv.h b/experimental/skotty/SkottyPriv.h
index 35b1e847a3..e39994100c 100644
--- a/experimental/skotty/SkottyPriv.h
+++ b/experimental/skotty/SkottyPriv.h
@@ -9,6 +9,7 @@
#define SkottyPriv_DEFINED
#include "SkJSONCPP.h"
+#include "SkPoint.h"
#include "SkScalar.h"
#include "SkString.h"
@@ -36,6 +37,13 @@ static inline bool ParseBool(const Json::Value& v, bool defaultValue) {
? v.asBool() : defaultValue;
}
+static inline SkPoint ParsePoint(const Json::Value& v, const SkPoint& defaultValue) {
+ return v.isObject()
+ ? SkPoint::Make(ParseScalar(v["x"], defaultValue.x()),
+ ParseScalar(v["y"], defaultValue.y()))
+ : defaultValue;
+}
+
} // namespace
#endif // SkottyPriv_DEFINED