]> git.tdb.fi Git - libs/gl.git/blobdiff - source/animation.cpp
Disable mipmaps from various render target textures
[libs/gl.git] / source / animation.cpp
index 1e2dda900fafc0d580bf84cb648772ccf7747ac3..e82a92a87ce4811b3e465b345e6f5477d1c61f27 100644 (file)
@@ -3,6 +3,7 @@
 #include <msp/datafile/collection.h>
 #include <msp/time/units.h>
 #include "animation.h"
+#include "animationeventobserver.h"
 #include "armature.h"
 #include "error.h"
 #include "pose.h"
@@ -43,26 +44,51 @@ const string &Animation::get_uniform_name(unsigned i) const
 
 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
 {
+       add_keyframe(t, kf, 1.0f, 1.0f);
+}
+
+void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope)
+{
+       add_keyframe(t, kf, slope, slope);
+}
+
+void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es)
+{
+       RefPtr<const KeyFrame> kfr(&kf);
+       kfr.keep();
+       add_keyframe(t, kfr, ss, es);
+}
+
+void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf, float ss, float es)
+{
+       if(keyframes.empty() && t!=Time::zero)
+               throw invalid_argument("Animation::add_keyframe");
        if(!keyframes.empty() && t<keyframes.back().time)
                throw invalid_argument("Animation::add_keyframe");
 
-       TimedKeyFrame tkf(*this);
+       bool realloc = (keyframes.size()>=keyframes.capacity());
+
+       keyframes.push_back(TimedKeyFrame());
+       TimedKeyFrame &tkf = keyframes.back();
        tkf.time = t;
-       tkf.keyframe = &kf;
-       tkf.keyframe.keep();
-       prepare_keyframe(tkf);
-       keyframes.push_back(tkf);
-}
+       tkf.start_slope = ss;
+       tkf.end_slope = es;
+       tkf.keyframe = kf;
 
-void Animation::set_looping(bool l)
-{
-       looping = l;
+       if(realloc)
+       {
+               for(unsigned i=1; i<keyframes.size(); ++i)
+                       if(keyframes[i].prev)
+                               keyframes[i].prev = &keyframes[i-1];
+       }
+       if(keyframes.size()>1 && t>(&tkf-1)->time)
+               tkf.prev = &tkf-1;
+
+       prepare_keyframe(tkf);
 }
 
 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
 {
-       tkf.prev = (keyframes.empty() ? 0 : &keyframes.back());
-
        const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
        for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
        {
@@ -79,7 +105,29 @@ void Animation::prepare_keyframe(TimedKeyFrame &tkf)
                        uniforms.push_back(UniformInfo(i->first, i->second.size));
        }
 
-       tkf.prepare();
+       tkf.prepare(*this);
+}
+
+void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v)
+{
+       Event event;
+       event.time = t;
+       event.name = n;
+       event.value = v;
+       events.push_back(event);
+}
+
+const Time::TimeDelta &Animation::get_duration() const
+{
+       if(keyframes.empty())
+               return Time::zero;
+
+       return keyframes.back().time;
+}
+
+void Animation::set_looping(bool l)
+{
+       looping = l;
 }
 
 
@@ -91,18 +139,19 @@ Animation::AxisInterpolation::AxisInterpolation():
 Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
 {
        // Compute a normalized vector halfway between the two endpoints
-       float half[3];
        float a1_len = 0;
        float h_len = 0;
+       float cos_half = 0;
        for(unsigned i=0; i<3; ++i)
        {
-               half[i] = (axis1[i]+axis2[i])/2;
+               float half_i = (axis1[i]+axis2[i])/2;
+               cos_half += axis1[i]*half_i;
                a1_len += axis1[i]*axis1[i];
-               h_len += half[i]*half[i];
+               h_len += half_i*half_i;
        }
 
        // Compute correction factors for smooth interpolation
-       float cos_half = (axis1[0]*half[0]+axis1[1]*half[1]+axis1[2]*half[2])/sqrt(a1_len*h_len);
+       cos_half = min(max(cos_half/sqrt(a1_len*h_len), -1.0f), 1.0f);
        float angle = acos(cos_half);
        slope = (angle ? angle/tan(angle) : 1);
        scale = cos_half;
@@ -170,12 +219,13 @@ Matrix Animation::MatrixInterpolation::get(float t) const
 }
 
 
-Animation::TimedKeyFrame::TimedKeyFrame(const Animation &a):
-       animation(a),
-       prev(0)
+Animation::TimedKeyFrame::TimedKeyFrame():
+       prev(0),
+       start_slope(1),
+       end_slope(1)
 { }
 
