AnimationClip.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. #include "Base.h"
  2. #include "AnimationClip.h"
  3. #include "Animation.h"
  4. #include "AnimationTarget.h"
  5. #include "Game.h"
  6. #include "Quaternion.h"
  7. namespace gameplay
  8. {
  9. AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
  10. : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), _repeatCount(1.0f),
  11. _activeDuration(_duration * _repeatCount), _speed(1.0f), _isPlaying(false), _timeStarted(0), _elapsedTime(0),
  12. _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), _isFadingOutStarted(false),
  13. _isFadingOut(false), _isFadingIn(false), _beginListeners(NULL), _endListeners(NULL)
  14. {
  15. assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
  16. unsigned int channelCount = _animation->_channels.size();
  17. for (unsigned int i = 0; i < channelCount; i++)
  18. {
  19. _values.push_back(new AnimationValue(_animation->_channels[i]->_curve->getComponentCount()));
  20. }
  21. }
  22. AnimationClip::~AnimationClip()
  23. {
  24. std::vector<AnimationValue*>::iterator valueIter = _values.begin();
  25. while (valueIter != _values.end())
  26. {
  27. SAFE_DELETE(*valueIter);
  28. valueIter++;
  29. }
  30. _values.clear();
  31. SAFE_RELEASE(_crossFadeToClip);
  32. SAFE_DELETE(_beginListeners);
  33. SAFE_DELETE(_endListeners);
  34. }
  35. const char* AnimationClip::getID() const
  36. {
  37. return _id.c_str();
  38. }
  39. Animation* AnimationClip::getAnimation() const
  40. {
  41. return _animation;
  42. }
  43. unsigned long AnimationClip::getStartTime() const
  44. {
  45. return _startTime;
  46. }
  47. unsigned long AnimationClip::getEndTime() const
  48. {
  49. return _endTime;
  50. }
  51. unsigned long AnimationClip::getElaspedTime() const
  52. {
  53. return _elapsedTime;
  54. }
  55. void AnimationClip::setRepeatCount(float repeatCount)
  56. {
  57. assert(repeatCount == REPEAT_INDEFINITE || repeatCount > 0.0f);
  58. _repeatCount = repeatCount;
  59. if (repeatCount == REPEAT_INDEFINITE)
  60. {
  61. _activeDuration = _duration;
  62. }
  63. else
  64. {
  65. _activeDuration = _repeatCount * _duration;
  66. }
  67. }
  68. float AnimationClip::getRepeatCount() const
  69. {
  70. return _repeatCount;
  71. }
  72. void AnimationClip::setActiveDuration(unsigned long duration)
  73. {
  74. if (duration == REPEAT_INDEFINITE)
  75. {
  76. _repeatCount = REPEAT_INDEFINITE;
  77. _activeDuration = _duration;
  78. }
  79. else
  80. {
  81. _activeDuration = _duration;
  82. _repeatCount = (float) _activeDuration / (float) _duration;
  83. }
  84. }
  85. unsigned long AnimationClip::getActiveDuration() const
  86. {
  87. if (_repeatCount == REPEAT_INDEFINITE)
  88. return REPEAT_INDEFINITE;
  89. return _activeDuration;
  90. }
  91. void AnimationClip::setSpeed(float speed)
  92. {
  93. _speed = speed;
  94. }
  95. float AnimationClip::getSpeed() const
  96. {
  97. return _speed;
  98. }
  99. void AnimationClip::setBlendWeight(float blendWeight)
  100. {
  101. _blendWeight = blendWeight;
  102. }
  103. float AnimationClip::getBlendWeight() const
  104. {
  105. return _blendWeight;
  106. }
  107. bool AnimationClip::isPlaying() const
  108. {
  109. return _isPlaying;
  110. }
  111. void AnimationClip::play()
  112. {
  113. _animation->_controller->schedule(this);
  114. _timeStarted = Game::getGameTime();
  115. }
  116. void AnimationClip::stop()
  117. {
  118. _animation->_controller->unschedule(this);
  119. if (_isPlaying)
  120. {
  121. _isPlaying = false;
  122. onEnd();
  123. }
  124. }
  125. void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
  126. {
  127. assert(clip);
  128. // If I already have a clip I'm fading to and it's not the same as the given clip release it.
  129. // Assign the new clip and increase it's ref count.
  130. // TODO: Do I need to anything else to the crossFade clip here before releasing?
  131. if (_crossFadeToClip)
  132. SAFE_RELEASE(_crossFadeToClip);
  133. _crossFadeToClip = clip;
  134. _crossFadeToClip->addRef();
  135. // Set the crossfade clip to fading in, and initialize it's blend weight to zero.
  136. _crossFadeToClip->_isFadingIn = true;
  137. _crossFadeToClip->_blendWeight = 0.0f;
  138. // Set this clip to fade out, set the fade duration and reset the fade elapsed time.
  139. _isFadingOut = true;
  140. _crossFadeOutElapsed = 0;
  141. _crossFadeOutDuration = duration;
  142. _isFadingOutStarted = true;
  143. // If this clip is currently not playing, we should start playing it.
  144. if (!_isPlaying)
  145. play();
  146. // Start playing the cross fade clip.
  147. _crossFadeToClip->play();
  148. }
  149. void AnimationClip::addBeginListener(AnimationClip::Listener* listener)
  150. {
  151. if (!_beginListeners)
  152. _beginListeners = new std::vector<Listener*>;
  153. _beginListeners->push_back(listener);
  154. }
  155. void AnimationClip::addEndListener(AnimationClip::Listener* listener)
  156. {
  157. if (!_endListeners)
  158. _endListeners = new std::vector<Listener*>;
  159. _endListeners->push_back(listener);
  160. }
  161. bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*>* activeTargets)
  162. {
  163. if (!_isPlaying)
  164. onBegin();
  165. else
  166. _elapsedTime += elapsedTime * _speed;
  167. unsigned long currentTime = 0L;
  168. // Check to see if clip is complete.
  169. if (_repeatCount != REPEAT_INDEFINITE && ((_speed >= 0 && _elapsedTime >= (long) _activeDuration) || (_speed <= 0 && _elapsedTime <= 0)))
  170. {
  171. _isPlaying = false;
  172. if (_speed >= 0)
  173. {
  174. currentTime = _activeDuration % _duration; // Get's the fractional part of the final repeat.
  175. if (currentTime == 0L)
  176. currentTime = _duration;
  177. }
  178. else
  179. {
  180. currentTime = 0L; // If we are negative speed, the end value should be 0.
  181. }
  182. }
  183. else
  184. {
  185. // Gets portion/fraction of the repeat.
  186. currentTime = (float) (_elapsedTime % _duration);
  187. }
  188. // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
  189. float percentComplete = (float)(_startTime + currentTime) / (float) _animation->_duration;
  190. if (_isFadingOut)
  191. {
  192. if (_isFadingOutStarted) // Calculate elapsed time since the fade out begin.
  193. {
  194. _crossFadeOutElapsed = (Game::getGameTime() - _crossFadeToClip->_timeStarted) * _speed;
  195. _isFadingOutStarted = false;
  196. }
  197. else
  198. {
  199. // continue tracking elapsed time.
  200. _crossFadeOutElapsed += elapsedTime * abs(_speed);
  201. }
  202. if (_crossFadeOutElapsed < _crossFadeOutDuration)
  203. {
  204. // Calculate this clip's blend weight.
  205. float tempBlendWeight = (float) (_crossFadeOutDuration - _crossFadeOutElapsed) / (float) _crossFadeOutDuration;
  206. // If this clip is fading in, adjust the crossfade clip's weight to be a percentage of your current blend weight
  207. if (_isFadingIn)
  208. {
  209. _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight) * _blendWeight;
  210. _blendWeight -= _crossFadeToClip->_blendWeight;
  211. }
  212. else
  213. {
  214. // Just set the blend weight.
  215. _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight);
  216. _blendWeight = tempBlendWeight;
  217. }
  218. }
  219. else
  220. { // Fade is done.
  221. // Set the crossFadeToClip's blend weight to 1
  222. _crossFadeToClip->_blendWeight = 1.0f;
  223. // Adjust the crossfade clip's blend weight if this clip is also fading in.
  224. if (_isFadingIn)
  225. _crossFadeToClip->_blendWeight *= _blendWeight;
  226. // The crossfade clip is no longer fading in
  227. _crossFadeToClip->_isFadingIn = false;
  228. // Release the crossfade clip, mark ourselves as done and set our blend weight to 0.
  229. SAFE_RELEASE(_crossFadeToClip);
  230. _blendWeight = 0.0f;
  231. _isFadingOut = false;
  232. _isPlaying = false;
  233. }
  234. }
  235. // Evaluate this clip.
  236. Animation::Channel* channel = NULL;
  237. AnimationValue* value = NULL;
  238. AnimationTarget* target = NULL;
  239. unsigned int channelCount = _animation->_channels.size();
  240. for (unsigned int i = 0; i < channelCount; i++)
  241. {
  242. channel = _animation->_channels[i];
  243. target = channel->_target;
  244. value = _values[i];
  245. // If the target's _animationPropertyBitFlag is clear, we can assume that this is the first
  246. // animation channel to act on the target and we can add the target to the list of
  247. // active targets stored by the AnimationController.
  248. if (target->_animationPropertyBitFlag == 0x00)
  249. activeTargets->push_front(target);
  250. // Evaluate the point on Curve
  251. channel->_curve->evaluate(percentComplete, value->_value);
  252. // Set the animation value on the target property.
  253. target->setAnimationPropertyValue(channel->_propertyId, value, _blendWeight);
  254. }
  255. // When ended. Probably should move to it's own method so we can call it when the clip is ended early.
  256. if (!_isPlaying)
  257. {
  258. onEnd();
  259. // Notify end listeners if any.
  260. if (_endListeners)
  261. {
  262. std::vector<Listener*>::iterator listener = _endListeners->begin();
  263. while (listener != _endListeners->end())
  264. {
  265. (*listener)->animationEvent(this, Listener::END);
  266. listener++;
  267. }
  268. }
  269. }
  270. return !_isPlaying;
  271. }
  272. void AnimationClip::onBegin()
  273. {
  274. // Initialize animation to play.
  275. _isPlaying = true;
  276. if (_speed >= 0)
  277. {
  278. _elapsedTime = 0;
  279. }
  280. else
  281. {
  282. _elapsedTime = _activeDuration;
  283. }
  284. _elapsedTime += (Game::getGameTime() - _timeStarted) * _speed;
  285. // Notify begin listeners.. if any.
  286. if (_beginListeners)
  287. {
  288. std::vector<Listener*>::iterator listener = _beginListeners->begin();
  289. while (listener != _beginListeners->end())
  290. {
  291. (*listener)->animationEvent(this, Listener::BEGIN);
  292. listener++;
  293. }
  294. }
  295. }
  296. void AnimationClip::onEnd()
  297. {
  298. _blendWeight = 1.0f;
  299. _timeStarted = 0;
  300. }
  301. }