]> git.tdb.fi Git - libs/gl.git/blobdiff - source/animation.cpp
Support overriding uniforms in inherited Techniques
[libs/gl.git] / source / animation.cpp
index b1d639e7c957dbffb3ce73f43256be5e0ba52c8a..1e2dda900fafc0d580bf84cb648772ccf7747ac3 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();
 }
@@ -116,7 +145,7 @@ Matrix Animation::MatrixInterpolation::get(float t) const
                        will be in the range [-1, 1]. */
                        float w = (axes[i].slope+(1-axes[i].slope)*u*u)*u*0.5f+0.5f;
 
-                       /* The interpolate vectors will also be shorter than unit length.  At
+                       /* The interpolated vectors will also be shorter than unit length.  At
                        the halfway point the length will be equal to the cosine of half the
                        angle, which was computed earlier.  Use a second degree polynomial to
                        approximate. */
@@ -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)