]> git.tdb.fi Git - libs/gl.git/blob - source/animationplayer.cpp
Keep track of which components have been set in Transform
[libs/gl.git] / source / animationplayer.cpp
1 #include <msp/core/algorithm.h>
2 #include "animatedobject.h"
3 #include "animationplayer.h"
4 #include "armature.h"
5 #include "programdata.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace GL {
11
12 AnimationPlayer::Target &AnimationPlayer::get_slot(Placeable &obj)
13 {
14         ObjectMap::iterator i = objects.find(&obj);
15         if(i!=objects.end())
16                 return i->second;
17
18         return objects.insert(ObjectMap::value_type(&obj, Target(obj))).first->second;
19 }
20
21 AnimationPlayer::Target &AnimationPlayer::play_(Placeable &obj, const Animation &anim, bool stacked, float speed)
22 {
23         Target &target = get_slot(obj);
24         if(!stacked)
25         {
26                 target.animations.clear();
27                 target.base_matrix = Matrix();
28         }
29         else if(target.animations.empty())
30                 target.base_matrix = *obj.get_matrix();
31         target.stacked = stacked;
32         // TODO check for incompatible armature
33         target.armature = anim.get_armature();
34         target.animations.push_back(PlayingAnimation(anim, speed));
35         return target;
36 }
37
38 void AnimationPlayer::play(AnimatedObject &obj, const Animation &anim, float speed)
39 {
40         Target &target = play_(obj, anim, false, speed);
41         target.object = &obj;
42 }
43
44 void AnimationPlayer::play(Placeable &obj, const Animation &anim, float speed)
45 {
46         play_(obj, anim, false, speed);
47 }
48
49 void AnimationPlayer::play_stacked(AnimatedObject &obj, const Animation &anim, float speed)
50 {
51         Target &target = play_(obj, anim, true, speed);
52         target.object = &obj;
53 }
54
55 void AnimationPlayer::play_stacked(Placeable &obj, const Animation &anim, float speed)
56 {
57         play_(obj, anim, true, speed);
58 }
59
60 unsigned AnimationPlayer::get_n_active_animations(const AnimatedObject &obj) const
61 {
62         ObjectMap::const_iterator i = objects.find(&obj);
63         return (i!=objects.end() ? i->second.animations.size() : 0);
64 }
65
66 void AnimationPlayer::observe_events(AnimatedObject &obj, AnimationEventObserver &observer)
67 {
68         Target &target = get_slot(obj);
69         if(find(target.event_observers, &observer)==target.event_observers.end())
70                 target.event_observers.push_back(&observer);
71 }
72
73 void AnimationPlayer::unobserve_events(AnimatedObject &obj, AnimationEventObserver &observer)
74 {
75         ObjectMap::iterator i = objects.find(&obj);
76         if(i==objects.end())
77                 return;
78
79         vector<AnimationEventObserver *>::iterator j = find(i->second.event_observers, &observer);
80         if(j!=i->second.event_observers.end())
81                 i->second.event_observers.erase(j);
82 }
83
84 void AnimationPlayer::unobserve_events(AnimationEventObserver &observer)
85 {
86         for(ObjectMap::iterator i=objects.begin(); i!=objects.end(); ++i)
87         {
88                 vector<AnimationEventObserver *>::iterator j = find(i->second.event_observers, &observer);
89                 if(j!=i->second.event_observers.end())
90                         i->second.event_observers.erase(j);
91         }
92 }
93
94 void AnimationPlayer::stop(AnimatedObject &obj)
95 {
96         objects.erase(&obj);
97 }
98
99 void AnimationPlayer::stop(AnimatedObject &obj, const Animation &anim)
100 {
101         ObjectMap::iterator i = objects.find(&obj);
102         if(i==objects.end())
103                 return;
104
105         for(vector<PlayingAnimation>::iterator j=i->second.animations.begin(); j!=i->second.animations.end(); ++j)
106                 if(j->animation==&anim)
107                 {
108                         i->second.animations.erase(j);
109                         break;
110                 }
111
112         if(i->second.animations.empty())
113                 objects.erase(i);
114 }
115
116 void AnimationPlayer::tick(const Time::TimeDelta &dt)
117 {
118         for(ObjectMap::iterator i=objects.begin(); i!=objects.end(); )
119         {
120                 if(i->second.stacked)
121                         tick_stacked(i->second, dt);
122                 else if(!i->second.animations.empty())
123                         tick_single(i->second, dt);
124
125                 if(i->second.animations.empty() && i->second.event_observers.empty())
126                         objects.erase(i++);
127                 else
128                         ++i;
129         }
130 }
131
132 void AnimationPlayer::tick_single(Target &target, const Time::TimeDelta &dt)
133 {
134         PlayingAnimation &anim = target.animations.front();
135         anim.iterator += dt*anim.speed;
136         target.placeable.set_matrix(anim.iterator.get_matrix());
137
138         if(target.object)
139         {
140                 unsigned n_uniforms = anim.animation->get_n_uniforms();
141                 for(unsigned i=0; i<n_uniforms; ++i)
142                         set_object_uniform(*target.object, anim.animation->get_uniform_name(i), anim.iterator.get_uniform(i));
143
144                 if(target.armature)
145                 {
146                         unsigned max_index = target.armature->get_max_link_index();
147                         for(unsigned i=0; i<=max_index; ++i)
148                                 target.object->set_pose_matrix(i, anim.iterator.get_pose_matrix(i));
149                 }
150         }
151
152         anim.iterator.dispatch_events(target);
153
154         if(anim.iterator.is_end())
155                 target.animations.clear();
156 }
157
158 void AnimationPlayer::tick_stacked(Target &target, const Time::TimeDelta &dt)
159 {
160         Matrix matrix = target.base_matrix;
161         for(vector<PlayingAnimation>::iterator i=target.animations.begin(); i!=target.animations.end(); ++i)
162         {
163                 i->iterator += dt*i->speed;
164                 matrix *= i->iterator.get_matrix();
165
166                 if(target.object)
167                 {
168                         unsigned n_uniforms = i->animation->get_n_uniforms();
169                         for(unsigned j=0; j<n_uniforms; ++j)
170                                 set_object_uniform(*target.object, i->animation->get_uniform_name(j), i->iterator.get_uniform(j));
171                 }
172         }
173         target.placeable.set_matrix(matrix);
174
175         if(target.object && target.armature)
176         {
177                 unsigned max_index = target.armature->get_max_link_index();
178                 for(unsigned i=0; i<=max_index; ++i)
179                 {
180                         matrix = Matrix();
181                         /* XXX This is in all likelihood incorrect.  The stacking should be
182                         performed on local matrices. */
183                         for(vector<PlayingAnimation>::iterator j=target.animations.begin(); j!=target.animations.end(); ++j)
184                                 if(j->animation->get_armature())
185                                         matrix *= j->iterator.get_pose_matrix(i);
186                         target.object->set_pose_matrix(i, matrix);
187                 }
188         }
189
190         for(vector<PlayingAnimation>::iterator i=target.animations.begin(); i!=target.animations.end(); )
191         {
192                 i->iterator.dispatch_events(target);
193
194                 if(i->iterator.is_end())
195                         i = target.animations.erase(i);
196                 else
197                         ++i;
198         }
199
200         if(target.animations.empty())
201                 target.stacked = false;
202 }
203
204 void AnimationPlayer::set_object_uniform(AnimatedObject &obj, const string &name, const KeyFrame::AnimatedUniform &uni)
205 {
206         ProgramData &shdata = obj.get_shader_data();
207
208         if(uni.size==1)
209                 shdata.uniform(name, uni.values[0]);
210         else if(uni.size==2)
211                 shdata.uniform2(name, uni.values);
212         else if(uni.size==3)
213                 shdata.uniform3(name, uni.values);
214         else if(uni.size==4)
215                 shdata.uniform4(name, uni.values);
216 }
217
218
219 AnimationPlayer::PlayingAnimation::PlayingAnimation(const Animation &a, float s):
220         animation(&a),
221         speed(s),
222         iterator(*animation)
223 { }
224
225
226 AnimationPlayer::Target::Target(Placeable &p):
227         placeable(p),
228         object(0),
229         armature(0),
230         stacked(false)
231 { }
232
233 void AnimationPlayer::Target::animation_event(Placeable *, const string &name, const Variant &value)
234 {
235         for(vector<AnimationEventObserver *>::const_iterator i=event_observers.begin(); i!=event_observers.end(); ++i)
236                 (*i)->animation_event(&placeable, name, value);
237 }
238
239 } // namespace GL
240 } // namespace Msp