]> Dogcows Code - chaz/yoink/blob - src/Animation.cc
bugfix: resource file searching was broken
[chaz/yoink] / src / Animation.cc
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #include <map>
13 #include <vector>
14
15 #include <Moof/Error.hh>
16 #include <Moof/Manager.hh>
17 #include <Moof/Log.hh>
18 #include <Moof/Script.hh>
19
20 #include "Animation.hh"
21
22
23 /**
24 * The collection of nested animation classes. The animation
25 * implementation consists of an Impl class which is allocated and
26 * initialized with the interface object. This class contains the specific
27 * fields which are required to run a single instance of an animation. The
28 * sequence data is loaded in a different class which can be shared amongst
29 * multiple animation implementation instances.
30 */
31
32 class Animation::Impl
33 {
34 public:
35
36 /**
37 * Contains "global" animation data for the various animations which
38 * get loaded. This is a mippleton, so it will be shared amongst any
39 * animation which wants to use these loaded sequences.
40 */
41
42 class Data : public Mf::Manager<Data>
43 {
44 public:
45
46 /**
47 * A frame of an animation sequence. A frame is merely an index
48 * which presumably represents a "slide" or tile which should be
49 * displayed, and the duration that is how long the slide will be
50 * shown.
51 */
52
53 class Frame
54 {
55 public:
56
57 unsigned mIndex; ///< Frame index.
58 Mf::Scalar mDuration; ///< Frame duration.
59
60 /**
61 * Construction is initialization. The frame data is loaded
62 * from a frame map which is probably loaded within an
63 * animation file.
64 */
65
66 Frame(Mf::Script& script, Mf::Script::Slot table) :
67 mIndex(0),
68 mDuration(1.0)
69 {
70 table.pushField("index");
71 script[-1].get(mIndex);
72 script.pop();
73
74 table.pushField("duration");
75 script[-1].get(mDuration);
76 script.pop();
77 }
78 };
79
80
81 /**
82 * A sequence is just a few attributes and a list of frames in the
83 * order that they should be played.
84 */
85
86 class Sequence
87 {
88 public:
89
90 std::vector<Frame> mFrames; ///< List of frames.
91 Mf::Scalar mDelay; ///< Scale frame durations.
92 bool mLoop; ///< Does the sequence repeat?
93 std::string mNext; ///< Next sequence name.
94
95 /**
96 * Construction is initialization. The constructor loads
97 * sequence data from the sequence map, presumably loaded from
98 * an animation file. The rest of the loading takes place in
99 * the frame's constructor which loads each individual frame.
100 */
101
102 Sequence(Mf::Script& script, Mf::Script::Slot table) :
103 mDelay(0.0),
104 mLoop(true)
105 {
106 table.pushField("delay");
107 script[-1].get(mDelay);
108 script.pop();
109
110 table.pushField("loop");
111 script[-1].get(mLoop);
112 script.pop();
113
114 table.pushField("next");
115 script[-1].get(mNext);
116 script.pop();
117
118 // TODO - sequence class/type not yet implemented
119
120 table.pushField("frames");
121 Mf::Script::Slot frameTable = script.getTop();
122 if (frameTable.isTable())
123 {
124 Mf::Script::Slot top = script[-1];
125 int index = 1;
126
127 for (;;)
128 {
129 script.push(index);
130 frameTable.pushField();
131
132 if (top.isTable())
133 {
134 mFrames.push_back(Frame(script, top));
135 }
136 else break;
137
138 ++index;
139 }
140 }
141 script.pop();
142 }
143 };
144
145
146 /**
147 * Starts loading a file with animation data. Such a file is
148 * formatted as a map of named sequences. The sequence
149 * constructor loads each individual sequence.
150 */
151
152 void init(const std::string& name)
153 {
154 Mf::Script script;
155 std::string path(name);
156
157 if (!Animation::getPath(path))
158 {
159 Mf::Error(Mf::Error::RESOURCE_NOT_FOUND).raise();
160 }
161
162 script.importBaseLibrary();
163 importLogFunctions(script);
164 importAnimationBindings(script);
165
166 if (script.doFile(path) != Mf::Script::SUCCESS)
167 {
168 std::string str;
169 script[-1].get(str);
170 Mf::logWarning(str);
171 }
172 }
173
174 int defineSequence(Mf::Script& script)
175 {
176 Mf::Script::Slot name = script[1].requireString();
177 Mf::Script::Slot table = script[2].requireTable();
178
179 std::string nameStr;
180 name.get(nameStr);
181
182 mSequences.insert(std::make_pair(nameStr,
183 Sequence(script, table)));
184
185 return 0;
186 }
187
188
189 void importAnimationBindings(Mf::Script& script)
190 {
191 script.importFunction("DefineSequence",
192 boost::bind(&Data::defineSequence,
193 this, _1));
194
195 script.push(1); script.set("ATTACK");
196 script.push(2); script.set("CHARGE");
197 script.push(3); script.set("FLY");
198 script.push(4); script.set("HIT");
199 script.push(5); script.set("JUMP");
200 script.push(6); script.set("RUN");
201 script.push(7); script.set("STAND");
202 }
203
204
205 std::map<std::string,Sequence> mSequences; ///< List of sequences.
206 };
207
208
209 /**
210 * Construction is intialization.
211 */
212
213 Impl(const std::string& name) :
214 mData(Data::getInstance(name)),
215 mCurrentSequence(0),
216 mFrameCounter(0),
217 mFrameIndex(0),
218 mTimeAccum(0),
219 mFrameDuration(0) {}
220
221
222 /**
223 * Sets up the animation classes to "play" a named sequence. If
224 * another sequence was active, it will be replaced. Future updates
225 * will progress the new sequence.
226 */
227
228 void startSequence(const std::string& name)
229 {
230 std::map<std::string,Data::Sequence>::iterator it;
231
232 it = mData->mSequences.find(name);
233
234 if (it != mData->mSequences.end())
235 {
236 mCurrentSequence = &(*it).second;
237 mFrameCounter = 0;
238 mFrameIndex = mCurrentSequence->mFrames[0].mIndex;
239 mTimeAccum = 0.0;
240 mFrameDuration = mCurrentSequence->mDelay *
241 mCurrentSequence->mFrames[0].mDuration;
242 }
243 }
244
245 /**
246 * Updates or progresses the animation sequence. If the time interval
247 * surpasses the duration of the current frame, a new frame becomes the
248 * current frame. If the last frame of a sequence expires, the active
249 * sequence will switch automatically to the designated "next"
250 * sequence, or if none is specified but the sequence is set to loop,
251 * the first frame of the sequence will become the current frame, and
252 * the animation essentially starts over again.
253 */
254
255 void update(Mf::Scalar t, Mf::Scalar dt)
256 {
257 if (!mCurrentSequence) return;
258
259 mTimeAccum += dt;
260
261 if (mTimeAccum >= mFrameDuration)
262 {
263 if (++mFrameCounter >= mCurrentSequence->mFrames.size())
264 {
265 if (!mCurrentSequence->mNext.empty())
266 {
267 startSequence(mCurrentSequence->mNext);
268 }
269 else if (mCurrentSequence->mLoop)
270 {
271 mFrameCounter = 0;
272 }
273 else
274 {
275 mFrameCounter--;
276 mCurrentSequence = 0;
277 }
278 }
279
280 mFrameIndex = mCurrentSequence->mFrames[mFrameCounter].mIndex;
281 mTimeAccum = mFrameDuration - mTimeAccum;
282 mFrameDuration = mCurrentSequence->mDelay *
283 mCurrentSequence->mFrames[mFrameCounter].mDuration;
284 }
285 }
286
287 boost::shared_ptr<Data> mData; ///< Internal data.
288
289 Data::Sequence* mCurrentSequence; ///< Active sequence.
290 unsigned mFrameCounter; ///< Current frame.
291 unsigned mFrameIndex; ///< Index of current frame.
292 Mf::Scalar mTimeAccum; ///< Time accumulation.
293 Mf::Scalar mFrameDuration; ///< Scaled frame duration.
294 };
295
296
297 Animation::Animation(const std::string& name) :
298 // pass through
299 mImpl(new Animation::Impl(name)) {}
300
301
302 void Animation::startSequence(const std::string& name)
303 {
304 // pass through
305 mImpl->startSequence(name);
306 }
307
308 void Animation::update(Mf::Scalar t, Mf::Scalar dt)
309 {
310 // pass through
311 mImpl->update(t, dt);
312 }
313
314
315 /**
316 * Gets the index for the current frame. This is presumably called by some
317 * drawing code which will draw the correct current frame.
318 */
319
320 unsigned Animation::getFrame() const
321 {
322 return mImpl->mFrameIndex;
323 }
324
325
326 /**
327 * Specialized search location for animation files. They can be found in
328 * the "animations" subdirectory of any of the search directories.
329 */
330
331 bool Animation::getPath(std::string& name)
332 {
333 return Mf::Resource::getPath(name, "animations/", "lua");
334 }
335
This page took 0.047099 seconds and 4 git commands to generate.