+++ /dev/null
-
-/*******************************************************************************
-
- Copyright (c) 2009, Charles McGarvey
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*******************************************************************************/
-
-#include <map>
-#include <vector>
-
-#include "Animation.hh"
-#include "Mippleton.hh"
-#include "Serializable.hh"
-
-
-namespace Mf {
-
-
-/**
- * The collection of nested animation classes. The animation implementation
- * consists of an Impl class 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
- * different class which can be shared amongst multiple animation implementation
- * instances.
- */
-
-class Animation::Impl
-{
- friend class Animation;
-
- /**
- * 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.
- */
-
- class Data : public Mippleton<Data>
- {
- friend class Impl;
- friend class Mippleton<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(SerializableP root) :
- index(0),
- duration(1.0)
- {
- Serializable::Map rootObj;
-
- if (root->get(rootObj))
- {
- Serializable::Map::iterator it;
-
- for (it = rootObj.begin(); it != rootObj.end(); ++it)
- {
- std::string key = (*it).first;
- if (key == "index")
- {
- long value = 0;
- (*it).second->get(value);
- index = unsigned(value);
- }
- else if (key == "duration")
- {
- double value = 0.0;
- (*it).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(SerializableP root) :
- delay(0.0),
- loop(true)
- {
- Serializable::Map rootObj;
-
- if (root->get(rootObj))
- {
- Serializable::Map::iterator it;
- for (it = rootObj.begin(); it != rootObj.end(); ++it)
- {
- std::string key = (*it).first;
-
- if (key == "frames")
- {
- Serializable::Array framesObj;
-
- if ((*it).second->get(framesObj))
- {
- Serializable::Array::iterator jt;
-
- for (jt = framesObj.begin();
- jt != framesObj.end(); ++jt)
- {
- if (*jt)
- {
- frames.push_back(Frame(*jt));
- }
- }
- }
- }
- else if (key == "delay")
- {
- double value;
- (*it).second->getNumber(value);
- delay = Scalar(value);
- }
- else if (key == "loop")
- {
- (*it).second->get(loop);
- }
- else if (key == "next")
- {
- (*it).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::getPath(getName());
-
- Deserializer deserializer(filePath);
-
- SerializableP root = deserializer.deserialize();
-
- if (root)
- {
- Serializable::Map rootObj;
-
- if (root->get(rootObj))
- {
- Serializable::Map::iterator it;
-
- for (it = rootObj.begin(); it != rootObj.end(); ++it)
- {
- sequences.insert(std::pair<std::string,Sequence>((*it).first,
- Sequence((*it).second)));
- }
- }
- }
- }
-
- /**
- * Construction is initialization. The animation class data container
- * registers itself as a mippleton and then loads the animation data.
- */
-
- explicit Data(const std::string& name) :
- Mippleton<Data>(name)
- {
- loadFromFile();
- }
-
- std::map<std::string,Sequence> sequences; ///< List of sequences.
- };
-
-
- /**
- * Construction is intialization.
- */
-
- Impl(const std::string& name) :
- data(Data::getInstance(name)),
- 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& name)
- {
- std::map<std::string,Data::Sequence>::iterator it;
-
- it = data->sequences.find(name);
-
- if (it != data->sequences.end())
- {
- currentSequence = &(*it).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<Data> data; ///< Internal data.
-
- 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::Impl(name)) {}
-
-
-void Animation::startSequence(const std::string& name)
-{
- // pass through
- impl_->startSequence(name);
-}
-
-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::getPath(const std::string& name)
-{
- return Resource::getPath("animations/" + name + ".json");
-}
-
-
-} // namespace Mf
-
-/** vim: set ts=4 sw=4 tw=80: *************************************************/
-