1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
19 #include "nel/3d/animation_playlist.h"
20 #include "nel/misc/common.h"
21 #include "nel/misc/stream.h"
23 using namespace NLMISC
;
32 // ***************************************************************************
34 CAnimationPlaylist::CAnimationPlaylist()
39 // Set default wrap mode
40 for (uint i
=0; i
<CChannelMixer::NumAnimationSlot
; i
++)
44 // ***************************************************************************
46 void CAnimationPlaylist::emptyPlayList ()
49 for (uint i
=0; i
<CChannelMixer::NumAnimationSlot
; i
++)
52 _SkeletonWeight
[i
]=empty
;
53 _InvertWeight
[i
]=false;
58 _StartWeightTime
[i
]= 0.f
;
59 _EndWeightTime
[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
173 for (uint8 s
=0; s
<CChannelMixer::NumAnimationSlot
; s
++)
180 // Get the animationSet pointer from the mixer
181 const CAnimationSet
*animSet
=mixer
.getAnimationSet ();
186 if (_Animations
[s
]!=empty
)
188 // Get the local time
189 TAnimationTime wrappedTime
= getLocalTime (s
, time
, *animSet
);
192 const CAnimation
*pAnimation
=animSet
->getAnimation (_Animations
[s
]);
195 if ((_WrapMode
[s
]==Disable
)&&((wrappedTime
<pAnimation
->getBeginTime ())||(wrappedTime
>pAnimation
->getEndTime ())))
200 mixer
.setSlotTime (s
, wrappedTime
);
204 // *** Set the animation
210 if (_Animations
[s
]==empty
)
214 // Set the animation id
215 mixer
.setSlotAnimation (s
, _Animations
[s
]);
217 // *** Set the skeleton weight
220 if (_SkeletonWeight
[s
]==empty
)
222 mixer
.resetSkeletonWeight (s
);
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
]));
238 // ***************************************************************************
240 float CAnimationPlaylist::getWeightValue (TGlobalAnimationTime startWeightTime
, TGlobalAnimationTime endWeightTime
, TGlobalAnimationTime time
, float startWeight
, float endWeight
, float smoothness
)
243 if (time
<=startWeightTime
)
246 if (time
>=endWeightTime
)
252 TGlobalAnimationTime linear
=startWeight
+(endWeight
-startWeight
)*(time
-startWeightTime
)/(endWeightTime
-startWeightTime
);
255 if (smoothness
<0.0001f
)
256 return (float)linear
;
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
);
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
)
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
313 const CAnimation
*pAnimation
=animSet
.getAnimation (_Animations
[slot
]);
315 // If this animation exists
318 // Compute the non-wrapped time
319 TAnimationTime wrappedTime
=pAnimation
->getBeginTime ()+(TAnimationTime
)((globalTime
-_TimeOrigin
[slot
])*_SpeedFactor
[slot
]);
322 switch (_WrapMode
[slot
])
325 clamp (wrappedTime
, pAnimation
->getBeginTime (), pAnimation
->getEndTime ());
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
);
334 wrappedTime
=pAnimation
->getBeginTime()+(float)fmod (wrappedTime
-pAnimation
->getBeginTime(), length
)+length
;
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 // ***************************************************************************