diff --git a/modules/skottie/src/animator/Vec2KeyframeAnimator.cpp b/modules/skottie/src/animator/Vec2KeyframeAnimator.cpp index 7907203156..6b90fc2d76 100644 --- a/modules/skottie/src/animator/Vec2KeyframeAnimator.cpp +++ b/modules/skottie/src/animator/Vec2KeyframeAnimator.cpp @@ -55,11 +55,6 @@ public: private: void backfill_spatial(const SpatialValue& val) { - if (fTi == SkV2{0,0} && fTo == SkV2{0,0}) { - // no tangents => linear - return; - } - SkASSERT(!fValues.empty()); auto& prev_val = fValues.back(); SkASSERT(!prev_val.cmeasure); @@ -110,13 +105,16 @@ public: return false; } - this->backfill_spatial(val); + if (fPendingSpatial) { + this->backfill_spatial(val); + } // Track the last keyframe spatial tangents (checked on next parseValue). - fTi = ParseDefault(jkf["ti"], {0,0}); - fTo = ParseDefault(jkf["to"], {0,0}); + fTi = ParseDefault(jkf["ti"], {0,0}); + fTo = ParseDefault(jkf["to"], {0,0}); + fPendingSpatial = fTi != SkV2{0,0} || fTo != SkV2{0,0}; - if (fValues.empty() || val.v2 != fValues.back().v2) { + if (fValues.empty() || val.v2 != fValues.back().v2 || fPendingSpatial) { fValues.push_back(std::move(val)); } @@ -130,6 +128,7 @@ public: float* fRotTarget; // optional SkV2 fTi{0,0}, fTo{0,0}; + bool fPendingSpatial = false; }; private: @@ -155,7 +154,33 @@ private: } StateChanged onSeek(float t) override { - const auto& lerp_info = this->getLERPInfo(t); + auto get_lerp_info = [this](float t) { + auto lerp_info = this->getLERPInfo(t); + + // When tracking rotation/orientation, the last keyframe requires special handling: + // it doesn't store any spatial information but it is expected to maintain the + // previous orientation (per AE semantics). + // + // The easiest way to achieve this is to actually swap with the previous keyframe, + // with an adjusted weight of 1. + const auto vidx = lerp_info.vrec0.idx; + if (fRotTarget && vidx == fValues.size() - 1 && vidx > 0) { + SkASSERT(!fValues[vidx].cmeasure); + SkASSERT(lerp_info.vrec1.idx == vidx); + + // Change LERPInfo{0, SIZE - 1, SIZE - 1} + // to LERPInfo{1, SIZE - 2, SIZE - 1} + lerp_info.weight = 1; + lerp_info.vrec0 = {vidx - 1}; + + // This yields equivalent lerp results because keyframed values are contiguous + // i.e frame[n-1].end_val == frame[n].start_val. + } + + return lerp_info; + }; + + const auto lerp_info = get_lerp_info(t); const auto& v0 = fValues[lerp_info.vrec0.idx]; if (v0.cmeasure) { diff --git a/resources/skottie/skottie-auto-orient-2.json b/resources/skottie/skottie-auto-orient-2.json new file mode 100644 index 0000000000..b3f3024f66 --- /dev/null +++ b/resources/skottie/skottie-auto-orient-2.json @@ -0,0 +1 @@ +{"assets":[{"id":"comp_0","layers":[{"ao":0,"bm":0,"ddd":0,"ind":1,"ip":0,"ks":{"a":{"a":0,"ix":1,"k":[0,0,0]},"o":{"a":0,"ix":11,"k":100},"p":{"a":0,"ix":2,"k":[250,250,0]},"r":{"a":0,"ix":10,"k":0},"s":{"a":0,"ix":6,"k":[100,100,100]}},"nm":"Shape Layer 1","op":601,"shapes":[{"bm":0,"cix":2,"hd":false,"it":[{"d":1,"hd":false,"ir":{"a":0,"ix":6,"k":5},"is":{"a":0,"ix":8,"k":0},"ix":1,"mn":"ADBE Vector Shape - Star","nm":"Polystar Path 1","or":{"a":0,"ix":7,"k":10},"os":{"a":0,"ix":9,"k":0},"p":{"a":0,"ix":4,"k":[0,0]},"pt":{"a":0,"ix":3,"k":3},"r":{"a":0,"ix":5,"k":-30},"sy":1,"ty":"sr"},{"bm":0,"c":{"a":0,"ix":4,"k":[1,0,0,1]},"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","o":{"a":0,"ix":5,"k":100},"r":1,"ty":"fl"},{"a":{"a":0,"ix":1,"k":[0,0]},"nm":"Transform","o":{"a":0,"ix":7,"k":100},"p":{"a":0,"ix":2,"k":[0,0]},"r":{"a":0,"ix":6,"k":0},"s":{"a":0,"ix":3,"k":[100,100]},"sa":{"a":0,"ix":5,"k":0},"sk":{"a":0,"ix":4,"k":0},"ty":"tr"}],"ix":1,"mn":"ADBE Vector Group","nm":"Group 1","np":2,"ty":"gr"},{"bm":0,"cix":2,"hd":false,"it":[{"d":1,"hd":false,"ir":{"a":0,"ix":6,"k":10},"is":{"a":0,"ix":8,"k":0},"ix":1,"mn":"ADBE Vector Shape - Star","nm":"Polystar Path 1","or":{"a":0,"ix":7,"k":20},"os":{"a":0,"ix":9,"k":0},"p":{"a":0,"ix":4,"k":[-10,0]},"pt":{"a":0,"ix":3,"k":3},"r":{"a":0,"ix":5,"k":-30},"sy":1,"ty":"sr"},{"bm":0,"c":{"a":0,"ix":4,"k":[0,0.98059129715,0.110340073705,1]},"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","o":{"a":0,"ix":5,"k":100},"r":1,"ty":"fl"},{"a":{"a":0,"ix":1,"k":[0,0]},"nm":"Transform","o":{"a":0,"ix":7,"k":100},"p":{"a":0,"ix":2,"k":[0,0]},"r":{"a":0,"ix":6,"k":0},"s":{"a":0,"ix":3,"k":[100,100]},"sa":{"a":0,"ix":5,"k":0},"sk":{"a":0,"ix":4,"k":0},"ty":"tr"}],"ix":2,"mn":"ADBE Vector Group","nm":"Group 2","np":2,"ty":"gr"}],"sr":1,"st":0,"ty":4}]}],"ddd":0,"fr":60,"h":500,"ip":0,"layers":[{"ao":1,"bm":0,"ddd":0,"h":500,"ind":1,"ip":0,"ks":{"a":{"a":0,"ix":1,"k":[250,250,0]},"o":{"a":0,"ix":11,"k":100},"p":{"a":1,"ix":2,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"s":[50,350,0],"t":0,"ti":[0,0,0],"to":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"s":[50,350,0],"t":60,"ti":[-50,41.667,0],"to":[50,-41.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"s":[350,100,0],"t":180,"ti":[0,0,0],"to":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"s":[350,100,0],"t":240,"ti":[389.833,130,0],"to":[295.167,113,0]},{"s":[50,350,0],"t":360}]},"r":{"a":0,"ix":10,"k":0},"s":{"a":0,"ix":6,"k":[100,100,100]}},"nm":"precomp","op":601,"refId":"comp_0","sr":1,"st":0,"ty":0,"w":500},{"ao":0,"bm":0,"ddd":0,"ind":2,"ip":0,"ks":{"a":{"a":0,"ix":1,"k":[0,0,0]},"o":{"a":0,"ix":11,"k":100},"p":{"a":0,"ix":2,"k":[250,250,0]},"r":{"a":0,"ix":10,"k":0},"s":{"a":0,"ix":6,"k":[100,100,100]}},"nm":"Shape Layer 1","op":421,"shapes":[{"hd":false,"ind":0,"ix":1,"ks":{"a":0,"ix":2,"k":{"c":false,"i":[[0,0],[-74.001,62.595],[52.868,-132.17],[175,59]],"o":[[74,-62.468],[0,0],[-40,100],[-116.558,-39.297]],"v":[[-201,101],[98,-148],[231,36],[-201,101]]}},"mn":"ADBE Vector Shape - Group","nm":"Path 1","ty":"sh"},{"bm":0,"c":{"a":0,"ix":3,"k":[0,0,0,1]},"hd":false,"lc":1,"lj":1,"ml":4,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","o":{"a":0,"ix":4,"k":100},"ty":"st","w":{"a":0,"ix":5,"k":2}}],"sr":1,"st":0,"ty":4},{"ao":0,"bm":0,"ddd":0,"ind":3,"ip":0,"ks":{"a":{"a":0,"ix":1,"k":[250,250,0]},"o":{"a":0,"ix":11,"k":100},"p":{"a":0,"ix":2,"k":[250,250,0]},"r":{"a":0,"ix":10,"k":0},"s":{"a":0,"ix":6,"k":[100,100,100]}},"nm":"White Solid 1","op":421,"sc":"#ffffff","sh":500,"sr":1,"st":0,"sw":500,"ty":1}],"markers":[],"nm":"tricky cases","op":421,"v":"5.7.0","w":500} \ No newline at end of file