]> git.tdb.fi Git - libs/gl.git/blobdiff - source/animation.cpp
Support animation of uniform variables
[libs/gl.git] / source / animation.cpp
index b1d639e7c957dbffb3ce73f43256be5e0ba52c8a..8f7dea03bd90e8c8513c5e2ac77379699072ed16 100644 (file)
@@ -1,10 +1,10 @@
 #include <cmath>
+#include <msp/core/maputils.h>
 #include <msp/datafile/collection.h>
 #include <msp/time/units.h>
 #include "animation.h"
 #include "armature.h"
 #include "error.h"
-#include "keyframe.h"
 #include "pose.h"
 
 using namespace std;
@@ -26,6 +26,21 @@ void Animation::set_armature(const Armature &a)
        armature = &a;
 }
 
+unsigned Animation::get_slot_for_uniform(const string &n) const
+{
+       for(unsigned i=0; i<uniforms.size(); ++i)
+               if(uniforms[i].name==n)
+                       return i;
+       throw key_error(n);
+}
+
+const string &Animation::get_uniform_name(unsigned i) const
+{
+       if(i>=uniforms.size())
+               throw out_of_range("Animation::get_uniform_name");
+       return uniforms[i].name;
+}
+
 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
 {
        if(!keyframes.empty() && t<keyframes.back().time)
@@ -47,8 +62,22 @@ void Animation::set_looping(bool l)
 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
 {
        tkf.prev = (keyframes.empty() ? 0 : &keyframes.back());
-       if(!tkf.prev)
-               return;
+
+       const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
+       for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
+       {
+               bool found = false;
+               for(unsigned j=0; (!found && j<uniforms.size()); ++j)
+                       if(uniforms[j].name==i->first)
+                       {
+                               if(uniforms[j].size!=i->second.size)
+                                       throw invalid_operation("Animation::prepare_keyframe");
+                               found = true;
+                       }
+
+               if(!found)
+                       uniforms.push_back(UniformInfo(i->first, i->second.size));
+       }
 
        tkf.prepare();
 }
@@ -148,8 +177,23 @@ Animation::TimedKeyFrame::TimedKeyFrame(const Animation &a):
 
 void Animation::TimedKeyFrame::prepare()
 {
+       const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
+       for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
+       {
+               unsigned j = animation.get_slot_for_uniform(i->first);
+               uniforms.reserve(j+1);
+               for(unsigned k=uniforms.size(); k<=j; ++k)
+                       uniforms.push_back(KeyFrame::AnimatedUniform(animation.uniforms[k].size, 0.0f));
+
+               uniforms[j] = i->second;
+       }
+
+       if(!prev)
+               return;
+
        delta_t = time-prev->time;
        matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix());
+
        if(animation.armature)
        {
                unsigned max_index = animation.armature->get_max_link_index();
@@ -167,6 +211,12 @@ void Animation::TimedKeyFrame::prepare()
 }
 
 
+Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
+       name(n),
+       size(s)
+{ }
+
+
 Animation::Iterator::Iterator(const Animation &a):
        animation(a),
        iter(animation.keyframes.begin()),
@@ -207,6 +257,24 @@ Matrix Animation::Iterator::get_matrix() const
        return iter->matrix.get(time_since_keyframe/iter->delta_t);
 }
 
+KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
+{
+       if(!iter->prev)
+       {
+               if(iter->uniforms.size()>i)
+                       return iter->uniforms[i];
+               else
+                       return KeyFrame::AnimatedUniform(animation.uniforms[i].size, 0.0f);
+       }
+
+       unsigned size = animation.uniforms[i].size;
+       float t = time_since_keyframe/iter->delta_t;
+       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;
+       return result;
+}
+
 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
 {
        if(!animation.armature)