diff --git a/src/Magnum/Animation/Player.h b/src/Magnum/Animation/Player.h index 7e40ac817..abe459e03 100644 --- a/src/Magnum/Animation/Player.h +++ b/src/Magnum/Animation/Player.h @@ -112,13 +112,19 @@ interpolated value changes, which is useful for triggering other events. See @ref addRawCallback() that allows for greater control and further performance optimizations. See its documentation for a usage example code snippet. -By default, the @ref duration() of an animation is calculated implicitly from -all added tracks. You can use @ref setDuration() to specify a custom duration ---- if it extends beyond the keyframe values, values of begin/end keyframes -will be extrapolated according to @ref Extrapolation specified for every track; -if it will be shorter, only a slice of the animation will be played. The -animation is implicitly played only once, use @ref setPlayCount() to set a -number of repeats or make it repeat indefinitely. +The animation is implicitly played only once, use @ref setPlayCount() to set a +number of repeats or make it repeat indefinitely. By default, the +@ref duration() of an animation is calculated implicitly from all added tracks. +You can use @ref setDuration() to specify a custom duration: + +- If it extends beyond the keyframe values, values of begin/end keyframes + will be extrapolated according to @ref Extrapolation specified for every + track. +- If it will be shorter, only a slice of the animation will be played. +- If duration size is empty (min and and max se to the same value) and + @ref setPlayCount() is set to inifite, then the animator will indefinitely + give out value from a key that's at the start of the duration. If play + count is finite, the animation will get stopped right away. @section Animation-Player-playback Animation playback @@ -239,7 +245,8 @@ template(*Scaler)(T, K); diff --git a/src/Magnum/Animation/Player.hpp b/src/Magnum/Animation/Player.hpp index 32cf072e9..9148f682c 100644 --- a/src/Magnum/Animation/Player.hpp +++ b/src/Magnum/Animation/Player.hpp @@ -164,16 +164,29 @@ template Player& Player::advance(T time) { the future, do nothing */ } else if(_state != State::Playing || time < _startTime) return *this; - /* Calculate current play iteration and key value in that iteration. If we - exceeded play count, stop the animation and give out value at duration - end. */ - UnsignedInt playCount; + /* If the player duration is empty, we can't call the scaler. If play count + is infinite, infinitely advance to a key at duration start. If not, stop + the animation. */ K key; - std::tie(playCount, key) = _scaler(timeToUse - _startTime, _duration.size()[0]); - if(_playCount && playCount >= _playCount) { - _state = State::Stopped; - _startTime = {}; - key = _duration.size()[0]; + const K duration = _duration.size()[0]; + if(duration == K{}) { + key = K{}; + if(_playCount != 0) { + _state = State::Stopped; + _startTime = {}; + } + + /* Otherwise calculate current play iteration and key value in that + iteration. If we exceeded play count, stop the animation and give out + value at duration end. */ + } else { + UnsignedInt playCount; + std::tie(playCount, key) = _scaler(timeToUse - _startTime, duration); + if(_playCount && playCount >= _playCount) { + _state = State::Stopped; + _startTime = {}; + key = duration; + } } /* Advance all tracks. Properly handle durations that don't start at 0. */ diff --git a/src/Magnum/Animation/Test/PlayerTest.cpp b/src/Magnum/Animation/Test/PlayerTest.cpp index 5a8ac5133..9233a83a6 100644 --- a/src/Magnum/Animation/Test/PlayerTest.cpp +++ b/src/Magnum/Animation/Test/PlayerTest.cpp @@ -54,6 +54,8 @@ struct PlayerTest: TestSuite::Tester { void advancePlayCount(); void advancePlayCountInfinite(); void advanceChrono(); + void advanceZeroDuration(); + void advanceZeroDurationChrono(); void setState(); @@ -108,6 +110,8 @@ PlayerTest::PlayerTest() { &PlayerTest::advancePlayCount, &PlayerTest::advancePlayCountInfinite, &PlayerTest::advanceChrono, + &PlayerTest::advanceZeroDuration, + &PlayerTest::advanceZeroDurationChrono, &PlayerTest::setState, @@ -560,6 +564,55 @@ void PlayerTest::advanceChrono() { CORRADE_COMPARE(value, 4.0f); } +void PlayerTest::advanceZeroDuration() { + Float value = -1.0f; + Player player; + player.add(Track, value) + /* 1.75 secs since the start of the original duration */ + .setDuration(Range1D::fromSize(1.0f + 1.75f, 0.0f)) + .setPlayCount(0) + .play(2.0f); + + CORRADE_COMPARE(player.duration().size(), 0.0f); + CORRADE_COMPARE(player.state(), State::Playing); + CORRADE_COMPARE(value, -1.0f); + + /* Still before starting time, nothing is done */ + player.advance(1.75f); + CORRADE_COMPARE(player.state(), State::Playing); + CORRADE_COMPARE(value, -1.0f); + + /* After that, the value at 1.75 secs is returned independent of time */ + player.advance(100.0f); + CORRADE_COMPARE(player.state(), State::Playing); + CORRADE_COMPARE(value, 4.0f); +} + +void PlayerTest::advanceZeroDurationChrono() { + Float value = -1.0f; + Player player; + player.add(Track, value) + /* 1.75 secs since the start of the original duration */ + .setDuration(Range1D::fromSize(1.0f + 1.75f, 0.0f)) + .setPlayCount(0) + .play(std::chrono::seconds{2}); + + CORRADE_COMPARE(player.duration().size(), 0.0f); + CORRADE_COMPARE(player.state(), State::Playing); + CORRADE_COMPARE(value, -1.0f); + + /* Still before starting time, nothing is done */ + player.advance(std::chrono::milliseconds{1750}); + CORRADE_COMPARE(player.state(), State::Playing); + CORRADE_COMPARE(value, -1.0f); + + /* After that, the value at 1.75 seconds is returned independent of the + time */ + player.advance(std::chrono::seconds{100}); + CORRADE_COMPARE(player.state(), State::Playing); + CORRADE_COMPARE(value, 4.0f); +} + void PlayerTest::setState() { Player player; CORRADE_COMPARE(player.state(), State::Stopped);