mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 03:17:02 +02:00
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:
parent
836cdeb103
commit
35196a0059
6 changed files with 226 additions and 10 deletions
77
libraries/animation/src/AnimClip.cpp
Normal file
77
libraries/animation/src/AnimClip.cpp
Normal 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;
|
||||||
|
}
|
|
@ -10,17 +10,41 @@
|
||||||
#ifndef hifi_AnimClip_h
|
#ifndef hifi_AnimClip_h
|
||||||
#define hifi_AnimClip_h
|
#define hifi_AnimClip_h
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "AnimationCache.h"
|
||||||
|
#include "AnimNode.h"
|
||||||
|
|
||||||
class AnimClip : public AnimNode {
|
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 setURL(const std::string& url);
|
||||||
void setStartFrame(AnimFrame startFrame);
|
const std::string& getURL() const { return _url; }
|
||||||
void setEndFrame(AnimFrame startFrame);
|
|
||||||
void setLoopFlag(bool loopFlag);
|
|
||||||
void setTimeScale(float timeScale);
|
|
||||||
|
|
||||||
public:
|
void setStartFrame(float startFrame);
|
||||||
virtual const float getEnd() const;
|
float getStartFrame() const { return _startFrame; }
|
||||||
virtual const AnimPose& evaluate(float t);
|
|
||||||
|
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
|
#endif // hifi_AnimClip_h
|
||||||
|
|
|
@ -10,10 +10,13 @@
|
||||||
#ifndef hifi_AnimNode_h
|
#ifndef hifi_AnimNode_h
|
||||||
#define hifi_AnimNode_h
|
#define hifi_AnimNode_h
|
||||||
|
|
||||||
|
typedef float AnimPose;
|
||||||
|
|
||||||
class AnimNode {
|
class AnimNode {
|
||||||
public:
|
public:
|
||||||
virtual float getEnd() const = 0;
|
virtual ~AnimNode() {}
|
||||||
virtual const AnimPose& evaluate(float t) = 0;
|
|
||||||
|
virtual const AnimPose& evaluate(float dt) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AnimNode_h
|
#endif // hifi_AnimNode_h
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Declare dependencies
|
# Declare dependencies
|
||||||
macro (setup_testcase_dependencies)
|
macro (setup_testcase_dependencies)
|
||||||
# link in the shared libraries
|
# 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()
|
copy_dlls_beside_windows_executable()
|
||||||
endmacro ()
|
endmacro ()
|
||||||
|
|
85
tests/animation/src/AnimClipTests.cpp
Normal file
85
tests/animation/src/AnimClipTests.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
27
tests/animation/src/AnimClipTests.h
Normal file
27
tests/animation/src/AnimClipTests.h
Normal 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
|
Loading…
Reference in a new issue