]> git.tdb.fi Git - libs/gl.git/blob - source/animation.cpp
6c9e179dc749dc16642b5b755f6afd7e36fecf2b
[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         if(!keyframes.empty() && &a!=armature)
27                 throw invalid_operation("Animation::set_armature");
28         armature = &a;
29 }
30
31 unsigned Animation::get_slot_for_uniform(const string &n) const
32 {
33         for(unsigned i=0; i<uniforms.size(); ++i)
34                 if(uniforms[i].name==n)
35                         return i;
36         throw key_error(n);
37 }
38
39 const string &Animation::get_uniform_name(unsigned i) const
40 {
41         if(i>=uniforms.size())
42                 throw out_of_range("Animation::get_uniform_name");
43         return uniforms[i].name;
44 }
45
46 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
47 {
48         add_keyframe(t, kf, 1.0f, 1.0f);
49 }
50
51 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope)
52 {
53         add_keyframe(t, kf, slope, slope);
54 }
55
56 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es)
57 {
58         RefPtr<const KeyFrame> kfr(&kf);
59         kfr.keep();
60         add_keyframe(t, kfr, ss, es);
61 }
62
63 void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf, float ss, float es)
64 {
65         if(keyframes.empty() && t!=Time::zero)
66                 throw invalid_argument("Animation::add_keyframe");
67         if(!keyframes.empty() && t<keyframes.back().time)
68                 throw invalid_argument("Animation::add_keyframe");
69         if(kf->get_pose() && armature && kf->get_pose()->get_armature()!=armature)
70                 throw invalid_argument("Animation::add_keyframe");
71
72         bool realloc = (keyframes.size()>=keyframes.capacity());
73
74         if(kf->get_pose() && !armature)
75                 armature = kf->get_pose()->get_armature();
76
77         keyframes.push_back(TimedKeyFrame());
78         TimedKeyFrame &tkf = keyframes.back();
79         tkf.time = t;
80         tkf.start_slope = ss;
81         tkf.end_slope = es;
82         tkf.keyframe = kf;
83
84         if(realloc)
85         {
86                 for(unsigned i=1; i<keyframes.size(); ++i)
87                         if(keyframes[i].prev)
88                                 keyframes[i].prev = &keyframes[i-1];
89         }
90         if(keyframes.size()>1 && t>(&tkf-1)->time)
91                 tkf.prev = &tkf-1;
92
93         prepare_keyframe(tkf);
94 }
95
96 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
97 {
98         const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
99         for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
100         {
101                 bool found = false;
102                 for(unsigned j=0; (!found && j<uniforms.size()); ++j)
103                         if(uniforms[j].name==i->first)
104                         {
105                                 if(uniforms[j].size!=i->second.size)
106                                         throw invalid_operation("Animation::prepare_keyframe");
107                                 found = true;
108                         }
109
110                 if(!found)
111                         uniforms.push_back(UniformInfo(i->first, i->second.size));
112         }
113
114         tkf.prepare(*this);
115 }
116
117 void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v)
118 {
119         Event event;
120         event.time = t;
121         event.name = n;
122         event.value = v;
123         events.push_back(event);
124 }
125
126 const Time::TimeDelta &Animation::get_duration() const
127 {
128         if(keyframes.empty())
129                 return Time::zero;
130
131         return keyframes.back().time;
132 }
133
134 void Animation::set_looping(bool l)
135 {
136         looping = l;
137 }
138
139
140 Animation::AxisInterpolation::AxisInterpolation():
141         slope(0),
142         scale(0)
143 { }
144
145 Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
146 {
147         // Compute a normalized vector halfway between the two endpoints
148         float a1_len = 0;
149         float h_len = 0;
150         float cos_half = 0;
151         for(unsigned i=0; i<3; ++i)
152         {
153                 float half_i = (axis1[i]+axis2[i])/2;
154                 cos_half += axis1[i]*half_i;
155                 a1_len += axis1[i]*axis1[i];
156                 h_len += half_i*half_i;
157         }
158
159         // Compute correction factors for smooth interpolation
160         cos_half = min(max(cos_half/sqrt(a1_len*h_len), -1.0f), 1.0f);
161         float angle = acos(cos_half);
162         slope = (angle ? angle/tan(angle) : 1);
163         scale = cos_half;
164 }
165
166
167 Animation::MatrixInterpolation::MatrixInterpolation():
168         matrix1(0),
169         matrix2(0)
170 { }
171
172 Animation::MatrixInterpolation::MatrixInterpolation(const Matrix &m1, const Matrix &m2):
173         matrix1(&m1),
174         matrix2(&m2)
175 {
176         const float *m1_data = matrix1->data();
177         const float *m2_data = matrix2->data();
178         for(unsigned i=0; i<3; ++i)
179                 axes[i] = AxisInterpolation(m1_data+i*4, m2_data+i*4);
180 }
181
182 Matrix Animation::MatrixInterpolation::get(float t) const
183 {
184         float u = t*2.0f-1.0f;
185
186         float matrix[16];
187         for(unsigned i=0; i<4; ++i)
188         {
189                 const float *m1_col = matrix1->data()+i*4;
190                 const float *m2_col = matrix2->data()+i*4;
191                 float *out_col = matrix+i*4;
192
193                 if(i<3)
194                 {
195                         /* Linear interpolation will produce vectors that fall on the line
196                         between the two endpoints, and has a higher angular velocity near the
197                         middle.  We compensate for the velocity by interpolating the angle
198                         around the halfway point and computing its tangent.  This is
199                         approximated by a third degree polynomial, scaled so that the result
200                         will be in the range [-1, 1]. */
201                         float w = (axes[i].slope+(1-axes[i].slope)*u*u)*u*0.5f+0.5f;
202
203                         /* The interpolated vectors will also be shorter than unit length.  At
204                         the halfway point the length will be equal to the cosine of half the
205                         angle, which was computed earlier.  Use a second degree polynomial to
206                         approximate. */
207                         float n = (axes[i].scale+(1-axes[i].scale)*u*u);
208
209                         for(unsigned j=0; j<3; ++j)
210                                 out_col[j] = ((1-w)*m1_col[j]+w*m2_col[j])/n;
211                 }
212                 else
213                 {
214                         for(unsigned j=0; j<3; ++j)
215                                 out_col[j] = (1-t)*m1_col[j]+t*m2_col[j];
216                 }
217         }
218
219         matrix[3] = 0;
220         matrix[7] = 0;
221         matrix[11] = 0;
222         matrix[15] = 1;
223
224         return matrix;
225 }
226
227
228 Animation::TimedKeyFrame::TimedKeyFrame():
229         prev(0),
230         start_slope(1),
231         end_slope(1)
232 { }
233
234 void Animation::TimedKeyFrame::prepare(const Animation &animation)
235 {
236         const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
237         for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
238         {
239                 unsigned j = animation.get_slot_for_uniform(i->first);
240                 uniforms.reserve(j+1);
241                 for(unsigned k=uniforms.size(); k<=j; ++k)
242                         uniforms.push_back(KeyFrame::AnimatedUniform(animation.uniforms[k].size, 0.0f));
243
244                 uniforms[j] = i->second;
245         }
246
247         if(!prev)
248                 return;
249
250         delta_t = time-prev->time;
251         matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix());
252
253         if(animation.armature)
254         {
255                 unsigned max_index = animation.armature->get_max_link_index();
256                 pose_matrices.resize(max_index+1);
257                 const Pose *pose1 = prev->keyframe->get_pose();
258                 const Pose *pose2 = keyframe->get_pose();
259                 static Matrix identity;
260                 for(unsigned i=0; i<=max_index; ++i)
261                 {
262                         const Matrix &matrix1 = (pose1 ? pose1->get_link_matrix(i) : identity);
263                         const Matrix &matrix2 = (pose2 ? pose2->get_link_matrix(i) : identity);
264                         pose_matrices[i] = MatrixInterpolation(matrix1, matrix2);
265                 }
266         }
267 }
268
269
270 Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
271         name(n),
272         size(s)
273 { }
274
275
276 Animation::Iterator::Iterator(const Animation &a):
277         animation(&a),
278         iter(animation->keyframes.begin()),
279         event_iter(animation->events.begin()),
280         x(0),
281         end(false)
282 {
283         if(iter==animation->keyframes.end())
284                 throw invalid_argument("Animation::Iterator::Iterator");
285 }
286
287 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
288 {
289         time_since_keyframe += t;
290         while(time_since_keyframe>iter->delta_t)
291         {
292                 vector<TimedKeyFrame>::const_iterator next = iter;
293                 ++next;
294                 if(next==animation->keyframes.end())
295                 {
296                         if(animation->looping)
297                                 next = animation->keyframes.begin();
298                         else
299                         {
300                                 end = true;
301                                 time_since_keyframe = iter->delta_t;
302                                 break;
303                         }
304                 }
305
306                 time_since_keyframe -= iter->delta_t;
307                 iter = next;
308         }
309
310         x = time_since_keyframe/iter->delta_t;
311         x += (iter->start_slope-1)*((x-2)*x+1)*x + (1-iter->end_slope)*(1-x)*x*x;
312
313         return *this;
314 }
315
316 void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
317 {
318         vector<Event>::const_iterator events_end = animation->events.end();
319         if(end)
320         {
321                 for(; event_iter!=events_end; ++event_iter)
322                         observer.animation_event(0, event_iter->name, event_iter->value);
323         }
324         else if(event_iter!=events_end)
325         {
326                 Time::TimeDelta t = time_since_keyframe;
327                 if(iter->prev)
328                         t += iter->prev->time;
329                 for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter)
330                         observer.animation_event(0, event_iter->name, event_iter->value);
331         }
332 }
333
334 Matrix Animation::Iterator::get_matrix() const
335 {
336         if(!iter->prev)
337                 return iter->keyframe->get_matrix();
338
339         return iter->matrix.get(x);
340 }
341
342 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
343 {
344         if(!iter->prev)
345         {
346                 if(iter->uniforms.size()>i)
347                         return iter->uniforms[i];
348                 else
349                         return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
350         }
351
352         unsigned size = animation->uniforms[i].size;
353         KeyFrame::AnimatedUniform result(size, 0.0f);
354         for(unsigned j=0; j<size; ++j)
355                 result.values[j] = iter->prev->uniforms[i].values[j]*(1-x)+iter->uniforms[i].values[j]*x;
356         return result;
357 }
358
359 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
360 {
361         if(!animation->armature)
362                 throw invalid_operation("Animation::Iterator::get_pose_matrix");
363         if(link>animation->armature->get_max_link_index())
364                 throw out_of_range("Animation::Iterator::get_pose_matrix");
365
366         if(!iter->prev)
367         {
368                 if(const Pose *pose = iter->keyframe->get_pose())
369                         return pose->get_link_matrix(link);
370                 else
371                         return Matrix();
372         }
373
374         // We must redo the base point correction since interpolation throws it off
375         // XXX This should probably be done on local matrices
376         Matrix result = iter->pose_matrices[link].get(x);
377         const Vector3 &base = animation->armature->get_link(link).get_base();
378         Vector3 new_base = result*base;
379         result = Matrix::translation(base-new_base)*result;
380         return result;
381 }
382
383
384 Animation::Loader::Loader(Animation &a):
385         DataFile::CollectionObjectLoader<Animation>(a, 0)
386 {
387         init();
388 }
389
390 Animation::Loader::Loader(Animation &a, Collection &c):
391         DataFile::CollectionObjectLoader<Animation>(a, &c)
392 {
393         init();
394 }
395
396 void Animation::Loader::init()
397 {
398         start_slope = 1;
399         end_slope = 1;
400         add("armature", &Animation::armature);
401         add("event", &Loader::event);
402         add("event", &Loader::event1i);
403         add("event", &Loader::event1f);
404         add("event", &Loader::event2f);
405         add("event", &Loader::event3f);
406         add("event", &Loader::event4f);
407         add("interval", &Loader::interval);
408         add("keyframe", &Loader::keyframe);
409         add("keyframe", &Loader::keyframe_inline);
410         add("looping", &Animation::looping);
411         add("slopes", &Loader::slopes);
412 }
413
414 void Animation::Loader::event(const string &n)
415 {
416         obj.add_event(current_time, n);
417 }
418
419 void Animation::Loader::event1i(const string &n, int v)
420 {
421         obj.add_event(current_time, n, v);
422 }
423
424 void Animation::Loader::event1f(const string &n, float v)
425 {
426         obj.add_event(current_time, n, v);
427 }
428
429 void Animation::Loader::event2f(const string &n, float v0, float v1)
430 {
431         obj.add_event(current_time, n, LinAl::Vector<float, 2>(v0, v1));
432 }
433
434 void Animation::Loader::event3f(const string &n, float v0, float v1, float v2)
435 {
436         obj.add_event(current_time, n, Vector3(v0, v1, v2));
437 }
438
439 void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3)
440 {
441         obj.add_event(current_time, n, Vector4(v0, v1, v2, v3));
442 }
443
444 void Animation::Loader::interval(float t)
445 {
446         current_time += t*Time::sec;
447 }
448
449 void Animation::Loader::keyframe(const string &n)
450 {
451         obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
452         start_slope = end_slope;
453         end_slope = 1;
454 }
455
456 void Animation::Loader::keyframe_inline()
457 {
458         RefPtr<KeyFrame> kf = new KeyFrame;
459         if(coll)
460                 load_sub(*kf, get_collection());
461         else
462                 load_sub(*kf);
463
464         obj.add_keyframe(current_time, kf, start_slope, end_slope);
465         start_slope = end_slope;
466         end_slope = 1;
467 }
468
469 void Animation::Loader::slopes(float s, float e)
470 {
471         start_slope = s;
472         end_slope = e;
473 }
474
475 } // namespace GL
476 } // namespace Msp