1 //****************************************************************************//
2 // mixer.cpp //
3 // Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger //
4 //****************************************************************************//
5 // This library is free software; you can redistribute it and/or modify it //
6 // under the terms of the GNU Lesser General Public License as published by //
7 // the Free Software Foundation; either version 2.1 of the License, or (at //
8 // your option) any later version. //
9 //****************************************************************************//
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 //****************************************************************************//
16 // Includes //
17 //****************************************************************************//
18
19 #include "cal3d/error.h"
20 #include "cal3d/mixer.h"
21 #include "cal3d/coremodel.h"
22 #include "cal3d/corebone.h"
23 #include "cal3d/coreanimation.h"
24 #include "cal3d/coretrack.h"
25 #include "cal3d/corekeyframe.h"
26 #include "cal3d/model.h"
27 #include "cal3d/skeleton.h"
28 #include "cal3d/bone.h"
29 #include "cal3d/animation.h"
30 #include "cal3d/animation_action.h"
31 #include "cal3d/animation_cycle.h"
32
33 /*****************************************************************************/
34 /** Constructs the mixer instance.
35 *
36 * This function is the default constructor of the mixer instance.
37 *****************************************************************************/
38
CalMixer(CalModel * pModel)39 CalMixer::CalMixer(CalModel* pModel)
40 {
41 assert(pModel);
42
43 m_pModel = pModel;
44
45 // build the animation table
46 int coreAnimationCount = m_pModel->getCoreModel()->getCoreAnimationCount();
47
48 m_vectorAnimation.reserve(coreAnimationCount);
49 CalAnimation* null = 0;
50 m_vectorAnimation.insert(m_vectorAnimation.begin(), coreAnimationCount, null);
51
52 // set the animation time/duration values to default
53 m_animationTime = 0.0f;
54 m_animationDuration = 0.0f;
55 m_timeFactor = 1.0f;
56 }
57
58 /*****************************************************************************/
59 /** Destructs the mixer instance.
60 *
61 * This function is the destructor of the mixer instance.
62 *****************************************************************************/
63
~CalMixer()64 CalMixer::~CalMixer()
65 {
66 // destroy all active animation actions
67 while(!m_listAnimationAction.empty())
68 {
69 CalAnimationAction *pAnimationAction = m_listAnimationAction.front();
70 m_listAnimationAction.pop_front();
71
72 delete pAnimationAction;
73 }
74
75 // destroy all active animation cycles
76 while(!m_listAnimationCycle.empty())
77 {
78 CalAnimationCycle *pAnimationCycle;
79 pAnimationCycle = m_listAnimationCycle.front();
80 m_listAnimationCycle.pop_front();
81
82 delete pAnimationCycle;
83 }
84
85 // clear the animation table
86 m_vectorAnimation.clear();
87
88 m_pModel = 0;
89 }
90
91 ///
92 /// Examines the given animation and if the first and last keyframe of a given track
93 /// do not match up, the first key frame is duplicated and added to the end of the track
94 /// to ensure smooth looping.
95 ///
addExtraKeyframeForLoopedAnim(CalCoreAnimation * pCoreAnimation)96 static void addExtraKeyframeForLoopedAnim(CalCoreAnimation* pCoreAnimation)
97 {
98 std::list<CalCoreTrack*>& listCoreTrack = pCoreAnimation->getListCoreTrack();
99
100 if(listCoreTrack.size() == 0)
101 return;
102
103 CalCoreTrack *coreTrack = listCoreTrack.front();
104 if(coreTrack == 0)
105 return;
106
107 CalCoreKeyframe *lastKeyframe = coreTrack->getCoreKeyframe(coreTrack->getCoreKeyframeCount()-1);
108 if(lastKeyframe == 0)
109 return;
110
111 if(lastKeyframe->getTime() < pCoreAnimation->getDuration())
112 {
113 std::list<CalCoreTrack *>::iterator itr;
114 for(itr=listCoreTrack.begin();itr!=listCoreTrack.end();++itr)
115 {
116 coreTrack = *itr;
117
118 CalCoreKeyframe *firstKeyframe = coreTrack->getCoreKeyframe(0);
119 CalCoreKeyframe *newKeyframe = new CalCoreKeyframe();
120
121 newKeyframe->setTranslation(firstKeyframe->getTranslation());
122 newKeyframe->setRotation(firstKeyframe->getRotation());
123 newKeyframe->setTime(pCoreAnimation->getDuration());
124
125 coreTrack->addCoreKeyframe(newKeyframe);
126 }
127 }
128 }
129
130 /*****************************************************************************/
131 /** Interpolates the weight of an animation cycle.
132 *
133 * This function interpolates the weight of an animation cycle to a new value
134 * in a given amount of time. If the specified animation cycle is not active
135 * yet, it is activated.
136 *
137 * @param id The ID of the animation cycle that should be blended.
138 * @param weight The weight to interpolate the animation cycle to.
139 * @param delay The time in seconds until the new weight should be reached.
140 *
141 * @return One of the following values:
142 * \li \b true if successful
143 * \li \b false if an error happend
144 *****************************************************************************/
145
blendCycle(int id,float weight,float delay)146 bool CalMixer::blendCycle(int id, float weight, float delay)
147 {
148 if((id < 0) || (id >= (int)m_vectorAnimation.size()))
149 {
150 CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
151 return false;
152 }
153
154 // get the animation for the given id
155 CalAnimation *pAnimation = m_vectorAnimation[id];
156
157 // create a new animation instance if it is not active yet
158 if(pAnimation == 0)
159 {
160 // take the fast way out if we are trying to clear an inactive animation
161 if(weight == 0.0f) return true;
162
163 // get the core animation
164 CalCoreAnimation *pCoreAnimation = m_pModel->getCoreModel()->getCoreAnimation(id);
165 if(pCoreAnimation == 0) return false;
166
167 // Ensure that the animation's first and last key frame match for proper
168 // looping.
169 ::addExtraKeyframeForLoopedAnim(pCoreAnimation);
170
171 // allocate a new animation cycle instance
172 CalAnimationCycle *pAnimationCycle = new CalAnimationCycle(pCoreAnimation);
173 if(pAnimationCycle == 0)
174 {
175 CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
176 return false;
177 }
178
179 // insert new animation into the tables
180 m_vectorAnimation[id] = pAnimationCycle;
181 m_listAnimationCycle.push_front(pAnimationCycle);
182
183 // blend the animation
184 return pAnimationCycle->blend(weight, delay);
185 }
186
187 // check if this is really a animation cycle instance
188 if(pAnimation->getType() != CalAnimation::TYPE_CYCLE)
189 {
190 CalError::setLastError(CalError::INVALID_ANIMATION_TYPE, __FILE__, __LINE__);
191 return false;
192 }
193
194 // clear the animation cycle from the active vector if the target weight is zero
195 if(weight == 0.0f)
196 {
197 m_vectorAnimation[id] = 0;
198 }
199
200 // cast it to an animation cycle
201 CalAnimationCycle *pAnimationCycle;
202 pAnimationCycle = (CalAnimationCycle *)pAnimation;
203
204 // blend the animation cycle
205 pAnimationCycle->blend(weight, delay);
206 pAnimationCycle->checkCallbacks(0,m_pModel);
207 return true;
208 }
209
210 /*****************************************************************************/
211 /** Fades an animation cycle out.
212 *
213 * This function fades an animation cycle out in a given amount of time.
214 *
215 * @param id The ID of the animation cycle that should be faded out.
216 * @param delay The time in seconds until the the animation cycle is
217 * completely removed.
218 *
219 * @return One of the following values:
220 * \li \b true if successful
221 * \li \b false if an error happend
222 *****************************************************************************/
223
clearCycle(int id,float delay)224 bool CalMixer::clearCycle(int id, float delay)
225 {
226 // check if the animation id is valid
227 if((id < 0) || (id >= (int)m_vectorAnimation.size()))
228 {
229 CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
230 return false;
231 }
232
233 // get the animation for the given id
234 CalAnimation *pAnimation;
235 pAnimation = m_vectorAnimation[id];
236
237 // we can only clear cycles that are active
238 if(pAnimation == 0) return true;
239
240 // check if this is really a animation cycle instance
241 if(pAnimation->getType() != CalAnimation::TYPE_CYCLE)
242 {
243 CalError::setLastError(CalError::INVALID_ANIMATION_TYPE, __FILE__, __LINE__);
244 return false;
245 }
246
247 // clear the animation cycle from the active vector
248 m_vectorAnimation[id] = 0;
249
250 // cast it to an animation cycle
251 CalAnimationCycle *pAnimationCycle;
252 pAnimationCycle = (CalAnimationCycle *)pAnimation;
253
254 // set animation cycle to async state
255 pAnimationCycle->setAsync(m_animationTime, m_animationDuration);
256
257 // blend the animation cycle
258 pAnimationCycle->blend(0.0f, delay);
259 pAnimationCycle->checkCallbacks(0, m_pModel);
260 return true;
261 }
262
263 /*****************************************************************************/
264 /** Executes an animation action.
265 *
266 * This function executes an animation action.
267 *
268 * @param id The ID of the animation action that should be blended.
269 * @param delayIn The time in seconds until the animation action reaches the
270 * full weight from the beginning of its execution.
271 * @param delayOut The time in seconds in which the animation action reaches
272 * zero weight at the end of its execution.
273 * @param weightTarget The weight to interpolate the animation action to.
274 * @param autoLock This prevents the Action from being reset and removed
275 * on the last keyframe if true.
276 *
277 * @return One of the following values:
278 * \li \b true if successful
279 * \li \b false if an error happend
280 *****************************************************************************/
executeAction(int id,float delayIn,float delayOut,float weightTarget,bool autoLock)281 bool CalMixer::executeAction(int id, float delayIn, float delayOut, float weightTarget, bool autoLock)
282 {
283 // get the core animation
284 CalCoreAnimation *pCoreAnimation;
285 pCoreAnimation = m_pModel->getCoreModel()->getCoreAnimation(id);
286 if(pCoreAnimation == 0)
287 {
288 return false;
289 }
290
291 // allocate a new animation action instance
292 CalAnimationAction *pAnimationAction = new CalAnimationAction(pCoreAnimation);
293 if(pAnimationAction == 0)
294 {
295 CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
296 return false;
297 }
298
299 // insert new animation into the table
300 m_listAnimationAction.push_front(pAnimationAction);
301
302 // execute the animation
303 pAnimationAction->execute(delayIn, delayOut, weightTarget, autoLock);
304 pAnimationAction->checkCallbacks(0, m_pModel);
305 return true;
306 }
307
308 /*****************************************************************************/
309 /** Clears an active animation action.
310 *
311 * This function removes an animation action from the blend list. This is
312 * particularly useful with auto-locked actions on their last frame.
313 *
314 * @param id The ID of the animation action that should be removed.
315 *
316 * @return One of the following values:
317 * \li \b true if successful
318 * \li \b false if an error happened or action was not found
319 *****************************************************************************/
removeAction(int id)320 bool CalMixer::removeAction(int id)
321 {
322 // get the core animation
323 CalCoreAnimation *pCoreAnimation;
324 pCoreAnimation = m_pModel->getCoreModel()->getCoreAnimation(id);
325 if(pCoreAnimation == 0)
326 {
327 return false;
328 }
329
330 // update all active animation actions of this model
331 std::list<CalAnimationAction *>::iterator iteratorAnimationAction;
332 iteratorAnimationAction = m_listAnimationAction.begin();
333
334 while(iteratorAnimationAction != m_listAnimationAction.end())
335 {
336 // find the specified action and remove it
337 if((*iteratorAnimationAction)->getCoreAnimation() == pCoreAnimation )
338 {
339 // found, so remove
340 (*iteratorAnimationAction)->completeCallbacks(m_pModel);
341 delete (*iteratorAnimationAction);
342 iteratorAnimationAction = m_listAnimationAction.erase(iteratorAnimationAction);
343 return true;
344 }
345 iteratorAnimationAction++;
346 }
347 return false;
348 }
349
350 /*****************************************************************************/
351 /** Updates all active animations.
352 *
353 * This function updates all active animations of the mixer instance for a
354 * given amount of time.
355 *
356 * @param deltaTime The elapsed time in seconds since the last update.
357 *****************************************************************************/
358
updateAnimation(float deltaTime)359 void CalMixer::updateAnimation(float deltaTime)
360 {
361 // update the current animation time
362 if(m_animationDuration == 0.0f)
363 {
364 m_animationTime = 0.0f;
365 }
366 else
367 {
368 m_animationTime += deltaTime * m_timeFactor;
369 if(m_animationTime >= m_animationDuration || m_animationTime<0)
370 {
371 m_animationTime = (float) fmod(m_animationTime, m_animationDuration);
372 }
373 if (m_animationTime < 0)
374 m_animationTime += m_animationDuration;
375
376 }
377
378 // update all active animation actions of this model
379 std::list<CalAnimationAction *>::iterator iteratorAnimationAction;
380 iteratorAnimationAction = m_listAnimationAction.begin();
381
382 while(iteratorAnimationAction != m_listAnimationAction.end())
383 {
384 // update and check if animation action is still active
385 if((*iteratorAnimationAction)->update(deltaTime))
386 {
387 (*iteratorAnimationAction)->checkCallbacks((*iteratorAnimationAction)->getTime(),m_pModel);
388 ++iteratorAnimationAction;
389 }
390 else
391 {
392 // animation action has ended, destroy and remove it from the animation list
393 (*iteratorAnimationAction)->completeCallbacks(m_pModel);
394 delete (*iteratorAnimationAction);
395 iteratorAnimationAction = m_listAnimationAction.erase(iteratorAnimationAction);
396 }
397 }
398
399 // todo: update all active animation poses of this model
400
401 // update the weight of all active animation cycles of this model
402 std::list<CalAnimationCycle *>::iterator iteratorAnimationCycle;
403 iteratorAnimationCycle = m_listAnimationCycle.begin();
404
405 float accumulatedWeight, accumulatedDuration;
406 accumulatedWeight = 0.0f;
407 accumulatedDuration = 0.0f;
408
409 while(iteratorAnimationCycle != m_listAnimationCycle.end())
410 {
411 // update and check if animation cycle is still active
412 if((*iteratorAnimationCycle)->update(deltaTime))
413 {
414 // check if it is in sync. if yes, update accumulated weight and duration
415 if((*iteratorAnimationCycle)->getState() == CalAnimation::STATE_SYNC)
416 {
417 accumulatedWeight += (*iteratorAnimationCycle)->getWeight();
418 accumulatedDuration += (*iteratorAnimationCycle)->getWeight() * (*iteratorAnimationCycle)->getCoreAnimation()->getDuration();
419 }
420
421 (*iteratorAnimationCycle)->checkCallbacks(m_animationTime,m_pModel);
422 ++iteratorAnimationCycle;
423 }
424 else
425 {
426 // animation cycle has ended, destroy and remove it from the animation list
427 (*iteratorAnimationCycle)->completeCallbacks(m_pModel);
428 delete (*iteratorAnimationCycle);
429 iteratorAnimationCycle = m_listAnimationCycle.erase(iteratorAnimationCycle);
430 }
431 }
432
433 // adjust the global animation cycle duration
434 if(accumulatedWeight > 0.0f)
435 {
436 m_animationDuration = accumulatedDuration / accumulatedWeight;
437 }
438 else
439 {
440 m_animationDuration = 0.0f;
441 }
442 }
443
updateSkeleton()444 void CalMixer::updateSkeleton()
445 {
446 // get the skeleton we need to update
447 CalSkeleton *pSkeleton;
448 pSkeleton = m_pModel->getSkeleton();
449 if(pSkeleton == 0) return;
450
451 // clear the skeleton state
452 pSkeleton->clearState();
453
454 // get the bone vector of the skeleton
455 std::vector<CalBone *>& vectorBone = pSkeleton->getVectorBone();
456
457 // loop through all animation actions
458 std::list<CalAnimationAction *>::iterator iteratorAnimationAction;
459 for(iteratorAnimationAction = m_listAnimationAction.begin(); iteratorAnimationAction != m_listAnimationAction.end(); ++iteratorAnimationAction)
460 {
461 // get the core animation instance
462 CalCoreAnimation *pCoreAnimation;
463 pCoreAnimation = (*iteratorAnimationAction)->getCoreAnimation();
464
465 // get the list of core tracks of above core animation
466 std::list<CalCoreTrack *>& listCoreTrack = pCoreAnimation->getListCoreTrack();
467
468 // loop through all core tracks of the core animation
469 std::list<CalCoreTrack *>::iterator iteratorCoreTrack;
470 for(iteratorCoreTrack = listCoreTrack.begin(); iteratorCoreTrack != listCoreTrack.end(); ++iteratorCoreTrack)
471 {
472 // get the appropriate bone of the track
473 CalBone *pBone;
474 pBone = vectorBone[(*iteratorCoreTrack)->getCoreBoneId()];
475
476 // get the current translation and rotation
477 CalVector translation;
478 CalQuaternion rotation;
479 (*iteratorCoreTrack)->getState((*iteratorAnimationAction)->getTime(), translation, rotation);
480
481 // blend the bone state with the new state
482 pBone->blendState((*iteratorAnimationAction)->getWeight(), translation, rotation);
483 }
484 }
485
486 // lock the skeleton state
487 pSkeleton->lockState();
488
489 // loop through all animation cycles
490 std::list<CalAnimationCycle *>::iterator iteratorAnimationCycle;
491 for(iteratorAnimationCycle = m_listAnimationCycle.begin(); iteratorAnimationCycle != m_listAnimationCycle.end(); ++iteratorAnimationCycle)
492 {
493 // get the core animation instance
494 CalCoreAnimation *pCoreAnimation;
495 pCoreAnimation = (*iteratorAnimationCycle)->getCoreAnimation();
496
497 // calculate adjusted time
498 float animationTime;
499 if((*iteratorAnimationCycle)->getState() == CalAnimation::STATE_SYNC)
500 {
501 if(m_animationDuration == 0.0f)
502 {
503 animationTime = 0.0f;
504 }
505 else
506 {
507 animationTime = m_animationTime * pCoreAnimation->getDuration() / m_animationDuration;
508 }
509 }
510 else
511 {
512 animationTime = (*iteratorAnimationCycle)->getTime();
513 }
514
515 // get the list of core tracks of above core animation
516 std::list<CalCoreTrack *>& listCoreTrack = pCoreAnimation->getListCoreTrack();
517
518 // loop through all core tracks of the core animation
519 std::list<CalCoreTrack *>::iterator iteratorCoreTrack;
520 for(iteratorCoreTrack = listCoreTrack.begin(); iteratorCoreTrack != listCoreTrack.end(); ++iteratorCoreTrack)
521 {
522 // get the appropriate bone of the track
523 CalBone *pBone;
524 pBone = vectorBone[(*iteratorCoreTrack)->getCoreBoneId()];
525
526 // get the current translation and rotation
527 CalVector translation;
528 CalQuaternion rotation;
529 (*iteratorCoreTrack)->getState(animationTime, translation, rotation);
530
531 // blend the bone state with the new state
532 pBone->blendState((*iteratorAnimationCycle)->getWeight(), translation, rotation);
533 }
534 }
535
536 // lock the skeleton state
537 pSkeleton->lockState();
538
539 // let the skeleton calculate its final state
540 pSkeleton->calculateState();
541 }
542
543 /*****************************************************************************/
544 /** Returns the animation time.
545 *
546 * This function returns the animation time of the mixer instance.
547 *
548 * @return The animation time in seconds.
549 *****************************************************************************/
550
getAnimationTime() const551 float CalMixer::getAnimationTime() const
552 {
553 return m_animationTime;
554 }
555
556 /*****************************************************************************/
557 /** Returns the animation duration.
558 *
559 * This function returns the animation duration of the mixer instance.
560 *
561 * @return The animation duration in seconds.
562 *****************************************************************************/
563
getAnimationDuration() const564 float CalMixer::getAnimationDuration() const
565 {
566 return m_animationDuration;
567 }
568
569 /*****************************************************************************/
570 /** Sets the animation time.
571 *
572 * This function sets the animation time of the mixer instance.
573 *
574 *****************************************************************************/
575
setAnimationTime(float animationTime)576 void CalMixer::setAnimationTime(float animationTime)
577 {
578 m_animationTime=animationTime;
579 }
580
581 /*****************************************************************************/
582 /** Set the time factor.
583 *
584 * This function sets the time factor of the mixer instance.
585 * this time factor affect only sync animation
586 *
587 *****************************************************************************/
588
setTimeFactor(float timeFactor)589 void CalMixer::setTimeFactor(float timeFactor)
590 {
591 m_timeFactor = timeFactor;
592 }
593
594 /*****************************************************************************/
595 /** Get the time factor.
596 *
597 * This function return the time factor of the mixer instance.
598 *
599 *****************************************************************************/
600
getTimeFactor() const601 float CalMixer::getTimeFactor() const
602 {
603 return m_timeFactor;
604 }
605
606 /*****************************************************************************/
607 /** Get the model.
608 *
609 * This function return the CalModel of the mixer instance.
610 *
611 *****************************************************************************/
612
getCalModel()613 CalModel *CalMixer::getCalModel()
614 {
615 return m_pModel;
616 }
617
618 /*****************************************************************************/
619 /** Get the animation vector.
620 *
621 * This function return the animation vector of the mixer instance.
622 *
623 *****************************************************************************/
624
getAnimationVector()625 std::vector<CalAnimation *> & CalMixer::getAnimationVector()
626 {
627 return m_vectorAnimation;
628 }
629
630 /*****************************************************************************/
631 /** Get the list of the action animation.
632 *
633 * This function return the list of the action animation of the mixer instance.
634 *
635 *****************************************************************************/
636
getAnimationActionList()637 std::list<CalAnimationAction *> & CalMixer::getAnimationActionList()
638 {
639 return m_listAnimationAction;
640 }
641
642 /*****************************************************************************/
643 /** Get the list of the cycle animation.
644 *
645 * This function return the list of the cycle animation of the mixer instance.
646 *
647 *****************************************************************************/
648
getAnimationCycle()649 std::list<CalAnimationCycle *> & CalMixer::getAnimationCycle()
650 {
651 return m_listAnimationCycle;
652 }
653
654 //****************************************************************************//
655