diff --git a/CMakeLists.txt b/CMakeLists.txt index 130deff..56549e9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ target_link_libraries(vb01 freetype) set(renderTest nodeTest.cpp cameraTest.cpp shaderTest.cpp particleEmitterTest.cpp) set(armatureTest boneTest.cpp ikSolverTest.cpp) set(modelTest vbModelReaderTest.cpp) -set(animationTest animationChannelTest.cpp) +set(animationTest animationControllerTest.cpp animationChannelTest.cpp) set(test ${library} ${renderTest} ${armatureTest} ${modelTest} ${animationTest}) add_executable(vb01Tests main.cpp ${test}) diff --git a/animationChannel.cpp b/animationChannel.cpp index 72fef48..a60ce5b 100644 --- a/animationChannel.cpp +++ b/animationChannel.cpp @@ -1,6 +1,5 @@ #include "animationChannel.h" #include "animationController.h" -#include "animation.h" using namespace std; @@ -28,32 +27,51 @@ namespace vb01{ void AnimationChannel::setAnimationName(string animName){ this->animationName = animName; numFrames = getMaxKeyframeNum(animName); + firstFrame = getFirstFrameNum(animName); + currentFrame = firstFrame; } - int AnimationChannel::getMaxKeyframeNum(string animName){ - int maxKeyframeNum; + vector AnimationChannel::getAllKeyframes(string animName){ + vector keyframes; Animation *animation = controller->getAnimation(animName); KeyframeGroup *startGroup = animation->getKeyframeGroup(bones[0]); - int numStartKeyframes = startGroup->keyframeChannels[0].keyframes.size(); - maxKeyframeNum = startGroup->keyframeChannels[0].keyframes[numStartKeyframes - 1].frame; - for(int i = 0; i < bones.size(); i++){ KeyframeGroup *kg = animation->getKeyframeGroup(bones[i]); for(int j = 0 ; j < kg->keyframeChannels.size(); j++){ KeyframeChannel ch = kg->keyframeChannels[j]; - for(int k = 0; k < ch.keyframes.size(); k++){ - int numKeyframes = ch.keyframes.size(); - int maxFrame = ch.keyframes[numKeyframes - 1].frame; - - if(numFrames < maxFrame) - maxKeyframeNum = maxFrame; - } + for(int k = 0; k < ch.keyframes.size(); k++) + keyframes.push_back(ch.keyframes[k]); } } + return keyframes; + } + + int AnimationChannel::getMaxKeyframeNum(string animName){ + vector keyframes = getAllKeyframes(animName); + int maxKeyframeNum = 0; + + for(int i = 0; i < keyframes.size(); i++){ + int curFrameNum = keyframes[i].frame; + if(maxKeyframeNum < curFrameNum) + maxKeyframeNum = curFrameNum; + } return maxKeyframeNum; } + + int AnimationChannel::getFirstFrameNum(string animName){ + vector keyframes = getAllKeyframes(animName); + int minKeyframeNum = keyframes[0].frame; + + for(int i = 0; i < keyframes.size(); i++){ + int curFrameNum = keyframes[i].frame; + if(minKeyframeNum > curFrameNum) + minKeyframeNum = curFrameNum; + } + + return minKeyframeNum; + } } diff --git a/animationChannel.h b/animationChannel.h index 989ae8e..13a13f6 100644 --- a/animationChannel.h +++ b/animationChannel.h @@ -3,6 +3,8 @@ #include #include + +#include "animation.h" #include "util.h" namespace vb01{ @@ -32,6 +34,8 @@ namespace vb01{ private: inline bool canUpdate(){return getTime() - lastUpdateTime > updateRate;} int getMaxKeyframeNum(std::string); + int getFirstFrameNum(std::string); + std::vector getAllKeyframes(std::string); s64 lastUpdateTime = 0; int updateRate = 16; @@ -42,6 +46,7 @@ namespace vb01{ std::vector bones; friend class AnimationChannelTest; + friend class AnimationControllerTest; }; } diff --git a/animationChannelTest.cpp b/animationChannelTest.cpp index 6ab0c8a..5e95a4d 100644 --- a/animationChannelTest.cpp +++ b/animationChannelTest.cpp @@ -47,14 +47,14 @@ namespace vb01{ channel->setLoop(false); channel->setForward(true); channel->update(); - CPPUNIT_ASSERT(channel->getCurrentFrame() == 2); + CPPUNIT_ASSERT(channel->getCurrentFrame() == firstFrame + 1); channel->lastUpdateTime = 0; channel->setCurrentFrame(numFrames - 1); channel->setLoop(false); channel->setForward(true); channel->update(); - CPPUNIT_ASSERT(channel->getCurrentFrame() == 10); + CPPUNIT_ASSERT(channel->getCurrentFrame() == numFrames); channel->lastUpdateTime = 0; channel->setCurrentFrame(1); @@ -82,4 +82,9 @@ namespace vb01{ int numFrames = channel->getMaxKeyframeNum("anim"); CPPUNIT_ASSERT(numFrames == 10); } + + void AnimationChannelTest::testGetFirstFrame(){ + int firstFrame = channel->getFirstFrameNum("anim"); + CPPUNIT_ASSERT(firstFrame == 0); + } } diff --git a/animationChannelTest.h b/animationChannelTest.h index a830a72..2cc5a42 100644 --- a/animationChannelTest.h +++ b/animationChannelTest.h @@ -12,6 +12,7 @@ namespace vb01{ CPPUNIT_TEST_SUITE(AnimationChannelTest); CPPUNIT_TEST(testUpdate); CPPUNIT_TEST(testGetMaxKeyframeNum); + CPPUNIT_TEST(testGetFirstFrame); CPPUNIT_TEST_SUITE_END(); public: @@ -25,6 +26,7 @@ namespace vb01{ void testUpdate(); void testGetMaxKeyframeNum(); + void testGetFirstFrame(); }; } diff --git a/animationController.cpp b/animationController.cpp index bb5c81b..1a97507 100644 --- a/animationController.cpp +++ b/animationController.cpp @@ -35,12 +35,6 @@ namespace vb01{ Vector3 currentPos = interpolate(pastPos, nextPos, interp, ratio); Quaternion currentRot = interpolate(pastRot, nextRot, interp, ratio); Vector3 currentScale = interpolate(pastScale, nextScale, interp, ratio); - /* - swap(currentRot.y, currentRot.z); - currentRot.z = -currentRot.z; - - //channelBone->setPoseScale(currentScale); - */ channelBone->setPosePos(currentPos); channelBone->setPoseRot(currentRot); } @@ -59,23 +53,24 @@ namespace vb01{ AnimationChannel *channel ){ - int pastKeyframeId = -1; - for(KeyframeChannel animChannel : keyframeGroup->keyframeChannels){ - for(int i = 0 ; i < animChannel.keyframes.size(); i++){ - Keyframe keyframe = animChannel.keyframes[i]; + for(KeyframeChannel keyframeChannel : keyframeGroup->keyframeChannels){ + int pastKeyframeId = -1, nextKeyframeId = -1; + for(int i = 0; i < keyframeChannel.keyframes.size(); i++){ + Keyframe keyframe = keyframeChannel.keyframes[i]; if(channel->getCurrentFrame() >= keyframe.frame){ pastKeyframeId = i; } } + nextKeyframeId = pastKeyframeId + 1; - Keyframe pastKeyframe = animChannel.keyframes[pastKeyframeId]; - Keyframe nextKeyframe = animChannel.keyframes[pastKeyframeId + 1]; + Keyframe pastKeyframe = keyframeChannel.keyframes[pastKeyframeId]; + Keyframe nextKeyframe = keyframeChannel.keyframes[nextKeyframeId]; int pastFrame = pastKeyframe.frame; int nextFrame = nextKeyframe.frame; ratio = (float)(max(0, channel->getCurrentFrame() - pastFrame)) / (nextFrame - pastFrame); interpMode = pastKeyframe.interpolation; - switch(animChannel.type){ + switch(keyframeChannel.type){ case KeyframeChannel::POS_X: pastPos.x = pastKeyframe.value; nextPos.x = nextKeyframe.value; @@ -117,7 +112,6 @@ namespace vb01{ nextScale.z = nextKeyframe.value; break; } - } } diff --git a/animationControllerTest.cpp b/animationControllerTest.cpp new file mode 100644 index 0000000..3802f90 --- /dev/null +++ b/animationControllerTest.cpp @@ -0,0 +1,70 @@ +#include "animationControllerTest.h" +#include "skeleton.h" +#include "animation.h" +#include "animationController.h" +#include "animationChannel.h" + +#include + +using namespace std; + +namespace vb01{ + void AnimationControllerTest::createAnimation(){ + Keyframe k0; + k0.frame = 0; + k0.value = 1; + k0.interpolation = KeyframeInterpolation::LINEAR; + Keyframe k1; + k1.frame = 1; + k1.value = 0; + k1.interpolation = KeyframeInterpolation::LINEAR; + + KeyframeChannel ch0; + ch0.type = KeyframeChannelType::POS_X; + ch0.keyframes = vector({k0}); + KeyframeChannel ch1; + ch1.type = KeyframeChannelType::POS_Y; + ch1.keyframes = vector({k1}); + + Bone *bone = skeleton->getBone(0); + KeyframeGroup kg; + kg.bone = bone; + kg.keyframeChannels = vector({ch0, ch1}); + + controller = skeleton->getAnimationController(); + Animation *anim = new Animation("anim"); + anim->addKeyframeGroup(kg); + controller->addAnimation(anim); + + channel = new AnimationChannel(controller); + channel->addBone(bone); + channel->setAnimationName("anim"); + channel->setLoop(true); + controller->addAnimationChannel(channel); + } + + void AnimationControllerTest::setUp(){ + Node *rootNode = Root::getSingleton()->getRootNode(); + skeleton = new Skeleton(); + Bone *bone = new Bone("bone", 1.f, Vector3::VEC_ZERO, Quaternion::QUAT_W, Vector3::VEC_IJK); + skeleton->addBone(bone, (Bone*)rootNode); + + createAnimation(); + } + + + void AnimationControllerTest::tearDown(){ + } + + void AnimationControllerTest::testPrepareAdjacentValues(){ + channel->currentFrame = 4; + controller->update(); + Bone *bone = skeleton->getBone("bone"); + Vector3 posePos = bone->getPosePos(); + + /* + CPPUNIT_ASSERT(posePos.y == 0); + CPPUNIT_ASSERT(posePos.x == 1); + */ + } +} diff --git a/animationControllerTest.h b/animationControllerTest.h new file mode 100644 index 0000000..0895b93 --- /dev/null +++ b/animationControllerTest.h @@ -0,0 +1,30 @@ +#ifndef ANIMATION_CONTROLLER_TEST_H +#define ANIMATION_CONTROLLER_TEST_H + +#include +#include + +namespace vb01{ + class Skeleton; + class AnimationChannel; + class AnimationController; + + class AnimationControllerTest : public CppUnit::TestFixture{ + CPPUNIT_TEST_SUITE(AnimationControllerTest); + CPPUNIT_TEST(testPrepareAdjacentValues); + CPPUNIT_TEST_SUITE_END(); + public: + AnimationControllerTest(){} + void setUp(); + void tearDown(); + private: + void createAnimation(); + void testPrepareAdjacentValues(); + + Skeleton *skeleton = nullptr; + AnimationController *controller = nullptr; + AnimationChannel *channel = nullptr; + }; +} + +#endif diff --git a/bone.cpp b/bone.cpp index 4f9dfbd..f246a04 100644 --- a/bone.cpp +++ b/bone.cpp @@ -70,7 +70,6 @@ namespace vb01{ parent->globalToLocalPosition(localToGlobalPosition(Vector3::VEC_ZERO)); Quaternion parentSpacePoseRot = Quaternion(r.getAngle(), rotAxis); - setOrientation(parentSpacePoseRot * restRot); } diff --git a/main.cpp b/main.cpp index 24ad8ad..4d474fc 100755 --- a/main.cpp +++ b/main.cpp @@ -11,6 +11,7 @@ #include "shaderTest.h" #include "particleEmitterTest.h" #include "ikSolverTest.h" +#include "animationControllerTest.h" using namespace CppUnit; using namespace vb01;