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