]> git.tdb.fi Git - libs/gl.git/blob - source/animation.cpp
02a2d371c71c1d32baff99aa3a120429d8c90d91
[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                         keyframes[i].prev = &keyframes[i-1];
82         }
83         else if(keyframes.size()>1)
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
277 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
278 {
279         time_since_keyframe += t;
280         while(time_since_keyframe>iter->delta_t)
281         {
282                 vector<TimedKeyFrame>::const_iterator next = iter;
283                 ++next;
284                 if(next==animation->keyframes.end())
285                 {
286                         if(animation->looping)
287                                 next = animation->keyframes.begin();
288                         else
289                         {
290                                 end = true;
291                                 time_since_keyframe = iter->delta_t;
292                                 break;
293                         }
294                 }
295
296                 time_since_keyframe -= iter->delta_t;
297                 iter = next;
298         }
299
300         x = time_since_keyframe/iter->delta_t;
301         x += (iter->start_slope-1)*((x-2)*x+1)*x + (1-iter->end_slope)*(1-x)*x*x;
302
303         return *this;
304 }
305
306 void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
307 {
308         vector<Event>::const_iterator events_end = animation->events.end();
309         if(end)
310         {
311                 for(; event_iter!=events_end; ++event_iter)
312                         observer.animation_event(0, event_iter->name, event_iter->value);
313         }
314         else if(event_iter!=events_end)
315         {
316                 Time::TimeDelta t = time_since_keyframe;
317                 if(iter->prev)
318                         t += iter->prev->time;
319                 for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter)
320                         observer.animation_event(0, event_iter->name, event_iter->value);
321         }
322 }
323
324 Matrix Animation::Iterator::get_matrix() const
325 {
326         if(!iter->prev)
327                 return iter->keyframe->get_matrix();
328
329         return iter->matrix.get(x);
330 }
331
332 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
333 {
334         if(!iter->prev)
335         {
336                 if(iter->uniforms.size()>i)
337                         return iter->uniforms[i];
338                 else
339                         return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
340         }
341
342         unsigned size = animation->uniforms[i].size;
343         KeyFrame::AnimatedUniform result(size, 0.0f);
344         for(unsigned j=0; j<size; ++j)
345                 result.values[j] = iter->prev->uniforms[i].values[j]*(1-x)+iter->uniforms[i].values[j]*x;
346         return result;
347 }
348
349 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
350 {
351         if(!animation->armature)
352                 throw invalid_operation("Animation::Iterator::get_pose_matrix");
353         if(link>animation->armature->get_max_link_index())
354                 throw out_of_range("Animation::Iterator::get_pose_matrix");
355
356         if(!iter->prev)
357         {
358                 if(const Pose *pose = iter->keyframe->get_pose())
359                         return pose->get_link_matrix(link);
360                 else
361                         return Matrix();
362         }
363
364         // We must redo the base point correction since interpolation throws it off
365         // XXX This should probably be done on local matrices
366         Matrix result = iter->pose_matrices[link].get(x);
367         const Vector3 &base = animation->armature->get_link(link).get_base();
368         Vector3 new_base = result*base;
369         result = Matrix::translation(base-new_base)*result;
370         return result;
371 }
372
373
374 Animation::Loader::Loader(Animation &a):
375         DataFile::CollectionObjectLoader<Animation>(a, 0)
376 {
377         init();
378 }
379
380 Animation::Loader::Loader(Animation &a, Collection &c):
381         DataFile::CollectionObjectLoader<Animation>(a, &c)
382 {
383         init();
384 }
385
386 void Animation::Loader::init()
387 {
388         start_slope = 1;
389         end_slope = 1;
390         add("armature", &Animation::armature);
391         add("event", &Loader::event);
392         add("event", &Loader::event1i);
393         add("event", &Loader::event1f);
394         add("event", &Loader::event2f);
395         add("event", &Loader::event3f);
396         add("event", &Loader::event4f);
397         add("interval", &Loader::interval);
398         add("keyframe", &Loader::keyframe);
399         add("keyframe", &Loader::keyframe_inline);
400         add("looping", &Animation::looping);
401         add("slopes", &Loader::slopes);
402 }
403
404 void Animation::Loader::event(const string &n)
405 {
406         obj.add_event(current_time, n);
407 }
408
409 void Animation::Loader::event1i(const string &n, int v)
410 {
411         obj.add_event(current_time, n, v);
412 }
413
414 void Animation::Loader::event1f(const string &n, float v)
415 {
416         obj.add_event(current_time, n, v);
417 }
418
419 void Animation::Loader::event2f(const string &n, float v0, float v1)
420 {
421         obj.add_event(current_time, n, LinAl::Vector<float, 2>(v0, v1));
422 }
423
424 void Animation::Loader::event3f(const string &n, float v0, float v1, float v2)
425 {
426         obj.add_event(current_time, n, Vector3(v0, v1, v2));
427 }
428
429 void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3)
430 {
431         obj.add_event(current_time, n, Vector4(v0, v1, v2, v3));
432 }
433
434 void Animation::Loader::interval(float t)
435 {
436         current_time += t*Time::sec;
437 }
438
439 void Animation::Loader::keyframe(const string &n)
440 {
441         obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
442         start_slope = end_slope;
443         end_slope = 1;
444 }
445
446 void Animation::Loader::keyframe_inline()
447 {
448         RefPtr<KeyFrame> kf = new KeyFrame;
449         if(coll)
450                 load_sub(*kf, get_collection());
451         else
452                 load_sub(*kf);
453
454         obj.add_keyframe(current_time, kf, start_slope, end_slope);
455         start_slope = end_slope;
456         end_slope = 1;
457 }
458
459 void Animation::Loader::slopes(float s, float e)
460 {
461         start_slope = s;
462         end_slope = e;
463 }
464
465 } // namespace GL
466 } // namespace Msp