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!=Time::zero)
65 throw invalid_argument("Animation::add_keyframe");
66 if(!keyframes.empty() && t<keyframes.back().time)
67 throw invalid_argument("Animation::add_keyframe");
69 bool realloc = (keyframes.size()>=keyframes.capacity());
71 keyframes.push_back(TimedKeyFrame());
72 TimedKeyFrame &tkf = keyframes.back();
80 for(unsigned i=1; i<keyframes.size(); ++i)
81 keyframes[i].prev = &keyframes[i-1];
83 else if(keyframes.size()>1)
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()),
277 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
279 time_since_keyframe += t;
280 while(time_since_keyframe>iter->delta_t)
282 vector<TimedKeyFrame>::const_iterator next = iter;
284 if(next==animation->keyframes.end())
286 if(animation->looping)
287 next = animation->keyframes.begin();
291 time_since_keyframe = iter->delta_t;
296 time_since_keyframe -= iter->delta_t;
300 x = time_since_keyframe/iter->delta_t;
301 x += (iter->start_slope-1)*((x-2)*x+1)*x + (1-iter->end_slope)*(1-x)*x*x;
306 void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
308 vector<Event>::const_iterator events_end = animation->events.end();
311 for(; event_iter!=events_end; ++event_iter)
312 observer.animation_event(0, event_iter->name, event_iter->value);
314 else if(event_iter!=events_end)
316 Time::TimeDelta t = time_since_keyframe;
318 t += iter->prev->time;
319 for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter)
320 observer.animation_event(0, event_iter->name, event_iter->value);
324 Matrix Animation::Iterator::get_matrix() const
327 return iter->keyframe->get_matrix();
329 return iter->matrix.get(x);
332 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
336 if(iter->uniforms.size()>i)
337 return iter->uniforms[i];
339 return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
342 unsigned size = animation->uniforms[i].size;
343 KeyFrame::AnimatedUniform result(size, 0.0f);
344 for(unsigned j=0; j<size; ++j)
345 result.values[j] = iter->prev->uniforms[i].values[j]*(1-x)+iter->uniforms[i].values[j]*x;
349 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
351 if(!animation->armature)
352 throw invalid_operation("Animation::Iterator::get_pose_matrix");
353 if(link>animation->armature->get_max_link_index())
354 throw out_of_range("Animation::Iterator::get_pose_matrix");
358 if(const Pose *pose = iter->keyframe->get_pose())
359 return pose->get_link_matrix(link);
364 // We must redo the base point correction since interpolation throws it off
365 // XXX This should probably be done on local matrices
366 Matrix result = iter->pose_matrices[link].get(x);
367 const Vector3 &base = animation->armature->get_link(link).get_base();
368 Vector3 new_base = result*base;
369 result = Matrix::translation(base-new_base)*result;
374 Animation::Loader::Loader(Animation &a):
375 DataFile::CollectionObjectLoader<Animation>(a, 0)
380 Animation::Loader::Loader(Animation &a, Collection &c):
381 DataFile::CollectionObjectLoader<Animation>(a, &c)
386 void Animation::Loader::init()
390 add("armature", &Animation::armature);
391 add("event", &Loader::event);
392 add("event", &Loader::event1i);
393 add("event", &Loader::event1f);
394 add("event", &Loader::event2f);
395 add("event", &Loader::event3f);
396 add("event", &Loader::event4f);
397 add("interval", &Loader::interval);
398 add("keyframe", &Loader::keyframe);
399 add("keyframe", &Loader::keyframe_inline);
400 add("looping", &Animation::looping);
401 add("slopes", &Loader::slopes);
404 void Animation::Loader::event(const string &n)
406 obj.add_event(current_time, n);
409 void Animation::Loader::event1i(const string &n, int v)
411 obj.add_event(current_time, n, v);
414 void Animation::Loader::event1f(const string &n, float v)
416 obj.add_event(current_time, n, v);
419 void Animation::Loader::event2f(const string &n, float v0, float v1)
421 obj.add_event(current_time, n, LinAl::Vector<float, 2>(v0, v1));
424 void Animation::Loader::event3f(const string &n, float v0, float v1, float v2)
426 obj.add_event(current_time, n, Vector3(v0, v1, v2));
429 void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3)
431 obj.add_event(current_time, n, Vector4(v0, v1, v2, v3));
434 void Animation::Loader::interval(float t)
436 current_time += t*Time::sec;
439 void Animation::Loader::keyframe(const string &n)
441 obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
442 start_slope = end_slope;
446 void Animation::Loader::keyframe_inline()
448 RefPtr<KeyFrame> kf = new KeyFrame;
450 load_sub(*kf, get_collection());
454 obj.add_keyframe(current_time, kf, start_slope, end_slope);
455 start_slope = end_slope;
459 void Animation::Loader::slopes(float s, float e)