1 //****************************************************************************//
2 // mixer.h                                                                    //
3 // Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger                       //
4 // Copyright (C) 2004 Mekensleep <licensing@mekensleep.com>                   //
5 //****************************************************************************//
6 // This library is free software; you can redistribute it and/or modify it    //
7 // under the terms of the GNU Lesser General Public License as published by   //
8 // the Free Software Foundation; either version 2.1 of the License, or (at    //
9 // your option) any later version.                                            //
10 //****************************************************************************//
11 
12 #ifndef CAL_MIXER_H
13 #define CAL_MIXER_H
14 
15 //****************************************************************************//
16 // Includes                                                                   //
17 //****************************************************************************//
18 
19 #include "cal3d/global.h"
20 
21 //****************************************************************************//
22 // Forward declarations                                                       //
23 //****************************************************************************//
24 
25 class CalModel;
26 class CalAnimation;
27 class CalAnimationAction;
28 class CalAnimationCycle;
29 
30 
31 
32 
33 /*****************************************************************************/
34 /**
35  * CalAbstractMixer defines the API that CalModel relies on for
36  * blending and scheduling animations. A third party mixer must
37  * implement this API in order to register itself with the
38  * CalModel::setAbstractMixer method. The default mixer (CalMixer) is
39  * an example of such implementation.
40  *
41  * cal3d expects a mixer to handle two tasks : scheduling and
42  * blending. Scheduling refers to everything related to time such
43  * as when an animation must run or when it must stop. Blending
44  * defines how concurrent animations influence each other: for
45  * instance walking and waving.
46  *
47  * If CalMixer proves to be insufficient for the applications needs,
48  * an alternate mixer can be implemented and used without notifying
49  * cal3d in any way. It is not mandatory to subclass
50  * CalAbstractMixer. However, when chosing this path, one must also
51  * avoid using the CalModel::update method because it would use the
52  * default mixer instantiated by the CalModel::create method with
53  * undesirable side effects. In addition libraries based on cal3d
54  * (think NebulaDevice or OpenSceneGraph adapters) are not aware of
55  * these constraints and will keep calling the CalModel::update method of
56  * CalModel regardless.
57  *
58  * Subclassing CalAbstractMixer when implementing an alternate mixer
59  * therefore provides a better integration with cal3d and libraries
60  * that rely on CalModel. However, an additional effort is required in
61  * order to achieve compatibility with libraries or applications that
62  * rely on the CalMixer API (i.e. that use methods such as blendCycle
63  * or executeAction).  The CalMixer API is not meant to be generic and
64  * there is no reason to define an abstract class that specifies
65  * it. For historical reasons and because CalMixer is the default
66  * mixer, some applications and libraries (think Soya or CrystalSpace)
67  * depend on it. If they want to switch to a scheduler with extended
68  * capabilities it might be painfull for them to learn a completely
69  * different API. A scheduler with the ambition to obsolete CalMixer
70  * should therefore provide an API compatible with it to ease the
71  * migration process.
72  *
73  * Short summary, if you want to write a new mixer:
74  *
75  * 1) An external mixer: ignore CalAbstractMixer and implement a mixer
76  * of your own. Avoid calling CalModel::update and any library or
77  * application that will call it behind your back. Avoid libraries and
78  * applications that rely on the default mixer CalMixer, as returned
79  * by CalModel::getMixer.
80  *
81  * 2) A mixer registered in cal3d : subclass CalAbstractMixer,
82  * register it with CalModel::setAbstractMixer.  Avoid libraries and
83  * applications that rely on the default mixer CalMixer, as returned
84  * by CalModel::getMixer. CalModel::getMixer will return a null
85  * pointer if CalModel::setAbstractMixer was called to set
86  * a mixer that is not an instance of CalMixer.
87  *
88  * 3) A CalMixer replacement : same as 2) and provide a subclass of
89  * your own mixer that implements the CalMixer API so that existing
90  * applications can switch to it by calling CalModel::getAbstractMixer
91  * instead of CalModel::getMixer. The existing code using the CalMixer
92  * methods will keep working and the developper will be able to
93  * switch to a new API when convenient.
94  *
95  *****************************************************************************/
96 
97 class CAL3D_API CalAbstractMixer
98 {
99 public:
CalAbstractMixer()100   CalAbstractMixer() {}
~CalAbstractMixer()101   virtual ~CalAbstractMixer() {}
102 
103   /*****************************************************************************/
104   /**
105    * Is the object an instance of the default mixer (i.e. an instance of CalMixer) ?
106    *
107    * @return \li \b true if an instance of CalMixer
108    *         \li \b false if not an instance of CalMixer
109    *
110    *****************************************************************************/
isDefaultMixer()111   virtual bool isDefaultMixer() const { return false; }
112 
113   /*****************************************************************************/
114   /**
115    * Notifies the instance that updateAnimation was last called
116    * deltaTime seconds ago. The internal scheduler of the instance
117    * should terminate animations or update the timing information of
118    * active animations accordingly. It should not blend animations
119    * together or otherwise modify the CalModel associated to these
120    * animations.
121    *
122    * The CalModel::update method will call updateSkeleton immediately
123    * after updateAnimation if the instance was allocated by
124    * CalModel::create (in which case it is a CalMixer instance) or if
125    * the instance was set via CalModel::setAbstractMixer.
126    *
127    * @param deltaTime The elapsed time in seconds since the last call.
128    *
129    *****************************************************************************/
130   virtual void updateAnimation(float deltaTime) = 0;
131 
132   /*****************************************************************************/
133   /**
134    * Updates the skeleton of the corresponding CalModel (as provided to
135    * the create method) to match the current animation state (as
136    * updated by the last call to updateAnimation).  The tracks of each
137    * active animation are blended to compute the position and
138    * orientation of each bone of the skeleton. The updateAnimation
139    * method should be called just before calling updateSkeleton to
140    * define the set of active animations.
141    *
142    * The CalModel::update method will call updateSkeleton immediately
143    * after updateAnimation if the instance was allocated by
144    * CalModel::create (in which case it is a CalMixer instance) or if
145    * the instance was set via CalModel::setAbstractMixer.
146    *
147    *****************************************************************************/
148   virtual void updateSkeleton() = 0;
149 };
150 
151 
152 class CAL3D_API CalMixer : public CalAbstractMixer
153 {
154 public:
155   CalMixer(CalModel* pModel);
156   virtual ~CalMixer();
157 
isDefaultMixer()158   virtual bool isDefaultMixer() const { return true; }
159   bool blendCycle(int id, float weight, float delay);
160   bool clearCycle(int id, float delay);
161   bool executeAction(int id, float delayIn, float delayOut, float weightTarget = 1.0f, bool autoLock=false);
162   bool removeAction(int id);
163   virtual void updateAnimation(float deltaTime);
164   virtual void updateSkeleton();
165   float getAnimationTime() const;
166   float getAnimationDuration() const;
167   void setAnimationTime(float animationTime);
168   void setTimeFactor(float timeFactor);
169   float getTimeFactor() const;
170   CalModel *getCalModel();
171   std::vector<CalAnimation *> &getAnimationVector();
172   std::list<CalAnimationAction *> &getAnimationActionList();
173   std::list<CalAnimationCycle *> &getAnimationCycle();
174 
175 protected:
176   CalModel *m_pModel;
177   std::vector<CalAnimation *> m_vectorAnimation;
178   std::list<CalAnimationAction *> m_listAnimationAction;
179   std::list<CalAnimationCycle *> m_listAnimationCycle;
180   float m_animationTime;
181   float m_animationDuration;
182   float m_timeFactor;
183 };
184 
185 #endif
186 
187 //****************************************************************************//
188