Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / animation_playlist.cpp
blob336d8d44b768191cf319f73e2ce3d2bd9639f856
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/animation_playlist.h"
20 #include "nel/misc/common.h"
21 #include "nel/misc/stream.h"
23 using namespace NLMISC;
25 #ifdef DEBUG_NEW
26 #define new DEBUG_NEW
27 #endif
29 namespace NL3D
32 // ***************************************************************************
34 CAnimationPlaylist::CAnimationPlaylist()
36 // Empty the playlist
37 emptyPlayList ();
39 // Set default wrap mode
40 for (uint i=0; i<CChannelMixer::NumAnimationSlot; i++)
41 _WrapMode[i]=Clamp;
44 // ***************************************************************************
46 void CAnimationPlaylist::emptyPlayList ()
48 // Empty each slot
49 for (uint i=0; i<CChannelMixer::NumAnimationSlot; i++)
51 _Animations[i]=empty;
52 _SkeletonWeight[i]=empty;
53 _InvertWeight[i]=false;
54 _TimeOrigin[i]=0.f;
55 _SpeedFactor[i]=1.f;
56 _StartWeight[i]=1.f;
57 _EndWeight[i]=1.f;
58 _StartWeightTime[i]= 0.f;
59 _EndWeightTime[i]= 0.f;
60 _Smoothness[i]= 0.f;
64 // ***************************************************************************
66 void CAnimationPlaylist::setAnimation (uint8 slot, uint animation)
68 _Animations[slot]=animation;
71 // ***************************************************************************
73 uint CAnimationPlaylist::getAnimation (uint8 slot) const
75 return _Animations[slot];
78 // ***************************************************************************
80 void CAnimationPlaylist::setSkeletonWeight (uint8 slot, uint skeletonId, bool inverted)
82 _SkeletonWeight[slot]=skeletonId;
83 _InvertWeight[slot]=inverted;
86 // ***************************************************************************
88 uint CAnimationPlaylist::getSkeletonWeight (uint8 slot, bool &inverted) const
90 inverted=_InvertWeight[slot];
91 return _SkeletonWeight[slot];
94 // ***************************************************************************
96 void CAnimationPlaylist::setTimeOrigin (uint8 slot, TGlobalAnimationTime timeOrigin)
98 _TimeOrigin[slot]=timeOrigin;
101 // ***************************************************************************
103 TGlobalAnimationTime CAnimationPlaylist::getTimeOrigin (uint8 slot) const
105 return _TimeOrigin[slot];
108 // ***************************************************************************
110 void CAnimationPlaylist::setSpeedFactor (uint8 slot, float speedFactor)
112 _SpeedFactor[slot]=speedFactor;
115 // ***************************************************************************
117 float CAnimationPlaylist::getSpeedFactor (uint8 slot) const
119 return _SpeedFactor[slot];
122 // ***************************************************************************
124 void CAnimationPlaylist::setStartWeight (uint8 slot, float startWeight, TGlobalAnimationTime time)
126 _StartWeight[slot]=startWeight;
127 _StartWeightTime[slot]=time;
130 // ***************************************************************************
132 float CAnimationPlaylist::getStartWeight (uint8 slot, TGlobalAnimationTime& time) const
134 time=_StartWeightTime[slot];
135 return _StartWeight[slot];
138 // ***************************************************************************
140 void CAnimationPlaylist::setEndWeight (uint8 slot, float endWeight, TGlobalAnimationTime time)
142 _EndWeight[slot]=endWeight;
143 _EndWeightTime[slot]=time;
146 // ***************************************************************************
148 float CAnimationPlaylist::getEndWeight (uint8 slot, TGlobalAnimationTime& time) const
150 time=_EndWeightTime[slot];
151 return _EndWeight[slot];
154 // ***************************************************************************
156 void CAnimationPlaylist::setWeightSmoothness (uint8 slot, float smoothness)
158 _Smoothness[slot]=smoothness;
161 // ***************************************************************************
163 float CAnimationPlaylist::getWeightSmoothness (uint8 slot) const
165 return _Smoothness[slot];
168 // ***************************************************************************
170 void CAnimationPlaylist::setupMixer (CChannelMixer& mixer, TGlobalAnimationTime time) const
172 // For each slot
173 for (uint8 s=0; s<CChannelMixer::NumAnimationSlot; s++)
175 // *** Set the time
177 // Animation enabled
178 bool enabled=true;
180 // Get the animationSet pointer from the mixer
181 const CAnimationSet *animSet=mixer.getAnimationSet ();
183 // If is exists
184 if (animSet)
186 if (_Animations[s]!=empty)
188 // Get the local time
189 TAnimationTime wrappedTime = getLocalTime (s, time, *animSet);
191 // Get the animation
192 const CAnimation *pAnimation=animSet->getAnimation (_Animations[s]);
194 // Disable mode ?
195 if ((_WrapMode[s]==Disable)&&((wrappedTime<pAnimation->getBeginTime ())||(wrappedTime>pAnimation->getEndTime ())))
196 enabled=false;
198 // Set the time
199 if (enabled)
200 mixer.setSlotTime (s, wrappedTime);
204 // *** Set the animation
206 // Still enabled
207 if (enabled)
209 // empty ?
210 if (_Animations[s]==empty)
211 // Empty the slot
212 mixer.emptySlot (s);
213 else
214 // Set the animation id
215 mixer.setSlotAnimation (s, _Animations[s]);
217 // *** Set the skeleton weight
219 // empty ?
220 if (_SkeletonWeight[s]==empty)
221 // Empty the slot
222 mixer.resetSkeletonWeight (s);
223 else
224 // Set the animation id
225 mixer.applySkeletonWeight (s, _SkeletonWeight[s], _InvertWeight[s]);
227 // *** Set the weight
228 mixer.setSlotWeight (s, getWeightValue (_StartWeightTime[s], _EndWeightTime[s], time, _StartWeight[s], _EndWeight[s], _Smoothness[s]));
230 else
232 // Disable this slot
233 mixer.emptySlot (s);
238 // ***************************************************************************
240 float CAnimationPlaylist::getWeightValue (TGlobalAnimationTime startWeightTime, TGlobalAnimationTime endWeightTime, TGlobalAnimationTime time, float startWeight, float endWeight, float smoothness)
242 // Clamp left
243 if (time<=startWeightTime)
244 return startWeight;
245 // Clamp left
246 if (time>=endWeightTime)
247 return endWeight;
249 // *** Interpolate
251 // Linear value
252 TGlobalAnimationTime linear=startWeight+(endWeight-startWeight)*(time-startWeightTime)/(endWeightTime-startWeightTime);
254 // Linear ?
255 if (smoothness<0.0001f)
256 return (float)linear;
258 // Quadratic value
259 double a=2.f*startWeight-2.f*endWeight;
260 double b=3.f*endWeight-3.f*startWeight;
261 double x=(time-startWeightTime)/(endWeightTime-startWeightTime);
262 double xSquare=x*x;
263 double xCube=x*xSquare;
264 double quad=a*xCube+b*xSquare+startWeight;
266 // Interpolate between linear and quadratic
267 return (float)(smoothness*quad+(1.f-smoothness)*linear);
270 // ***************************************************************************
272 void CAnimationPlaylist::setWrapMode (uint8 slot, TWrapMode wrapMode)
274 _WrapMode[slot]=wrapMode;
277 // ***************************************************************************
279 CAnimationPlaylist::TWrapMode CAnimationPlaylist::getWrapMode (uint8 slot) const
281 return _WrapMode[slot];
284 // ***************************************************************************
286 void CAnimationPlaylist::serial (NLMISC::IStream& f)
288 // Serial a version
289 (void)f.serialVersion (0);
291 // Serial all the values
292 for (uint i=0; i<CChannelMixer::NumAnimationSlot; i++)
294 f.serial (_Animations[i]);
295 f.serial (_SkeletonWeight[i]);
296 f.serial (_InvertWeight[i]);
297 f.serial (_TimeOrigin[i]);
298 f.serial (_SpeedFactor[i]);
299 f.serial (_StartWeight[i]);
300 f.serial (_StartWeightTime[i]);
301 f.serial (_EndWeight[i]);
302 f.serial (_EndWeightTime[i]);
303 f.serial (_Smoothness[i]);
304 f.serialEnum (_WrapMode[i]);
308 // ***************************************************************************
310 TAnimationTime CAnimationPlaylist::getLocalTime (uint8 slot, TGlobalAnimationTime globalTime, const CAnimationSet& animSet) const
312 // Get the animation
313 const CAnimation *pAnimation=animSet.getAnimation (_Animations[slot]);
315 // If this animation exists
316 if (pAnimation)
318 // Compute the non-wrapped time
319 TAnimationTime wrappedTime=pAnimation->getBeginTime ()+(TAnimationTime)((globalTime-_TimeOrigin[slot])*_SpeedFactor[slot]);
321 // Wrap mode
322 switch (_WrapMode[slot])
324 case Clamp:
325 clamp (wrappedTime, pAnimation->getBeginTime (), pAnimation->getEndTime ());
326 break;
327 case Repeat:
328 // Mod repeat the time
330 float length=pAnimation->getEndTime ()-pAnimation->getBeginTime();
331 if (wrappedTime>=pAnimation->getBeginTime())
332 wrappedTime=pAnimation->getBeginTime()+(float)fmod (wrappedTime-pAnimation->getBeginTime(), length);
333 else
334 wrappedTime=pAnimation->getBeginTime()+(float)fmod (wrappedTime-pAnimation->getBeginTime(), length)+length;
336 break;
337 default: break;
340 // Return localTime
341 return wrappedTime;
344 return (TAnimationTime)globalTime;
347 // ***************************************************************************
349 float CAnimationPlaylist::getLocalWeight (uint8 slot, TGlobalAnimationTime globalTime) const
351 return getWeightValue (_StartWeightTime[slot], _EndWeightTime[slot], globalTime, _StartWeight[slot], _EndWeight[slot], _Smoothness[slot]);
354 // ***************************************************************************
357 } // NL3D