Fix crash
[ryzomcore.git] / snowballs2 / client / src / animation.cpp
blob4238725997f47b52dde496d47a53d5d5a2ad4afd
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
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/>.
21 // Includes
24 #include <nel/misc/types_nl.h>
26 #include <list>
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"
47 #include "entities.h"
48 #include "snowballs_client.h"
51 // Namespaces
54 using namespace std;
55 using namespace NLMISC;
56 using namespace NL3D;
58 namespace SBCLIENT {
61 // Constantes
64 // Amount of time for the transistion between 2 animations
65 CAnimationTime TransitionTime = 0.25f;
68 // Variables
71 UAnimationSet *AnimationSet = NULL;
72 UPlayListManager *PlayListManager = NULL;
74 struct Anim
76 const char *Name;
77 bool Loop;
78 uint Id;
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 } },
97 // Functions
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)
132 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())
163 return;
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)
196 return;
198 PlayListManager->deletePlayList (entity.PlayList);
199 entity.PlayList= NULL;
203 void initAnimation()
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!!!");
239 continue;
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!!!!!!");
251 continue;
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);
268 else
269 entity.PlayList->setWrapMode (0, UPlayList::Clamp);
271 entity.StartAnimationTime = currentTime;
272 */ }
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 */
289 /* end of file */