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