]> git.tdb.fi Git - libs/gl.git/blob - source/animation.cpp
Add a class to unify loading coordinate transforms
[libs/gl.git] / source / animation.cpp
1 #include <cmath>
2 #include <msp/core/maputils.h>
3 #include <msp/datafile/collection.h>
4 #include "animation.h"
5 #include "animationeventobserver.h"
6 #include "armature.h"
7 #include "error.h"
8 #include "pose.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 Animation::Animation():
16         armature(0),
17         looping(false)
18 { }
19
20 // Avoid synthesizing ~RefPtr in files including animation.h
21 Animation::~Animation()
22 { }
23
24 void Animation::set_armature(const Armature &a)
25 {
26         armature = &a;
27 }
28
29 unsigned Animation::get_slot_for_uniform(const string &n) const
30 {
31         for(unsigned i=0; i<uniforms.size(); ++i)
32                 if(uniforms[i].name==n)
33                         return i;
34         throw key_error(n);
35 }
36
37 const string &Animation::get_uniform_name(unsigned i) const
38 {
39         if(i>=uniforms.size())
40                 throw out_of_range("Animation::get_uniform_name");
41         return uniforms[i].name;
42 }
43
44 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
45 {
46         add_keyframe(t, kf, 1.0f, 1.0f);
47 }
48
49 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope)
50 {
51         add_keyframe(t, kf, slope, slope);
52 }
53
54 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es)
55 {
56         RefPtr<const KeyFrame> kfr(&kf);
57         kfr.keep();
58         add_keyframe(t, kfr, ss, es);
59 }
60
61 void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf, float ss, float es)
62 {
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");
67
68         bool realloc = (keyframes.size()>=keyframes.capacity());
69
70         keyframes.push_back(TimedKeyFrame());
71         TimedKeyFrame &tkf = keyframes.back();
72         tkf.time = t;
73         tkf.start_slope = ss;
74         tkf.end_slope = es;
75         tkf.keyframe = kf;
76
77         if(realloc)
78         {
79                 for(unsigned i=1; i<keyframes.size(); ++i)
80                         if(keyframes[i].prev)
81                                 keyframes[i].prev = &keyframes[i-1];
82         }
83         if(keyframes.size()>1 && t>(&tkf-1)->time)
84                 tkf.prev = &tkf-1;
85
86         prepare_keyframe(tkf);
87 }
88
89 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
90 {
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)
93         {
94                 bool found = false;
95                 for(unsigned j=0; (!found && j<uniforms.size()); ++j)
96                         if(uniforms[j].name==i->first)
97                         {
98                                 if(uniforms[j].size!=i->second.size)
99                                         throw invalid_operation("Animation::prepare_keyframe");
100                                 found = true;
101                         }
102
103                 if(!found)
104                         uniforms.push_back(UniformInfo(i->first, i->second.size));
105         }
106
107         tkf.prepare(*this);
108 }
109
110 void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v)
111 {
112         Event event;
113         event.time = t;
114         event.name = n;
115         event.value = v;
116         events.push_back(event);
117 }
118
119 const Time::TimeDelta &Animation::get_duration() const
120 {
121         if(keyframes.empty())
122                 return Time::zero;
123
124         return keyframes.back().time;
125 }
126
127 void Animation::set_looping(bool l)
128 {
129         looping = l;
130 }
131
132
133 Animation::AxisInterpolation::AxisInterpolation():
134         slope(0),
135         scale(0)
136 { }
137
138 Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
139 {
140         // Compute a normalized vector halfway between the two endpoints
141         float a1_len = 0;
142         float h_len = 0;
143         float cos_half = 0;
144         for(unsigned i=0; i<3; ++i)
145         {
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;
150         }
151
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);
156         scale = cos_half;
157 }
158
159
160 Animation::MatrixInterpolation::MatrixInterpolation():
161         matrix1(0),
162         matrix2(0)
163 { }
164
165 Animation::MatrixInterpolation::MatrixInterpolation(const Matrix &m1, const Matrix &m2):
166         matrix1(&m1),
167         matrix2(&m2)
168 {
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);
173 }
174
175 Matrix Animation::MatrixInterpolation::get(float t) const
176 {
177         float u = t*2.0f-1.0f;
178
179         float matrix[16];
180         for(unsigned i=0; i<4; ++i)
181         {
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;
185
186                 if(i<3)
187                 {
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;
195
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
199                         approximate. */
200                         float n = (axes[i].scale+(1-axes[i].scale)*u*u);
201
202                         for(unsigned j=0; j<3; ++j)
203                                 out_col[j] = ((1-w)*m1_col[j]+w*m2_col[j])/n;
204                 }
205                 else
206                 {
207                         for(unsigned j=0; j<3; ++j)
208                                 out_col[j] = (1-t)*m1_col[j]+t*m2_col[j];
209                 }
210         }
211
212         matrix[3] = 0;
213         matrix[7] = 0;
214         matrix[11] = 0;
215         matrix[15] = 1;
216
217         return matrix;
218 }
219
220
221 Animation::TimedKeyFrame::TimedKeyFrame():
222         prev(0),
223         start_slope(1),
224         end_slope(1)
225 { }
226
227 void Animation::TimedKeyFrame::prepare(const Animation &animation)
228 {
229         const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
230         for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
231         {
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));
236
237                 uniforms[j] = i->second;
238         }
239
240         if(!prev)
241                 return;
242
243         delta_t = time-prev->time;
244         matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix());
245
246         if(animation.armature)
247         {
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)
254                 {
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);
258                 }
259         }
260 }
261
262
263 Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
264         name(n),
265         size(s)
266 { }
267
268
269 Animation::Iterator::Iterator(const Animation &a):
270         animation(&a),
271         iter(animation->keyframes.begin()),
272         event_iter(animation->events.begin()),
273         x(0),
274         end(false)
275 {
276         if(iter==animation->keyframes.end())
277                 throw invalid_argument("Animation::Iterator::Iterator");
278 }
279
280 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
281 {
282         time_since_keyframe += t;
283         while(time_since_keyframe>iter->delta_t)
284         {
285                 vector<TimedKeyFrame>::const_iterator next = iter;
286                 ++next;
287                 if(next==animation->keyframes.end())
288                 {
289                         if(animation->looping)
290                                 next = animation->keyframes.begin();
291                         else
292                         {
293                                 end = true;
294                                 time_since_keyframe = iter->delta_t;
295                                 break;
296                         }
297                 }
298
299                 time_since_keyframe -= iter->delta_t;
300                 iter = next;
301         }
302
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;
305
306         return *this;
307 }
308
309 void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
310 {
311         vector<Event>::const_iterator events_end = animation->events.end();
312         if(end)
313         {
314                 for(; event_iter!=events_end; ++event_iter)
315                         observer.animation_event(0, event_iter->name, event_iter->value);
316         }
317         else if(event_iter!=events_end)
318         {
319                 Time::TimeDelta t = time_since_keyframe;
320                 if(iter->prev)
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);
324         }
325 }
326
327 Matrix Animation::Iterator::get_matrix() const
328 {
329         if(!iter->prev)
330                 return iter->keyframe->get_matrix();
331
332         return iter->matrix.get(x);
333 }
334
335 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
336 {
337         if(!iter->prev)
338         {
339                 if(iter->uniforms.size()>i)
340                         return iter->uniforms[i];
341                 else
342                         return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
343         }
344
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;
349         return result;
350 }
351
352 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
353 {
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");
358
359         if(!iter->prev)
360         {
361                 if(const Pose *pose = iter->keyframe->get_pose())
362                         return pose->get_link_matrix(link);
363                 else
364                         return Matrix();
365         }
366
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;
373         return result;
374 }
375
376
377 Animation::Loader::Loader(Animation &a):
378         DataFile::CollectionObjectLoader<Animation>(a, 0)
379 {
380         init();
381 }
382
383 Animation::Loader::Loader(Animation &a, Collection &c):
384         DataFile::CollectionObjectLoader<Animation>(a, &c)
385 {
386         init();
387 }
388
389 void Animation::Loader::init()
390 {
391         start_slope = 1;
392         end_slope = 1;
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);
405 }
406
407 void Animation::Loader::event(const string &n)
408 {
409         obj.add_event(current_time, n);
410 }
411
412 void Animation::Loader::event1i(const string &n, int v)
413 {
414         obj.add_event(current_time, n, v);
415 }
416
417 void Animation::Loader::event1f(const string &n, float v)
418 {
419         obj.add_event(current_time, n, v);
420 }
421
422 void Animation::Loader::event2f(const string &n, float v0, float v1)
423 {
424         obj.add_event(current_time, n, LinAl::Vector<float, 2>(v0, v1));
425 }
426
427 void Animation::Loader::event3f(const string &n, float v0, float v1, float v2)
428 {
429         obj.add_event(current_time, n, Vector3(v0, v1, v2));
430 }
431
432 void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3)
433 {
434         obj.add_event(current_time, n, Vector4(v0, v1, v2, v3));
435 }
436
437 void Animation::Loader::interval(float t)
438 {
439         current_time += t*Time::sec;
440 }
441
442 void Animation::Loader::keyframe(const string &n)
443 {
444         obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
445         start_slope = end_slope;
446         end_slope = 1;
447 }
448
449 void Animation::Loader::keyframe_inline()
450 {
451         RefPtr<KeyFrame> kf = new KeyFrame;
452         if(coll)
453                 load_sub(*kf, get_collection());
454         else
455                 load_sub(*kf);
456
457         obj.add_keyframe(current_time, kf, start_slope, end_slope);
458         start_slope = end_slope;
459         end_slope = 1;
460 }
461
462 void Animation::Loader::slopes(float s, float e)
463 {
464         start_slope = s;
465         end_slope = e;
466 }
467
468 } // namespace GL
469 } // namespace Msp