+#include <msp/core/algorithm.h>
#include "animatedobject.h"
#include "animationplayer.h"
#include "armature.h"
namespace Msp {
namespace GL {
-AnimationPlayer::ObjectSlot &AnimationPlayer::get_slot(AnimatedObject &obj)
+AnimationPlayer::Target &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;
+ return objects.insert(ObjectMap::value_type(&obj, Target(obj))).first->second;
}
void AnimationPlayer::play(AnimatedObject &obj, const Animation &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));
+ Target &target = get_slot(obj);
+ target.animations.clear();
+ target.base_matrix = Matrix();
+ target.stacked = false;
+ target.armature = anim.get_armature();
+ target.animations.push_back(PlayingAnimation(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();
+ Target &target = get_slot(obj);
+ if(target.animations.empty())
+ target.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));
+ target.stacked = true;
+ target.armature = anim.get_armature();
+ target.animations.push_back(PlayingAnimation(anim));
}
unsigned AnimationPlayer::get_n_active_animations(const AnimatedObject &obj) const
return (i!=objects.end() ? i->second.animations.size() : 0);
}
+void AnimationPlayer::observe_events(AnimatedObject &obj, AnimationEventObserver &observer)
+{
+ Target &target = get_slot(obj);
+ if(find(target.event_observers, &observer)==target.event_observers.end())
+ target.event_observers.push_back(&observer);
+}
+
+void AnimationPlayer::unobserve_events(AnimatedObject &obj, AnimationEventObserver &observer)
+{
+ ObjectMap::iterator i = objects.find(&obj);
+ if(i==objects.end())
+ return;
+
+ vector<AnimationEventObserver *>::iterator j = find(i->second.event_observers, &observer);
+ if(j!=i->second.event_observers.end())
+ i->second.event_observers.erase(j);
+}
+
+void AnimationPlayer::unobserve_events(AnimationEventObserver &observer)
+{
+ for(ObjectMap::iterator i=objects.begin(); i!=objects.end(); ++i)
+ {
+ vector<AnimationEventObserver *>::iterator j = find(i->second.event_observers, &observer);
+ if(j!=i->second.event_observers.end())
+ i->second.event_observers.erase(j);
+ }
+}
+
void AnimationPlayer::stop(AnimatedObject &obj)
{
objects.erase(&obj);
if(i==objects.end())
return;
- for(vector<AnimationSlot>::iterator j=i->second.animations.begin(); j!=i->second.animations.end(); ++j)
+ for(vector<PlayingAnimation>::iterator j=i->second.animations.begin(); j!=i->second.animations.end(); ++j)
if(j->animation==&anim)
{
i->second.animations.erase(j);
{
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);
+ tick_stacked(i->second, dt);
+ else if(!i->second.animations.empty())
+ tick_single(i->second, dt);
- if(!keep)
+ if(i->second.animations.empty() && i->second.event_observers.empty())
objects.erase(i++);
else
++i;
}
}
-bool AnimationPlayer::tick_single(ObjectSlot &slot, const Time::TimeDelta &dt)
+void AnimationPlayer::tick_single(Target &target, const Time::TimeDelta &dt)
{
- AnimationSlot &anim = slot.animations.front();
+ PlayingAnimation &anim = target.animations.front();
anim.iterator += dt;
- slot.object.set_matrix(anim.iterator.get_matrix());
+ target.object.set_matrix(anim.iterator.get_matrix());
unsigned n_uniforms = anim.animation->get_n_uniforms();
for(unsigned i=0; i<n_uniforms; ++i)
- set_object_uniform(slot.object, anim.animation->get_uniform_name(i), anim.iterator.get_uniform(i));
+ set_object_uniform(target.object, anim.animation->get_uniform_name(i), anim.iterator.get_uniform(i));
- if(slot.armature)
+ if(target.armature)
{
- unsigned max_index = slot.armature->get_max_link_index();
+ unsigned max_index = target.armature->get_max_link_index();
for(unsigned i=0; i<=max_index; ++i)
- slot.object.set_pose_matrix(i, anim.iterator.get_pose_matrix(i));
+ target.object.set_pose_matrix(i, anim.iterator.get_pose_matrix(i));
}
- return !anim.iterator.is_end();
+ anim.iterator.dispatch_events(target);
+
+ if(anim.iterator.is_end())
+ target.animations.clear();
}
-bool AnimationPlayer::tick_stacked(ObjectSlot &slot, const Time::TimeDelta &dt)
+void AnimationPlayer::tick_stacked(Target &target, const Time::TimeDelta &dt)
{
- Matrix matrix = slot.base_matrix;
- for(vector<AnimationSlot>::iterator i=slot.animations.begin(); i!=slot.animations.end(); ++i)
+ Matrix matrix = target.base_matrix;
+ for(vector<PlayingAnimation>::iterator i=target.animations.begin(); i!=target.animations.end(); ++i)
{
i->iterator += dt;
matrix *= i->iterator.get_matrix();
unsigned n_uniforms = i->animation->get_n_uniforms();
for(unsigned j=0; j<n_uniforms; ++j)
- set_object_uniform(slot.object, i->animation->get_uniform_name(j), i->iterator.get_uniform(j));
+ set_object_uniform(target.object, i->animation->get_uniform_name(j), i->iterator.get_uniform(j));
}
- slot.object.set_matrix(matrix);
+ target.object.set_matrix(matrix);
- if(slot.armature)
+ if(target.armature)
{
- unsigned max_index = slot.armature->get_max_link_index();
+ unsigned max_index = target.armature->get_max_link_index();
for(unsigned i=0; i<=max_index; ++i)
{
matrix = Matrix();
/* XXX This is in all likelihood incorrect. The stacking should be
performed on local matrices. */
- for(vector<AnimationSlot>::iterator j=slot.animations.begin(); j!=slot.animations.end(); ++j)
+ for(vector<PlayingAnimation>::iterator j=target.animations.begin(); j!=target.animations.end(); ++j)
if(j->animation->get_armature())
matrix *= j->iterator.get_pose_matrix(i);
- slot.object.set_pose_matrix(i, matrix);
+ target.object.set_pose_matrix(i, matrix);
}
}
- for(vector<AnimationSlot>::iterator i=slot.animations.begin(); i!=slot.animations.end(); )
+ for(vector<PlayingAnimation>::iterator i=target.animations.begin(); i!=target.animations.end(); )
{
+ i->iterator.dispatch_events(target);
+
if(i->iterator.is_end())
- i = slot.animations.erase(i);
+ i = target.animations.erase(i);
else
++i;
}
- return !slot.animations.empty();
+ if(target.animations.empty())
+ target.stacked = false;
}
void AnimationPlayer::set_object_uniform(AnimatedObject &obj, const string &name, const KeyFrame::AnimatedUniform &uni)
}
-AnimationPlayer::ObjectSlot::ObjectSlot(AnimatedObject &o):
+AnimationPlayer::PlayingAnimation::PlayingAnimation(const Animation &a):
+ animation(&a),
+ iterator(*animation)
+{ }
+
+
+AnimationPlayer::Target::Target(AnimatedObject &o):
object(o),
armature(0),
stacked(false)
{ }
-
-AnimationPlayer::AnimationSlot::AnimationSlot(const Animation &a):
- animation(&a),
- iterator(*animation)
-{ }
+void AnimationPlayer::Target::animation_event(AnimatedObject *, const string &name, const Variant &value)
+{
+ for(vector<AnimationEventObserver *>::const_iterator i=event_observers.begin(); i!=event_observers.end(); ++i)
+ (*i)->animation_event(&object, name, value);
+}
} // namespace GL
} // namespace Msp