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.

335 lines
11 KiB

/*
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)