123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- #include "Animation3D.h"
- #include "Model3D.h"
- using namespace Framework;
- // create an animation for a specific bone
- // \param boneId the id of the bone
- // \param originPos the position of the bone at the beginning of the animation
- // \param originRot the rotation of the bone at the beginning of the animation
- BoneAnimation::BoneAnimation(
- int boneId, Vec3<float> originPos, Vec3<float> originRot)
- : ReferenceCounter(),
- boneId(boneId),
- frameCount(1),
- maxTime(0.0),
- loop(0)
- {
- frames = new KeyFrame[1];
- frames[0].time = 0.0;
- frames[0].pos = originPos;
- frames[0].rot = originRot;
- current = frames[0];
- }
- // destructor
- BoneAnimation::~BoneAnimation()
- {
- delete[] frames;
- }
- // make the animation to a loop that starts again if the end is reached
- void BoneAnimation::setLoop(bool loop)
- {
- this->loop = loop;
- }
- //! adds a keyframe
- //! \param time the time in seconds since the start of the animation at
- //! which the bone should have the given position and rotation relative
- //! to its parent bone \param pos the position of the bone \param rot
- //! the rotation of the bone
- void BoneAnimation::addKeyFrame(double time, Vec3<float> pos, Vec3<float> rot)
- {
- if (time < 0)
- throw "Illegal argument exception: time of a keyframe can not be lower "
- "than 0";
- if (maxTime < time) maxTime = time;
- frameCount++;
- KeyFrame* tmp = new KeyFrame[frameCount];
- bool added = 0;
- for (int i = 0; i < frameCount; i++)
- {
- if (i < frameCount - 1 && frames[i - (int)added].time <= time)
- {
- tmp[i] = frames[i];
- }
- else
- {
- if (!added)
- {
- tmp[i].time = time;
- tmp[i].pos = pos;
- tmp[i].rot = rot;
- added = 1;
- }
- else
- {
- tmp[i] = frames[i - 1];
- }
- }
- }
- delete[] frames;
- frames = tmp;
- }
- // adds a keyframe that is the same as the last keyframe with the time time
- // \returns true if the keyframe was added successfully, false if time is maller
- // than the current length of the animation
- bool BoneAnimation::doNothingUntil(double time)
- {
- if (time > maxTime)
- {
- KeyFrame& last = frames[frameCount - 1];
- addKeyFrame(time, last.pos, last.rot);
- }
- return 0;
- }
- // calculates the positions and rotation at the next time
- // \param time the passed time in seconds since the last call
- void BoneAnimation::tick(double time)
- {
- if (frameCount <= 1) return;
- current.time += time;
- if (loop)
- {
- while (current.time >= maxTime)
- {
- current.time -= maxTime;
- }
- }
- else if (current.time > maxTime)
- {
- current.time = maxTime;
- }
- int last = -1;
- int next = -1;
- for (int i = 0; i < frameCount; i++)
- {
- last = next;
- next = i;
- if (frames[i].time > current.time)
- {
- break;
- }
- }
- float timePart = (float)(current.time - frames[last].time);
- current.pos
- = frames[last].pos + (frames[next].pos - frames[last].pos) * timePart;
- current.rot
- = frames[last].rot + (frames[next].rot - frames[last].rot) * timePart;
- }
- //! applys the animation on a given skeleton
- //! \param zS: the sceleton
- void BoneAnimation::apply(Skeleton* zSkelett) const
- {
- Bone* zK = zSkelett->zBone(boneId);
- if (zK)
- {
- zK->setPosition(current.pos);
- zK->setRotation(current.rot);
- }
- }
- // returns true if the animation has reached the last keyframe and does
- // not loop
- bool BoneAnimation::isFinished() const
- {
- return current.time >= maxTime;
- }
- // returns the bone id this animation is for
- int BoneAnimation::getBoneId() const
- {
- return boneId;
- }
- // returns the maximum time of the animation
- double BoneAnimation::getMaxTime() const
- {
- return maxTime;
- }
- //! Constructor
- SkeletonAnimation::SkeletonAnimation()
- : ReferenceCounter(),
- loop(0)
- {}
- // make the animation to a loop that starts again if the end is reached
- void SkeletonAnimation::setLoop(bool loop)
- {
- this->loop = loop;
- for (BoneAnimation* animation : subAnimations)
- {
- animation->setLoop(loop);
- }
- }
- // adds an animation for a specific bone
- // \param boneId the bone id
- // \param originPos the position of the bone at the beginning of the animation
- // \param originRot the rotation of the bone at the beginning of the animation
- bool SkeletonAnimation::addAnimation(
- int boneId, Vec3<float> originPos, Vec3<float> originRot)
- {
- for (BoneAnimation* animation : subAnimations)
- {
- if (animation->getBoneId() == boneId)
- {
- return 0;
- }
- }
- subAnimations.add(new BoneAnimation(boneId, originPos, originRot));
- return 1;
- }
- //! adds a keyframe for a specific bone of the sceleton
- //! \param kId id of the bone
- //! \param time the time in seconds since the start of the animation at
- //! which the bone should have the given position and rotation relative
- //! to its parent bone \param pos the position of the bone \param rot
- //! the rotation of the bone
- bool SkeletonAnimation::addKeyFrame(
- int boneId, double time, Vec3<float> pos, Vec3<float> rot)
- {
- for (BoneAnimation* animation : subAnimations)
- {
- if (animation->getBoneId() == boneId)
- {
- animation->addKeyFrame(time, pos, rot);
- return 1;
- }
- }
- return 0;
- }
- //! applys the animation on a given skeleton
- //! \param zS: the sceleton
- void SkeletonAnimation::apply(Skeleton* zS) const
- {
- for (BoneAnimation* animation : subAnimations)
- {
- animation->apply(zS);
- }
- }
- // calculates the positions and rotation at the next time
- // \param time the passed time in seconds since the last call
- void SkeletonAnimation::tick(double time)
- {
- for (BoneAnimation* animation : subAnimations)
- {
- animation->tick(time);
- }
- }
- // returns true if the animation has reached the last keyframe and does
- // not loop
- bool SkeletonAnimation::isFinished() const
- {
- for (BoneAnimation* animation : subAnimations)
- {
- if (!animation->isFinished()) return 0;
- }
- return 1;
- }
- // returns the maximum time of the animation
- double SkeletonAnimation::getMaxTime() const
- {
- double max = 0;
- for (BoneAnimation* animation : subAnimations)
- {
- max = MAX(animation->getMaxTime(), max);
- }
- return max;
- }
- // returns the animation for a specific bone or 0 if it does not exist
- BoneAnimation* SkeletonAnimation::zAnimation(int boneId) const
- {
- for (BoneAnimation* animation : subAnimations)
- {
- if (animation->getBoneId() == boneId) return animation;
- }
- return 0;
- }
|