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