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