]> git.tdb.fi Git - libs/gl.git/blob - source/animationplayer.cpp
Add support for playing multiple stacked animations on an object
[libs/gl.git] / source / animationplayer.cpp
1 #include "animatedobject.h"
2 #include "animationplayer.h"
3 #include "armature.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9
10 AnimationPlayer::ObjectSlot &AnimationPlayer::get_slot(AnimatedObject &obj)
11 {
12         ObjectMap::iterator i = objects.find(&obj);
13         if(i!=objects.end())
14                 return i->second;
15
16         return objects.insert(ObjectMap::value_type(&obj, ObjectSlot(obj))).first->second;
17 }
18
19 void AnimationPlayer::play(AnimatedObject &obj, const Animation &anim)
20 {
21         ObjectSlot &obj_slot = get_slot(obj);
22         obj_slot.animations.clear();
23         obj_slot.base_matrix = Matrix();
24         obj_slot.stacked = false;
25         obj_slot.armature = anim.get_armature();
26         obj_slot.animations.push_back(AnimationSlot(anim));
27 }
28
29 void AnimationPlayer::play_stacked(AnimatedObject &obj, const Animation &anim)
30 {
31         ObjectSlot &obj_slot = get_slot(obj);
32         if(obj_slot.animations.empty())
33                 obj_slot.base_matrix = *obj.get_matrix();
34         // TODO check for incompatible armature
35         obj_slot.stacked = true;
36         obj_slot.armature = anim.get_armature();
37         obj_slot.animations.push_back(AnimationSlot(anim));
38 }
39
40 void AnimationPlayer::stop(AnimatedObject &obj)
41 {
42         objects.erase(&obj);
43 }
44
45 void AnimationPlayer::tick(const Time::TimeDelta &dt)
46 {
47         for(ObjectMap::iterator i=objects.begin(); i!=objects.end(); )
48         {
49                 bool keep = false;
50                 if(i->second.stacked)
51                         keep = tick_stacked(i->second, dt);
52                 else
53                         keep = tick_single(i->second, dt);
54
55                 if(!keep)
56                         objects.erase(i++);
57                 else
58                         ++i;
59         }
60 }
61
62 bool AnimationPlayer::tick_single(ObjectSlot &slot, const Time::TimeDelta &dt)
63 {
64         AnimatedObject &obj = slot.object;
65         AnimationSlot &anim = slot.animations.front();
66         anim.iterator += dt;
67         obj.set_matrix(anim.iterator.get_matrix());
68         if(slot.armature)
69         {
70                 unsigned max_index = slot.armature->get_max_link_index();
71                 for(unsigned i=0; i<=max_index; ++i)
72                         obj.set_pose_matrix(i, anim.iterator.get_pose_matrix(i));
73         }
74
75         return !anim.iterator.is_end();
76 }
77
78 bool AnimationPlayer::tick_stacked(ObjectSlot &slot, const Time::TimeDelta &dt)
79 {
80         Matrix matrix = slot.base_matrix;
81         for(AnimationList::iterator i=slot.animations.begin(); i!=slot.animations.end(); ++i)
82         {
83                 i->iterator += dt;
84                 matrix *= i->iterator.get_matrix();
85         }
86         slot.object.set_matrix(matrix);
87
88         if(slot.armature)
89         {
90                 unsigned max_index = slot.armature->get_max_link_index();
91                 for(unsigned i=0; i<=max_index; ++i)
92                 {
93                         matrix = Matrix();
94                         /* XXX This is in all likelihood incorrect.  The stacking should be
95                         performed on local matrices. */
96                         for(AnimationList::iterator j=slot.animations.begin(); j!=slot.animations.end(); ++j)
97                                 if(j->animation.get_armature())
98                                         matrix *= j->iterator.get_pose_matrix(i);
99                         slot.object.set_pose_matrix(i, matrix);
100                 }
101         }
102
103         for(AnimationList::iterator i=slot.animations.begin(); i!=slot.animations.end(); )
104         {
105                 if(i->iterator.is_end())
106                         slot.animations.erase(i++);
107                 else
108                         ++i;
109         }
110
111         return !slot.animations.empty();
112 }
113
114
115 AnimationPlayer::ObjectSlot::ObjectSlot(AnimatedObject &o):
116         object(o),
117         armature(0),
118         stacked(false)
119 { }
120
121
122 AnimationPlayer::AnimationSlot::AnimationSlot(const Animation &a):
123         animation(a),
124         iterator(animation)
125 { }
126
127 } // namespace GL
128 } // namespace Msp