2 #include <msp/core/maputils.h>
3 #include <msp/datafile/collection.h>
4 #include <msp/time/units.h>
6 #include "animationeventobserver.h"
16 Animation::Animation():
21 // Avoid synthesizing ~RefPtr in files including animation.h
22 Animation::~Animation()
25 void Animation::set_armature(const Armature &a)
30 unsigned Animation::get_slot_for_uniform(const string &n) const
32 for(unsigned i=0; i<uniforms.size(); ++i)
33 if(uniforms[i].name==n)
38 const string &Animation::get_uniform_name(unsigned i) const
40 if(i>=uniforms.size())
41 throw out_of_range("Animation::get_uniform_name");
42 return uniforms[i].name;
45 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
47 add_keyframe(t, kf, 1.0f, 1.0f);
50 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope)
52 add_keyframe(t, kf, slope, slope);
55 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es)
57 RefPtr<const KeyFrame> kfr(&kf);
59 add_keyframe(t, kfr, ss, es);
62 void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf, float ss, float es)
64 if(!keyframes.empty() && t<keyframes.back().time)
65 throw invalid_argument("Animation::add_keyframe");
67 bool realloc = (keyframes.size()>=keyframes.capacity());
69 keyframes.push_back(TimedKeyFrame());
70 TimedKeyFrame &tkf = keyframes.back();
78 for(unsigned i=1; i<keyframes.size(); ++i)
79 keyframes[i].prev = &keyframes[i-1];
81 else if(keyframes.size()>1)
84 prepare_keyframe(tkf);
87 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
89 const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
90 for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
93 for(unsigned j=0; (!found && j<uniforms.size()); ++j)
94 if(uniforms[j].name==i->first)
96 if(uniforms[j].size!=i->second.size)
97 throw invalid_operation("Animation::prepare_keyframe");
102 uniforms.push_back(UniformInfo(i->first, i->second.size));
108 void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v)
114 events.push_back(event);
117 const Time::TimeDelta &Animation::get_duration() const
119 if(keyframes.empty())
122 return keyframes.back().time;
125 void Animation::set_looping(bool l)
131 Animation::AxisInterpolation::AxisInterpolation():
136 Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
138 // Compute a normalized vector halfway between the two endpoints
142 for(unsigned i=0; i<3; ++i)
144 float half_i = (axis1[i]+axis2[i])/2;
145 cos_half += axis1[i]*half_i;
146 a1_len += axis1[i]*axis1[i];
147 h_len += half_i*half_i;
150 // Compute correction factors for smooth interpolation
151 cos_half = min(max(cos_half/sqrt(a1_len*h_len), -1.0f), 1.0f);
152 float angle = acos(cos_half);
153 slope = (angle ? angle/tan(angle) : 1);
158 Animation::MatrixInterpolation::MatrixInterpolation():
163 Animation::MatrixInterpolation::MatrixInterpolation(const Matrix &m1, const Matrix &m2):
167 const float *m1_data = matrix1->data();
168 const float *m2_data = matrix2->data();
169 for(unsigned i=0; i<3; ++i)
170 axes[i] = AxisInterpolation(m1_data+i*4, m2_data+i*4);
173 Matrix Animation::MatrixInterpolation::get(float t) const
175 float u = t*2.0f-1.0f;
178 for(unsigned i=0; i<4; ++i)
180 const float *m1_col = matrix1->data()+i*4;
181 const float *m2_col = matrix2->data()+i*4;
182 float *out_col = matrix+i*4;
186 /* Linear interpolation will produce vectors that fall on the line
187 between the two endpoints, and has a higher angular velocity near the
188 middle. We compensate for the velocity by interpolating the angle
189 around the halfway point and computing its tangent. This is
190 approximated by a third degree polynomial, scaled so that the result
191 will be in the range [-1, 1]. */
192 float w = (axes[i].slope+(1-axes[i].slope)*u*u)*u*0.5f+0.5f;
194 /* The interpolated vectors will also be shorter than unit length. At
195 the halfway point the length will be equal to the cosine of half the
196 angle, which was computed earlier. Use a second degree polynomial to
198 float n = (axes[i].scale+(1-axes[i].scale)*u*u);
200 for(unsigned j=0; j<3; ++j)
201 out_col[j] = ((1-w)*m1_col[j]+w*m2_col[j])/n;
205 for(unsigned j=0; j<3; ++j)
206 out_col[j] = (1-t)*m1_col[j]+t*m2_col[j];
219 Animation::TimedKeyFrame::TimedKeyFrame():
225 void Animation::TimedKeyFrame::prepare(const Animation &animation)
227 const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
228 for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
230 unsigned j = animation.get_slot_for_uniform(i->first);
231 uniforms.reserve(j+1);
232 for(unsigned k=uniforms.size(); k<=j; ++k)
233 uniforms.push_back(KeyFrame::AnimatedUniform(animation.uniforms[k].size, 0.0f));
235 uniforms[j] = i->second;
241 delta_t = time-prev->time;
242 matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix());
244 if(animation.armature)
246 unsigned max_index = animation.armature->get_max_link_index();
247 pose_matrices.resize(max_index+1);
248 const Pose *pose1 = prev->keyframe->get_pose();
249 const Pose *pose2 = keyframe->get_pose();
250 static Matrix identity;
251 for(unsigned i=0; i<=max_index; ++i)
253 const Matrix &matrix1 = (pose1 ? pose1->get_link_matrix(i) : identity);
254 const Matrix &matrix2 = (pose2 ? pose2->get_link_matrix(i) : identity);
255 pose_matrices[i] = MatrixInterpolation(matrix1, matrix2);
261 Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
267 Animation::Iterator::Iterator(const Animation &a):
269 iter(animation->keyframes.begin()),
270 event_iter(animation->events.begin()),
275 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
277 time_since_keyframe += t;
278 while(time_since_keyframe>iter->delta_t)
280 vector<TimedKeyFrame>::const_iterator next = iter;
282 if(next==animation->keyframes.end())
284 if(animation->looping)
285 next = animation->keyframes.begin();
289 time_since_keyframe = iter->delta_t;
294 time_since_keyframe -= iter->delta_t;
298 x = time_since_keyframe/iter->delta_t;
299 x += (iter->start_slope-1)*((x-2)*x+1)*x + (1-iter->end_slope)*(1-x)*x*x;
304 void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
306 vector<Event>::const_iterator events_end = animation->events.end();
309 for(; event_iter!=events_end; ++event_iter)
310 observer.animation_event(0, event_iter->name, event_iter->value);
312 else if(event_iter!=events_end)
314 Time::TimeDelta t = time_since_keyframe;
316 t += iter->prev->time;
317 for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter)
318 observer.animation_event(0, event_iter->name, event_iter->value);
322 Matrix Animation::Iterator::get_matrix() const
325 return iter->keyframe->get_matrix();
327 return iter->matrix.get(x);
330 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
334 if(iter->uniforms.size()>i)
335 return iter->uniforms[i];
337 return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
340 unsigned size = animation->uniforms[i].size;
341 KeyFrame::AnimatedUniform result(size, 0.0f);
342 for(unsigned j=0; j<size; ++j)
343 result.values[j] = iter->prev->uniforms[i].values[j]*(1-x)+iter->uniforms[i].values[j]*x;
347 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
349 if(!animation->armature)
350 throw invalid_operation("Animation::Iterator::get_pose_matrix");
351 if(link>animation->armature->get_max_link_index())
352 throw out_of_range("Animation::Iterator::get_pose_matrix");
356 if(const Pose *pose = iter->keyframe->get_pose())
357 return pose->get_link_matrix(link);
362 // We must redo the base point correction since interpolation throws it off
363 // XXX This should probably be done on local matrices
364 Matrix result = iter->pose_matrices[link].get(x);
365 const Vector3 &base = animation->armature->get_link(link).get_base();
366 Vector3 new_base = result*base;
367 result = Matrix::translation(base-new_base)*result;
372 Animation::Loader::Loader(Animation &a):
373 DataFile::CollectionObjectLoader<Animation>(a, 0)
378 Animation::Loader::Loader(Animation &a, Collection &c):
379 DataFile::CollectionObjectLoader<Animation>(a, &c)
384 void Animation::Loader::init()
388 add("armature", &Animation::armature);
389 add("event", &Loader::event);
390 add("event", &Loader::event1i);
391 add("event", &Loader::event1f);
392 add("event", &Loader::event2f);
393 add("event", &Loader::event3f);
394 add("event", &Loader::event4f);
395 add("interval", &Loader::interval);
396 add("keyframe", &Loader::keyframe);
397 add("keyframe", &Loader::keyframe_inline);
398 add("looping", &Animation::looping);
399 add("slopes", &Loader::slopes);
402 void Animation::Loader::event(const string &n)
404 obj.add_event(current_time, n);
407 void Animation::Loader::event1i(const string &n, int v)
409 obj.add_event(current_time, n, v);
412 void Animation::Loader::event1f(const string &n, float v)
414 obj.add_event(current_time, n, v);
417 void Animation::Loader::event2f(const string &n, float v0, float v1)
419 obj.add_event(current_time, n, LinAl::Vector<float, 2>(v0, v1));
422 void Animation::Loader::event3f(const string &n, float v0, float v1, float v2)
424 obj.add_event(current_time, n, Vector3(v0, v1, v2));
427 void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3)
429 obj.add_event(current_time, n, Vector4(v0, v1, v2, v3));
432 void Animation::Loader::interval(float t)
434 current_time += t*Time::sec;
437 void Animation::Loader::keyframe(const string &n)
439 obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
440 start_slope = end_slope;
444 void Animation::Loader::keyframe_inline()
446 RefPtr<KeyFrame> kf = new KeyFrame;
448 load_sub(*kf, get_collection());
452 obj.add_keyframe(current_time, kf, start_slope, end_slope);
453 start_slope = end_slope;
457 void Animation::Loader::slopes(float s, float e)