Add infos into target window
[ryzomcore.git] / ryzom / client / src / entity_animation_manager.cpp
blobc2bcb28d8bb3645434ac20c372a2ba4fc3809a4d
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 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/>.
22 #include "stdpch.h"
25 /////////////
26 // INCLUDE //
27 /////////////
28 // client
29 #include "entity_animation_manager.h"
30 #include "animation_misc.h"
31 #include "animation_set.h"
32 #include "debug_client.h"
33 #include "sheet_manager.h"
34 #include "time_client.h"
35 #include "global.h"
36 // misc
37 #include "nel/misc/path.h"
38 #include "nel/misc/smart_ptr.h"
39 #include "nel/misc/file.h"
40 #include "nel/misc/progress_callback.h"
41 // 3d
42 #include "nel/3d/u_skeleton.h"
43 #include "nel/3d/u_driver.h"
44 #include "nel/3d/u_scene.h"
45 #include "nel/3d/u_track.h"
46 #include "nel/3d/u_play_list.h"
47 #include "nel/3d/u_play_list_manager.h"
48 #include "nel/3d/u_animation_set.h"
50 ///////////
51 // USING //
52 ///////////
53 using namespace NLMISC;
54 using namespace std;
55 using namespace NLGEORGES;
58 ////////////
59 // EXTERN //
60 ////////////
61 extern NL3D::UScene * Scene;
63 ////////////
64 // GLOBAL //
65 ////////////
67 // Hierarchical timer
68 H_AUTO_DECL ( RZ_Client_Entity_Animation_Mngr )
70 ////////////////////
71 // STATIC MEMBERS //
72 ////////////////////
73 CEntityAnimationManager *CEntityAnimationManager::_Instance = 0;
74 NL3D::UPlayListManager *CEntityAnimationManager::_PlayListManager = 0;
77 ////////////////////
78 // STATIC METHODS //
79 ////////////////////
80 //---------------------------------------------------
81 // getInstance :
82 // Instanciate CEntityAnimationManager. There can be only one instance (singleton)
83 // \return CEntityAnimationManager * : Pointer on CEntityAnimationManager.
84 //---------------------------------------------------
85 CEntityAnimationManager * CEntityAnimationManager::getInstance()
87 if(_Instance == 0)
89 _Instance = new CEntityAnimationManager();
90 if(Scene)
91 _PlayListManager = Scene->createPlayListManager();
92 else
93 nlwarning("CEntityAnimationManager::getInstance : Scene is not allocated.");
95 return _Instance;
96 }// instance //
98 //-----------------------------------------------
99 // delInstance :
100 // Release the current instance
101 // \warning If you the kept the pointer given by getInstance, it will be invalid.
102 //-----------------------------------------------
103 void CEntityAnimationManager::delInstance()
105 // Release the singleton
106 if(_Instance)
108 delete _Instance;
109 _Instance = 0;
111 }// delInstance //
114 /////////////
115 // METHODS //
116 /////////////
117 //---------------------------------------------------
118 // CEntityAnimationManager :
119 // Constructor.
120 //---------------------------------------------------
121 CEntityAnimationManager::CEntityAnimationManager()
123 _AnimationSet = NULL;
124 _AutomatonList = NULL;
125 _EmotList = NULL;
127 }// CEntityAnimationManager //
129 //---------------------------------------------------
130 // ~CEntityAnimationManager :
131 // Destructor.
132 //---------------------------------------------------
133 CEntityAnimationManager::~CEntityAnimationManager()
135 // Delete the playlist manager
136 if(_PlayListManager)
138 // if(Scene)
139 // Scene->deletePlayListManager(_PlayListManager);
140 _PlayListManager = 0;
143 // Release all things initialized by the load method.
144 release();
145 }// ~CEntityAnimationManager //
147 //-----------------------------------------------
148 // release
149 // Release all things initialized by the load method.
150 //-----------------------------------------------
151 void CEntityAnimationManager::release()
153 // Animation set cache
154 _AnimationSetPosCache.clear();
155 _AnimationSetRotCache.clear();
156 // Release animsets.
157 _AnimSet.clear();
158 // Release Automatons and Release the emots list
159 // Nothing to release here : all is in the sheet manager so kept during all the time the game is running
160 // Release the AnimationSet.
161 if(_AnimationSet)
163 Driver->deleteAnimationSet(_AnimationSet);
164 _AnimationSet = 0;
167 // owned by CSheetManager
168 _AutomatonList = NULL;
170 }// release //
172 //---------------------------------------------------
173 // load :
174 //---------------------------------------------------
175 void CEntityAnimationManager::load(NLMISC::IProgressCallback &/* progress */, bool /* forceRepack */ /* = false */)
177 // Whole initInGame profile
178 NLMISC::TTime initStart;
179 initStart = ryzomGetLocalTime ();
181 // Before loading, release the old stuff.
182 release();
184 // Log in the animation file.
185 //setDebugOutput(getLogDirectory() + "animation.dbg");
186 setDebugOutput(""); // no log
188 // Create the animation set for all entities.
189 _AnimationSet = Driver->createAnimationSet();
190 if(_AnimationSet == 0)
191 pushDebugStr("_AnimationSet is Null !.");
193 // Loading Emots
194 pushInfoStr("COMPUTING EMOTS ...");
195 // Initialize the emot list
196 _EmotList = dynamic_cast<CEmotListSheet*>(SheetMngr.get(CSheetId("list.emot")));
197 nlassert(_EmotList != NULL);
199 pushInfoStr("COMPUTING AUTOMATON ...");
200 // Initialize the automaton.
201 _AutomatonList = dynamic_cast<CAutomatonListSheet*>(SheetMngr.get(CSheetId("automaton.automaton_list")));
202 nlassert(_AutomatonList != NULL);
204 pushInfoStr("COMPUTING ANIMATION SET ...");
205 // Initialize the list of animsets
206 CAnimationSetListSheet *pASLS = dynamic_cast<CAnimationSetListSheet*>(SheetMngr.get(CSheetId("entities.animset_list")));
207 nlassert(pASLS != NULL);
208 for (uint32 i = 0; i < pASLS->AnimSetList.size(); ++i)
210 CAnimationSet as;
211 string sTmp = toLowerAscii(pASLS->AnimSetList[i].Name);
212 sTmp = sTmp.substr(0,sTmp.rfind('.'));
213 pair<map<string,CAnimationSet>::iterator, bool> it;
214 it = _AnimSet.insert(pair<string,CAnimationSet>(sTmp,as));
215 it.first->second.init (&pASLS->AnimSetList[i], _AnimationSet);
218 // Build 3d Animation Set (called after all animations added in the animation set).
219 _AnimationSetPosCache.resize (0, NULL);
220 _AnimationSetRotCache.resize (0, NULL);
221 if(_AnimationSet)
223 _AnimationSet->build();
225 // Build animation set cache
226 uint i;
227 const uint count = _AnimationSet->getNumAnimation ();
228 _AnimationSetPosCache.resize (count, NULL);
229 _AnimationSetRotCache.resize (count, NULL);
230 for (i=0; i<count; i++)
232 // Get the animation
233 NL3D::UAnimation *anim = _AnimationSet->getAnimation (i);
234 if (anim)
236 // Get the tracks
237 _AnimationSetPosCache[i] = anim->getTrackByName("pos");
238 _AnimationSetRotCache[i] = anim->getTrackByName("rotquat");
243 // Flush debug information
244 flushDebugStack("-- ANIMATIONS OTHER --");
246 // Stop to Log in the animation file.
247 setDebugOutput("");
249 // Whole load profile
250 nlinfo ("%d seconds for EAM->load()", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
252 /* // Memory debug
253 uint32 nTotalAnimSet = _AnimSet.size();
254 TAnimSet::iterator it = _AnimSet.begin();
255 uint32 nTotalAnimState = 0;
256 uint32 nTotalAnim = 0;
257 uint32 nTotalAnimFx = 0;
258 bool bOnce = false;
259 while (it != _AnimSet.end())
261 CAnimationSet &rAS = it->second;
262 uint32 nAS = rAS.getNumAnimationState();
263 nTotalAnimState += nAS;
264 for (uint i = 0; i < nAS; ++i)
266 CAnimationState *pAnimState = rAS.getAnimationStateByIndex(i);
267 uint32 nAnim = pAnimState->getNumAnimation();
268 nTotalAnim += nAnim;
269 for (uint j = 0; j < nAnim; ++j)
271 CAnimation *pAnim = pAnimState->getAnimationByIndex(j);
272 nTotalAnimFx += pAnim->getFXSet().FX.size();
273 if (!bOnce)
275 bOnce = true;
276 nlinfo ("%d %d %d", sizeof(rAS), sizeof(*pAnimState), sizeof(*pAnim));
281 it++;
284 nlinfo ("%d %d %d", nTotalAnimSet, nTotalAnimState, nTotalAnim, nTotalAnimFx);
286 }// load //
289 //---------------------------------------------------
290 // animate :
291 // Animate all the playlists.
292 // \param double time : play time.
293 //---------------------------------------------------
294 void CEntityAnimationManager::animate(double time)
296 H_AUTO_USE ( RZ_Client_Entity_Animation_Mngr )
298 _PlayListManager->animate(time);
299 }// animate //
302 //---------------------------------------------------
303 // Setup :
304 // Setup all the playlists.
305 // \param double time : play time.
306 //---------------------------------------------------
307 void CEntityAnimationManager::setup(double time)
309 H_AUTO_USE ( RZ_Client_Entity_Animation_Mngr )
311 if (_PlayListManager) _PlayListManager->setup(time);
312 }// setup //
315 //---------------------------------------------------
316 // mState :
317 // Return a ref on a state of the moving automaton defined by its key.
318 // \param string automatonName : the automaton's name.
319 // \param TAnimStateKey key : the key of the state.
320 // \return CMovingAutomatonState * : pointer .
321 //---------------------------------------------------
322 const CAutomatonStateSheet *CEntityAnimationManager::mState(const string &automaton, TAnimStateKey key)
324 // Search for the automaton
325 std::map<std::string, CAutomatonSheet *>::iterator it = _AutomatonList->Automatons.find(automaton);
326 if(it != _AutomatonList->Automatons.end())
328 // Get the state.
329 const CAutomatonStateSheet *statePtr = ((*it).second)->state(key);
330 if(statePtr == 0)
332 nlwarning("CEntityAnimationManager::mState: the state '%s' does not exist for the automaton '%s'", CAnimationState::getAnimationStateName(key).c_str(), automaton.c_str());
333 return 0;
335 else
336 return statePtr;
338 // Automaton not found
339 else
340 return 0;
341 }// mState //
343 //---------------------------------------------------
344 // deletePlayList:
345 // Delete a play list.
346 // \param UPlayList * pl : pointer on the play list to delete.
347 //---------------------------------------------------
348 void CEntityAnimationManager::deletePlayList(NL3D::UPlayList * pl)
350 // Check if the playlist is not Null.
351 if(pl)
353 _PlayListManager->deletePlayList(pl);
354 pl = 0;
356 }// deletePlayList //
359 //---------------------------------------------------
360 // processLogic :
362 //---------------------------------------------------
363 void CEntityAnimationManager::processLogic(const std::string &animListName, TAnimStateKey animationId, CAnimationTime startTimeOffset, CAnimationTime endTimeOffset, UTrack *&soundTrack, vector<CAnimationTime>& result)
365 result.clear();
367 // Get the animation set according to the animation list name
368 UAnimationSet *animSet = getAnimationSet(animListName);
369 if(animSet)
371 // Get the animation Id.
372 uint idAnim = animSet->getAnimationIdByName(animationId);
373 if(idAnim != UAnimationSet::NotFound)
375 // Get the animation pointer and get the length.
376 UAnimation *anim = animSet->getAnimation(idAnim);
377 if(anim)
379 char *soundTrackName = "NoteTrack";
380 soundTrack = anim->getTrackByName( soundTrackName );
381 if( soundTrack != NULL )
383 UTrackKeyframer * soundTrackKF = dynamic_cast<UTrackKeyframer *>(soundTrack);
384 if( soundTrackKF == NULL )
386 nlerror("The track %s is not a key framer track",soundTrackName);
389 soundTrackKF->getKeysInRange(startTimeOffset, endTimeOffset, result);
394 }// processLogic //
402 //---------------------------------------------------
403 // getAnimationLength :
404 // Return an animation length (in sec).
405 // \param string animName : Animation Name.
406 // \return double : the length of the animation.
407 // \warning This method never return a value <= 0.0 and so will return 1.0 instead.
408 // \warning This Method is slower than the one with the animation Id instead of the animation Name.
409 //---------------------------------------------------
410 double CEntityAnimationManager::getAnimationLength(const std::string &animName) const
412 double length = CAnimationMisc::getAnimationLength(_AnimationSet, animName);
413 if(length <= 0.0)
414 return 1.0;
416 return length;
417 }// getAnimationLength //
419 //---------------------------------------------------
420 // getAnimationLength :
421 // Return an animation length (in sec).
422 // \param idAnim : id of the animation.
423 // \return double : the length of the animation.
424 // \warning This method never return a value <= 0.0 and so will return 1.0 instead.
425 // \warning This Method is slower than the one with the animation Id instead of the animation Name.
426 //---------------------------------------------------
427 double CEntityAnimationManager::getAnimationLength(uint idAnim) const
429 if (idAnim == NL3D::UAnimationSet::NotFound) return 0.f;
430 double length = CAnimationMisc::getAnimationLength(_AnimationSet, idAnim);
431 if(length <= 0.0)
432 return 1.0;
434 return length;
435 }// getAnimationLength //
438 //---------------------------------------------------
439 // getAnimationAverageSpeed :
440 // Get the average speed of an animation (in meters/sec).
441 // \param string animName : Animation Name.
442 // \return double : the average speed (in m/s).
443 //---------------------------------------------------
444 double CEntityAnimationManager::getAnimationAverageSpeed(const std::string &animName) const
446 return CAnimationMisc::getAnimationAverageSpeed(_AnimationSet, animName);
447 }// getAnimationAverageSpeed //
449 //---------------------------------------------------
450 // getAnimationAverageSpeed :
451 // Get the average speed of an animation (in meters/sec).
452 // \param string animName : Animation Name.
453 // \return double : the average speed (in m/s).
454 //---------------------------------------------------
455 double CEntityAnimationManager::getAnimationAverageSpeed(uint idAnim) const
457 return CAnimationMisc::getAnimationAverageSpeed(_AnimationSet, idAnim);
458 }// getAnimationAverageSpeed //
461 //---------------------------------------------------
462 // getAnimSet :
463 // Return a pointer on the set according to the set name.
464 // \param animSet : name of the set.
465 // \return CAnimationSet * : pointer of the right Set or 0.
466 //---------------------------------------------------
467 const CAnimationSet *CEntityAnimationManager::getAnimSet(const std::string &animSet) const
469 // Search the right animation set.
470 TAnimSet::const_iterator itAnimSet = _AnimSet.find(animSet);
471 if(itAnimSet == _AnimSet.end())
472 // Set not found.
473 return 0;
475 // Return the pointer
476 return &((*itAnimSet).second);
477 }// getAnimSet //
480 //---------------------------------------------------
481 // createPlayList :
482 // Create a playlist.
483 // \return UPlayList * : a pointer on a play list or 0 if any pb.
484 //---------------------------------------------------
485 NL3D::UPlayList *CEntityAnimationManager::createPlayList() const
487 if (_PlayListManager == 0)
488 return 0;
490 return _PlayListManager->createPlayList(_AnimationSet);
491 }// createPlayList //
495 //-----------------------------------------------
496 // serial :
497 // Serialize a CEntityAnimationManager.
498 //-----------------------------------------------
499 void CEntityAnimationManager::serial(NLMISC::IStream &/* f */)
501 }// serial //
504 // ***************************************************************************
505 void CEntityAnimationManager::resetAllSoundAnimId()
507 TAnimSet::iterator it(_AnimSet.begin()), last(_AnimSet.end());
508 for(;it!=last;it++)
510 CAnimationSet &animSet= it->second;
511 uint numAnimState= animSet.getNumAnimationState();
512 for(uint i=0;i<numAnimState;i++)
514 CAnimationState *state= animSet.getAnimationStateByIndex(i);
515 if(state)
517 uint numAnim= state->getNumAnimation();
518 for(uint j=0;j<numAnim;j++)
520 CAnimation *anim= state->getAnimationByIndex(j);
521 if(anim)
522 anim->resetSoundAnim();
529 // ***************************************************************************
530 void CEntityAnimationManager::reloadAllSoundAnim()
532 TAnimSet::iterator it(_AnimSet.begin()), last(_AnimSet.end());
533 for(;it!=last;it++)
535 CAnimationSet &animSet= it->second;
536 uint numAnimState= animSet.getNumAnimationState();
537 for(uint i=0;i<numAnimState;i++)
539 CAnimationState *state= animSet.getAnimationStateByIndex(i);
540 if(state)
542 uint numAnim= state->getNumAnimation();
543 for(uint j=0;j<numAnim;j++)
545 CAnimation *anim= state->getAnimationByIndex(j);
546 if(anim)
547 anim->reloadSoundAnim();
556 // \todo GUIGUI : A REFAIRE.
558 //---------------------------------------------------
559 // createFacePlayList :
560 // Create an uninitialized playlist for the face animations.
561 // \param type : type of the play list to create.
562 // \return UPlayList * : a pointer on an initialized play list.
563 //---------------------------------------------------
564 UPlayList * CEntityAnimationManager::createFacePlayList(const CTypeEntity& type)
566 // get the animation set
567 UAnimationSet *animationSet = getFaceAnimationSet(type);
568 if(animationSet)
569 return _PlayListManager->createPlayList(animationSet);
570 else
571 return 0;
572 }// createFacePlayList //
574 //---------------------------------------------------
575 // createFaceAnimationSet :
576 // Create an animation set for the Face.
577 //---------------------------------------------------
578 void CEntityAnimationManager::createFaceAnimationSet(const CTypeEntity& type)
580 UAnimationSet * faceAnimationSet = Driver->createAnimationSet();
581 if(faceAnimationSet == 0)
582 nlwarning("CEntityAnimationManager::createFaceAnimationSet : cannot create an animation set for the Face.");
583 // Insert the new animation set in the map
584 else
585 _FaceAnimationSets.insert(make_pair(type, faceAnimationSet));
586 }// createFaceAnimationSet //
589 //---------------------------------------------------
590 // getFaceAnimationSet :
591 // Get an animation set for face.
592 // \param type : type of the animation set you want.
593 // \return UAnimationSet * : a pointer on the animation set or 0 if there is not animation set for this type.
594 //---------------------------------------------------
595 UAnimationSet * CEntityAnimationManager::getFaceAnimationSet(const CTypeEntity& type)
597 map<CTypeEntity, UAnimationSet *>::iterator itAnimSet = _FaceAnimationSets.find(type);
598 if(itAnimSet == _FaceAnimationSets.end())
599 return 0;
600 else
601 return (*itAnimSet).second;
602 }// getFaceAnimationSet //
604 //---------------------------------------------------
605 // chooseFaceAnim :
606 // Choose an animation for the face according to the type and the emotion.
607 // \param type : type of the face.
608 // \param emotion : emotion to play.
609 // \return uint : the index of the animation.
610 // \todo GUIGUI : make a real choice according to the percentage.
611 //---------------------------------------------------
612 uint CEntityAnimationManager::chooseFaceAnim(const CTypeEntity& type, const string &emotion)
614 std::map<CTypeEntity, TFaceEmotions>::iterator itFEPT = _FaceEmotionsPerType.find(type);
615 if(itFEPT == _FaceEmotionsPerType.end())
617 nlwarning("CEntityAnimationManager::chooseFaceAnim : Nothing associated to the type.");
618 return UAnimationSet::NotFound;
621 TFaceEmotions &faceEmotions = (*itFEPT).second;
622 TFaceEmotions::iterator itFE = faceEmotions.find(emotion);
623 if(itFE == faceEmotions.end())
625 nlwarning("CEntityAnimationManager::chooseFaceAnim : Face Emotion '%s' does not exist for this type.", emotion.c_str());
626 return UAnimationSet::NotFound;
629 CFaceEmotion &faceEmotion = (*itFE).second;
630 if(faceEmotion._Anims.empty())
632 nlwarning("No animation in the Emotion '%s'.", emotion.c_str());
633 return UAnimationSet::NotFound;
636 string anim = (*faceEmotion._Anims.begin()).first;
637 UAnimationSet *animSet = getFaceAnimationSet(type);
638 if(animSet)
639 return animSet->getAnimationIdByName(anim);
640 else
641 return UAnimationSet::NotFound;
642 }// chooseFaceAnim //
644 //-----------------------------------------------
645 // loadFaceAnimations :
646 // Load table containing infos about face animations.
647 // \param type : table is different according to the type.
648 // \param fileName : the name of the file containing the animation infos.
649 // \todo GUIGUI : Check that we can add the same animation more than once with no problem or do i have to check if the animation is already in.
650 //-----------------------------------------------
651 void CEntityAnimationManager::loadFaceAnimations(const CTypeEntity& type, const char * fileName)
653 // Get the animation set.
654 UAnimationSet * animationSet = getFaceAnimationSet(type);
655 if(!animationSet)
657 nlwarning("CEntityAnimationManager::loadFaceAnimations : animationSet is Null for the type -> Face Animations not loaded.");
658 return;
661 // Create Face Emotions struct.
662 TFaceEmotions faceEmotions;
664 // CST loader
665 CSTLoader cstl;
667 // Build file format
668 map<string, CSTLoader::TDataType> fileFormat;
669 fileFormat.insert(make_pair(string("name"), CSTLoader::STRING));
670 fileFormat.insert(make_pair(string("filename"), CSTLoader::STRING));
671 fileFormat.insert(make_pair(string("percentage"), CSTLoader::FLOAT));
673 // Init loader
674 cstl.init(fileName, fileFormat);
675 // Read the file line per line.
676 while(cstl.readLine())
678 // Get the name of the emotion.
679 string emotionName;
680 string animFilename;
681 float percentage;
682 cstl.getStringValue ("name", emotionName);
683 cstl.getStringValue ("filename", animFilename);
684 cstl.getValue ("percentage", percentage);
686 // Try to add the anim in the animation set.
687 if(animationSet->addAnimation((animFilename + ".anim").c_str(), animFilename.c_str()) == UAnimationSet::NotFound)
688 nlwarning("CEntityAnimationManager::loadFaceAnimations : anim '%s' is not found.", (animFilename + ".anim").c_str());
689 // The animation is right added in the set -> add anim in the right face emotion.
690 else
692 // Attempt on find this name in the map.
693 map<string, CFaceEmotion>::iterator itFaceEmotion = faceEmotions.find(emotionName);
694 // This emotion already exist -> add new animation to the emotion.
695 if(itFaceEmotion != faceEmotions.end())
697 CFaceEmotion &faceEmotion = (*itFaceEmotion).second;
698 faceEmotion.addAnim(animFilename, percentage);
700 else
702 CFaceEmotion faceEmotion;
703 faceEmotion.addAnim(animFilename, percentage);
704 faceEmotions.insert(make_pair(emotionName, faceEmotion));
709 // Close file
710 cstl.close();
712 // Add Emotions for the type.
713 _FaceEmotionsPerType.insert(make_pair(type, faceEmotions));
714 }// loadFaceAnimations //