]> Dogcows Code - chaz/yoink/blobdiff - src/animation.cc
big batch of progress
[chaz/yoink] / src / animation.cc
index 745f0e4493eddcb486c5334f6b841d42da9575fe..c03a49d7195a08e4f3d0252f1581eb18f3b00855 100644 (file)
 
 *******************************************************************************/
 
+#include <map>
+#include <vector>
+
+#include "serializable.hh"
+#include "mippleton.hh"
 #include "animation.hh"
 
 
 namespace dc {
 
 
-class animation_impl
+/**
+ * The collection of nested animation classes.  The animation implementation
+ * consists of an animation_impl classes which is allocated and initialized with
+ * the interface object.  This class contains the specific fields which are
+ * required to run a single instance of an animation.  The sequence data is
+ * loaded in a difference class which can be shared amongst multiple animation
+ * implementation instances.
+ */
+
+struct animation::animation_impl
 {
-public:
 
-       class sequence
+       /**
+        * Contains "global" animation data for the various animations which get
+        * loaded.  This is a mippleton, so it will be shared amongst any animation
+        * which wants to use these loaded sequences.
+        */
+
+       struct animation_data : public mippleton<animation_data>
        {
+               /**
+                * A frame of an animation sequence.  A frame is merely an index which
+                * presumably represents a "slide" or tile which should be displayed,
+                * and the duration that is how long the slide will be shown.
+                */
+
+               struct frame
+               {
+                       unsigned        index;                                  ///< Frame index.
+                       scalar          duration;                               ///< Frame duration.
+
+                       /**
+                        * Construction is initialization.  The frame data is loaded from a
+                        * frame map which is probably loaded within an animation file.
+                        */
+               
+                       frame(serializable_ptr root) :
+                               index(0),
+                               duration(1.0)
+                       {
+                               std::map<std::string,serializable_ptr> rootObj;
+
+                               if (root->get(rootObj))
+                               {
+                                       std::map<std::string,serializable_ptr>::iterator i;
+                                       for (i = rootObj.begin(); i != rootObj.end(); i++)
+                                       {
+                                               std::string key = (*i).first;
+                                               if (key == "index")
+                                               {
+                                                       long value = 0;
+                                                       (*i).second->get(value);
+                                                       index = unsigned(value);
+                                               }
+                                               else if (key == "duration")
+                                               {
+                                                       double value = 0.0;
+                                                       (*i).second->getNumber(value);
+                                                       duration = scalar(value);
+                                               }
+                                       }
+                               }
+                       }
+               };
+
+
+               /**
+                * A sequence is just a few attributes and a list of frames in the order
+                * that they should be played.
+                */
+
+               struct sequence
+               {
+                       std::vector<frame>      frames;                 ///< List of frames.
+                       scalar                          delay;                  ///< Scale frame durations.
+                       bool                            loop;                   ///< Does the sequence repeat?
+                       std::string                     next;                   ///< Next sequence name.
+
+                       /**
+                        * Construction is initialization.  The constructor loads sequence
+                        * data from the sequence map, presumably loaded from an animation
+                        * file.  The rest of the loading takes place in the frame's
+                        * constructor which loads each individual frame.
+                        */
+
+                       sequence(serializable_ptr root) :
+                               delay(0.0),
+                               loop(true)
+                       {
+                               std::map<std::string,serializable_ptr> rootObj;
+
+                               if (root->get(rootObj))
+                               {
+                                       std::map<std::string,serializable_ptr>::iterator i;
+                                       for (i = rootObj.begin(); i != rootObj.end(); i++)
+                                       {
+                                               std::string key = (*i).first;
+
+                                               if (key == "frames")
+                                               {
+                                                       std::vector<serializable_ptr> framesObj;
+
+                                                       if ((*i).second->get(framesObj))
+                                                       {
+                                                               std::vector<serializable_ptr>::iterator j;
+
+                                                               for (j = framesObj.begin();
+                                                                               j != framesObj.end(); j++)
+                                                               {
+                                                                       if (*j)
+                                                                       {
+                                                                               frames.push_back(frame(*j));
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               else if (key == "delay")
+                                               {
+                                                       double value;
+                                                       (*i).second->getNumber(value);
+                                                       delay = scalar(value);
+                                               }
+                                               else if (key == "loop")
+                                               {
+                                                       (*i).second->get(loop);
+                                               }
+                                               else if (key == "next")
+                                               {
+                                                       (*i).second->get(next);
+                                               }
+                                       }
+                               }
+                       }
+               };
+
+
+               /**
+                * Starts loading a file with animation data.  Such a file is formatted
+                * as a map of named sequences.   The sequence constructor loads each
+                * individual sequence.
+                */
+
+               void loadFromFile()
+               {
+                       std::string filePath = animation::getPathToResource(getName());
+
+                       deserializer in(filePath);
+
+                       serializable_ptr root = in.deserialize();
+
+                       if (root)
+                       {
+                               std::map<std::string,serializable_ptr> rootObj;
+
+                               if (root->get(rootObj))
+                               {
+                                       std::map<std::string,serializable_ptr>::iterator i;
+
+                                       for (i = rootObj.begin(); i != rootObj.end(); i++)
+                                       {
+                                               sequences.insert(std::pair<std::string,sequence>((*i).first,
+                                                                       sequence((*i).second)));
+                                       }
+                               }
+                       }
+               }
+
+               /**
+                * Construction is initialization.  The animation class data container
+                * registers itself as a mippleton and then loads the animation data.
+                */
+
+               explicit animation_data(const std::string& name) :
+                       mippleton<animation_data>(name)
+               {
+                       loadFromFile();
+               }
+
+               std::map<std::string,sequence> sequences;               ///< List of sequences.
        };
 
-       std::map<std::string,sequence> sequences;
+
+       /**
+        * Construction is intialization.
+        */
+
+       animation_impl(const std::string& name) :
+               data(animation_data::retain(name), &animation_data::release),
+               currentSequence(0),
+               frameCounter(0),
+               frameIndex(0),
+               timeAccum(0),
+               frameDuration(0) {}
+
+
+       /**
+        * Sets up the animation classes to "play" a named sequence.  If another
+        * sequence was active, it will be replaced as the current sequence.  Future
+        * updates will progress the new sequence.
+        */
+
+       void startSequence(const std::string& sequenceName)
+       {
+               std::map<std::string,animation_data::sequence>::iterator i;
+
+               i = data->sequences.find(sequenceName);
+
+               if (i != data->sequences.end())
+               {
+                       currentSequence = &(*i).second;
+                       frameCounter = 0;
+                       frameIndex = currentSequence->frames[0].index;
+                       timeAccum = 0.0;
+                       frameDuration = currentSequence->delay *
+                               currentSequence->frames[0].duration;
+               }
+       }
+
+       /**
+        * Updates or progresses the animation sequence.  If the time interval
+        * surpasses the duration of the current frame, a new frame becomes the
+        * current frame.  If the last frame of a sequence expires, the active
+        * sequence will switch automatically to the designated "next" sequence, or
+        * if none is specified but the sequence is set to loop, the first frame of
+        * the sequence will become the current frame, and the animation essentially
+        * starts over again.
+        */
+
+       void update(scalar t, scalar dt)
+       {
+               if (currentSequence)
+               {
+                       timeAccum += dt;
+
+                       if (timeAccum >= frameDuration)
+                       {
+                               if (++frameCounter >= currentSequence->frames.size())
+                               {
+                                       if (!currentSequence->next.empty())
+                                       {
+                                               startSequence(currentSequence->next);
+                                       }
+                                       else if (currentSequence->loop)
+                                       {
+                                               frameCounter = 0;
+                                       }
+                                       else
+                                       {
+                                               frameCounter--;
+                                               currentSequence = 0;
+                                       }
+                               }
+
+                               frameIndex = currentSequence->frames[frameCounter].index;
+                               timeAccum = frameDuration - timeAccum;
+                               frameDuration = currentSequence->delay *
+                                       currentSequence->frames[frameCounter].duration;
+                       }
+               }
+       }
+
+       boost::shared_ptr<animation_data> data;                 ///< Internal data.
+
+       animation_data::sequence*       currentSequence;        ///< Active sequence.
+       unsigned        frameCounter;                                           ///< Current frame.
+       unsigned        frameIndex;                                                     ///< Index of current frame.
+       scalar          timeAccum;                                                      ///< Time accumulation.
+       scalar          frameDuration;                                          ///< Scaled frame duration.
 };
 
 
+animation::animation(const std::string& name) :
+       // pass through
+       impl(new animation::animation_impl(name)) {}
+
+
+void animation::startSequence(const std::string& sequenceName)
+{
+       // pass through
+       impl->startSequence(sequenceName);
+}
+
+void animation::update(scalar t, scalar dt)
+{
+       // pass through
+       impl->update(t, dt);
+}
+
+
+/**
+ * Gets the index for the current frame.  This is presumably called by some
+ * drawing code which will draw the correct current frame.
+ */
+
+unsigned animation::getFrame() const
+{
+       return impl->frameIndex;
+}
+
+
+/**
+ * Specialized search location for animation files.  They can be found in the
+ * "animations" subdirectory of any of the searched directories.
+ */
+
+std::string animation::getPathToResource(const std::string& name)
+{
+       return resource::getPathToResource("animations/" + name + ".json");
+}
 
 
 } // namespace dc
 
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
This page took 0.023908 seconds and 4 git commands to generate.