1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2020 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "modules/skottie/src/animator/KeyframeAnimator.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "modules/skottie/src/SkottieJson.h" 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#define DUMP_KF_RECORDS 0 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_cinamespace skottie::internal { 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ciKeyframeAnimator::~KeyframeAnimator() = default; 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ciKeyframeAnimator::LERPInfo KeyframeAnimator::getLERPInfo(float t) const { 19cb93a386Sopenharmony_ci SkASSERT(!fKFs.empty()); 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci if (t <= fKFs.front().t) { 22cb93a386Sopenharmony_ci // Constant/clamped segment. 23cb93a386Sopenharmony_ci return { 0, fKFs.front().v, fKFs.front().v }; 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci if (t >= fKFs.back().t) { 26cb93a386Sopenharmony_ci // Constant/clamped segment. 27cb93a386Sopenharmony_ci return { 0, fKFs.back().v, fKFs.back().v }; 28cb93a386Sopenharmony_ci } 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci // Cache the current segment (most queries have good locality). 31cb93a386Sopenharmony_ci if (!fCurrentSegment.contains(t)) { 32cb93a386Sopenharmony_ci fCurrentSegment = this->find_segment(t); 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci SkASSERT(fCurrentSegment.contains(t)); 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci if (fCurrentSegment.kf0->mapping == Keyframe::kConstantMapping) { 37cb93a386Sopenharmony_ci // Constant/hold segment. 38cb93a386Sopenharmony_ci return { 0, fCurrentSegment.kf0->v, fCurrentSegment.kf0->v }; 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci return { 42cb93a386Sopenharmony_ci this->compute_weight(fCurrentSegment, t), 43cb93a386Sopenharmony_ci fCurrentSegment.kf0->v, 44cb93a386Sopenharmony_ci fCurrentSegment.kf1->v, 45cb93a386Sopenharmony_ci }; 46cb93a386Sopenharmony_ci} 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ciKeyframeAnimator::KFSegment KeyframeAnimator::find_segment(float t) const { 49cb93a386Sopenharmony_ci SkASSERT(fKFs.size() > 1); 50cb93a386Sopenharmony_ci SkASSERT(t > fKFs.front().t); 51cb93a386Sopenharmony_ci SkASSERT(t < fKFs.back().t); 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci auto kf0 = &fKFs.front(), 54cb93a386Sopenharmony_ci kf1 = &fKFs.back(); 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci // Binary-search, until we reduce to sequential keyframes. 57cb93a386Sopenharmony_ci while (kf0 + 1 != kf1) { 58cb93a386Sopenharmony_ci SkASSERT(kf0 < kf1); 59cb93a386Sopenharmony_ci SkASSERT(kf0->t <= t && t < kf1->t); 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci const auto mid_kf = kf0 + (kf1 - kf0) / 2; 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci if (t >= mid_kf->t) { 64cb93a386Sopenharmony_ci kf0 = mid_kf; 65cb93a386Sopenharmony_ci } else { 66cb93a386Sopenharmony_ci kf1 = mid_kf; 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci return {kf0, kf1}; 71cb93a386Sopenharmony_ci} 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_cifloat KeyframeAnimator::compute_weight(const KFSegment &seg, float t) const { 74cb93a386Sopenharmony_ci SkASSERT(seg.contains(t)); 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci // Linear weight. 77cb93a386Sopenharmony_ci auto w = (t - seg.kf0->t) / (seg.kf1->t - seg.kf0->t); 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci // Optional cubic mapper. 80cb93a386Sopenharmony_ci if (seg.kf0->mapping >= Keyframe::kCubicIndexOffset) { 81cb93a386Sopenharmony_ci const auto mapper_index = SkToSizeT(seg.kf0->mapping - Keyframe::kCubicIndexOffset); 82cb93a386Sopenharmony_ci w = fCMs[mapper_index].computeYFromX(w); 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci return w; 86cb93a386Sopenharmony_ci} 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ciAnimatorBuilder::~AnimatorBuilder() = default; 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_cibool AnimatorBuilder::parseKeyframes(const AnimationBuilder& abuilder, 91cb93a386Sopenharmony_ci const skjson::ArrayValue& jkfs) { 92cb93a386Sopenharmony_ci // Keyframe format: 93cb93a386Sopenharmony_ci // 94cb93a386Sopenharmony_ci // [ // array of 95cb93a386Sopenharmony_ci // { 96cb93a386Sopenharmony_ci // "t": <float> // keyframe time 97cb93a386Sopenharmony_ci // "s": <T> // keyframe value 98cb93a386Sopenharmony_ci // "h": <bool> // optional constant/hold keyframe marker 99cb93a386Sopenharmony_ci // "i": [<float,float>] // optional "in" Bezier control point 100cb93a386Sopenharmony_ci // "o": [<float,float>] // optional "out" Bezier control point 101cb93a386Sopenharmony_ci // }, 102cb93a386Sopenharmony_ci // ... 103cb93a386Sopenharmony_ci // ] 104cb93a386Sopenharmony_ci // 105cb93a386Sopenharmony_ci // Legacy keyframe format: 106cb93a386Sopenharmony_ci // 107cb93a386Sopenharmony_ci // [ // array of 108cb93a386Sopenharmony_ci // { 109cb93a386Sopenharmony_ci // "t": <float> // keyframe time 110cb93a386Sopenharmony_ci // "s": <T> // keyframe start value 111cb93a386Sopenharmony_ci // "e": <T> // keyframe end value 112cb93a386Sopenharmony_ci // "h": <bool> // optional constant/hold keyframe marker (constant mapping) 113cb93a386Sopenharmony_ci // "i": [<float,float>] // optional "in" Bezier control point (cubic mapping) 114cb93a386Sopenharmony_ci // "o": [<float,float>] // optional "out" Bezier control point (cubic mapping) 115cb93a386Sopenharmony_ci // }, 116cb93a386Sopenharmony_ci // ... 117cb93a386Sopenharmony_ci // { 118cb93a386Sopenharmony_ci // "t": <float> // last keyframe only specifies a t 119cb93a386Sopenharmony_ci // // the value is prev. keyframe end value 120cb93a386Sopenharmony_ci // } 121cb93a386Sopenharmony_ci // ] 122cb93a386Sopenharmony_ci // 123cb93a386Sopenharmony_ci // Note: the legacy format contains duplicates, as normal frames are contiguous: 124cb93a386Sopenharmony_ci // frame(n).e == frame(n+1).s 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci const auto parse_value = [&](const skjson::ObjectValue& jkf, size_t i, Keyframe::Value* v) { 127cb93a386Sopenharmony_ci auto parsed = this->parseKFValue(abuilder, jkf, jkf["s"], v); 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci // A missing value is only OK for the last legacy KF 130cb93a386Sopenharmony_ci // (where it is pulled from prev KF 'end' value). 131cb93a386Sopenharmony_ci if (!parsed && i > 0 && i == jkfs.size() - 1) { 132cb93a386Sopenharmony_ci const skjson::ObjectValue* prev_kf = jkfs[i - 1]; 133cb93a386Sopenharmony_ci SkASSERT(prev_kf); 134cb93a386Sopenharmony_ci parsed = this->parseKFValue(abuilder, jkf, (*prev_kf)["e"], v); 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci return parsed; 138cb93a386Sopenharmony_ci }; 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci bool constant_value = true; 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci fKFs.reserve(jkfs.size()); 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_ci for (size_t i = 0; i < jkfs.size(); ++i) { 145cb93a386Sopenharmony_ci const skjson::ObjectValue* jkf = jkfs[i]; 146cb93a386Sopenharmony_ci if (!jkf) { 147cb93a386Sopenharmony_ci return false; 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci float t; 151cb93a386Sopenharmony_ci if (!Parse<float>((*jkf)["t"], &t)) { 152cb93a386Sopenharmony_ci return false; 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci Keyframe::Value v; 156cb93a386Sopenharmony_ci if (!parse_value(*jkf, i, &v)) { 157cb93a386Sopenharmony_ci return false; 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci if (i > 0) { 161cb93a386Sopenharmony_ci auto& prev_kf = fKFs.back(); 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci // Ts must be strictly monotonic. 164cb93a386Sopenharmony_ci if (t <= prev_kf.t) { 165cb93a386Sopenharmony_ci return false; 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci // We can power-reduce the mapping of repeated values (implicitly constant). 169cb93a386Sopenharmony_ci if (v.equals(prev_kf.v, keyframe_type)) { 170cb93a386Sopenharmony_ci prev_kf.mapping = Keyframe::kConstantMapping; 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci } 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci fKFs.push_back({t, v, this->parseMapping(*jkf)}); 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci constant_value = constant_value && (v.equals(fKFs.front().v, keyframe_type)); 177cb93a386Sopenharmony_ci } 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci SkASSERT(fKFs.size() == jkfs.size()); 180cb93a386Sopenharmony_ci fCMs.shrink_to_fit(); 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_ci if (constant_value) { 183cb93a386Sopenharmony_ci // When all keyframes hold the same value, we can discard all but one 184cb93a386Sopenharmony_ci // (interpolation has no effect). 185cb93a386Sopenharmony_ci fKFs.resize(1); 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci#if(DUMP_KF_RECORDS) 189cb93a386Sopenharmony_ci SkDEBUGF("Animator[%p], values: %lu, KF records: %zu\n", 190cb93a386Sopenharmony_ci this, fKFs.back().v_idx + 1, fKFs.size()); 191cb93a386Sopenharmony_ci for (const auto& kf : fKFs) { 192cb93a386Sopenharmony_ci SkDEBUGF(" { t: %1.3f, v_idx: %lu, mapping: %lu }\n", kf.t, kf.v_idx, kf.mapping); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci#endif 195cb93a386Sopenharmony_ci return true; 196cb93a386Sopenharmony_ci} 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ciuint32_t AnimatorBuilder::parseMapping(const skjson::ObjectValue& jkf) { 199cb93a386Sopenharmony_ci if (ParseDefault(jkf["h"], false)) { 200cb93a386Sopenharmony_ci return Keyframe::kConstantMapping; 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci SkPoint c0, c1; 204cb93a386Sopenharmony_ci if (!Parse(jkf["o"], &c0) || 205cb93a386Sopenharmony_ci !Parse(jkf["i"], &c1) || 206cb93a386Sopenharmony_ci SkCubicMap::IsLinear(c0, c1)) { 207cb93a386Sopenharmony_ci return Keyframe::kLinearMapping; 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci // De-dupe sequential cubic mappers. 211cb93a386Sopenharmony_ci if (c0 != prev_c0 || c1 != prev_c1 || fCMs.empty()) { 212cb93a386Sopenharmony_ci fCMs.emplace_back(c0, c1); 213cb93a386Sopenharmony_ci prev_c0 = c0; 214cb93a386Sopenharmony_ci prev_c1 = c1; 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci SkASSERT(!fCMs.empty()); 218cb93a386Sopenharmony_ci return SkToU32(fCMs.size()) - 1 + Keyframe::kCubicIndexOffset; 219cb93a386Sopenharmony_ci} 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci} // namespace skottie::internal 222