-void Animation::TimedKeyFrame::prepare()
+void Animation::TimedKeyFrame::prepare(const Animation &animation)
 {
        const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
        for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
@@ -218,22 +268,27 @@ Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
 
 
 Animation::Iterator::Iterator(const Animation &a):
-       animation(a),
-       iter(animation.keyframes.begin()),
+       animation(&a),
+       iter(animation->keyframes.begin()),
+       event_iter(animation->events.begin()),
+       x(0),
        end(false)
-{ }
+{
+       if(iter==animation->keyframes.end())
+               throw invalid_argument("Animation::Iterator::Iterator");
+}
 
 Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
 {
        time_since_keyframe += t;
        while(time_since_keyframe>iter->delta_t)
        {
-               KeyFrameList::const_iterator next = iter;
+               vector<TimedKeyFrame>::const_iterator next = iter;
                ++next;
-               if(next==animation.keyframes.end())
+               if(next==animation->keyframes.end())
                {
-                       if(animation.looping)
-                               next = animation.keyframes.begin();
+                       if(animation->looping)
+                               next = animation->keyframes.begin();
                        else
                        {
                                end = true;
@@ -246,15 +301,36 @@ Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t)
                iter = next;
        }
 
+       x = time_since_keyframe/iter->delta_t;
+       x += (iter->start_slope-1)*((x-2)*x+1)*x + (1-iter->end_slope)*(1-x)*x*x;
+
        return *this;
 }
 
+void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
+{
+       vector<Event>::const_iterator events_end = animation->events.end();
+       if(end)
+       {
+               for(; event_iter!=events_end; ++event_iter)
+                       observer.animation_event(0, event_iter->name, event_iter->value);
+       }
+       else if(event_iter!=events_end)
+       {
+               Time::TimeDelta t = time_since_keyframe;
+               if(iter->prev)
+                       t += iter->prev->time;
+               for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter)
+                       observer.animation_event(0, event_iter->name, event_iter->value);
+       }
+}
+
 Matrix Animation::Iterator::get_matrix() const
 {
        if(!iter->prev)
                return iter->keyframe->get_matrix();
 
-       return iter->matrix.get(time_since_keyframe/iter->delta_t);
+       return iter->matrix.get(x);
 }
 
 KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
@@ -264,22 +340,21 @@ KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
                if(iter->uniforms.size()>i)
                        return iter->uniforms[i];
                else
-                       return KeyFrame::AnimatedUniform(animation.uniforms[i].size, 0.0f);
+                       return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f);
        }
 
-       unsigned size = animation.uniforms[i].size;
-       float t = time_since_keyframe/iter->delta_t;
+       unsigned size = animation->uniforms[i].size;
        KeyFrame::AnimatedUniform result(size, 0.0f);
        for(unsigned j=0; j<size; ++j)
-               result.values[j] = iter->prev->uniforms[i].values[j]*(1-t)+iter->uniforms[i].values[j]*t;
+               result.values[j] = iter->prev->uniforms[i].values[j]*(1-x)+iter->uniforms[i].values[j]*x;
        return result;
 }
 
 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
 {
-       if(!animation.armature)
+       if(!animation->armature)
                throw invalid_operation("Animation::Iterator::get_pose_matrix");
-       if(link>animation.armature->get_max_link_index())
+       if(link>animation->armature->get_max_link_index())
                throw out_of_range("Animation::Iterator::get_pose_matrix");
 
        if(!iter->prev)
@@ -290,10 +365,10 @@ Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
                        return Matrix();
        }
 
-       // We must redo the base point correction since interpolation throws if off
+       // We must redo the base point correction since interpolation throws it off
        // XXX This should probably be done on local matrices
-       Matrix result = iter->pose_matrices[link].get(time_since_keyframe/iter->delta_t);
-       const Vector3 &base = animation.armature->get_link(link).get_base();
+       Matrix result = iter->pose_matrices[link].get(x);
+       const Vector3 &base = animation->armature->get_link(link).get_base();
        Vector3 new_base = result*base;
        result = Matrix::translation(base-new_base)*result;
        return result;
@@ -314,16 +389,62 @@ Animation::Loader::Loader(Animation &a, Collection &c):
 
 void Animation::Loader::init()
 {
+       start_slope = 1;
+       end_slope = 1;
        add("armature", &Animation::armature);
+       add("event", &Loader::event);
+       add("event", &Loader::event1i);
+       add("event", &Loader::event1f);
+       add("event", &Loader::event2f);
+       add("event", &Loader::event3f);
+       add("event", &Loader::event4f);
        add("interval", &Loader::interval);
        add("keyframe", &Loader::keyframe);
        add("keyframe", &Loader::keyframe_inline);
        add("looping", &Animation::looping);
+       add("slopes", &Loader::slopes);
+}
+
+void Animation::Loader::event(const string &n)
+{
+       obj.add_event(current_time, n);
+}
+
+void Animation::Loader::event1i(const string &n, int v)
+{
+       obj.add_event(current_time, n, v);
+}
+
+void Animation::Loader::event1f(const string &n, float v)
+{
+       obj.add_event(current_time, n, v);
+}
+
+void Animation::Loader::event2f(const string &n, float v0, float v1)
+{
+       obj.add_event(current_time, n, LinAl::Vector<float, 2>(v0, v1));
+}
+
+void Animation::Loader::event3f(const string &n, float v0, float v1, float v2)
+{
+       obj.add_event(current_time, n, Vector3(v0, v1, v2));
+}
+
+void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3)
+{
+       obj.add_event(current_time, n, Vector4(v0, v1, v2, v3));
+}
+
+void Animation::Loader::interval(float t)
+{
+       current_time += t*Time::sec;
 }
 
 void Animation::Loader::keyframe(const string &n)
 {
-       obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n));
+       obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
+       start_slope = end_slope;
+       end_slope = 1;
 }
 
 void Animation::Loader::keyframe_inline()
@@ -334,16 +455,15 @@ void Animation::Loader::keyframe_inline()
        else
                load_sub(*kf);
 
-       TimedKeyFrame tkf(obj);
-       tkf.time = current_time;
-       tkf.keyframe = kf;
-       obj.prepare_keyframe(tkf);
-       obj.keyframes.push_back(tkf);
+       obj.add_keyframe(current_time, kf, start_slope, end_slope);
+       start_slope = end_slope;
+       end_slope = 1;
 }
 
-void Animation::Loader::interval(float t)
+void Animation::Loader::slopes(float s, float e)
 {
-       current_time += t*Time::sec;
+       start_slope = s;
+       end_slope = e;
 }
 
 } // namespace GL