1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <nel/misc/types_nl.h>
28 #include <nel/misc/event_listener.h>
29 #include <nel/misc/command.h>
30 #include <nel/misc/log.h>
31 #include <nel/misc/displayer.h>
32 #include <nel/misc/aabbox.h>
34 #include <nel/3d/u_driver.h>
35 #include <nel/3d/u_scene.h>
36 #include <nel/3d/u_skeleton.h>
37 #include <nel/3d/u_play_list.h>
38 #include <nel/3d/u_animation_set.h>
39 #include <nel/3d/u_animation.h>
40 #include <nel/3d/u_play_list_manager.h>
41 #include <nel/3d/u_play_list.h>
42 #include <nel/3d/u_transform.h>
43 #include <nel/3d/u_instance.h>
44 #include <nel/3d/u_text_context.h>
46 #include "animation.h"
48 #include "snowballs_client.h"
55 using namespace NLMISC
;
64 // Amount of time for the transistion between 2 animations
65 CAnimationTime TransitionTime
= 0.25f
;
71 UAnimationSet
*AnimationSet
= NULL
;
72 UPlayListManager
*PlayListManager
= NULL
;
79 UAnimation
*Animation
;
82 Anim AnimIdArray
[][2] =
84 { { "patterfeet.anim", false, 0, NULL
}, { "", false, 0, NULL
} },
85 { { "marche.anim", true, 0, NULL
}, { "", false, 0, NULL
} },
86 { { "idle.anim", true, 0, NULL
}, { "", false, 0, NULL
} },
87 { { "log_on.anim", false, 0, NULL
}, { "", false, 0, NULL
} },
88 { { "log_off.anim", false, 0, NULL
}, { "", false, 0, NULL
} },
89 { { "lancelaboule.anim", false, 0, NULL
}, { "", false, 0, NULL
} },
90 { { "prepaboule.anim", false, 0, NULL
}, { "", false, 0, NULL
} },
91 { { "prepaboulecycle.anim", true, 0, NULL
}, { "", false, 0, NULL
} },
92 { { "impact.anim", false, 0, NULL
}, { "", false, 0, NULL
} },
100 void computeAnimation (CEntity
&entity
, EAnim anim
)
102 // Get the current time
103 double currentTime
= AnimationTime
;
105 // nlinfo ("%d playing animation", anim);
106 // nlinfo ("%d playing animation %s ct%f st%f et%f", anim, AnimIdArray[anim][0].Name, currentTime, AnimIdArray[anim][0].Animation->getBeginTime (), AnimIdArray[anim][0].Animation->getEndTime ());
108 // Find the new slot for the full animation (0 or 1)
109 uint newSlot
= entity
.NextEmptySlot
;
110 uint oldSlot
= 1 - entity
.NextEmptySlot
;
111 entity
.NextEmptySlot
= 1 - entity
.NextEmptySlot
;
113 UPlayList::TWrapMode wrapMode
= AnimIdArray
[anim
][0].Loop
? UPlayList::Repeat
: UPlayList::Clamp
;
115 entity
.PlayList
->setAnimation (newSlot
, AnimIdArray
[anim
][0].Id
);
116 entity
.PlayList
->setTimeOrigin (newSlot
, currentTime
);
117 entity
.PlayList
->setWeightSmoothness (newSlot
, 1.0f
);
118 entity
.PlayList
->setWrapMode (newSlot
, wrapMode
);
120 double OldStartTime
, OldEndTime
;
121 double NewStartTime
, NewEndTime
;
123 // Get the starting time of the old animation slot
124 entity
.PlayList
->getStartWeight (oldSlot
, OldStartTime
);
126 // Compute the time delta between start of the old animation and now
127 double dt
= currentTime
- OldStartTime
;
129 // Compute the new transition value depending of the current time
131 if (dt
> TransitionTime
)
134 OldStartTime
= currentTime
- (TransitionTime
- dt
);
135 OldEndTime
= currentTime
+ dt
;
137 NewStartTime
= currentTime
;
138 NewEndTime
= currentTime
+ dt
;
140 // Set new weights on the old and the new animation slot
142 entity
.PlayList
->setStartWeight (oldSlot
, 1.0f
, OldStartTime
);
143 entity
.PlayList
->setEndWeight (oldSlot
, 0.0f
, OldEndTime
);
145 entity
.PlayList
->setStartWeight (newSlot
, 0.0f
, NewStartTime
);
146 entity
.PlayList
->setEndWeight (newSlot
, 1.0f
, OldEndTime
);
148 // Keep in mind what is the last animation id we set
149 entity
.StartAnimationTime
= (float)currentTime
;
153 void playAnimation (CEntity
&entity
, EAnim anim
, bool force
)
155 nlassert (anim
> -2 && anim
< 20);
156 // nlinfo ("playAnimation() %d", anim);
158 // Get the current time
159 CAnimationTime currentTime
= AnimationTime
;
161 // Can't do animation without skeleton
162 if (entity
.Skeleton
.empty())
165 // If the first time we play an animation, creates the animation class
166 if (entity
.PlayList
== NULL
)
167 createAnimation (entity
);
169 if (force
|| entity
.AnimQueue
.empty())
171 computeAnimation (entity
, anim
);
173 // clear the animation queue
174 //nlinfo ("clearing animation queue");
175 while (!entity
.AnimQueue
.empty())
176 entity
.AnimQueue
.pop ();
179 // nlinfo ("pushing animation %d", anim);
180 // nlinfo ("pushing animation %s", AnimIdArray[anim][0].Name);
181 entity
.AnimQueue
.push (anim
);
184 void createAnimation (CEntity
&entity
)
186 nlassert (!entity
.Instance
.empty() && !entity
.Skeleton
.empty() && AnimationSet
!= NULL
);
188 entity
.PlayList
= PlayListManager
->createPlayList (AnimationSet
);
189 entity
.PlayList
->registerTransform (entity
.Instance
);
190 entity
.PlayList
->registerTransform (entity
.Skeleton
);
193 void deleteAnimation (CEntity
&entity
)
195 if (entity
.PlayList
== NULL
)
198 PlayListManager
->deletePlayList (entity
.PlayList
);
199 entity
.PlayList
= NULL
;
205 AnimationSet
= Driver
->createAnimationSet ();
207 // Add all animations in the animation set
208 for (uint i
= 0; i
< sizeof (AnimIdArray
) / sizeof (AnimIdArray
[0]); i
++)
210 if (AnimIdArray
[i
][0].Name
[0] != '\0')
212 AnimIdArray
[i
][0].Id
= AnimationSet
->addAnimation (AnimIdArray
[i
][0].Name
, AnimIdArray
[i
][0].Name
);
213 AnimIdArray
[i
][0].Animation
= AnimationSet
->getAnimation (AnimIdArray
[i
][0].Id
);
216 if (AnimIdArray
[i
][1].Name
[0] != '\0')
218 AnimIdArray
[i
][1].Id
= AnimationSet
->addAnimation (AnimIdArray
[i
][1].Name
, AnimIdArray
[i
][1].Name
);
219 AnimIdArray
[i
][1].Animation
= AnimationSet
->getAnimation (AnimIdArray
[i
][1].Id
);
222 AnimationSet
->build ();
224 PlayListManager
= Scene
->createPlayListManager ();
227 void updateAnimation()
229 // Get the current time
230 CAnimationTime currentTime
= AnimationTime
;
232 for (EIT eit
= Entities
.begin (); eit
!= Entities
.end (); eit
++)
234 CEntity
&entity
= (*eit
).second
;
236 if (entity
.AnimQueue
.empty ())
238 // nlwarning ("empty queue update!!!");
242 EAnim currentAnim
= entity
.AnimQueue
.front ();
243 if (!AnimIdArray
[currentAnim
][0].Loop
&& currentTime
>= entity
.StartAnimationTime
+ AnimIdArray
[currentAnim
][0].Animation
->getEndTime () - TransitionTime
/2)
245 // remove the current anim
246 entity
.AnimQueue
.pop ();
248 if (entity
.AnimQueue
.empty ())
250 // nlwarning ("empty queue!!!!!!");
254 EAnim newAnim
= entity
.AnimQueue
.front ();
256 computeAnimation (entity
, newAnim
);
258 nlinfo ("playing animation %s ct%f st%f et%f", AnimIdArray[newAnim][0].Name, currentTime, AnimIdArray[newAnim][0].Animation->getBeginTime (), AnimIdArray[newAnim][0].Animation->getEndTime ());
259 // setup the new anim
260 entity.PlayList->setAnimation (0, AnimIdArray[newAnim][0].Id);
261 entity.PlayList->setTimeOrigin (0, currentTime);
262 entity.PlayList->setStartWeight (0, 1.0f, currentTime);
263 entity.PlayList->setEndWeight (0, 1.0f, currentTime+TransitionTime);
264 entity.PlayList->setWeightSmoothness (0, 1.0f);
266 if (AnimIdArray[newAnim][0].Loop)
267 entity.PlayList->setWrapMode (0, UPlayList::Repeat);
269 entity.PlayList->setWrapMode (0, UPlayList::Clamp);
271 entity.StartAnimationTime = currentTime;
275 // compute new animation position depending of the current time
276 PlayListManager
->animate (AnimationTime
);
279 void releaseAnimation()
281 Scene
->deletePlayListManager (PlayListManager
);
283 // The next line doesn t work (say that AnimationSet is not a valid AnimationSet Ptr) so we comment it.
284 // Scene->deleteAnimationSet (AnimationSet);
287 } /* namespace SBCLIENT */