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.h"
20 #include "nel/3d/animation_set.h"
21 #include "nel/3d/track.h"
22 #include "nel/3d/track_sampled_quat_small_header.h"
24 #include "nel/misc/file.h"
25 #include "nel/misc/path.h"
26 #include "nel/misc/hierarchical_timer.h"
27 #include "nel/misc/algo.h"
31 using namespace NLMISC
;
40 H_AUTO_DECL( NL3D_UI_Animation
)
42 #define NL3D_HAUTO_UI_ANIMATION H_AUTO_USE( NL3D_UI_Animation )
45 // ***************************************************************************
47 CAnimation::CAnimation() : _BeginTimeTouched(true), _EndTimeTouched(true), _AnimLoopTouched(true)
49 _MinEndTime
= -FLT_MAX
;
50 _TrackSamplePack
= NULL
;
51 _AnimationSetOwner
= NULL
;
54 // ***************************************************************************
56 CAnimation::~CAnimation ()
58 // Delete all the pointers in the array
59 for (uint i
=0; i
<_TrackVector
.size(); i
++)
61 delete _TrackVector
[i
];
63 // if created, release the _TrackSamplePack
65 delete _TrackSamplePack
;
66 _TrackSamplePack
= NULL
;
69 // ***************************************************************************
71 void CAnimation::addTrack (const std::string
& name
, ITrack
* pChannel
)
73 // must not already be HeaderOptimized
74 nlassert(_IdByChannelId
.empty());
76 // Add an entry in the map
77 _IdByName
.insert (TMapStringUInt::value_type (name
, (uint32
)_TrackVector
.size()));
79 // Add an entry in the array
80 _TrackVector
.push_back (pChannel
);
83 _BeginTimeTouched
= _EndTimeTouched
= _AnimLoopTouched
= true;
87 // ***************************************************************************
89 void CAnimation::serial (NLMISC::IStream
& f
)
91 // cannot save if anim header compressed
92 nlassert(_IdByChannelId
.empty());
95 f
.serialCheck (NELID("_LEN"));
96 f
.serialCheck (NELID("MINA"));
99 sint version
=f
.serialVersion (2);
104 // Serial the name/id map
105 f
.serialCont(_IdByName
);
108 f
.serialContPolyPtr (_TrackVector
);
110 // Serial the min end time
113 f
.serial (_MinEndTime
);
116 // Serial the SSS shapes
119 f
.serialCont (_SSSShapes
);
123 //nlinfo("ANIMYOYO: Anim NumTracks: %d", _TrackVector.size());
127 // ***************************************************************************
128 uint
CAnimation::getIdTrackByName (const std::string
& name
) const
131 // if not be HeaderOptimized
132 if (_IdByChannelId
.empty())
134 // Find an entry in the name/id map
135 TMapStringUInt::const_iterator ite
=_IdByName
.find (name
);
138 if (ite
==_IdByName
.end ())
142 // no, return track ID
143 return (uint
)ite
->second
;
147 nlassert(_AnimationSetOwner
);
148 // get the channel id from name
149 uint channelId
= _AnimationSetOwner
->getChannelIdByName(name
);
150 if(channelId
==CAnimationSet::NotFound
)
151 return CAnimation::NotFound
;
153 return getIdTrackByChannelId(channelId
);
157 // ***************************************************************************
158 void CAnimation::getTrackNames (std::set
<std::string
>& setString
) const
161 // if not be HeaderOptimized
162 if (_IdByChannelId
.empty())
164 // For each track name
165 TMapStringUInt::const_iterator ite
=_IdByName
.begin();
166 while (ite
!=_IdByName
.end())
168 // Add the name in the map
169 setString
.insert (ite
->first
);
177 nlassert(_AnimationSetOwner
);
178 // For each track channel Id,
179 for(uint i
=0;i
<_IdByChannelId
.size();i
++)
181 // Add in the map the channel name => same as track name
182 setString
.insert ( _AnimationSetOwner
->getChannelName(_IdByChannelId
[i
]) );
187 // ***************************************************************************
188 TAnimationTime
CAnimation::getBeginTime () const
190 NL3D_HAUTO_UI_ANIMATION
;
192 if (_BeginTimeTouched
)
195 uint trackCount
=(uint
)_TrackVector
.size();
197 // Track count empty ?
201 // Look for the lowest
202 _BeginTime
=_TrackVector
[0]->getBeginTime ();
205 for (uint t
=1; t
<trackCount
; t
++)
207 if (_TrackVector
[t
]->getBeginTime ()<_BeginTime
)
208 _BeginTime
=_TrackVector
[t
]->getBeginTime ();
211 _BeginTimeTouched
= false;
217 // ***************************************************************************
219 TAnimationTime
CAnimation::getEndTime () const
221 NL3D_HAUTO_UI_ANIMATION
;
226 uint trackCount
=(uint
)_TrackVector
.size();
228 // Track count empty ?
232 // Look for the highest
233 _EndTime
=_TrackVector
[0]->getEndTime ();
236 for (uint t
=1; t
<trackCount
; t
++)
238 if (_TrackVector
[t
]->getEndTime ()>_EndTime
)
239 _EndTime
=_TrackVector
[t
]->getEndTime ();
242 // Check min end time
243 if (_EndTime
< _MinEndTime
)
244 _EndTime
= _MinEndTime
;
246 _EndTimeTouched
= false;
252 // ***************************************************************************
253 bool CAnimation::allTrackLoop() const
255 NL3D_HAUTO_UI_ANIMATION
;
260 uint trackCount
=(uint
)_TrackVector
.size();
266 for (uint t
=0; t
<trackCount
; t
++)
268 if (!_TrackVector
[t
]->getLoopMode())
274 _AnimLoopTouched
= false;
280 // ***************************************************************************
282 UTrack
* CAnimation::getTrackByName (const char* name
)
284 NL3D_HAUTO_UI_ANIMATION
;
287 uint id
=getIdTrackByName (name
);
290 if (id
==CAnimation::NotFound
)
291 // Error, return NULL
294 // No error, return the track
295 return getTrack (id
);
298 // ***************************************************************************
300 void CAnimation::releaseTrack (UTrack
* /* track */)
302 NL3D_HAUTO_UI_ANIMATION
;
307 // ***************************************************************************
309 void CAnimation::setMinEndTime (TAnimationTime minEndTime
)
311 _MinEndTime
= minEndTime
;
314 // ***************************************************************************
316 UAnimation
* UAnimation::createAnimation (const char* sPath
)
318 NL3D_HAUTO_UI_ANIMATION
;
320 // Allocate an animation
321 CUniquePtr
<CAnimation
> anim (new CAnimation
);
325 if (file
.open ( NLMISC::CPath::lookup( sPath
) ) )
327 // Serial the animation
331 CAnimation
*ret
=anim
.release ();
333 // Return the animation interface
340 // ***************************************************************************
342 void UAnimation::releaseAnimation (UAnimation
* animation
)
344 NL3D_HAUTO_UI_ANIMATION
;
347 CAnimation
* release
=(CAnimation
*)animation
;
353 // ***************************************************************************
354 void CAnimation::applySampleDivisor(uint sampleDivisor
)
356 NL3D_HAUTO_UI_ANIMATION
;
358 for(uint i
=0;i
<_TrackVector
.size();i
++)
360 ITrack
*track
= _TrackVector
[i
];
362 track
->applySampleDivisor(sampleDivisor
);
367 // ***************************************************************************
368 void CAnimation::applyTrackQuatHeaderCompression()
370 NL3D_HAUTO_UI_ANIMATION
;
372 // if the header compression has already been donne, no op
376 // **** First pass: count the number of keys to allocate
377 CTrackSampleCounter sampleCounter
;
378 bool someTrackOK
= false;
379 for(uint i
=0;i
<_TrackVector
.size();i
++)
381 ITrack
*track
= _TrackVector
[i
];
384 // return true only for CTrackSampledQuat
385 if(track
->applyTrackQuatHeaderCompressionPass0(sampleCounter
))
390 // **** second pass: fill, onlmy if some track matchs (fails for instance for big animations)
395 // must create the Sample packer
396 _TrackSamplePack
= new CTrackSamplePack
;
398 // just copy the built track headers
399 _TrackSamplePack
->TrackHeaders
.resize((uint32
)sampleCounter
.TrackHeaders
.size());
400 for(i
=0;i
<_TrackSamplePack
->TrackHeaders
.size();i
++)
402 _TrackSamplePack
->TrackHeaders
[i
]= sampleCounter
.TrackHeaders
[i
];
406 _TrackSamplePack
->Times
.resize(sampleCounter
.NumKeys
);
407 _TrackSamplePack
->Keys
.resize(sampleCounter
.NumKeys
);
409 // start the counter for Pass1 to work
410 uint globalKeyOffset
= 0;
412 // fill it for each track
413 for(i
=0;i
<_TrackVector
.size();i
++)
415 ITrack
*track
= _TrackVector
[i
];
418 ITrack
*newTrack
= track
->applyTrackQuatHeaderCompressionPass1(globalKeyOffset
, *_TrackSamplePack
);
422 // delete the old track, and replace with compressed one
423 delete _TrackVector
[i
];
424 _TrackVector
[i
]= newTrack
;
429 nlassert(globalKeyOffset
== _TrackSamplePack
->Keys
.size());
436 // ***************************************************************************
437 struct CTempTrackInfo
442 bool operator<(const CTempTrackInfo
&o
) const
444 return ChannelId
< o
.ChannelId
;
447 void CAnimation::applyAnimHeaderCompression(CAnimationSet
*animationSetOwner
, const std::map
<std::string
, uint32
> &channelMap
)
450 nlassert(animationSetOwner
);
451 // must not be already done
452 nlassert(_IdByChannelId
.empty());
454 // fill the track info, with Track
455 std::vector
<CTempTrackInfo
> tempTrackInfo
;
456 tempTrackInfo
.resize(_TrackVector
.size());
457 for(i
=0;i
<tempTrackInfo
.size();i
++)
459 tempTrackInfo
[i
].Track
= _TrackVector
[i
];
462 // fill the track info, with ChannelId
463 TMapStringUInt::iterator it
;
464 for(it
= _IdByName
.begin();it
!=_IdByName
.end();it
++)
466 // search this track in the channelMap
467 std::map
<std::string
, uint32
>::const_iterator itChan
= channelMap
.find(it
->first
);
468 nlassert(itChan
!=channelMap
.end());
469 // store the channelId in the associated track
470 tempTrackInfo
[it
->second
].ChannelId
= (uint16
)itChan
->second
;
474 sort(tempTrackInfo
.begin(), tempTrackInfo
.end());
476 // refill the TrackVector (sorted)
477 _IdByChannelId
.resize( tempTrackInfo
.size() );
478 for(i
=0;i
<tempTrackInfo
.size();i
++)
480 _TrackVector
[i
]= tempTrackInfo
[i
].Track
;
481 _IdByChannelId
[i
]= tempTrackInfo
[i
].ChannelId
;
484 // clear the no more needed track map
485 contReset(_IdByName
);
487 // must keep the animSet
488 _AnimationSetOwner
= animationSetOwner
;
492 // ***************************************************************************
493 uint
CAnimation::getIdTrackByChannelId (uint16 channelId
) const
495 if(_IdByChannelId
.empty())
496 return CAnimation::NotFound
;
499 uint trackId
= searchLowerBound(_IdByChannelId
, channelId
);
500 // verify that the channel is really found
501 if(_IdByChannelId
[trackId
]==channelId
)
506 return CAnimation::NotFound
;
510 // ***************************************************************************
511 void CAnimation::addSSSShape(const std::string
&shape
)
513 _SSSShapes
.push_back(shape
);