bare-bones AnimClip implementation with tests!

It accumulates time and handles looping, and should handle
onDone and onLoop events in the future.
This commit is contained in:
Anthony J. Thibault 2015-07-30 22:07:05 -07:00 committed by Anthony J. Thibault
parent 836cdeb103
commit 35196a0059
6 changed files with 226 additions and 10 deletions

View file

@ -0,0 +1,77 @@
//
// AnimClip.cpp
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AnimClip.h"
#include "AnimationLogging.h"
AnimClip::AnimClip(const std::string& url, float startFrame, float endFrame, float timeScale, bool loopFlag) :
_url(url),
_startFrame(startFrame),
_endFrame(endFrame),
_timeScale(timeScale),
_frame(startFrame),
_loopFlag(loopFlag)
{
}
AnimClip::~AnimClip() {
}
void AnimClip::setURL(const std::string& url) {
// TODO:
_url = url;
}
void AnimClip::setStartFrame(float startFrame) {
_startFrame = startFrame;
}
void AnimClip::setEndFrame(float endFrame) {
_endFrame = endFrame;
}
void AnimClip::setLoopFlag(bool loopFlag) {
_loopFlag = loopFlag;
}
const AnimPose& AnimClip::evaluate(float dt) {
const float startFrame = std::min(_startFrame, _endFrame);
if (startFrame == _endFrame) {
// when startFrame >= endFrame
_frame = _endFrame;
} else if (_timeScale > 0.0f) {
// accumulate time, keeping track of loops and end of animation events.
const float FRAMES_PER_SECOND = 30.0f;
float framesRemaining = (dt * _timeScale) * FRAMES_PER_SECOND;
while (framesRemaining > 0.0f) {
float framesTillEnd = _endFrame - _frame;
if (framesRemaining >= framesTillEnd) {
if (_loopFlag) {
// anim loop
// TODO: trigger onLoop event
framesRemaining -= framesTillEnd;
_frame = startFrame;
} else {
// anim end
// TODO: trigger onDone event
_frame = _endFrame;
framesRemaining = 0.0f;
}
} else {
_frame += framesRemaining;
framesRemaining = 0.0f;
}
}
}
// TODO: eval animation
return _frame;
}

View file

@ -10,17 +10,41 @@
#ifndef hifi_AnimClip_h
#define hifi_AnimClip_h
#include <string>
#include "AnimationCache.h"
#include "AnimNode.h"
class AnimClip : public AnimNode {
public:
friend class AnimClipTests;
AnimClip(const std::string& url, float startFrame, float endFrame, float timeScale, bool loopFlag);
virtual ~AnimClip();
void setURL(const std::string& url);
void setStartFrame(AnimFrame startFrame);
void setEndFrame(AnimFrame startFrame);
void setLoopFlag(bool loopFlag);
void setTimeScale(float timeScale);
const std::string& getURL() const { return _url; }
public:
virtual const float getEnd() const;
virtual const AnimPose& evaluate(float t);
void setStartFrame(float startFrame);
float getStartFrame() const { return _startFrame; }
void setEndFrame(float endFrame);
float getEndFrame() const { return _endFrame; }
void setTimeScale(float timeScale) { _timeScale = timeScale; }
float getTimeScale() const { return _timeScale; }
void setLoopFlag(bool loopFlag);
bool getLoopFlag() const { return _loopFlag; }
virtual const AnimPose& evaluate(float dt);
protected:
AnimationPointer _anim;
std::string _url;
float _startFrame;
float _endFrame;
float _timeScale;
float _frame;
bool _loopFlag;
};
#endif // hifi_AnimClip_h

View file

@ -10,10 +10,13 @@
#ifndef hifi_AnimNode_h
#define hifi_AnimNode_h
typedef float AnimPose;
class AnimNode {
public:
virtual float getEnd() const = 0;
virtual const AnimPose& evaluate(float t) = 0;
virtual ~AnimNode() {}
virtual const AnimPose& evaluate(float dt) = 0;
};
#endif // hifi_AnimNode_h

View file

@ -1,7 +1,7 @@
# Declare dependencies
macro (setup_testcase_dependencies)
# link in the shared libraries
link_hifi_libraries(shared animation gpu fbx model)
link_hifi_libraries(shared animation gpu fbx model networking)
copy_dlls_beside_windows_executable()
endmacro ()

View file

@ -0,0 +1,85 @@
//
// AnimClipTests.cpp
// tests/rig/src
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AnimClipTests.h"
#include "AnimClip.h"
#include "AnimationLogging.h"
#include <../QTestExtensions.h>
QTEST_MAIN(AnimClipTests)
const float EPSILON = 0.001f;
void AnimClipTests::testAccessors() {
std::string url = "foo";
float startFrame = 2.0f;
float endFrame = 20.0f;
float timeScale = 1.1f;
float loopFlag = true;
AnimClip clip(url, startFrame, endFrame, timeScale, loopFlag);
QVERIFY(clip.getURL() == url);
QVERIFY(clip.getStartFrame() == startFrame);
QVERIFY(clip.getEndFrame() == endFrame);
QVERIFY(clip.getTimeScale() == timeScale);
QVERIFY(clip.getLoopFlag() == loopFlag);
std::string url2 = "bar";
float startFrame2 = 22.0f;
float endFrame2 = 100.0f;
float timeScale2 = 1.2f;
float loopFlag2 = false;
clip.setURL(url2);
clip.setStartFrame(startFrame2);
clip.setEndFrame(endFrame2);
clip.setTimeScale(timeScale2);
clip.setLoopFlag(loopFlag2);
QVERIFY(clip.getURL() == url2);
QVERIFY(clip.getStartFrame() == startFrame2);
QVERIFY(clip.getEndFrame() == endFrame2);
QVERIFY(clip.getTimeScale() == timeScale2);
QVERIFY(clip.getLoopFlag() == loopFlag2);
}
static float secsToFrames(float secs) {
const float FRAMES_PER_SECOND = 30.0f;
return secs * FRAMES_PER_SECOND;
}
static float framesToSec(float secs) {
const float FRAMES_PER_SECOND = 30.0f;
return secs / FRAMES_PER_SECOND;
}
void AnimClipTests::testEvaulate() {
std::string url = "foo";
float startFrame = 2.0f;
float endFrame = 22.0f;
float timeScale = 1.0f;
float loopFlag = true;
AnimClip clip(url, startFrame, endFrame, timeScale, loopFlag);
clip.evaluate(framesToSec(10.0f));
QCOMPARE_WITH_ABS_ERROR(clip._frame, 12.0f, EPSILON);
// does it loop?
clip.evaluate(framesToSec(11.0f));
QCOMPARE_WITH_ABS_ERROR(clip._frame, 3.0f, EPSILON);
// does it pause at end?
clip.setLoopFlag(false);
clip.evaluate(framesToSec(20.0f));
QCOMPARE_WITH_ABS_ERROR(clip._frame, 22.0f, EPSILON);
}

View file

@ -0,0 +1,27 @@
//
// AnimClipTests.h
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AnimClipTests_h
#define hifi_AnimClipTests_h
#include <QtTest/QtTest>
#include <glm/glm.hpp>
inline float getErrorDifference(float a, float b) {
return fabs(a - b);
}
class AnimClipTests : public QObject {
Q_OBJECT
private slots:
void testAccessors();
void testEvaulate();
};
#endif // hifi_TransformTests_h