namespace Msp {
namespace GL {
+AnimationPlayer::ObjectSlot &AnimationPlayer::get_slot(AnimatedObject &obj)
+{
+ ObjectMap::iterator i = objects.find(&obj);
+ if(i!=objects.end())
+ return i->second;
+
+ return objects.insert(ObjectMap::value_type(&obj, ObjectSlot(obj))).first->second;
+}
+
void AnimationPlayer::play(AnimatedObject &obj, const Animation &anim)
{
- slots.push_back(Slot(obj, anim));
+ ObjectSlot &obj_slot = get_slot(obj);
+ obj_slot.animations.clear();
+ obj_slot.base_matrix = Matrix();
+ obj_slot.stacked = false;
+ obj_slot.armature = anim.get_armature();
+ obj_slot.animations.push_back(AnimationSlot(anim));
+}
+
+void AnimationPlayer::play_stacked(AnimatedObject &obj, const Animation &anim)
+{
+ ObjectSlot &obj_slot = get_slot(obj);
+ if(obj_slot.animations.empty())
+ obj_slot.base_matrix = *obj.get_matrix();
+ // TODO check for incompatible armature
+ obj_slot.stacked = true;
+ obj_slot.armature = anim.get_armature();
+ obj_slot.animations.push_back(AnimationSlot(anim));
+}
+
+void AnimationPlayer::stop(AnimatedObject &obj)
+{
+ objects.erase(&obj);
}
void AnimationPlayer::tick(const Time::TimeDelta &dt)
{
- for(list<Slot>::iterator i=slots.begin(); i!=slots.end(); )
+ for(ObjectMap::iterator i=objects.begin(); i!=objects.end(); )
+ {
+ bool keep = false;
+ if(i->second.stacked)
+ keep = tick_stacked(i->second, dt);
+ else
+ keep = tick_single(i->second, dt);
+
+ if(!keep)
+ objects.erase(i++);
+ else
+ ++i;
+ }
+}
+
+bool AnimationPlayer::tick_single(ObjectSlot &slot, const Time::TimeDelta &dt)
+{
+ AnimatedObject &obj = slot.object;
+ AnimationSlot &anim = slot.animations.front();
+ anim.iterator += dt;
+ obj.set_matrix(anim.iterator.get_matrix());
+ if(slot.armature)
+ {
+ unsigned max_index = slot.armature->get_max_link_index();
+ for(unsigned i=0; i<=max_index; ++i)
+ obj.set_pose_matrix(i, anim.iterator.get_pose_matrix(i));
+ }
+
+ return !anim.iterator.is_end();
+}
+
+bool AnimationPlayer::tick_stacked(ObjectSlot &slot, const Time::TimeDelta &dt)
+{
+ Matrix matrix = slot.base_matrix;
+ for(AnimationList::iterator i=slot.animations.begin(); i!=slot.animations.end(); ++i)
{
i->iterator += dt;
- i->object.set_matrix(i->iterator.get_matrix());
- if(const Armature *armature = i->animation.get_armature())
+ matrix *= i->iterator.get_matrix();
+ }
+ slot.object.set_matrix(matrix);
+
+ if(slot.armature)
+ {
+ unsigned max_index = slot.armature->get_max_link_index();
+ for(unsigned i=0; i<=max_index; ++i)
{
- unsigned max_index = armature->get_max_link_index();
- for(unsigned j=0; j<=max_index; ++j)
- i->object.set_pose_matrix(j, i->iterator.get_pose_matrix(j));
+ matrix = Matrix();
+ /* XXX This is in all likelihood incorrect. The stacking should be
+ performed on local matrices. */
+ for(AnimationList::iterator j=slot.animations.begin(); j!=slot.animations.end(); ++j)
+ if(j->animation.get_armature())
+ matrix *= j->iterator.get_pose_matrix(i);
+ slot.object.set_pose_matrix(i, matrix);
}
+ }
+ for(AnimationList::iterator i=slot.animations.begin(); i!=slot.animations.end(); )
+ {
if(i->iterator.is_end())
- slots.erase(i++);
+ slot.animations.erase(i++);
else
++i;
}
+
+ return !slot.animations.empty();
}
-AnimationPlayer::Slot::Slot(AnimatedObject &o, const Animation &a):
+AnimationPlayer::ObjectSlot::ObjectSlot(AnimatedObject &o):
object(o),
+ armature(0),
+ stacked(false)
+{ }
+
+
+AnimationPlayer::AnimationSlot::AnimationSlot(const Animation &a):
animation(a),
iterator(animation)
{ }
class AnimationPlayer
{
private:
- struct Slot
+ struct AnimationSlot
{
- AnimatedObject &object;
const Animation &animation;
Animation::Iterator iterator;
- Slot(AnimatedObject &, const Animation &);
+ AnimationSlot(const Animation &);
+ };
+
+ typedef std::list<AnimationSlot> AnimationList;
+
+ struct ObjectSlot
+ {
+ AnimatedObject &object;
+ Matrix base_matrix;
+ const Armature *armature;
+ AnimationList animations;
+ bool stacked;
+
+ ObjectSlot(AnimatedObject &);
};
- std::list<Slot> slots;
+ typedef std::map<AnimatedObject *, ObjectSlot> ObjectMap;
+
+ ObjectMap objects;
+
+private:
+ ObjectSlot &get_slot(AnimatedObject &);
public:
- /** Plays an animation on an object. */
+ /// Plays an animation on an object. Any previous animations are replaced.
void play(AnimatedObject &, const Animation &);
+ /** Plays an animation, stacked with other animations. If no animations are
+ playing yet, the object's current matrix is used as the base. */
+ void play_stacked(AnimatedObject &, const Animation &);
+
+ /// Stops any animations affecting an object.
+ void stop(AnimatedObject &);
+
/** Advances all playing animations. Should be called in a regular manner,
preferably just before rendering. */
void tick(const Time::TimeDelta &);
+
+private:
+ bool tick_single(ObjectSlot &, const Time::TimeDelta &);
+ bool tick_stacked(ObjectSlot &, const Time::TimeDelta &);
};
} // namespace GL