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