diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2020-03-27 11:47:20 +0100 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2020-03-30 07:27:33 +0100 |
commit | 08281b3661547688b19cdaa52d5cf7bbdc171f56 (patch) | |
tree | 7dc52b973bad09f909912baf939765bf0b24ecc4 | |
parent | 62d11afb41e0c3b8a21b4a307cebdfc406ecdf98 (diff) |
Properly stop running animations when using a negative playrate
When reaching a normalized time of 0 they would otherwise continue
to run
Change-Id: Idaea755d3a12f9c9da9c25732c2221e9b3f9f4c7
Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rw-r--r-- | src/animation/backend/animationutils.cpp | 8 | ||||
-rw-r--r-- | src/animation/backend/animationutils_p.h | 12 | ||||
-rw-r--r-- | src/animation/backend/evaluateblendclipanimatorjob.cpp | 2 | ||||
-rw-r--r-- | src/animation/frontend/qclock.cpp | 5 | ||||
-rw-r--r-- | tests/auto/animation/animationutils/tst_animationutils.cpp | 108 |
5 files changed, 126 insertions, 9 deletions
diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 3f386d92a..a5656e230 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -80,7 +80,8 @@ ClipEvaluationData evaluationDataForClip(AnimationClip *clip, animatorData.playbackRate, clip->duration(), animatorData.loopCount, result.currentLoop); result.isFinalFrame = isFinalFrame(result.localTime, clip->duration(), - result.currentLoop, animatorData.loopCount); + result.currentLoop, animatorData.loopCount, + animatorData.playbackRate); const bool hasNormalizedTime = isValidNormalizedTime(animatorData.normalizedLocalTime); result.normalizedLocalTime = hasNormalizedTime ? animatorData.normalizedLocalTime : result.localTime / clip->duration(); @@ -112,9 +113,10 @@ double localTimeFromElapsedTime(double t_current_local, t_local = std::fmod(t_local, duration); // Ensure we clamp to end of final loop - if (int(loopNumber) == loopCount) { + + if (int(loopNumber) == loopCount || int(loopNumber) < 0) { loopNumber = loopCount - 1; - t_local = duration; + t_local = playbackRate >= 0.0 ? duration : 0.0; } } diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 8c71e704a..0501d9598 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -318,11 +318,15 @@ AnimatorEvaluationData evaluationDataForAnimator(Animator animator, inline bool isFinalFrame(double localTime, double duration, int currentLoop, - int loopCount) + int loopCount, + double playbackRate) { - return (localTime >= duration && - loopCount != 0 && - currentLoop >= loopCount - 1); + // We must be on the final loop and + // - if playing forward, localTime must be equal or above the duration + // - if playing backward, localTime must be equal or below 0 + if (playbackRate >= 0.0) + return (loopCount != 0 && currentLoop >= loopCount - 1 && localTime >= duration); + return (loopCount != 0 && currentLoop <= 0 && localTime <= 0); } inline bool isValidNormalizedTime(float t) diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index 765531902..8a5f1e533 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -129,7 +129,7 @@ void EvaluateBlendClipAnimatorJob::run() blendedClipAnimator->setCurrentLoop(animatorData.currentLoop); // Prepare the change record - const bool finalFrame = isFinalFrame(localTime, duration, animatorData.currentLoop, animatorData.loopCount); + const bool finalFrame = isFinalFrame(localTime, duration, animatorData.currentLoop, animatorData.loopCount, animatorData.playbackRate); const QVector<MappingData> mappingData = blendedClipAnimator->mappingData(); auto record = prepareAnimationRecord(blendedClipAnimator->peerId(), mappingData, diff --git a/src/animation/frontend/qclock.cpp b/src/animation/frontend/qclock.cpp index f38c21807..519edd388 100644 --- a/src/animation/frontend/qclock.cpp +++ b/src/animation/frontend/qclock.cpp @@ -63,7 +63,10 @@ QClock::~QClock() /*! \property Qt3DAnimation::QClock::playbackRate - The playback speed of the animation. + The playback speed of the animation. The playback speed can be negative. + When that is the case the animation will be played back from the current + normalized time value back to 0 and for the number of loops it had been + played for with a positive playback rate. */ double QClock::playbackRate() const diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index b19d74a25..76909d124 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -2059,6 +2059,114 @@ private Q_SLOTS: QTest::newRow("clip1.json, elapsedTime = duration + 1, loops = 2, current_loop = 1") << handler << clip << animatorData << clipData; } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = clip->duration(); + const int loops = 1; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + animator->setCurrentLoop(1); + clipData.currentLoop = animator->currentLoop(); + const qint64 elapsedTimeNS = toNsecs(clip->duration() * 0.5); // +1 to ensure beyond end of clip + + Clock clock; + clock.setPlaybackRate(-1.0); + + animatorData = evaluationDataForAnimator(animator, &clock, elapsedTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime, + animatorData.elapsedTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = false; + + QTest::newRow("clip1.json, elapsedTime = duration / 2, loops = 1, current_loop = 1, playback_rate = -1") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = clip->duration(); + const int loops = 1; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + animator->setCurrentLoop(1); + clipData.currentLoop = animator->currentLoop(); + const qint64 elapsedTimeNS = toNsecs(clip->duration() + 1); // +1 to ensure beyond end of clip + + Clock clock; + clock.setPlaybackRate(-1.0); + + animatorData = evaluationDataForAnimator(animator, &clock, elapsedTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime, + animatorData.elapsedTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = true; + + QTest::newRow("clip1.json, elapsedTime = duration + 1, loops = 1, current_loop = 1, playback_rate = -1") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = clip->duration(); + const int loops = 2; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + animator->setCurrentLoop(0); + clipData.currentLoop = animator->currentLoop(); + const qint64 elapsedTimeNS = toNsecs(clip->duration() + 1); // +1 to ensure beyond end of clip + + Clock clock; + clock.setPlaybackRate(-1.0); + + animatorData = evaluationDataForAnimator(animator, &clock, elapsedTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime, + animatorData.elapsedTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = true; + + QTest::newRow("clip1.json, elapsedTime = duration + 1, loops = 2, current_loop = 0, playback_rate = -1") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = clip->duration(); + const int loops = 2; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + animator->setCurrentLoop(1); + clipData.currentLoop = animator->currentLoop(); + const qint64 elapsedTimeNS = toNsecs(clip->duration() * 2.0 + 1); // +1 to ensure beyond end of clip + + Clock clock; + clock.setPlaybackRate(-1.0); + + animatorData = evaluationDataForAnimator(animator, &clock, elapsedTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime, + animatorData.elapsedTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = true; + + QTest::newRow("clip1.json, elapsedTime = duration + 1, loops = 2, current_loop = 1, playback_rate = -1") + << handler << clip << animatorData << clipData; + } } void checkEvaluationDataForClip() |