2 #include <msp/core/maputils.h>
3 #include <msp/datafile/collection.h>
4 #include <msp/time/units.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 RefPtr<const KeyFrame> kfr(&kf);
51 void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf)
53 if(!keyframes.empty() && t<keyframes.back().time)
54 throw invalid_argument("Animation::add_keyframe");
56 bool realloc = (keyframes.size()>=keyframes.capacity());
58 keyframes.push_back(TimedKeyFrame(*this));
59 TimedKeyFrame &tkf = keyframes.back();
65 for(unsigned i=1; i<keyframes.size(); ++i)
66 keyframes[i].prev = &keyframes[i-1];
68 else if(keyframes.size()>1)
71 prepare_keyframe(tkf);
74 void Animation::set_looping(bool l)
79 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
81 const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
82 for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
85 for(unsigned j=0; (!found && j<uniforms.size()); ++j)
86 if(uniforms[j].name==i->first)
88 if(uniforms[j].size!=i->second.size)
89 throw invalid_operation("Animation::prepare_keyframe");
94 uniforms.push_back(UniformInfo(i->first, i->second.size));
101 Animation::AxisInterpolation::AxisInterpolation():
106 Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
108 // Compute a normalized vector halfway between the two endpoints
112 for(unsigned i=0; i<3; ++i)
114 half[i] = (axis1[i]+axis2[i])/2;
115 a1_len += axis1[i]*axis1[i];
116 h_len += half[i]*half[i];
119 // Compute correction factors for smooth interpolation
120 float cos_half = (axis1[0]*half[0]+axis1[1]*half[1]+axis1[2]*half[2])/sqrt(a1_len*h_len);
121 float angle = acos(cos_half);
122 slope = (angle ? angle/tan(angle) : 1);
127 Animation::MatrixInterpolation::MatrixInterpolation():
132 Animation::MatrixInterpolation::MatrixInterpolation(const Matrix &m1, const Matrix &m2):
136 const float *m1_data = matrix1->data();
137 const float *m2_data = matrix2->data();
138 for(unsigned i=0; i<3; ++i)
139 axes[i] = AxisInterpolation(m1_data+i*4, m2_data+i*4);
142 Matrix Animation::MatrixInterpolation::get(float t) const
144 float u = t*2.0f-1.0f;
147 for(unsigned i=0; i<4; ++i)
149 const float *m1_col = matrix1->data()+i*4;
150 const float *m2_col = matrix2->data()+i*4;
151 float *out_col = matrix+i*4;
155 /* Linear interpolation will produce vectors that fall on the line
156 between the two endpoints, and has a higher angular velocity near the
157 middle. We compensate for the velocity by interpolating the angle
158 around the halfway point and computing its tangent. This is
159 approximated by a third degree polynomial, scaled so that the result
160 will be in the range [-1, 1]. */
161 float w = (axes[i].slope+(1-axes[i].slope)*u*u)*u*0.5f+0.5f;
163 /* The interpolated vectors will also be shorter than unit length. At
164 the halfway point the length will be equal to the cosine of half the
165 angle, which was computed earlier. Use a second degree polynomial to
167 float n = (axes[i].scale+(1-axes[i].scale)*u*u);
169 for(unsigned j=0; j<3; ++j)
170 out_col[j] = ((1-w)*m1_col[j]+w*m2_col[j])/n;
174 for(unsigned j=0; j<3; ++j)
175 out_col[j] = (1-t)*m1_col[j]+t*m2_col[j];
188 Animation::TimedKeyFrame::TimedKeyFrame(const Animation &a):
193 void Animation::TimedKeyFrame::prepare()
195 const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
196 for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
198 unsigned j = animation.get_slot_for_uniform(i->first);
199 uniforms.reserve(j+1);
200 for(unsigned k=uniforms.size(); k<=j; ++k)
201 uniforms.push_back(KeyFrame::AnimatedUniform(animation.uniforms[k].size, 0.0f));
203 uniforms[j] = i->second;
209 delta_t = time-prev->time;
210 matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix());
212 if(animation.armature)
214 unsigned max_index = animation.armature->get_max_link_index();
215 pose_matrices.resize(max_index+1);
216 const Pose *pose1 = prev->keyframe->get_pose();
217 const Pose *pose2 = keyframe->get_pose();
218 static Matrix identity;
219 for(unsigned i=0; i<=max_index; ++i)
221 const Matrix &matrix1 = (pose1 ? pose1->get_link_matrix(i) : identity);
222 const Matrix &matrix2 = (pose2 ? pose2->get_link_matrix(i) : identity);
223 pose_matrices[i] = MatrixInterpolation(matrix1, matrix2);
229 Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
235 Animation::Iterator::Iterator(const Animation &a):
237 iter(animation->keyframes.begin()),
241 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
243 time_since_keyframe += t;
244 while(time_since_keyframe>iter->delta_t)
246 vector<TimedKeyFrame>::const_iterator next = iter;
248 if(next==animation->keyframes.end())
250 if(animation->looping)
251 next = animation->keyframes.begin();
255 time_since_keyframe = iter->delta_t;
260 time_since_keyframe -= iter->delta_t;
267 Matrix Animation::Iterator::get_matrix() const
270 return iter->keyframe->get_matrix();
272 return iter->matrix.get(time_since_keyframe/iter->delta_t);
275 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
279 if(iter->uniforms.size()>i)
280 return iter->uniforms[i];
282 return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
285 unsigned size = animation->uniforms[i].size;
286 float t = time_since_keyframe/iter->delta_t;
287 KeyFrame::AnimatedUniform result(size, 0.0f);
288 for(unsigned j=0; j<size; ++j)
289 result.values[j] = iter->prev->uniforms[i].values[j]*(1-t)+iter->uniforms[i].values[j]*t;
293 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
295 if(!animation->armature)
296 throw invalid_operation("Animation::Iterator::get_pose_matrix");
297 if(link>animation->armature->get_max_link_index())
298 throw out_of_range("Animation::Iterator::get_pose_matrix");
302 if(const Pose *pose = iter->keyframe->get_pose())
303 return pose->get_link_matrix(link);
308 // We must redo the base point correction since interpolation throws if off
309 // XXX This should probably be done on local matrices
310 Matrix result = iter->pose_matrices[link].get(time_since_keyframe/iter->delta_t);
311 const Vector3 &base = animation->armature->get_link(link).get_base();
312 Vector3 new_base = result*base;
313 result = Matrix::translation(base-new_base)*result;
318 Animation::Loader::Loader(Animation &a):
319 DataFile::CollectionObjectLoader<Animation>(a, 0)
324 Animation::Loader::Loader(Animation &a, Collection &c):
325 DataFile::CollectionObjectLoader<Animation>(a, &c)
330 void Animation::Loader::init()
332 add("armature", &Animation::armature);
333 add("interval", &Loader::interval);
334 add("keyframe", &Loader::keyframe);
335 add("keyframe", &Loader::keyframe_inline);
336 add("looping", &Animation::looping);
339 void Animation::Loader::keyframe(const string &n)
341 obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n));
344 void Animation::Loader::keyframe_inline()
346 RefPtr<KeyFrame> kf = new KeyFrame;
348 load_sub(*kf, get_collection());
352 obj.add_keyframe(current_time, kf);
355 void Animation::Loader::interval(float t)
357 current_time += t*Time::sec;