]> git.tdb.fi Git - libs/gl.git/blobdiff - source/animation.cpp
Convert Matrix to use floats
[libs/gl.git] / source / animation.cpp
index 9f93a8d494222424dcc276e9547b29d488f9cd81..b1d639e7c957dbffb3ce73f43256be5e0ba52c8a 100644 (file)
@@ -2,19 +2,30 @@
 #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;
 
-#include <msp/io/print.h>
-
 namespace Msp {
 namespace GL {
 
 Animation::Animation():
+       armature(0),
        looping(false)
 { }
 
+// Avoid synthesizing ~RefPtr in files including animation.h
+Animation::~Animation()
+{ }
+
+void Animation::set_armature(const Armature &a)
+{
+       armature = &a;
+}
+
 void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
 {
        if(!keyframes.empty() && t<keyframes.back().time)
@@ -40,7 +51,6 @@ void Animation::prepare_keyframe(TimedKeyFrame &tkf)
                return;
 
        tkf.prepare();
-
 }
 
 
@@ -49,23 +59,22 @@ Animation::AxisInterpolation::AxisInterpolation():
        scale(0)
 { }
 
-Animation::AxisInterpolation::AxisInterpolation(const double *axis1, const double *axis2)
+Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
 {
        // Compute a normalized vector halfway between the two endpoints
-       double half[3];
-       double len = 0;
+       float half[3];
+       float a1_len = 0;
+       float h_len = 0;
        for(unsigned i=0; i<3; ++i)
        {
                half[i] = (axis1[i]+axis2[i])/2;
-               len += half[i]*half[i];
+               a1_len += axis1[i]*axis1[i];
+               h_len += half[i]*half[i];
        }
-       len = sqrt(len);
-       for(unsigned i=0; i<3; ++i)
-               half[i] /= len;
 
        // Compute correction factors for smooth interpolation
-       double cos_half = axis1[0]*half[0]+axis1[1]*half[1]+axis1[2]*half[2];
-       double angle = acos(cos_half);
+       float cos_half = (axis1[0]*half[0]+axis1[1]*half[1]+axis1[2]*half[2])/sqrt(a1_len*h_len);
+       float angle = acos(cos_half);
        slope = (angle ? angle/tan(angle) : 1);
        scale = cos_half;
 }
@@ -80,8 +89,8 @@ Animation::MatrixInterpolation::MatrixInterpolation(const Matrix &m1, const Matr
        matrix1(&m1),
        matrix2(&m2)
 {
-       const double *m1_data = matrix1->data();
-       const double *m2_data = matrix2->data();
+       const float *m1_data = matrix1->data();
+       const float *m2_data = matrix2->data();
        for(unsigned i=0; i<3; ++i)
                axes[i] = AxisInterpolation(m1_data+i*4, m2_data+i*4);
 }
@@ -90,12 +99,12 @@ Matrix Animation::MatrixInterpolation::get(float t) const
 {
        float u = t*2.0f-1.0f;
 
-       double matrix[16];
+       float matrix[16];
        for(unsigned i=0; i<4; ++i)
        {
-               const double *m1_col = matrix1->data()+i*4;
-               const double *m2_col = matrix2->data()+i*4;
-               double *out_col = matrix+i*4;
+               const float *m1_col = matrix1->data()+i*4;
+               const float *m2_col = matrix2->data()+i*4;
+               float *out_col = matrix+i*4;
 
                if(i<3)
                {
@@ -141,6 +150,20 @@ void Animation::TimedKeyFrame::prepare()
 {
        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();
+               pose_matrices.resize(max_index+1);
+               const Pose *pose1 = prev->keyframe->get_pose();
+               const Pose *pose2 = keyframe->get_pose();
+               static Matrix identity;
+               for(unsigned i=0; i<=max_index; ++i)
+               {
+                       const Matrix &matrix1 = (pose1 ? pose1->get_link_matrix(i) : identity);
+                       const Matrix &matrix2 = (pose2 ? pose2->get_link_matrix(i) : identity);
+                       pose_matrices[i] = MatrixInterpolation(matrix1, matrix2);
+               }
+       }
 }
 
 
@@ -184,6 +207,30 @@ Matrix Animation::Iterator::get_matrix() const
        return iter->matrix.get(time_since_keyframe/iter->delta_t);
 }
 
+Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
+{
+       if(!animation.armature)
+               throw invalid_operation("Animation::Iterator::get_pose_matrix");
+       if(link>animation.armature->get_max_link_index())
+               throw out_of_range("Animation::Iterator::get_pose_matrix");
+
+       if(!iter->prev)
+       {
+               if(const Pose *pose = iter->keyframe->get_pose())
+                       return pose->get_link_matrix(link);
+               else
+                       return Matrix();
+       }
+
+       // We must redo the base point correction since interpolation throws if 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();
+       Vector3 new_base = result*base;
+       result = Matrix::translation(base-new_base)*result;
+       return result;
+}
+
 
 Animation::Loader::Loader(Animation &a):
        DataFile::CollectionObjectLoader<Animation>(a, 0)
@@ -199,6 +246,7 @@ Animation::Loader::Loader(Animation &a, Collection &c):
 
 void Animation::Loader::init()
 {
+       add("armature", &Animation::armature);
        add("interval", &Loader::interval);
        add("keyframe", &Loader::keyframe);
        add("keyframe", &Loader::keyframe_inline);
@@ -213,7 +261,10 @@ void Animation::Loader::keyframe(const string &n)
 void Animation::Loader::keyframe_inline()
 {
        RefPtr<KeyFrame> kf = new KeyFrame;
-       load_sub(*kf);
+       if(coll)
+               load_sub(*kf, get_collection());
+       else
+               load_sub(*kf);
 
        TimedKeyFrame tkf(obj);
        tkf.time = current_time;