1 /***********************************************************************
2 created: 7/8/2010
3 author: Martin Preisler
4
5 purpose: Implements the AnimationManager class
6 *************************************************************************/
7 /***************************************************************************
8 * Copyright (C) 2004 - 2010 Paul D Turner & The CEGUI Development Team
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining
11 * a copy of this software and associated documentation files (the
12 * "Software"), to deal in the Software without restriction, including
13 * without limitation the rights to use, copy, modify, merge, publish,
14 * distribute, sublicense, and/or sell copies of the Software, and to
15 * permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 ***************************************************************************/
29 #include "CEGUI/AnimationManager.h"
30 #include "CEGUI/Logger.h"
31 #include "CEGUI/Animation.h"
32 #include "CEGUI/AnimationInstance.h"
33 #include "CEGUI/TplInterpolators.h"
34 #include "CEGUI/Exceptions.h"
35 #include "CEGUI/System.h"
36 #include "CEGUI/XMLParser.h"
37 #include "CEGUI/Animation_xmlHandler.h"
38
39 // Start of CEGUI namespace section
40 namespace CEGUI
41 {
42 /*************************************************************************
43 Static Data Definitions
44 *************************************************************************/
45 // singleton instance pointer
46 template<> AnimationManager* Singleton<AnimationManager>::ms_Singleton = 0;
47 // Name of the xsd schema file used to validate animation XML files.
48 const String AnimationManager::XMLSchemaName("Animation.xsd");
49 // String that holds the default resource group for loading animations
50 String AnimationManager::s_defaultResourceGroup("");
51 const String AnimationManager::GeneratedAnimationNameBase("__ceanim_uid_");
52
53 /*************************************************************************
54 Constructor
55 *************************************************************************/
AnimationManager(void)56 AnimationManager::AnimationManager(void)
57 {
58 char addr_buff[32];
59 sprintf(addr_buff, "(%p)", static_cast<void*>(this));
60 Logger::getSingleton().logEvent(
61 "CEGUI::AnimationManager singleton created " + String(addr_buff));
62
63 // todo: is this too dirty?
64 # define addBasicInterpolator(i) { Interpolator* in = i; addInterpolator(in); d_basicInterpolators.push_back(in); }
65
66 // create and add basic interpolators shipped with CEGUI
67 addBasicInterpolator(CEGUI_NEW_AO TplDiscreteRelativeInterpolator<String>("String"));
68 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<float>("float"));
69 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<int>("int"));
70 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<uint>("uint"));
71 addBasicInterpolator(CEGUI_NEW_AO TplDiscreteInterpolator<bool>("bool"));
72 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<Sizef >("Sizef"));
73 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<Vector2f >("Vector2f"));
74 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<Vector3f >("Vector3f"));
75 addBasicInterpolator(CEGUI_NEW_AO QuaternionSlerpInterpolator());
76 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<Rectf >("Rectf"));
77 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<Colour>("Colour"));
78 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<ColourRect>("ColourRect"));
79 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<UDim>("UDim"));
80 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<UVector2>("UVector2"));
81 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<URect>("URect"));
82 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<UBox>("UBox"));
83 addBasicInterpolator(CEGUI_NEW_AO TplLinearInterpolator<USize>("USize"));
84 }
85
86
87 /*************************************************************************
88 Destructor
89 *************************************************************************/
~AnimationManager()90 AnimationManager::~AnimationManager()
91 {
92 // by destroying all animations their instances also get deleted
93 destroyAllAnimations();
94
95 // and lastly, we remove all interpolators, but we don't delete them!
96 // it is the creator's responsibility to delete them
97 d_interpolators.clear();
98
99 // we only destroy inbuilt interpolators
100 for (BasicInterpolatorList::const_iterator it = d_basicInterpolators.begin();
101 it != d_basicInterpolators.end(); ++it)
102 {
103 CEGUI_DELETE_AO *it;
104 }
105
106 d_basicInterpolators.clear();
107
108 char addr_buff[32];
109 sprintf(addr_buff, "(%p)", static_cast<void*>(this));
110 Logger::getSingleton().logEvent(
111 "CEGUI::AnimationManager singleton destroyed " + String(addr_buff));
112 }
113
114 //----------------------------------------------------------------------------//
addInterpolator(Interpolator * interpolator)115 void AnimationManager::addInterpolator(Interpolator* interpolator)
116 {
117 if (d_interpolators.find(interpolator->getType()) != d_interpolators.end())
118 {
119 CEGUI_THROW(AlreadyExistsException("Interpolator of type '"
120 + interpolator->getType() + "' already exists."));
121 }
122
123 d_interpolators.insert(
124 std::make_pair(interpolator->getType(), interpolator));
125 }
126
127 //----------------------------------------------------------------------------//
removeInterpolator(Interpolator * interpolator)128 void AnimationManager::removeInterpolator(Interpolator* interpolator)
129 {
130 InterpolatorMap::iterator it = d_interpolators.find(interpolator->getType());
131
132 if (it == d_interpolators.end())
133 {
134 CEGUI_THROW(UnknownObjectException("Interpolator of type '"
135 + interpolator->getType() + "' not found."));
136 }
137
138 d_interpolators.erase(it);
139 }
140
141 //----------------------------------------------------------------------------//
getInterpolator(const String & type) const142 Interpolator* AnimationManager::getInterpolator(const String& type) const
143 {
144 InterpolatorMap::const_iterator it = d_interpolators.find(type);
145
146 if (it == d_interpolators.end())
147 {
148 CEGUI_THROW(UnknownObjectException("Interpolator of type '" + type +
149 "' not found."));
150 }
151
152 return it->second;
153 }
154
155 //----------------------------------------------------------------------------//
createAnimation(const String & name)156 Animation* AnimationManager::createAnimation(const String& name)
157 {
158 if (isAnimationPresent(name))
159 {
160 CEGUI_THROW(UnknownObjectException("Animation with name '"
161 + name + "' already exists."));
162 }
163
164 String finalName(name.empty() ? generateUniqueAnimationName() : name);
165
166 Animation* ret = CEGUI_NEW_AO Animation(finalName);
167 d_animations.insert(std::make_pair(finalName, ret));
168
169 return ret;
170 }
171
172 //----------------------------------------------------------------------------//
destroyAnimation(Animation * animation)173 void AnimationManager::destroyAnimation(Animation* animation)
174 {
175 destroyAnimation(animation->getName());
176 }
177
178 //----------------------------------------------------------------------------//
destroyAnimation(const String & name)179 void AnimationManager::destroyAnimation(const String& name)
180 {
181 AnimationMap::iterator it = d_animations.find(name);
182
183 if (it == d_animations.end())
184 {
185 CEGUI_THROW(UnknownObjectException("Animation with name '" + name
186 + "' not found."));
187 }
188
189 Animation* animation = it->second;
190 destroyAllInstancesOfAnimation(animation);
191
192 d_animations.erase(it);
193 CEGUI_DELETE_AO animation;
194 }
195
196 //----------------------------------------------------------------------------//
destroyAllAnimations()197 void AnimationManager::destroyAllAnimations()
198 {
199 // we have to destroy all instances to avoid dangling pointers
200 // destroying all instances now is also faster than doing that for each
201 // animation that is being destroyed
202 destroyAllAnimationInstances();
203
204 for (AnimationMap::const_iterator it = d_animations.begin();
205 it != d_animations.end(); ++it)
206 {
207 CEGUI_DELETE_AO it->second;
208 }
209
210 d_animations.clear();
211 }
212
213 //----------------------------------------------------------------------------//
getAnimation(const String & name) const214 Animation* AnimationManager::getAnimation(const String& name) const
215 {
216 AnimationMap::const_iterator it = d_animations.find(name);
217
218 if (it == d_animations.end())
219 {
220 CEGUI_THROW(UnknownObjectException("Animation with name '" + name
221 + "' not found."));
222 }
223
224 return it->second;
225 }
226
227 //----------------------------------------------------------------------------//
isAnimationPresent(const String & name) const228 bool AnimationManager::isAnimationPresent(const String& name) const
229 {
230 return (d_animations.find(name) != d_animations.end());
231 }
232
233 //----------------------------------------------------------------------------//
getAnimationAtIdx(size_t index) const234 Animation* AnimationManager::getAnimationAtIdx(size_t index) const
235 {
236 if (index >= d_animations.size())
237 {
238 CEGUI_THROW(InvalidRequestException("Out of bounds."));
239 }
240
241 AnimationMap::const_iterator it = d_animations.begin();
242 std::advance(it, index);
243
244 return it->second;
245 }
246
247 //----------------------------------------------------------------------------//
getNumAnimations() const248 size_t AnimationManager::getNumAnimations() const
249 {
250 return d_animations.size();
251 }
252
253 //----------------------------------------------------------------------------//
instantiateAnimation(Animation * animation)254 AnimationInstance* AnimationManager::instantiateAnimation(Animation* animation)
255 {
256 if (!animation)
257 {
258 CEGUI_THROW(InvalidRequestException("I refuse to instantiate NULL "
259 "animation, please provide a valid pointer."));
260 }
261
262 AnimationInstance* ret = CEGUI_NEW_AO AnimationInstance(animation);
263 d_animationInstances.insert(std::make_pair(animation, ret));
264
265 return ret;
266 }
267
268 //----------------------------------------------------------------------------//
instantiateAnimation(const String & name)269 AnimationInstance* AnimationManager::instantiateAnimation(const String& name)
270 {
271 return instantiateAnimation(getAnimation(name));
272 }
273
274 //----------------------------------------------------------------------------//
destroyAnimationInstance(AnimationInstance * instance)275 void AnimationManager::destroyAnimationInstance(AnimationInstance* instance)
276 {
277 AnimationInstanceMap::iterator it =
278 d_animationInstances.find(instance->getDefinition());
279
280 for (; it != d_animationInstances.end(); ++it)
281 {
282 if (it->second == instance)
283 {
284 d_animationInstances.erase(it);
285 CEGUI_DELETE_AO instance;
286 return;
287 }
288 }
289
290 CEGUI_THROW(InvalidRequestException("Given animation instance not found."));
291 }
292
293 //----------------------------------------------------------------------------//
destroyAllInstancesOfAnimation(Animation * animation)294 void AnimationManager::destroyAllInstancesOfAnimation(Animation* animation)
295 {
296 AnimationInstanceMap::iterator it = d_animationInstances.find(animation);
297
298 // the first instance of given animation is now it->second (if there is any)
299 while (it != d_animationInstances.end() && it->first == animation)
300 {
301 AnimationInstanceMap::iterator toErase = it;
302 ++it;
303
304 CEGUI_DELETE_AO toErase->second;
305 d_animationInstances.erase(toErase);
306 }
307 }
308
309 //----------------------------------------------------------------------------//
destroyAllAnimationInstances()310 void AnimationManager::destroyAllAnimationInstances()
311 {
312 for (AnimationInstanceMap::const_iterator it = d_animationInstances.begin();
313 it != d_animationInstances.end(); ++it)
314 {
315 CEGUI_DELETE_AO it->second;
316 }
317
318 d_animationInstances.clear();
319 }
320
321 //----------------------------------------------------------------------------//
getAnimationInstanceAtIdx(size_t index) const322 AnimationInstance* AnimationManager::getAnimationInstanceAtIdx(size_t index) const
323 {
324 if (index >= d_animationInstances.size())
325 {
326 CEGUI_THROW(InvalidRequestException("Out of bounds."));
327 }
328
329 AnimationInstanceMap::const_iterator it = d_animationInstances.begin();
330 std::advance(it, index);
331
332 return it->second;
333 }
334
335 //----------------------------------------------------------------------------//
getNumAnimationInstances() const336 size_t AnimationManager::getNumAnimationInstances() const
337 {
338 return d_animationInstances.size();
339 }
340
341 //----------------------------------------------------------------------------//
autoStepInstances(float delta)342 void AnimationManager::autoStepInstances(float delta)
343 {
344 for (AnimationInstanceMap::const_iterator it = d_animationInstances.begin();
345 it != d_animationInstances.end(); ++it)
346 {
347 if (it->second->isAutoSteppingEnabled())
348 it->second->step(delta);
349 }
350 }
351
352 //----------------------------------------------------------------------------//
loadAnimationsFromXML(const String & filename,const String & resourceGroup)353 void AnimationManager::loadAnimationsFromXML(const String& filename,
354 const String& resourceGroup)
355 {
356 if (filename.empty())
357 CEGUI_THROW(InvalidRequestException(
358 "filename supplied for file loading must be valid."));
359
360 Animation_xmlHandler handler;
361
362 // do parse (which uses handler to create actual data)
363 CEGUI_TRY
364 {
365 System::getSingleton().getXMLParser()->
366 parseXMLFile(handler, filename, XMLSchemaName,
367 resourceGroup.empty() ? s_defaultResourceGroup :
368 resourceGroup);
369 }
370 CEGUI_CATCH(...)
371 {
372 Logger::getSingleton().logEvent(
373 "AnimationManager::loadAnimationsFromXML: "
374 "loading of animations from file '" + filename + "' has failed.",
375 Errors);
376
377 CEGUI_RETHROW;
378 }
379 }
380
loadAnimationsFromString(const String & source)381 void AnimationManager::loadAnimationsFromString(const String& source)
382 {
383 Animation_xmlHandler handler;
384
385 // do parse (which uses handler to create actual data)
386 CEGUI_TRY
387 {
388 System::getSingleton().getXMLParser()->parseXMLString(handler, source, XMLSchemaName);
389 }
390 CEGUI_CATCH(...)
391 {
392 Logger::getSingleton().logEvent("AnimationManager::loadAnimationsFromString - loading of animations from string failed.", Errors);
393 CEGUI_RETHROW;
394 }
395 }
396
397 //---------------------------------------------------------------------------//
writeAnimationDefinitionToStream(const Animation & animation,OutStream & out_stream) const398 void AnimationManager::writeAnimationDefinitionToStream(const Animation& animation, OutStream& out_stream) const
399 {
400 XMLSerializer xml(out_stream);
401
402 animation.writeXMLToStream(xml);
403 }
404
405 //---------------------------------------------------------------------------//
getAnimationDefinitionAsString(const Animation & animation) const406 String AnimationManager::getAnimationDefinitionAsString(const Animation& animation) const
407 {
408 std::ostringstream str;
409 writeAnimationDefinitionToStream(animation, str);
410
411 return String(reinterpret_cast<const encoded_char*>(str.str().c_str()));
412 }
413
414 //---------------------------------------------------------------------------//
generateUniqueAnimationName()415 String AnimationManager::generateUniqueAnimationName()
416 {
417 const String ret = GeneratedAnimationNameBase +
418 PropertyHelper<unsigned long>::toString(d_uid_counter);
419
420 // update counter for next time
421 unsigned long old_uid = d_uid_counter;
422 ++d_uid_counter;
423
424 // log if we ever wrap-around (which should be pretty unlikely)
425 if (d_uid_counter < old_uid)
426 Logger::getSingleton().logEvent("UID counter for generated Animation "
427 "names has wrapped around - the fun shall now commence!");
428
429 return ret;
430 }
431
432 } // End of CEGUI namespace section
433