|
|
|
|
/*
|
|
|
|
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
|
|
|
|
|
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Magnum is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU Lesser General Public License version 3
|
|
|
|
|
only, as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
|
|
Magnum is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU Lesser General Public License version 3 for more details.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <TestSuite/Tester.h>
|
|
|
|
|
|
|
|
|
|
#include "SceneGraph/Animable.h"
|
|
|
|
|
#include "SceneGraph/AnimableGroup.h"
|
|
|
|
|
#include "SceneGraph/MatrixTransformation3D.h"
|
|
|
|
|
|
|
|
|
|
namespace Magnum { namespace SceneGraph { namespace Test {
|
|
|
|
|
|
|
|
|
|
class AnimableTest: public Corrade::TestSuite::Tester {
|
|
|
|
|
public:
|
|
|
|
|
AnimableTest();
|
|
|
|
|
|
|
|
|
|
void state();
|
|
|
|
|
void step();
|
|
|
|
|
void duration();
|
|
|
|
|
void repeat();
|
|
|
|
|
void stop();
|
|
|
|
|
void pause();
|
|
|
|
|
|
|
|
|
|
void debug();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D<>> Object3D;
|
|
|
|
|
|
|
|
|
|
AnimableTest::AnimableTest() {
|
|
|
|
|
addTests(&AnimableTest::state,
|
|
|
|
|
&AnimableTest::step,
|
|
|
|
|
&AnimableTest::duration,
|
|
|
|
|
&AnimableTest::repeat,
|
|
|
|
|
&AnimableTest::stop,
|
|
|
|
|
&AnimableTest::pause,
|
|
|
|
|
&AnimableTest::debug);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimableTest::state() {
|
|
|
|
|
class StateTrackingAnimable: public SceneGraph::Animable<3> {
|
|
|
|
|
public:
|
|
|
|
|
StateTrackingAnimable(AbstractObject<3>* object, AnimableGroup<3>* group = nullptr): SceneGraph::Animable<3>(object, group) {
|
|
|
|
|
setDuration(1.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string trackedState;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void animationStep(GLfloat, GLfloat) override {}
|
|
|
|
|
|
|
|
|
|
void animationStarted() override { trackedState += "started"; }
|
|
|
|
|
void animationPaused() override { trackedState += "paused"; }
|
|
|
|
|
void animationResumed() override { trackedState += "resumed"; }
|
|
|
|
|
void animationStopped() override { trackedState += "stopped"; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Object3D object;
|
|
|
|
|
AnimableGroup<3> group;
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 0);
|
|
|
|
|
|
|
|
|
|
/* Verify initial state */
|
|
|
|
|
StateTrackingAnimable animable(&object, &group);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Stopped);
|
|
|
|
|
CORRADE_VERIFY(animable.trackedState.empty());
|
|
|
|
|
group.step(1.0f, 1.0f);
|
|
|
|
|
CORRADE_VERIFY(animable.trackedState.empty());
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 0);
|
|
|
|
|
|
|
|
|
|
/* Stopped -> paused is not supported */
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Stopped);
|
|
|
|
|
animable.setState(AnimationState::Paused);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Stopped);
|
|
|
|
|
|
|
|
|
|
/* Stopped -> running */
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Stopped);
|
|
|
|
|
animable.trackedState.clear();
|
|
|
|
|
animable.setState(AnimationState::Running);
|
|
|
|
|
CORRADE_VERIFY(animable.trackedState.empty());
|
|
|
|
|
group.step(1.0f, 1.0f);
|
|
|
|
|
CORRADE_COMPARE(animable.trackedState, "started");
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 1);
|
|
|
|
|
|
|
|
|
|
/* Running -> paused */
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
animable.trackedState.clear();
|
|
|
|
|
animable.setState(AnimationState::Paused);
|
|
|
|
|
CORRADE_VERIFY(animable.trackedState.empty());
|
|
|
|
|
group.step(1.0f, 1.0f);
|
|
|
|
|
CORRADE_COMPARE(animable.trackedState, "paused");
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 0);
|
|
|
|
|
|
|
|
|
|
/* Paused -> running */
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Paused);
|
|
|
|
|
animable.trackedState.clear();
|
|
|
|
|
animable.setState(AnimationState::Running);
|
|
|
|
|
CORRADE_VERIFY(animable.trackedState.empty());
|
|
|
|
|
group.step(1.0f, 1.0f);
|
|
|
|
|
CORRADE_COMPARE(animable.trackedState, "resumed");
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 1);
|
|
|
|
|
|
|
|
|
|
/* Running -> stopped */
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
animable.trackedState.clear();
|
|
|
|
|
animable.setState(AnimationState::Stopped);
|
|
|
|
|
CORRADE_VERIFY(animable.trackedState.empty());
|
|
|
|
|
group.step(1.0f, 1.0f);
|
|
|
|
|
CORRADE_COMPARE(animable.trackedState, "stopped");
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 0);
|
|
|
|
|
|
|
|
|
|
animable.setState(AnimationState::Running);
|
|
|
|
|
group.step(1.0f, 1.0f);
|
|
|
|
|
animable.setState(AnimationState::Paused);
|
|
|
|
|
|
|
|
|
|
/* Paused -> stopped */
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Paused);
|
|
|
|
|
animable.trackedState.clear();
|
|
|
|
|
animable.setState(AnimationState::Stopped);
|
|
|
|
|
CORRADE_VERIFY(animable.trackedState.empty());
|
|
|
|
|
group.step(1.0f, 1.0f);
|
|
|
|
|
CORRADE_COMPARE(animable.trackedState, "stopped");
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 0);
|
|
|
|
|
|
|
|
|
|
/* Verify running count can go past 0/1 */
|
|
|
|
|
group.add((new StateTrackingAnimable(&object, &group))->setState(AnimationState::Running));
|
|
|
|
|
group.add((new StateTrackingAnimable(&object, &group))->setState(AnimationState::Running));
|
|
|
|
|
group.step(1.0f, 1.0f);
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class OneShotAnimable: public SceneGraph::Animable<3> {
|
|
|
|
|
public:
|
|
|
|
|
OneShotAnimable(AbstractObject<3>* object, AnimableGroup<3>* group = nullptr): SceneGraph::Animable<3>(object, group), time(-1.0f) {
|
|
|
|
|
setDuration(10.0f);
|
|
|
|
|
setState(AnimationState::Running);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLfloat time;
|
|
|
|
|
std::string stateChanges;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void animationStep(GLfloat time, GLfloat) override {
|
|
|
|
|
this->time = time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void animationStarted() override {
|
|
|
|
|
stateChanges += "started;";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void animationStopped() override {
|
|
|
|
|
stateChanges += "stopped;";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void AnimableTest::step() {
|
|
|
|
|
class InifiniteAnimable: public SceneGraph::Animable<3> {
|
|
|
|
|
public:
|
|
|
|
|
InifiniteAnimable(AbstractObject<3>* object, AnimableGroup<3>* group = nullptr): SceneGraph::Animable<3>(object, group), time(-1.0f), delta(0.0f) {}
|
|
|
|
|
|
|
|
|
|
GLfloat time, delta;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void animationStep(GLfloat time, GLfloat delta) override {
|
|
|
|
|
this->time = time;
|
|
|
|
|
this->delta = delta;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Object3D object;
|
|
|
|
|
AnimableGroup<3> group;
|
|
|
|
|
InifiniteAnimable animable(&object, &group);
|
|
|
|
|
|
|
|
|
|
/* Calling step() if no object is running should do nothing */
|
|
|
|
|
group.step(5.0f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 0);
|
|
|
|
|
CORRADE_COMPARE(animable.time, -1.0f);
|
|
|
|
|
CORRADE_COMPARE(animable.delta, 0.0f);
|
|
|
|
|
|
|
|
|
|
/* Calling step() with running animation should start it with zero
|
|
|
|
|
absolute time */
|
|
|
|
|
animable.setState(AnimationState::Running);
|
|
|
|
|
group.step(5.0f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 1);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 0.0f);
|
|
|
|
|
CORRADE_COMPARE(animable.delta, 0.5f);
|
|
|
|
|
|
|
|
|
|
/* Repeated call to step() will add to absolute animation time */
|
|
|
|
|
group.step(8.0f, 0.75f);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 3.0f);
|
|
|
|
|
CORRADE_COMPARE(animable.delta, 0.75f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimableTest::duration() {
|
|
|
|
|
Object3D object;
|
|
|
|
|
AnimableGroup<3> group;
|
|
|
|
|
OneShotAnimable animable(&object, &group);
|
|
|
|
|
CORRADE_VERIFY(!animable.isRepeated());
|
|
|
|
|
|
|
|
|
|
/* First animation step is in duration, verify that animation is still
|
|
|
|
|
running and animationStep() is called */
|
|
|
|
|
group.step(1.0f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
CORRADE_COMPARE(animable.stateChanges, "started;");
|
|
|
|
|
CORRADE_COMPARE(animable.time, 0.0f);
|
|
|
|
|
|
|
|
|
|
/* Next animation step is out of duration and repeat is not enabled,
|
|
|
|
|
animationStep() shouldn't be called and animation should be stopped */
|
|
|
|
|
group.step(12.75f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Stopped);
|
|
|
|
|
CORRADE_COMPARE(animable.stateChanges, "started;stopped;");
|
|
|
|
|
CORRADE_COMPARE(animable.time, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimableTest::repeat() {
|
|
|
|
|
class RepeatingAnimable: public SceneGraph::Animable<3> {
|
|
|
|
|
public:
|
|
|
|
|
RepeatingAnimable(AbstractObject<3>* object, AnimableGroup<3>* group = nullptr): SceneGraph::Animable<3>(object, group), time(-1.0f) {
|
|
|
|
|
setDuration(10.0f);
|
|
|
|
|
setState(AnimationState::Running);
|
|
|
|
|
setRepeated(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLfloat time;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void animationStep(GLfloat time, GLfloat) override {
|
|
|
|
|
this->time = time;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Object3D object;
|
|
|
|
|
AnimableGroup<3> group;
|
|
|
|
|
RepeatingAnimable animable(&object, &group);
|
|
|
|
|
CORRADE_COMPARE(animable.repeatCount(), 0);
|
|
|
|
|
|
|
|
|
|
/* First animation steps is in first loop iteration */
|
|
|
|
|
group.step(1.0f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 0.0f);
|
|
|
|
|
|
|
|
|
|
/* Next animation step is in second loop iteration, animation should be
|
|
|
|
|
still running with time shifted by animation duration */
|
|
|
|
|
group.step(11.5f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 0.5f);
|
|
|
|
|
|
|
|
|
|
/* Third loop iteration (just to be sure) */
|
|
|
|
|
group.step(25.5f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 4.5f);
|
|
|
|
|
|
|
|
|
|
/* Cap repeat count to 3, the animation should be stopped now (and
|
|
|
|
|
animationStep() shouldn't be called)*/
|
|
|
|
|
animable.setRepeatCount(3);
|
|
|
|
|
group.step(33.0f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Stopped);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 4.5f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimableTest::stop() {
|
|
|
|
|
Object3D object;
|
|
|
|
|
AnimableGroup<3> group;
|
|
|
|
|
OneShotAnimable animable(&object, &group);
|
|
|
|
|
CORRADE_COMPARE(animable.repeatCount(), 0);
|
|
|
|
|
|
|
|
|
|
/* Eat up some absolute time */
|
|
|
|
|
group.step(1.0f, 0.5f);
|
|
|
|
|
group.step(1.5f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 0.5f);
|
|
|
|
|
|
|
|
|
|
/* Stop the animable, nothing should be done */
|
|
|
|
|
animable.setState(AnimationState::Stopped);
|
|
|
|
|
group.step(1.5f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Stopped);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 0.5f);
|
|
|
|
|
|
|
|
|
|
/* Restarting the animation should start with zero absolute time */
|
|
|
|
|
animable.setState(AnimationState::Running);
|
|
|
|
|
group.step(2.5f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimableTest::pause() {
|
|
|
|
|
Object3D object;
|
|
|
|
|
AnimableGroup<3> group;
|
|
|
|
|
OneShotAnimable animable(&object, &group);
|
|
|
|
|
|
|
|
|
|
/* First two steps, animation is running */
|
|
|
|
|
group.step(1.0f, 0.5f);
|
|
|
|
|
group.step(2.5f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 1.5f);
|
|
|
|
|
|
|
|
|
|
/* Pausing the animation, first step should decrease count of running
|
|
|
|
|
animations and save paused time, next steps shouldn't affect anything */
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 1);
|
|
|
|
|
animable.setState(AnimationState::Paused);
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 1);
|
|
|
|
|
group.step(3.0f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(group.runningCount(), 0);
|
|
|
|
|
group.step(4.5f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Paused);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 1.5f);
|
|
|
|
|
|
|
|
|
|
/* Unpausing, next step should continue from absolute time when pause
|
|
|
|
|
occured */
|
|
|
|
|
animable.setState(AnimationState::Running);
|
|
|
|
|
group.step(5.0f, 0.5f);
|
|
|
|
|
CORRADE_COMPARE(animable.state(), AnimationState::Running);
|
|
|
|
|
CORRADE_COMPARE(animable.time, 2.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimableTest::debug() {
|
|
|
|
|
std::ostringstream o;
|
|
|
|
|
Debug(&o) << AnimationState::Running;
|
|
|
|
|
CORRADE_COMPARE(o.str(), "SceneGraph::AnimationState::Running\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}}}
|
|
|
|
|
|
|
|
|
|
CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::AnimableTest)
|