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_set.h"
20 #include "nel/3d/driver.h"
21 #include "nel/3d/shape_bank.h"
22 #include "nel/misc/stream.h"
23 #include "nel/misc/path.h"
24 #include "nel/misc/file.h"
25 #include "nel/misc/algo.h"
30 using namespace NLMISC
;
39 // ***************************************************************************
40 CAnimationSet::CAnimationSet (bool headerOptim
)
43 _AnimHeaderOptimisation
= headerOptim
;
47 // ***************************************************************************
48 CAnimationSet::~CAnimationSet ()
50 // Erase all animations.
51 for (uint a
=0; a
<_Animation
.size(); a
++)
53 for (uint s
=0; s
<_SkeletonWeight
.size(); s
++)
54 delete _SkeletonWeight
[s
];
57 // ***************************************************************************
58 uint
CAnimationSet::getNumChannelId () const
60 return (uint
)_ChannelIdByName
.size ();
63 // ***************************************************************************
64 uint
CAnimationSet::addAnimation (const char* name
, CAnimation
* animation
)
66 // error to add an animation after a build() if the animation set is in HeaderCompress mode
67 nlassert(! (_Built
&& _AnimHeaderOptimisation
) );
69 // if sampleDivisor, apply to the animation
71 animation
->applySampleDivisor(_SampleDivisor
);
73 // compress CTrackSampledQuat header
74 if(_AnimHeaderOptimisation
)
75 animation
->applyTrackQuatHeaderCompression();
78 _Animation
.push_back (animation
);
79 _AnimationName
.push_back (name
);
81 // Add an entry name / animation
82 _AnimationIdByName
.insert (std::map
<std::string
, uint32
>::value_type (name
, (uint32
)_Animation
.size()-1));
84 // Return animation id
85 return (uint
)_Animation
.size()-1;
88 // ***************************************************************************
89 uint
CAnimationSet::addSkeletonWeight (const char* name
, CSkeletonWeight
* skeletonWeight
)
92 _SkeletonWeight
.push_back (skeletonWeight
);
93 _SkeletonWeightName
.push_back (name
);
95 // Add an entry name / animation
96 _SkeletonWeightIdByName
.insert (std::map
<std::string
, uint32
>::value_type (name
, (uint32
)_SkeletonWeight
.size()-1));
98 // Return animation id
99 return (uint
)_SkeletonWeight
.size()-1;
102 // ***************************************************************************
103 void CAnimationSet::reset ()
106 _SkeletonWeight
.clear();
107 _ChannelName
.clear();
108 _AnimationName
.clear();
109 _SkeletonWeightName
.clear();
110 _ChannelIdByName
.clear();
111 _AnimationIdByName
.clear();
112 _SkeletonWeightIdByName
.clear();
116 // ***************************************************************************
117 void CAnimationSet::build ()
119 // error to rebuild in if already done while _AnimHeaderOptimisation,
120 // cause applyAnimHeaderCompression() won't work
121 if(_Built
&& _AnimHeaderOptimisation
)
125 // Clear the channel map
126 _ChannelName
.clear();
127 _ChannelIdByName
.clear ();
130 std::set
<std::string
> channelNames
;
132 // For each animation in the set
134 for (a
=0; a
<_Animation
.size(); a
++)
136 // Fill the set of channel names
137 getAnimation (a
)->getTrackNames (channelNames
);
140 // Add this name in the map with there iD
142 std::set
<std::string
>::iterator ite
=channelNames
.begin ();
143 while (ite
!=channelNames
.end ())
146 _ChannelIdByName
.insert (std::map
<std::string
, uint32
>::value_type (*ite
, id
++));
152 // build ChannelName From Map
153 buildChannelNameFromMap();
155 // If the animation set is in HeaderOptim mode, reduce memory load by removing map<string, trackId>
156 if(_AnimHeaderOptimisation
)
158 for (uint a
=0; a
<_Animation
.size(); a
++)
160 _Animation
[a
]->applyAnimHeaderCompression (this, _ChannelIdByName
);
164 // Build the set of SSS Shapes from each animation
165 for (a
=0; a
<_Animation
.size(); a
++)
167 const std::vector
<std::string
> &shapes
= _Animation
[a
]->getSSSShapes();
168 for(uint s
=0;s
<shapes
.size();s
++)
170 // insert (may be already done)
171 _SSSShapes
.insert(shapes
[s
]);
177 /*nlinfo("ANIMYOYO: %d channels", _ChannelIdByName.size());
178 std::map <std::string, uint32>::iterator it;
179 for(it= _ChannelIdByName.begin();it!=_ChannelIdByName.end();it++)
181 nlinfo("ANIMYOYO: %3d: %s", it->second, it->first.c_str());
185 // ***************************************************************************
186 void CAnimationSet::serial (NLMISC::IStream
& f
)
188 // serial not possible if header optimisation enabled
189 nlassert(!_AnimHeaderOptimisation
);
192 f
.serialCheck (NELID("_LEN"));
193 f
.serialCheck (NELID("MINA"));
194 f
.serialCheck (NELID("TES_"));
197 uint ver
= f
.serialVersion (1);
200 f
.serialContPtr (_Animation
);
201 f
.serialContPtr (_SkeletonWeight
);
202 f
.serialCont (_AnimationName
);
203 f
.serialCont (_SkeletonWeightName
);
204 f
.serialCont(_ChannelIdByName
);
205 f
.serialCont(_AnimationIdByName
);
206 f
.serialCont(_SkeletonWeightIdByName
);
208 f
.serialCont(_ChannelName
);
210 buildChannelNameFromMap();
213 // ***************************************************************************
214 bool CAnimationSet::loadFromFiles(const std::string
&path
, bool recurse
/* = true*/, const char *ext
/*= "anim"*/, bool wantWarningMessage
/*= true*/)
216 bool everythingOk
= true;
217 std::vector
<std::string
> anims
;
218 NLMISC::CPath::getPathContent(path
, recurse
, false, true, anims
);
219 for (uint k
= 0; k
< anims
.size(); ++k
)
221 std::string fileExt
= NLMISC::CFile::getExtension(anims
[k
]);
222 if (fileExt
== ext
) // an animation file ?
226 NLMISC::CIFile iFile
;
227 iFile
.open(anims
[k
]);
228 CUniquePtr
<CAnimation
> anim(new CAnimation
);
230 addAnimation(NLMISC::CFile::getFilenameWithoutExtension(anims
[k
]).c_str(), anim
.release());
234 catch (const NLMISC::EStream
&e
)
236 if (wantWarningMessage
)
238 nlinfo("Unable to load an automatic animation : %s", e
.what());
240 everythingOk
= false;
248 // ***************************************************************************
249 void CAnimationSet::setAnimationSampleDivisor(uint sampleDivisor
)
251 _SampleDivisor
= sampleDivisor
;
253 if(_SampleDivisor
==0)
257 // ***************************************************************************
258 uint
CAnimationSet::getAnimationSampleDivisor() const
260 return _SampleDivisor
;
263 // ***************************************************************************
264 void CAnimationSet::buildChannelNameFromMap()
266 contReset(_ChannelName
);
267 _ChannelName
.resize(_ChannelIdByName
.size());
268 std::map
<std::string
, uint32
>::iterator it
;
269 for(it
= _ChannelIdByName
.begin();it
!=_ChannelIdByName
.end();it
++)
271 _ChannelName
[it
->second
]= it
->first
;
275 // ***************************************************************************
276 void CAnimationSet::preloadSSSShapes(IDriver
&drv
, CShapeBank
&shapeBank
)
278 const std::string shapeCacheName
= "SSS_PreLoad";
280 // Create the Animation Set Shape cache if do not exist
281 if(!shapeBank
.isShapeCache(shapeCacheName
))
283 // allow "inifinite" number of preloaded shapes
284 shapeBank
.addShapeCache(shapeCacheName
);
285 shapeBank
.setShapeCacheSize(shapeCacheName
, 1000000);
289 std::set
<std::string
>::iterator it
;
290 for(it
=_SSSShapes
.begin();it
!=_SSSShapes
.end();it
++)
292 string fileName
= toLowerAscii(*it
);
294 // link the shape to the shapeCache
295 shapeBank
.linkShapeToShapeCache(fileName
, shapeCacheName
);
297 // If !present in the shapeBank
298 if( shapeBank
.getPresentState(fileName
)==CShapeBank::NotPresent
)
300 // Don't load it if no more space in the cache
301 if( shapeBank
.getShapeCacheFreeSpace(shapeCacheName
)>0 )
304 shapeBank
.load(fileName
);
307 if( shapeBank
.getPresentState(fileName
)==CShapeBank::Present
)
309 // When a shape is first added to the bank, it is not in the cache.
310 // add it and release it to force it to be in the cache.
311 IShape
*shp
= shapeBank
.addRef(fileName
);
314 //nlinfo("Loading %s", CPath::lookup(fileName.c_str(), false, false).c_str());
315 shp
->flushTextures(drv
, 0);
316 shapeBank
.release(shp
);