mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
775 lines
24 KiB
775 lines
24 KiB
|
8 years ago
|
/*
|
||
|
|
This file is part of Magnum.
|
||
|
|
|
||
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
||
|
|
|
||
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
|
copy of this software and associated documentation files (the "Software"),
|
||
|
|
to deal in the Software without restriction, including without limitation
|
||
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
||
|
|
Software is furnished to do so, subject to the following conditions:
|
||
|
|
|
||
|
|
The above copyright notice and this permission notice shall be included
|
||
|
|
in all copies or substantial portions of the Software.
|
||
|
|
|
||
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
|
DEALINGS IN THE SOFTWARE.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <sstream>
|
||
|
|
#include <Corrade/TestSuite/Tester.h>
|
||
|
|
#include <Corrade/TestSuite/Compare/Numeric.h>
|
||
|
|
|
||
|
|
#include "Magnum/Animation/Player.h"
|
||
|
|
|
||
|
|
namespace Magnum { namespace Animation { namespace Test {
|
||
|
|
|
||
|
|
struct PlayerTest: TestSuite::Tester {
|
||
|
|
explicit PlayerTest();
|
||
|
|
|
||
|
|
void constructEmpty();
|
||
|
|
void construct();
|
||
|
|
void constructChrono();
|
||
|
|
void constructCopy();
|
||
|
|
void constructMove();
|
||
|
|
|
||
|
|
void setDurationExtend();
|
||
|
|
void setDurationReplace();
|
||
|
|
|
||
|
|
void trackInvalidIndex();
|
||
|
|
|
||
|
|
void advanceNotRunning();
|
||
|
|
void advancePlaying();
|
||
|
|
void advanceRestart();
|
||
|
|
void advanceStop();
|
||
|
|
void advancePauseResume();
|
||
|
|
void advancePauseStop();
|
||
|
|
void advancePlayCount();
|
||
|
|
void advancePlayCountInfinite();
|
||
|
|
void advanceChrono();
|
||
|
|
|
||
|
|
void setState();
|
||
|
|
|
||
|
|
void add();
|
||
|
|
void addWithCallback();
|
||
|
|
void addWithCallbackTemplate();
|
||
|
|
void addWithCallbackOnChange();
|
||
|
|
void addWithCallbackOnChangeTemplate();
|
||
|
|
|
||
|
|
void runFor100YearsFloat();
|
||
|
|
void runFor100YearsChrono();
|
||
|
|
|
||
|
|
void debugState();
|
||
|
|
};
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
const struct {
|
||
|
|
const char* name;
|
||
|
|
Float offsetFloat;
|
||
|
|
std::chrono::nanoseconds offsetChrono;
|
||
|
|
bool failsFloat, failsFuzzyFloat;
|
||
|
|
} RunFor100YearsData[]{
|
||
|
|
{"0", {}, {}, false, false},
|
||
|
|
{"1 minute", 60.0f, std::chrono::minutes{1}, false, false},
|
||
|
|
{"5 minutes", 5.0f*60.0f, std::chrono::minutes{5}, true, false},
|
||
|
|
{"30 minutes", 30.0f*60.0f, std::chrono::minutes{30}, true, false},
|
||
|
|
{"1 hour", 60.0f*60.0f, std::chrono::hours{1}, true, false},
|
||
|
|
{"1 day", 24.0f*60.0f*60.0f, std::chrono::hours{24}, true, true},
|
||
|
|
{"100 days", 100.0f*24.0f*60.0f*60.0f, std::chrono::hours{100*24}, true, true},
|
||
|
|
{"100 years", 100.0f*365.0f*24.0f*60.0f*60.0f, std::chrono::hours{100*365*24}, true, true},
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
PlayerTest::PlayerTest() {
|
||
|
|
addTests({&PlayerTest::constructEmpty,
|
||
|
|
&PlayerTest::construct,
|
||
|
|
&PlayerTest::constructCopy,
|
||
|
|
&PlayerTest::constructMove,
|
||
|
|
|
||
|
|
&PlayerTest::setDurationExtend,
|
||
|
|
&PlayerTest::setDurationReplace,
|
||
|
|
|
||
|
|
&PlayerTest::trackInvalidIndex,
|
||
|
|
|
||
|
|
&PlayerTest::advanceNotRunning,
|
||
|
|
&PlayerTest::advancePlaying,
|
||
|
|
&PlayerTest::advanceRestart,
|
||
|
|
&PlayerTest::advanceStop,
|
||
|
|
&PlayerTest::advancePauseResume,
|
||
|
|
&PlayerTest::advancePauseStop,
|
||
|
|
&PlayerTest::advancePlayCount,
|
||
|
|
&PlayerTest::advancePlayCountInfinite,
|
||
|
|
&PlayerTest::advanceChrono,
|
||
|
|
|
||
|
|
&PlayerTest::setState,
|
||
|
|
|
||
|
|
&PlayerTest::add,
|
||
|
|
&PlayerTest::addWithCallback,
|
||
|
|
&PlayerTest::addWithCallbackTemplate,
|
||
|
|
&PlayerTest::addWithCallbackOnChange,
|
||
|
|
&PlayerTest::addWithCallbackOnChangeTemplate});
|
||
|
|
|
||
|
|
addInstancedTests({
|
||
|
|
&PlayerTest::runFor100YearsFloat,
|
||
|
|
&PlayerTest::runFor100YearsChrono},
|
||
|
|
Containers::arraySize(RunFor100YearsData));
|
||
|
|
|
||
|
|
addTests({&PlayerTest::debugState});
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::constructEmpty() {
|
||
|
|
Player<Float> player;
|
||
|
|
CORRADE_VERIFY(player.scaler());
|
||
|
|
CORRADE_COMPARE(player.duration(), Range1D{});
|
||
|
|
CORRADE_COMPARE(player.playCount(), 1);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_VERIFY(player.isEmpty());
|
||
|
|
CORRADE_COMPARE(player.size(), 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
const Animation::Track<Float, Float> Track{{
|
||
|
|
{1.0f, 1.5f},
|
||
|
|
{2.5f, 3.0f},
|
||
|
|
{3.0f, 5.0f},
|
||
|
|
{4.0f, 2.0f}
|
||
|
|
}, Math::lerp};
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::construct() {
|
||
|
|
Animation::Track<Float, Int> track2{{
|
||
|
|
{0.5f, 42},
|
||
|
|
{3.0f, 1337},
|
||
|
|
{3.5f, -17}
|
||
|
|
}, Math::select};
|
||
|
|
|
||
|
|
Float value = -1.0f;
|
||
|
|
Int value2 = -1;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.add(track2, value2)
|
||
|
|
.setPlayCount(37);
|
||
|
|
CORRADE_VERIFY(player.scaler());
|
||
|
|
CORRADE_COMPARE(player.duration(), (Range1D{0.5f, 4.0f}));
|
||
|
|
CORRADE_COMPARE(player.playCount(), 37);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_VERIFY(!player.isEmpty());
|
||
|
|
CORRADE_COMPARE(player.size(), 2);
|
||
|
|
CORRADE_COMPARE(player.track(0).keys().data(), Track.keys().data());
|
||
|
|
CORRADE_COMPARE(player.track(1).keys().data(), track2.keys().data());
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::constructChrono() {
|
||
|
|
Animation::Track<Float, Int> track2{{
|
||
|
|
{0.5f, 42},
|
||
|
|
{3.0f, 1337},
|
||
|
|
{3.5f, -17}
|
||
|
|
}, Math::select};
|
||
|
|
|
||
|
|
Float value = -1.0f;
|
||
|
|
Int value2 = -1;
|
||
|
|
Player<std::chrono::nanoseconds, Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.add(track2, value2)
|
||
|
|
.setPlayCount(37);
|
||
|
|
CORRADE_VERIFY(player.scaler());
|
||
|
|
CORRADE_COMPARE(player.duration(), (Range1D{0.5f, 4.0f}));
|
||
|
|
CORRADE_COMPARE(player.playCount(), 37);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_VERIFY(!player.isEmpty());
|
||
|
|
CORRADE_COMPARE(player.size(), 2);
|
||
|
|
CORRADE_COMPARE(player.track(0).keys().data(), Track.keys().data());
|
||
|
|
CORRADE_COMPARE(player.track(1).keys().data(), track2.keys().data());
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::constructCopy() {
|
||
|
|
CORRADE_VERIFY(!(std::is_constructible<Player<Float>, const Player<Float>&>{}));
|
||
|
|
CORRADE_VERIFY(!(std::is_assignable<Player<Float>, const Player<Float>&>{}));
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::constructMove() {
|
||
|
|
Animation::Track<Float, Int> track2{{
|
||
|
|
{0.5f, 42},
|
||
|
|
{3.0f, 1337},
|
||
|
|
{3.5f, -17}
|
||
|
|
}, Math::select};
|
||
|
|
|
||
|
|
Float value = -1.0f;
|
||
|
|
Int value2 = -1;
|
||
|
|
Player<Float> a;
|
||
|
|
a.add(Track, value)
|
||
|
|
.add(track2, value2)
|
||
|
|
.setPlayCount(37)
|
||
|
|
.play({});
|
||
|
|
CORRADE_COMPARE(a.duration(), (Range1D{0.5f, 4.0f}));
|
||
|
|
CORRADE_COMPARE(a.playCount(), 37);
|
||
|
|
CORRADE_COMPARE(a.state(), State::Playing);
|
||
|
|
CORRADE_VERIFY(!a.isEmpty());
|
||
|
|
CORRADE_COMPARE(a.size(), 2);
|
||
|
|
CORRADE_COMPARE(a.track(0).keys().data(), Track.keys().data());
|
||
|
|
CORRADE_COMPARE(a.track(1).keys().data(), track2.keys().data());
|
||
|
|
|
||
|
|
Player<Float> b{std::move(a)};
|
||
|
|
CORRADE_COMPARE(b.duration(), (Range1D{0.5f, 4.0f}));
|
||
|
|
CORRADE_COMPARE(b.playCount(), 37);
|
||
|
|
CORRADE_COMPARE(b.state(), State::Playing);
|
||
|
|
CORRADE_VERIFY(!b.isEmpty());
|
||
|
|
CORRADE_COMPARE(b.size(), 2);
|
||
|
|
CORRADE_COMPARE(b.track(0).keys().data(), Track.keys().data());
|
||
|
|
CORRADE_COMPARE(b.track(1).keys().data(), track2.keys().data());
|
||
|
|
|
||
|
|
Player<Float> c;
|
||
|
|
c.setDuration({1.2f, 1.3f});
|
||
|
|
c = std::move(b);
|
||
|
|
CORRADE_COMPARE(c.duration(), (Range1D{0.5f, 4.0f}));
|
||
|
|
CORRADE_COMPARE(c.playCount(), 37);
|
||
|
|
CORRADE_COMPARE(c.state(), State::Playing);
|
||
|
|
CORRADE_VERIFY(!c.isEmpty());
|
||
|
|
CORRADE_COMPARE(c.size(), 2);
|
||
|
|
CORRADE_COMPARE(c.track(0).keys().data(), Track.keys().data());
|
||
|
|
CORRADE_COMPARE(c.track(1).keys().data(), track2.keys().data());
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::setDurationExtend() {
|
||
|
|
Float value;
|
||
|
|
Player<Float> player;
|
||
|
|
player.setDuration({-1.0f, 2.0f});
|
||
|
|
CORRADE_COMPARE(player.duration(), (Range1D{-1.0f, 2.0f}));
|
||
|
|
|
||
|
|
player.add(Track, value);
|
||
|
|
CORRADE_COMPARE(player.duration(), (Range1D{-1.0f, 4.0f}));
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::setDurationReplace() {
|
||
|
|
Float value;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value);
|
||
|
|
CORRADE_COMPARE(player.duration(), (Range1D{1.0f, 4.0f}));
|
||
|
|
|
||
|
|
player.setDuration({-1.0f, 2.0f});
|
||
|
|
CORRADE_COMPARE(player.duration(), (Range1D{-1.0f, 2.0f}));
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::trackInvalidIndex() {
|
||
|
|
std::ostringstream out;
|
||
|
|
Error redirectError{&out};
|
||
|
|
|
||
|
|
Player<Float> player;
|
||
|
|
player.track(0);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(out.str(), "Animation::Player::track(): index out of range\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advanceNotRunning() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
player.advance(1.75f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advancePlaying() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.duration().size(), 3.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);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
|
||
|
|
/* 2.67 secs in */
|
||
|
|
player.advance(4.6666667f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 3.0f);
|
||
|
|
|
||
|
|
/* When the player gets stopped, the value at the stop time is written */
|
||
|
|
player.advance(5.5f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, 2.0f);
|
||
|
|
|
||
|
|
/* But further advancing will not write anything */
|
||
|
|
value = -1.0f;
|
||
|
|
player.advance(100.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advanceRestart() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.play(2.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);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
|
||
|
|
/* Call play again, will restart from the beginning... */
|
||
|
|
value = -1.0f;
|
||
|
|
player.play(4.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* ... but only after calling advance() again. Now at 1 sec in. */
|
||
|
|
player.advance(5.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 2.5f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advanceStop() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
|
||
|
|
/* Stop, should not update anything */
|
||
|
|
value = -1.0;
|
||
|
|
player.stop();
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* Advancing will update with a value from beginning of the duration */
|
||
|
|
player.advance(5.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, 1.5f);
|
||
|
|
|
||
|
|
/* But further advancing will not write anything */
|
||
|
|
value = -1.0f;
|
||
|
|
player.advance(100.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advancePauseResume() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
|
||
|
|
/* Pausing should not update anything */
|
||
|
|
value = -1.0f;
|
||
|
|
player.pause(4.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Paused);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* Pausing again should be a no-op */
|
||
|
|
player.pause(4.1f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Paused);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* But advance() after should. No matter what time is passed to it, it
|
||
|
|
should update with time of pause. */
|
||
|
|
player.advance(4.5f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Paused);
|
||
|
|
CORRADE_COMPARE(value, 5.0f); /* value at 2.0f, not 2.5f */
|
||
|
|
|
||
|
|
/* Advancing further should do nothing */
|
||
|
|
value = -1.0f;
|
||
|
|
player.advance(50.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Paused);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* Resuming the animation, again should not update anything */
|
||
|
|
player.play(100.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* Advancing the animation should update again. It was paused after two
|
||
|
|
seconds, so continuing at 2.5 seconds now. */
|
||
|
|
player.advance(100.5f);
|
||
|
|
CORRADE_COMPARE(value, 3.5f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advancePauseStop() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
|
||
|
|
/* Pause, get value from the pause time */
|
||
|
|
player.pause(4.0f);
|
||
|
|
player.advance(4.5f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Paused);
|
||
|
|
CORRADE_COMPARE(value, 5.0f);
|
||
|
|
|
||
|
|
/* Stop, should not update anything */
|
||
|
|
value = -1.0;
|
||
|
|
player.stop();
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* Advancing will update with a value from beginning of the duration */
|
||
|
|
player.advance(5.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, 1.5f);
|
||
|
|
|
||
|
|
/* But further advancing will not write anything */
|
||
|
|
value = -1.0f;
|
||
|
|
player.advance(100.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* Pause while stopped is a no-op */
|
||
|
|
player.pause(101.0f);
|
||
|
|
player.advance(101.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advancePlayCount() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.setPlayCount(3)
|
||
|
|
.play(2.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);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
|
||
|
|
/* 2 secs in, second round */
|
||
|
|
player.advance(7.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 5.0f);
|
||
|
|
|
||
|
|
/* 1.75 secs in, third round */
|
||
|
|
player.advance(9.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
|
||
|
|
/* When the player gets stopped, the value at the stop time is written */
|
||
|
|
player.advance(11.5f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, 2.0f);
|
||
|
|
|
||
|
|
/* But further advancing will not write anything */
|
||
|
|
value = -1.0f;
|
||
|
|
player.advance(100.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advancePlayCountInfinite() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.setPlayCount(0)
|
||
|
|
.play(2.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);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
|
||
|
|
/* 2 secs in, second round */
|
||
|
|
player.advance(7.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 5.0f);
|
||
|
|
|
||
|
|
/* 1.75 secs in, 10th round */
|
||
|
|
player.advance(33.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::advanceChrono() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<std::chrono::nanoseconds, Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.play(std::chrono::seconds{2});
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.duration().size(), 3.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);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(std::chrono::milliseconds{3750});
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::setState() {
|
||
|
|
Player<Float> player;
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
|
||
|
|
player.setState(State::Playing, {});
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
|
||
|
|
player.setState(State::Paused, {});
|
||
|
|
CORRADE_COMPARE(player.state(), State::Paused);
|
||
|
|
|
||
|
|
player.setState(State::Stopped, {});
|
||
|
|
CORRADE_COMPARE(player.state(), State::Stopped);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::add() {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.duration().size(), 3.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 4.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::addWithCallback() {
|
||
|
|
struct Data {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Int called = 0;
|
||
|
|
} data;
|
||
|
|
Player<Float> player;
|
||
|
|
player.addWithCallback(Track, [](const Float&, const Float& value, void* userData) {
|
||
|
|
static_cast<Data*>(userData)->value = value;
|
||
|
|
++static_cast<Data*>(userData)->called;
|
||
|
|
}, &data)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.duration().size(), 3.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(data.value, -1.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 0);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(data.value, 4.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::addWithCallbackTemplate() {
|
||
|
|
struct Data {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Int called = 0;
|
||
|
|
} data;
|
||
|
|
Player<Float> player;
|
||
|
|
player.addWithCallback(Track, [](const Float&, const Float& value, Data& userData) {
|
||
|
|
userData.value = value;
|
||
|
|
++userData.called;
|
||
|
|
}, data)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.duration().size(), 3.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(data.value, -1.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 0);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(data.value, 4.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::addWithCallbackOnChange() {
|
||
|
|
struct Data {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Int called = 0;
|
||
|
|
} data;
|
||
|
|
Player<Float> player;
|
||
|
|
player.addWithCallbackOnChange(Track, [](const Float&, const Float& value, void* userData) {
|
||
|
|
static_cast<Data*>(userData)->value = value;
|
||
|
|
++static_cast<Data*>(userData)->called;
|
||
|
|
}, data.value, &data)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.duration().size(), 3.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(data.value, -1.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 0);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(data.value, 4.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 1);
|
||
|
|
|
||
|
|
/* At the same time, same value, should not be called again */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(data.value, 4.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 1);
|
||
|
|
|
||
|
|
/* Different time, different value, called again */
|
||
|
|
player.advance(4.0f);
|
||
|
|
CORRADE_COMPARE(data.value, 5.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::addWithCallbackOnChangeTemplate() {
|
||
|
|
struct Data {
|
||
|
|
Float value = -1.0f;
|
||
|
|
Int called = 0;
|
||
|
|
} data;
|
||
|
|
Player<Float> player;
|
||
|
|
player.addWithCallbackOnChange(Track, [](const Float&, const Float& value, Data& userData) {
|
||
|
|
userData.value = value;
|
||
|
|
++userData.called;
|
||
|
|
}, data.value, data)
|
||
|
|
.play(2.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.duration().size(), 3.0f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(data.value, -1.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 0);
|
||
|
|
|
||
|
|
/* 1.75 secs in */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(data.value, 4.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 1);
|
||
|
|
|
||
|
|
/* At the same time, same value, should not be called again */
|
||
|
|
player.advance(3.75f);
|
||
|
|
CORRADE_COMPARE(data.value, 4.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 1);
|
||
|
|
|
||
|
|
/* Different time, different value, called again */
|
||
|
|
player.advance(4.0f);
|
||
|
|
CORRADE_COMPARE(data.value, 5.0f);
|
||
|
|
CORRADE_COMPARE(data.called, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::runFor100YearsFloat() {
|
||
|
|
auto&& data = RunFor100YearsData[testCaseInstanceId()];
|
||
|
|
setTestCaseDescription(data.name);
|
||
|
|
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.setPlayCount(0)
|
||
|
|
.play({});
|
||
|
|
|
||
|
|
/* The track must fit an integer number of times into the day for this test
|
||
|
|
to work (3 seconds do fit) */
|
||
|
|
CORRADE_COMPARE(player.duration().size()[0], 3.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* 2.67 secs in given iteration. Comparing with a slightly larger epsilon,
|
||
|
|
because it fails right after five minutes otherwise. */
|
||
|
|
player.advance(data.offsetFloat + 2.6666666666667f);
|
||
|
|
|
||
|
|
if(data.failsFloat || data.failsFuzzyFloat)
|
||
|
|
Debug{} << "Calculated value:" << value;
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
{
|
||
|
|
CORRADE_EXPECT_FAIL_IF(data.failsFuzzyFloat, "Imprecision larger than 2.5e-4f.");
|
||
|
|
CORRADE_COMPARE_WITH(value, 3.0f, TestSuite::Compare::around(0.00025f));
|
||
|
|
}
|
||
|
|
if(!data.failsFuzzyFloat) {
|
||
|
|
CORRADE_EXPECT_FAIL_IF(data.failsFloat, "Imprecision larger than 1e-6f.");
|
||
|
|
CORRADE_COMPARE(value, 3.0f);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::runFor100YearsChrono() {
|
||
|
|
auto&& data = RunFor100YearsData[testCaseInstanceId()];
|
||
|
|
setTestCaseDescription(data.name);
|
||
|
|
|
||
|
|
Float value = -1.0f;
|
||
|
|
Player<std::chrono::nanoseconds, Float> player;
|
||
|
|
player.add(Track, value)
|
||
|
|
.setPlayCount(0)
|
||
|
|
.play({});
|
||
|
|
|
||
|
|
/* The track must fit an integer number of times into the day for this test
|
||
|
|
to work (3 seconds do fit) */
|
||
|
|
CORRADE_COMPARE(player.duration().size()[0], 3.0f);
|
||
|
|
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, -1.0f);
|
||
|
|
|
||
|
|
/* 2.67 secs in */
|
||
|
|
player.advance(data.offsetChrono + std::chrono::nanoseconds{2666666667ull});
|
||
|
|
CORRADE_COMPARE(player.state(), State::Playing);
|
||
|
|
CORRADE_COMPARE(value, 3.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void PlayerTest::debugState() {
|
||
|
|
std::ostringstream out;
|
||
|
|
|
||
|
|
Debug{&out} << State::Playing << State(0xde);
|
||
|
|
CORRADE_COMPARE(out.str(), "Animation::State::Playing Animation::State(0xde)\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
}}}
|
||
|
|
|
||
|
|
CORRADE_TEST_MAIN(Magnum::Animation::Test::PlayerTest)
|