]> git.tdb.fi Git - libs/gl.git/blobdiff - source/animationplayer.cpp
Fix an incorrect negation
[libs/gl.git] / source / animationplayer.cpp
index 9bcb5e5720872d006b28ac6f8a9c1dec7421c26b..7c693ad2c3eef32ce7ec2a8aa74f4e754d130258 100644 (file)
+#include <msp/core/algorithm.h>
 #include "animatedobject.h"
 #include "animationplayer.h"
 #include "armature.h"
+#include "programdata.h"
 
 using namespace std;
 
 namespace Msp {
 namespace GL {
 
+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, Target(obj))).first->second;
+}
+
 void AnimationPlayer::play(AnimatedObject &obj, const Animation &anim)
 {
-       slots.push_back(Slot(obj, 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)
+{
+       Target &target = get_slot(obj);
+       if(target.animations.empty())
+               target.base_matrix = *obj.get_matrix();
+       // TODO check for incompatible armature
+       target.stacked = true;
+       target.armature = anim.get_armature();
+       target.animations.push_back(PlayingAnimation(anim));
+}
+
+unsigned AnimationPlayer::get_n_active_animations(const AnimatedObject &obj) const
+{
+       ObjectMap::const_iterator i = objects.find(&obj);
+       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);
+}
+
+void AnimationPlayer::stop(AnimatedObject &obj, const Animation &anim)
+{
+       ObjectMap::iterator i = objects.find(&obj);
+       if(i==objects.end())
+               return;
+
+       for(vector<PlayingAnimation>::iterator j=i->second.animations.begin(); j!=i->second.animations.end(); ++j)
+               if(j->animation==&anim)
+               {
+                       i->second.animations.erase(j);
+                       break;
+               }
+
+       if(i->second.animations.empty())
+               objects.erase(i);
 }
 
 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(); )
+       {
+               if(i->second.stacked)
+                       tick_stacked(i->second, dt);
+               else if(!i->second.animations.empty())
+                       tick_single(i->second, dt);
+
+               if(i->second.animations.empty() && i->second.event_observers.empty())
+                       objects.erase(i++);
+               else
+                       ++i;
+       }
+}
+
+void AnimationPlayer::tick_single(Target &target, const Time::TimeDelta &dt)
+{
+       PlayingAnimation &anim = target.animations.front();
+       anim.iterator += dt;
+       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(target.object, anim.animation->get_uniform_name(i), anim.iterator.get_uniform(i));
+
+       if(target.armature)
+       {
+               unsigned max_index = target.armature->get_max_link_index();
+               for(unsigned i=0; i<=max_index; ++i)
+                       target.object.set_pose_matrix(i, anim.iterator.get_pose_matrix(i));
+       }
+
+       anim.iterator.dispatch_events(target);
+
+       if(anim.iterator.is_end())
+               target.animations.clear();
+}
+
+void AnimationPlayer::tick_stacked(Target &target, const Time::TimeDelta &dt)
+{
+       Matrix matrix = target.base_matrix;
+       for(vector<PlayingAnimation>::iterator i=target.animations.begin(); i!=target.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();
+
+               unsigned n_uniforms = i->animation->get_n_uniforms();
+               for(unsigned j=0; j<n_uniforms; ++j)
+                       set_object_uniform(target.object, i->animation->get_uniform_name(j), i->iterator.get_uniform(j));
+       }
+       target.object.set_matrix(matrix);
+
+       if(target.armature)
+       {
+               unsigned max_index = target.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(vector<PlayingAnimation>::iterator j=target.animations.begin(); j!=target.animations.end(); ++j)
+                               if(j->animation->get_armature())
+                                       matrix *= j->iterator.get_pose_matrix(i);
+                       target.object.set_pose_matrix(i, matrix);
                }
+       }
+
+       for(vector<PlayingAnimation>::iterator i=target.animations.begin(); i!=target.animations.end(); )
+       {
+               i->iterator.dispatch_events(target);
 
                if(i->iterator.is_end())
-                       slots.erase(i++);
+                       i = target.animations.erase(i);
                else
                        ++i;
        }
+
+       if(target.animations.empty())
+               target.stacked = false;
+}
+
+void AnimationPlayer::set_object_uniform(AnimatedObject &obj, const string &name, const KeyFrame::AnimatedUniform &uni)
+{
+       ProgramData &shdata = obj.get_shader_data();
+
+       if(uni.size==1)
+               shdata.uniform(name, uni.values[0]);
+       else if(uni.size==2)
+               shdata.uniform2(name, uni.values);
+       else if(uni.size==2)
+               shdata.uniform3(name, uni.values);
+       else if(uni.size==4)
+               shdata.uniform4(name, uni.values);
 }
 
 
-AnimationPlayer::Slot::Slot(AnimatedObject &o, const Animation &a):
+AnimationPlayer::PlayingAnimation::PlayingAnimation(const Animation &a):
+       animation(&a),
+       iterator(*animation)
+{ }
+
+
+AnimationPlayer::Target::Target(AnimatedObject &o):
        object(o),
-       animation(a),
-       iterator(animation)
+       armature(0),
+       stacked(false)
 { }
 
+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