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)
82 keyframes[i].prev = &keyframes[i-1];
84 if(keyframes.size()>1 && t>(&tkf-1)->time)
87 prepare_keyframe(tkf);
90 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
92 const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
93 for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
96 for(unsigned j=0; (!found && j<uniforms.size()); ++j)
97 if(uniforms[j].name==i->first)
99 if(uniforms[j].size!=i->second.size)
100 throw invalid_operation("Animation::prepare_keyframe");
105 uniforms.push_back(UniformInfo(i->first, i->second.size));
111 void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v)
117 events.push_back(event);
120 const Time::TimeDelta &Animation::get_duration() const
122 if(keyframes.empty())
125 return keyframes.back().time;
128 void Animation::set_looping(bool l)
134 Animation::AxisInterpolation::AxisInterpolation():
139 Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
141 // Compute a normalized vector halfway between the two endpoints
145 for(unsigned i=0; i<3; ++i)
147 float half_i = (axis1[i]+axis2[i])/2;
148 cos_half += axis1[i]*half_i;
149 a1_len += axis1[i]*axis1[i];
150 h_len += half_i*half_i;
153 // Compute correction factors for smooth interpolation
154 cos_half = min(max(cos_half/sqrt(a1_len*h_len), -1.0f), 1.0f);
155 float angle = acos(cos_half);
156 slope = (angle ? angle/tan(angle) : 1);
161 Animation::MatrixInterpolation::MatrixInterpolation():
166 Animation::MatrixInterpolation::MatrixInterpolation(const Matrix &m1, const Matrix &m2):
170 const float *m1_data = matrix1->data();
171 const float *m2_data = matrix2->data();
172 for(unsigned i=0; i<3; ++i)
173 axes[i] = AxisInterpolation(m1_data+i*4, m2_data+i*4);
176 Matrix Animation::MatrixInterpolation::get(float t) const
178 float u = t*2.0f-1.0f;
181 for(unsigned i=0; i<4; ++i)
183 const float *m1_col = matrix1->data()+i*4;
184 const float *m2_col = matrix2->data()+i*4;
185 float *out_col = matrix+i*4;
189 /* Linear interpolation will produce vectors that fall on the line
190 between the two endpoints, and has a higher angular velocity near the
191 middle. We compensate for the velocity by interpolating the angle
192 around the halfway point and computing its tangent. This is
193 approximated by a third degree polynomial, scaled so that the result
194 will be in the range [-1, 1]. */
195 float w = (axes[i].slope+(1-axes[i].slope)*u*u)*u*0.5f+0.5f;
197 /* The interpolated vectors will also be shorter than unit length. At
198 the halfway point the length will be equal to the cosine of half the
199 angle, which was computed earlier. Use a second degree polynomial to
201 float n = (axes[i].scale+(1-axes[i].scale)*u*u);
203 for(unsigned j=0; j<3; ++j)
204 out_col[j] = ((1-w)*m1_col[j]+w*m2_col[j])/n;
208 for(unsigned j=0; j<3; ++j)
209 out_col[j] = (1-t)*m1_col[j]+t*m2_col[j];
222 Animation::TimedKeyFrame::TimedKeyFrame():
228 void Animation::TimedKeyFrame::prepare(const Animation &animation)
230 const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
231 for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
233 unsigned j = animation.get_slot_for_uniform(i->first);
234 uniforms.reserve(j+1);
235 for(unsigned k=uniforms.size(); k<=j; ++k)
236 uniforms.push_back(KeyFrame::AnimatedUniform(animation.uniforms[k].size, 0.0f));
238 uniforms[j] = i->second;
244 delta_t = time-prev->time;
245 matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix());
247 if(animation.armature)
249 unsigned max_index = animation.armature->get_max_link_index();
250 pose_matrices.resize(max_index+1);
251 const Pose *pose1 = prev->keyframe->get_pose();
252 const Pose *pose2 = keyframe->get_pose();
253 static Matrix identity;
254 for(unsigned i=0; i<=max_index; ++i)
256 const Matrix &matrix1 = (pose1 ? pose1->get_link_matrix(i) : identity);
257 const Matrix &matrix2 = (pose2 ? pose2->get_link_matrix(i) : identity);
258 pose_matrices[i] = MatrixInterpolation(matrix1, matrix2);
264 Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
270 Animation::Iterator::Iterator(const Animation &a):
272 iter(animation->keyframes.begin()),
273 event_iter(animation->events.begin()),
277 if(iter==animation->keyframes.end())
278 throw invalid_argument("Animation::Iterator::Iterator");
281 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
283 time_since_keyframe += t;
284 while(time_since_keyframe>iter->delta_t)
286 vector<TimedKeyFrame>::const_iterator next = iter;
288 if(next==animation->keyframes.end())
290 if(animation->looping)
291 next = animation->keyframes.begin();
295 time_since_keyframe = iter->delta_t;
300 time_since_keyframe -= iter->delta_t;
304 x = time_since_keyframe/iter->delta_t;
305 x += (iter->start_slope-1)*((x-2)*x+1)*x + (1-iter->end_slope)*(1-x)*x*x;
310 void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
312 vector<Event>::const_iterator events_end = animation->events.end();
315 for(; event_iter!=events_end; ++event_iter)
316 observer.animation_event(0, event_iter->name, event_iter->value);
318 else if(event_iter!=events_end)
320 Time::TimeDelta t = time_since_keyframe;
322 t += iter->prev->time;
323 for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter)
324 observer.animation_event(0, event_iter->name, event_iter->value);
328 Matrix Animation::Iterator::get_matrix() const
331 return iter->keyframe->get_matrix();
333 return iter->matrix.get(x);
336 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
340 if(iter->uniforms.size()>i)
341 return iter->uniforms[i];
343 return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
346 unsigned size = animation->uniforms[i].size;
347 KeyFrame::AnimatedUniform result(size, 0.0f);
348 for(unsigned j=0; j<size; ++j)
349 result.values[j] = iter->prev->uniforms[i].values[j]*(1-x)+iter->uniforms[i].values[j]*x;
353 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
355 if(!animation->armature)
356 throw invalid_operation("Animation::Iterator::get_pose_matrix");
357 if(link>animation->armature->get_max_link_index())
358 throw out_of_range("Animation::Iterator::get_pose_matrix");
362 if(const Pose *pose = iter->keyframe->get_pose())
363 return pose->get_link_matrix(link);
368 // We must redo the base point correction since interpolation throws it off
369 // XXX This should probably be done on local matrices
370 Matrix result = iter->pose_matrices[link].get(x);
371 const Vector3 &base = animation->armature->get_link(link).get_base();
372 Vector3 new_base = result*base;
373 result = Matrix::translation(base-new_base)*result;
378 Animation::Loader::Loader(Animation &a):
379 DataFile::CollectionObjectLoader<Animation>(a, 0)
384 Animation::Loader::Loader(Animation &a, Collection &c):
385 DataFile::CollectionObjectLoader<Animation>(a, &c)
390 void Animation::Loader::init()
394 add("armature", &Animation::armature);
395 add("event", &Loader::event);
396 add("event", &Loader::event1i);
397 add("event", &Loader::event1f);
398 add("event", &Loader::event2f);
399 add("event", &Loader::event3f);
400 add("event", &Loader::event4f);
401 add("interval", &Loader::interval);
402 add("keyframe", &Loader::keyframe);
403 add("keyframe", &Loader::keyframe_inline);
404 add("looping", &Animation::looping);
405 add("slopes", &Loader::slopes);
408 void Animation::Loader::event(const string &n)
410 obj.add_event(current_time, n);
413 void Animation::Loader::event1i(const string &n, int v)
415 obj.add_event(current_time, n, v);
418 void Animation::Loader::event1f(const string &n, float v)
420 obj.add_event(current_time, n, v);
423 void Animation::Loader::event2f(const string &n, float v0, float v1)
425 obj.add_event(current_time, n, LinAl::Vector<float, 2>(v0, v1));
428 void Animation::Loader::event3f(const string &n, float v0, float v1, float v2)
430 obj.add_event(current_time, n, Vector3(v0, v1, v2));
433 void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3)
435 obj.add_event(current_time, n, Vector4(v0, v1, v2, v3));
438 void Animation::Loader::interval(float t)
440 current_time += t*Time::sec;
443 void Animation::Loader::keyframe(const string &n)
445 obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
446 start_slope = end_slope;
450 void Animation::Loader::keyframe_inline()
452 RefPtr<KeyFrame> kf = new KeyFrame;
454 load_sub(*kf, get_collection());
458 obj.add_keyframe(current_time, kf, start_slope, end_slope);
459 start_slope = end_slope;
463 void Animation::Loader::slopes(float s, float e)