+++ /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 "serializable.hh"
-#include "mippleton.hh"
-#include "animation.hh"
-
-
-namespace dc {
-
-
-/**
- * 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
-{
-
- /**
- * 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.
- };
-
-
- /**
- * 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: *************************************************/
-