2 #include <msp/core/maputils.h>
3 #include <msp/datafile/collection.h>
5 #include "animationeventobserver.h"
15 Animation::Animation():
20 // Avoid synthesizing ~RefPtr in files including animation.h
21 Animation::~Animation()
24 void Animation::set_armature(const Armature &a)
29 unsigned Animation::get_slot_for_uniform(const string &n) const
31 for(unsigned i=0; i<uniforms.size(); ++i)
32 if(uniforms[i].name==n)
37 const string &Animation::get_uniform_name(unsigned i) const
39 if(i>=uniforms.size())
40 throw out_of_range("Animation::get_uniform_name");
41 return uniforms[i].name;
44 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
46 add_keyframe(t, kf, 1.0f, 1.0f);
49 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope)
51 add_keyframe(t, kf, slope, slope);
54 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es)
56 RefPtr<const KeyFrame> kfr(&kf);
58 add_keyframe(t, kfr, ss, es);
61 void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf, float ss, float es)
63 if(keyframes.empty() && t!=Time::zero)
64 throw invalid_argument("Animation::add_keyframe");
65 if(!keyframes.empty() && t<keyframes.back().time)
66 throw invalid_argument("Animation::add_keyframe");
68 bool realloc = (keyframes.size()>=keyframes.capacity());
70 keyframes.push_back(TimedKeyFrame());
71 TimedKeyFrame &tkf = keyframes.back();
79 for(unsigned i=1; i<keyframes.size(); ++i)
81 keyframes[i].prev = &keyframes[i-1];
83 if(keyframes.size()>1 && t>(&tkf-1)->time)
86 prepare_keyframe(tkf);
89 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
91 const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
92 for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
95 for(unsigned j=0; (!found && j<uniforms.size()); ++j)
96 if(uniforms[j].name==i->first)
98 if(uniforms[j].size!=i->second.size)
99 throw invalid_operation("Animation::prepare_keyframe");
104 uniforms.push_back(UniformInfo(i->first, i->second.size));
110 void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v)
116 events.push_back(event);
119 const Time::TimeDelta &Animation::get_duration() const
121 if(keyframes.empty())
124 return keyframes.back().time;
127 void Animation::set_looping(bool l)
133 Animation::AxisInterpolation::AxisInterpolation():
138 Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
140 // Compute a normalized vector halfway between the two endpoints
144 for(unsigned i=0; i<3; ++i)
146 float half_i = (axis1[i]+axis2[i])/2;
147 cos_half += axis1[i]*half_i;
148 a1_len += axis1[i]*axis1[i];
149 h_len += half_i*half_i;
152 // Compute correction factors for smooth interpolation
153 cos_half = min(max(cos_half/sqrt(a1_len*h_len), -1.0f), 1.0f);
154 float angle = acos(cos_half);
155 slope = (angle ? angle/tan(angle) : 1);
160 Animation::MatrixInterpolation::MatrixInterpolation():
165 Animation::MatrixInterpolation::MatrixInterpolation(const Matrix &m1, const Matrix &m2):
169 const float *m1_data = matrix1->data();
170 const float *m2_data = matrix2->data();
171 for(unsigned i=0; i<3; ++i)
172 axes[i] = AxisInterpolation(m1_data+i*4, m2_data+i*4);
175 Matrix Animation::MatrixInterpolation::get(float t) const
177 float u = t*2.0f-1.0f;
180 for(unsigned i=0; i<4; ++i)
182 const float *m1_col = matrix1->data()+i*4;
183 const float *m2_col = matrix2->data()+i*4;
184 float *out_col = matrix+i*4;
188 /* Linear interpolation will produce vectors that fall on the line
189 between the two endpoints, and has a higher angular velocity near the
190 middle. We compensate for the velocity by interpolating the angle
191 around the halfway point and computing its tangent. This is
192 approximated by a third degree polynomial, scaled so that the result
193 will be in the range [-1, 1]. */
194 float w = (axes[i].slope+(1-axes[i].slope)*u*u)*u*0.5f+0.5f;
196 /* The interpolated vectors will also be shorter than unit length. At
197 the halfway point the length will be equal to the cosine of half the
198 angle, which was computed earlier. Use a second degree polynomial to
200 float n = (axes[i].scale+(1-axes[i].scale)*u*u);
202 for(unsigned j=0; j<3; ++j)
203 out_col[j] = ((1-w)*m1_col[j]+w*m2_col[j])/n;
207 for(unsigned j=0; j<3; ++j)
208 out_col[j] = (1-t)*m1_col[j]+t*m2_col[j];
221 Animation::TimedKeyFrame::TimedKeyFrame():
227 void Animation::TimedKeyFrame::prepare(const Animation &animation)
229 const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
230 for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
232 unsigned j = animation.get_slot_for_uniform(i->first);
233 uniforms.reserve(j+1);
234 for(unsigned k=uniforms.size(); k<=j; ++k)
235 uniforms.push_back(KeyFrame::AnimatedUniform(animation.uniforms[k].size, 0.0f));
237 uniforms[j] = i->second;
243 delta_t = time-prev->time;
244 matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix());
246 if(animation.armature)
248 unsigned max_index = animation.armature->get_max_link_index();
249 pose_matrices.resize(max_index+1);
250 const Pose *pose1 = prev->keyframe->get_pose();
251 const Pose *pose2 = keyframe->get_pose();
252 static Matrix identity;
253 for(unsigned i=0; i<=max_index; ++i)
255 const Matrix &matrix1 = (pose1 ? pose1->get_link_matrix(i) : identity);
256 const Matrix &matrix2 = (pose2 ? pose2->get_link_matrix(i) : identity);
257 pose_matrices[i] = MatrixInterpolation(matrix1, matrix2);
263 Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
269 Animation::Iterator::Iterator(const Animation &a):
271 iter(animation->keyframes.begin()),
272 event_iter(animation->events.begin()),
276 if(iter==animation->keyframes.end())
277 throw invalid_argument("Animation::Iterator::Iterator");
280 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
282 time_since_keyframe += t;
283 while(time_since_keyframe>iter->delta_t)
285 vector<TimedKeyFrame>::const_iterator next = iter;
287 if(next==animation->keyframes.end())
289 if(animation->looping)
290 next = animation->keyframes.begin();
294 time_since_keyframe = iter->delta_t;
299 time_since_keyframe -= iter->delta_t;
303 x = time_since_keyframe/iter->delta_t;
304 x += (iter->start_slope-1)*((x-2)*x+1)*x + (1-iter->end_slope)*(1-x)*x*x;
309 void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
311 vector<Event>::const_iterator events_end = animation->events.end();
314 for(; event_iter!=events_end; ++event_iter)
315 observer.animation_event(0, event_iter->name, event_iter->value);
317 else if(event_iter!=events_end)
319 Time::TimeDelta t = time_since_keyframe;
321 t += iter->prev->time;
322 for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter)
323 observer.animation_event(0, event_iter->name, event_iter->value);
327 Matrix Animation::Iterator::get_matrix() const
330 return iter->keyframe->get_matrix();
332 return iter->matrix.get(x);
335 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
339 if(iter->uniforms.size()>i)
340 return iter->uniforms[i];
342 return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
345 unsigned size = animation->uniforms[i].size;
346 KeyFrame::AnimatedUniform result(size, 0.0f);
347 for(unsigned j=0; j<size; ++j)
348 result.values[j] = iter->prev->uniforms[i].values[j]*(1-x)+iter->uniforms[i].values[j]*x;
352 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
354 if(!animation->armature)
355 throw invalid_operation("Animation::Iterator::get_pose_matrix");
356 if(link>animation->armature->get_max_link_index())
357 throw out_of_range("Animation::Iterator::get_pose_matrix");
361 if(const Pose *pose = iter->keyframe->get_pose())
362 return pose->get_link_matrix(link);
367 // We must redo the base point correction since interpolation throws it off
368 // XXX This should probably be done on local matrices
369 Matrix result = iter->pose_matrices[link].get(x);
370 const Vector3 &base = animation->armature->get_link(link).get_base();
371 Vector3 new_base = result*base;
372 result = Matrix::translation(base-new_base)*result;
377 Animation::Loader::Loader(Animation &a):
378 DataFile::CollectionObjectLoader<Animation>(a, 0)
383 Animation::Loader::Loader(Animation &a, Collection &c):
384 DataFile::CollectionObjectLoader<Animation>(a, &c)
389 void Animation::Loader::init()
393 add("armature", &Animation::armature);
394 add("event", &Loader::event);
395 add("event", &Loader::event1i);
396 add("event", &Loader::event1f);
397 add("event", &Loader::event2f);
398 add("event", &Loader::event3f);
399 add("event", &Loader::event4f);
400 add("interval", &Loader::interval);
401 add("keyframe", &Loader::keyframe);
402 add("keyframe", &Loader::keyframe_inline);
403 add("looping", &Animation::looping);
404 add("slopes", &Loader::slopes);
407 void Animation::Loader::event(const string &n)
409 obj.add_event(current_time, n);
412 void Animation::Loader::event1i(const string &n, int v)
414 obj.add_event(current_time, n, v);
417 void Animation::Loader::event1f(const string &n, float v)
419 obj.add_event(current_time, n, v);
422 void Animation::Loader::event2f(const string &n, float v0, float v1)
424 obj.add_event(current_time, n, LinAl::Vector<float, 2>(v0, v1));
427 void Animation::Loader::event3f(const string &n, float v0, float v1, float v2)
429 obj.add_event(current_time, n, Vector3(v0, v1, v2));
432 void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3)
434 obj.add_event(current_time, n, Vector4(v0, v1, v2, v3));
437 void Animation::Loader::interval(float t)
439 current_time += t*Time::sec;
442 void Animation::Loader::keyframe(const string &n)
444 obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
445 start_slope = end_slope;
449 void Animation::Loader::keyframe_inline()
451 RefPtr<KeyFrame> kf = new KeyFrame;
453 load_sub(*kf, get_collection());
457 obj.add_keyframe(current_time, kf, start_slope, end_slope);
458 start_slope = end_slope;
462 void Animation::Loader::slopes(float s, float e)