From 4127f4ce7abc37ad90b592eb448d44a97bfc69a3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 22 Aug 2023 11:28:56 +0900 Subject: [PATCH] loader/lottie: revised the key-frame searching Replace the linear search algorithm with binary-search. The performance enhancement may not yield significant benefits in normal cases. However, it becomes crucial if the animation comprises an extensive number of frames... --- src/loaders/lottie/tvgLottieProperty.h | 135 ++++++++++++++++--------- 1 file changed, 87 insertions(+), 48 deletions(-) diff --git a/src/loaders/lottie/tvgLottieProperty.h b/src/loaders/lottie/tvgLottieProperty.h index 947d2495..bc537ece 100644 --- a/src/loaders/lottie/tvgLottieProperty.h +++ b/src/loaders/lottie/tvgLottieProperty.h @@ -183,12 +183,19 @@ struct LottieProperty if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value; if (frameNo >= frames->last().no) return frames->last().value; - for (auto frame = frames->data + 1; frame < frames->end(); ++frame) { - if (frameNo > frame->no) continue; + uint32_t low = 1; + uint32_t high = frames->count - 1; + + while (low <= high) { + auto mid = low + (high - low) / 2; + auto frame = frames->data + mid; if (frameNo == frame->no) return frame->value; - return (frame - 1)->interpolate(frame, frameNo); + else if (frameNo > frame->no) low = mid + 1; + else high = mid - 1; } - return value; + + auto frame = frames->data + low; + return (frame - 1)->interpolate(frame, frameNo); } float angle(int32_t frameNo) { return 0; } @@ -258,29 +265,38 @@ struct LottiePathSet return true; } - for (auto frame = frames->data + 1; frame < frames->end(); ++frame) { - if (frameNo > frame->no) continue; + uint32_t low = 1; + uint32_t high = frames->count - 1; + + while (low <= high) { + auto mid = low + (high - low) / 2; + auto frame = frames->data + mid; if (frameNo == frame->no) { copy(frame->value, cmds); copy(frame->value, pts); return true; + } else if (frameNo > frame->no) { + low = mid + 1; + } else { + high = mid - 1; } - //interpolate - auto pframe = frame - 1; - copy(pframe->value, cmds); - - auto t = float(frameNo - pframe->no) / float(frame->no - pframe->no); - if (pframe->interpolator) t = pframe->interpolator->progress(t); - - auto s = pframe->value.pts; - auto e = frame->value.pts; - - for (auto i = 0; i < pframe->value.ptsCnt; ++i, ++s, ++e) { - pts.push(mathLerp(*s, *e, t)); - } - return true; } - return false; + + //interpolate + auto frame = frames->data + low; + auto pframe = frame - 1; + copy(pframe->value, cmds); + + auto t = float(frameNo - pframe->no) / float(frame->no - pframe->no); + if (pframe->interpolator) t = pframe->interpolator->progress(t); + + auto s = pframe->value.pts; + auto e = frame->value.pts; + + for (auto i = 0; i < pframe->value.ptsCnt; ++i, ++s, ++e) { + pts.push(mathLerp(*s, *e, t)); + } + return true; } void prepare() {} @@ -340,34 +356,43 @@ struct LottieColorStop return; } - for (auto frame = frames->data + 1; frame < frames->end(); ++frame) { - if (frameNo > frame->no) continue; + uint32_t low = 1; + uint32_t high = frames->count - 1; + + while (low <= high) { + auto mid = low + (high - low) / 2; + auto frame = frames->data + mid; if (frameNo == frame->no) { fill->colorStops(frame->value.data, count); return; + } else if (frameNo > frame->no) { + low = mid + 1; + } else { + high = mid - 1; } + } - //interpolate - auto pframe = frame - 1; - auto t = float(frameNo - pframe->no) / float(frame->no - pframe->no); - if (pframe->interpolator) t = pframe->interpolator->progress(t); + //interpolate + auto frame = frames->data + low; + auto pframe = frame - 1; + auto t = float(frameNo - pframe->no) / float(frame->no - pframe->no); + if (pframe->interpolator) t = pframe->interpolator->progress(t); - auto s = pframe->value.data; - auto e = frame->value.data; + auto s = pframe->value.data; + auto e = frame->value.data; - Array result; + Array result; - for (auto i = 0; i < count; ++i, ++s, ++e) { - auto offset = mathLerp(s->offset, e->offset, t); - auto r = mathLerp(s->r, e->r, t); - auto g = mathLerp(s->g, e->g, t); - auto b = mathLerp(s->b, e->b, t); - result.push({offset, r, g, b, 255}); - } - fill->colorStops(result.data, count); - return; - } + for (auto i = 0; i < count; ++i, ++s, ++e) { + auto offset = mathLerp(s->offset, e->offset, t); + auto r = mathLerp(s->r, e->r, t); + auto g = mathLerp(s->g, e->g, t); + auto b = mathLerp(s->b, e->b, t); + result.push({offset, r, g, b, 255}); + } + fill->colorStops(result.data, count); } + void prepare() {} }; @@ -409,12 +434,19 @@ struct LottiePosition if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value; if (frameNo >= frames->last().no) return frames->last().value; - for (auto frame = frames->data + 1; frame < frames->end(); ++frame) { - if (frameNo > frame->no) continue; + uint32_t low = 1; + uint32_t high = frames->count - 1; + + while (low <= high) { + auto mid = low + (high - low) / 2; + auto frame = frames->data + mid; if (frameNo == frame->no) return frame->value; - return (frame - 1)->interpolate(frame, frameNo); + else if (frameNo > frame->no) low = mid + 1; + else high = mid - 1; } - return value; + + auto frame = frames->data + low; + return (frame - 1)->interpolate(frame, frameNo); } float angle(int32_t frameNo) @@ -423,11 +455,18 @@ struct LottiePosition if (frames->count == 1 || frameNo <= frames->first().no) return 0; if (frameNo >= frames->last().no) return 0; - for (auto frame = frames->data + 1; frame < frames->end(); ++frame) { - if (frameNo > frame->no) continue; - return (frame - 1)->angle(frame, frameNo); + uint32_t low = 1; + uint32_t high = frames->count - 1; + + while (low <= high) { + auto mid = low + (high - low) / 2; + auto frame = frames->data + mid; + if (frameNo > frame->no) low = mid + 1; + else high = mid - 1; } - return 0; + + auto frame = frames->data + low; + return (frame - 1)->angle(frame, frameNo); } void prepare()