]> Dogcows Code - chaz/yoink/blob - src/Animation.cc
fixed documentation about where to find licenses
[chaz/yoink] / src / Animation.cc
1
2 /*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
3 **] All rights reserved.
4 *
5 * Distributable under the terms and conditions of the 2-clause BSD license;
6 * see the file COPYING for a complete text of the license.
7 *
8 *****************************************************************************/
9
10 #include <map>
11 #include <stdexcept>
12 #include <vector>
13
14 #include <moof/manager.hh>
15 #include <moof/log.hh>
16 #include <moof/resource.hh>
17 #include <moof/script.hh>
18
19 #include "Animation.hh"
20
21
22 /**
23 * The collection of nested animation classes. The animation implementation
24 * consists of an impl class which is allocated and initialized with the
25 * interface object. This class contains the specific fields which are
26 * required to run a single instance of an animation. The sequence data is
27 * loaded in a different class which can be shared amongst multiple animation
28 * implementation instances.
29 */
30 class Animation::impl
31 {
32 public:
33
34 /**
35 * Contains "global" animation data for the various animations which
36 * get loaded. This is a manager, so it will be shared amongst any
37 * animation which wants to use these loaded sequences.
38 */
39 class Data : public moof::manager<Data>
40 {
41 public:
42
43 /**
44 * A frame of an animation sequence. A frame is merely an
45 * index which presumably represents a "slide" or tile which
46 * should be displayed, and the duration that is how long the
47 * slide will be shown.
48 */
49 class Frame
50 {
51 public:
52
53 unsigned mIndex; ///< Frame index.
54 moof::scalar mDuration; ///< Frame duration.
55
56 /**
57 * Construction is initialization. The frame data is
58 * loaded from a frame map which is probably loaded
59 * within an animation file.
60 */
61 Frame(const moof::script::slot& table) :
62 mIndex(0),
63 mDuration(1.0)
64 {
65 table.get(mIndex, "index");
66 table.get(mDuration, "duration");
67 }
68 };
69
70 /**
71 * A sequence is just a few attributes and a list of frames in
72 * the order that they should be played.
73 */
74 class Sequence
75 {
76 public:
77
78 std::vector<Frame> mFrames; ///< List of frames.
79 moof::scalar mDelay; ///< Scale frame durations.
80 bool mLoop; ///< Does the sequence repeat?
81 std::string mNext; ///< Next sequence name.
82
83 /**
84 * Construction is initialization. The constructor
85 * loads sequence data from the sequence map,
86 * presumably loaded from an animation file. The rest
87 * of the loading takes place in the frame's
88 * constructor which loads each individual frame.
89 */
90 Sequence(const moof::script::slot& table) :
91 mDelay(0.0),
92 mLoop(true)
93 {
94 table.get(mDelay, "delay");
95 table.get(mLoop, "loop");
96 table.get(mNext, "next");
97
98 // TODO - sequence class/type not yet implemented
99
100 moof::script::slot frameTable = table.push_field("frames");
101 if (frameTable.is_table()) {
102 int max = frameTable.length();
103 for (int index = 1; index <= max; ++index) {
104 moof::script::slot top = frameTable.push_field(index);
105
106 if (top.is_table())
107 mFrames.push_back(Frame(top));
108 else
109 moof::log_warning << "invalid frame at index "
110 << index << std::endl;
111 }
112 }
113 frameTable.remove();
114 }
115 };
116
117 /**
118 * Starts loading a file with animation data. Such a file is
119 * formatted as a map of named sequences. The sequence
120 * constructor loads each individual sequence.
121 */
122 void init(const std::string& name)
123 {
124 moof::script script;
125 std::string path = moof::resource::find_file("animations/"+name, "lua");
126
127 script.import_base_library();
128 moof::log::import(script);
129 importAnimationBindings(script);
130
131 if (script.do_file(path) != moof::script::success) {
132 std::string str;
133 script[-1].get(str);
134 moof::log_warning(str);
135 }
136 }
137
138 int defineSequence(moof::script& script)
139 {
140 moof::script::slot name = script[1].require_string();
141 moof::script::slot table = script[2].require_table();
142
143 std::string nameStr;
144 name.get(nameStr);
145
146 mSequences.insert(std::make_pair(nameStr, Sequence(table)));
147
148 return 0;
149 }
150
151 void importAnimationBindings(moof::script& script)
152 {
153 script.import_function("DefineSequence",
154 boost::bind(&Data::defineSequence, this, _1));
155
156 script.globals().set_field("ATTACK", 1);
157 script.globals().set_field("CHARGE", 2);
158 script.globals().set_field("FLY", 3);
159 script.globals().set_field("HIT", 4);
160 script.globals().set_field("JUMP", 5);
161 script.globals().set_field("RUN", 6);
162 script.globals().set_field("STAND", 7);
163 }
164
165 std::map<std::string,Sequence> mSequences; ///< List of sequences.
166 };
167
168 /**
169 * Construction is intialization.
170 */
171 impl(const std::string& name) :
172 mData(Data::instance(name)),
173 mCurrentSequence(0),
174 mFrameCounter(0),
175 mFrameIndex(0),
176 mTimeAccum(0),
177 mFrameDuration(0) {}
178
179 /**
180 * Sets up the animation classes to "play" a named sequence. If
181 * another sequence was active, it will be replaced. Future updates
182 * will progress the new sequence.
183 */
184 void startSequence(const std::string& name)
185 {
186 std::map<std::string,Data::Sequence>::iterator it;
187
188 it = mData->mSequences.find(name);
189 if (it != mData->mSequences.end()) {
190 mCurrentSequence = &(*it).second;
191 mFrameCounter = 0;
192 mFrameIndex = mCurrentSequence->mFrames[0].mIndex;
193 mTimeAccum = 0.0;
194 mFrameDuration = mCurrentSequence->mDelay *
195 mCurrentSequence->mFrames[0].mDuration;
196 }
197 }
198
199 /**
200 * Updates or progresses the animation sequence. If the time interval
201 * surpasses the duration of the current frame, a new frame becomes
202 * the current frame. If the last frame of a sequence expires, the
203 * active sequence will switch automatically to the designated "next"
204 * sequence, or if none is specified but the sequence is set to loop,
205 * the first frame of the sequence will become the current frame, and
206 * the animation essentially starts over again.
207 */
208 void update(moof::scalar t, moof::scalar dt)
209 {
210 if (!mCurrentSequence) return;
211
212 mTimeAccum += dt;
213
214 if (mTimeAccum >= mFrameDuration) {
215 if (++mFrameCounter >= mCurrentSequence->mFrames.size()) {
216 if (!mCurrentSequence->mNext.empty()) {
217 startSequence(mCurrentSequence->mNext);
218 }
219 else if (mCurrentSequence->mLoop) {
220 mFrameCounter = 0;
221 }
222 else {
223 mFrameCounter--;
224 mCurrentSequence = 0;
225 }
226 }
227
228 mFrameIndex = mCurrentSequence->mFrames[mFrameCounter].mIndex;
229 mTimeAccum = mFrameDuration - mTimeAccum;
230 mFrameDuration = mCurrentSequence->mDelay *
231 mCurrentSequence->mFrames[mFrameCounter].mDuration;
232 }
233 }
234
235 boost::shared_ptr<Data> mData; ///< Internal data.
236
237 Data::Sequence* mCurrentSequence; ///< Active sequence.
238 unsigned mFrameCounter; ///< Current frame.
239 unsigned mFrameIndex; ///< Index of current frame.
240 moof::scalar mTimeAccum; ///< Time accumulation.
241 moof::scalar mFrameDuration; ///< Scaled frame duration.
242 };
243
244 Animation::Animation(const std::string& name) :
245 // pass through
246 impl_(new Animation::impl(name)) {}
247
248 void Animation::startSequence(const std::string& name)
249 {
250 // pass through
251 impl_->startSequence(name);
252 }
253
254 void Animation::update(moof::scalar t, moof::scalar dt)
255 {
256 // pass through
257 impl_->update(t, dt);
258 }
259
260 /**
261 * Gets the index for the current frame. This is presumably called by some
262 * drawing code which will draw the correct current frame.
263 */
264 unsigned Animation::getFrame() const
265 {
266 return impl_->mFrameIndex;
267 }
268
This page took 0.044022 seconds and 5 git commands to generate.