Animation3D.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include "Animation3D.h"
  2. #include "Model3D.h"
  3. using namespace Framework;
  4. // create an animation for a specific bone
  5. // \param boneId the id of the bone
  6. // \param originPos the position of the bone at the beginning of the animation
  7. // \param originRot the rotation of the bone at the beginning of the animation
  8. BoneAnimation::BoneAnimation(
  9. int boneId, Vec3<float> originPos, Vec3<float> originRot)
  10. : ReferenceCounter(),
  11. boneId(boneId),
  12. frameCount(1),
  13. maxTime(0.0),
  14. loop(0)
  15. {
  16. frames = new KeyFrame[1];
  17. frames[0].time = 0.0;
  18. frames[0].pos = originPos;
  19. frames[9].rot = originRot;
  20. current = frames[0];
  21. }
  22. // destructor
  23. BoneAnimation::~BoneAnimation()
  24. {
  25. delete[] frames;
  26. }
  27. // make the animation to a loop that starts again if the end is reached
  28. void BoneAnimation::setLoop(bool loop)
  29. {
  30. this->loop = loop;
  31. }
  32. //! adds a keyframe
  33. //! \param time the time in seconds since the start of the animation at
  34. //! which the bone should have the given position and rotation relative
  35. //! to its parent bone \param pos the position of the bone \param rot
  36. //! the rotation of the bone
  37. void BoneAnimation::addKeyFrame(double time, Vec3<float> pos, Vec3<float> rot)
  38. {
  39. if (time < 0)
  40. throw "Illegal argument exception: time of a keyframe can not be lower "
  41. "than 0";
  42. if (maxTime < time) maxTime = time;
  43. frameCount++;
  44. KeyFrame* tmp = new KeyFrame[frameCount];
  45. bool added = 0;
  46. for (int i = 0; i < frameCount; i++)
  47. {
  48. if (i < frameCount - 1 && frames[i - (int)added].time <= time)
  49. {
  50. tmp[i] = frames[i];
  51. }
  52. else
  53. {
  54. if (!added)
  55. {
  56. tmp[i].time = time;
  57. tmp[i].pos = pos;
  58. tmp[i].rot = rot;
  59. added = 1;
  60. }
  61. else
  62. {
  63. tmp[i] = frames[i - 1];
  64. }
  65. }
  66. }
  67. delete[] frames;
  68. frames = tmp;
  69. }
  70. // calculates the positions and rotation at the next time
  71. // \param time the passed time in seconds since the last call
  72. void BoneAnimation::tick(double time)
  73. {
  74. if (frameCount <= 1) return;
  75. current.time += time;
  76. if (loop)
  77. {
  78. while (current.time >= maxTime)
  79. {
  80. current.time -= maxTime;
  81. }
  82. }
  83. else if (current.time > maxTime)
  84. {
  85. current.time = maxTime;
  86. }
  87. int last = -1;
  88. int next = -1;
  89. for (int i = 0; i < frameCount; i++)
  90. {
  91. last = next;
  92. next = i;
  93. if (frames[i].time > current.time)
  94. {
  95. break;
  96. }
  97. }
  98. float timePart = (float)(current.time - frames[last].time);
  99. current.pos
  100. = frames[last].pos + (frames[next].pos - frames[last].pos) * timePart;
  101. current.rot
  102. = frames[last].rot + (frames[next].rot - frames[last].rot) * timePart;
  103. }
  104. //! applys the animation on a given skeleton
  105. //! \param zS: the sceleton
  106. void BoneAnimation::apply(Skeleton* zSkelett) const
  107. {
  108. Bone* zK = zSkelett->zBone(boneId);
  109. if (zK)
  110. {
  111. zK->setPosition(current.pos);
  112. zK->setRotation(current.rot);
  113. }
  114. }
  115. // returns true if the animation has reached the last keyframe and does
  116. // not loop
  117. bool BoneAnimation::isFinished() const
  118. {
  119. return current.time >= maxTime;
  120. }
  121. // returns the bone id this animation is for
  122. int BoneAnimation::getBoneId() const
  123. {
  124. return boneId;
  125. }
  126. //! Constructor
  127. SkeletonAnimation::SkeletonAnimation()
  128. : ReferenceCounter(),
  129. loop(0)
  130. {}
  131. // make the animation to a loop that starts again if the end is reached
  132. void SkeletonAnimation::setLoop(bool loop)
  133. {
  134. this->loop = loop;
  135. for (BoneAnimation* animation : subAnimations)
  136. {
  137. animation->setLoop(loop);
  138. }
  139. }
  140. // adds an animation for a specific bone
  141. // \param boneId the bone id
  142. // \param originPos the position of the bone at the beginning of the animation
  143. // \param originRot the rotation of the bone at the beginning of the animation
  144. bool SkeletonAnimation::addAnimation(
  145. int boneId, Vec3<float> originPos, Vec3<float> originRot)
  146. {
  147. for (BoneAnimation* animation : subAnimations)
  148. {
  149. if (animation->getBoneId() == boneId)
  150. {
  151. return 0;
  152. }
  153. }
  154. subAnimations.add(new BoneAnimation(boneId, originPos, originRot));
  155. return 1;
  156. }
  157. //! adds a keyframe for a specific bone of the sceleton
  158. //! \param kId id of the bone
  159. //! \param time the time in seconds since the start of the animation at
  160. //! which the bone should have the given position and rotation relative
  161. //! to its parent bone \param pos the position of the bone \param rot
  162. //! the rotation of the bone
  163. bool SkeletonAnimation::addKeyFrame(
  164. int boneId, double time, Vec3<float> pos, Vec3<float> rot)
  165. {
  166. for (BoneAnimation* animation : subAnimations)
  167. {
  168. if (animation->getBoneId() == boneId)
  169. {
  170. animation->addKeyFrame(time, pos, rot);
  171. return 1;
  172. }
  173. }
  174. return 0;
  175. }
  176. //! applys the animation on a given skeleton
  177. //! \param zS: the sceleton
  178. void SkeletonAnimation::apply(Skeleton* zS) const
  179. {
  180. for (BoneAnimation* animation : subAnimations)
  181. {
  182. animation->apply(zS);
  183. }
  184. }
  185. // calculates the positions and rotation at the next time
  186. // \param time the passed time in seconds since the last call
  187. void SkeletonAnimation::tick(double time)
  188. {
  189. for (BoneAnimation* animation : subAnimations)
  190. {
  191. animation->tick(time);
  192. }
  193. }
  194. // returns true if the animation has reached the last keyframe and does
  195. // not loop
  196. bool SkeletonAnimation::isFinished() const
  197. {
  198. for (BoneAnimation* animation : subAnimations)
  199. {
  200. if (!animation->isFinished()) return 0;
  201. }
  202. return 1;
  203. }