X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fanimation.cpp;h=8f7dea03bd90e8c8513c5e2ac77379699072ed16;hp=efb67c972ded72ad916c286def76bd34bf5de28c;hb=6a045019fbd68738b77849629e6dfd3dfd9a4d93;hpb=164d77011ab4ebe76c9bf2b7ed8d8dd8ebc20e61 diff --git a/source/animation.cpp b/source/animation.cpp index efb67c97..8f7dea03 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -1,9 +1,10 @@ #include +#include #include #include #include "animation.h" #include "armature.h" -#include "keyframe.h" +#include "error.h" #include "pose.h" using namespace std; @@ -16,11 +17,30 @@ Animation::Animation(): looping(false) { } +// Avoid synthesizing ~RefPtr in files including animation.h +Animation::~Animation() +{ } + 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()) + 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() && tget_uniforms(); + for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i) + { + bool found = false; + for(unsigned j=0; (!found && jfirst) + { + 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(); } @@ -54,23 +88,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; } @@ -85,8 +118,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); } @@ -95,12 +128,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) { @@ -144,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(); @@ -163,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()), @@ -203,10 +257,28 @@ 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; jprev->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) - throw logic_error("Animation::Iterator::get_pose_matrix"); + 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"); @@ -219,10 +291,11 @@ Matrix Animation::Iterator::get_pose_matrix(unsigned link) const } // 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.x-new_base.x, base.y-new_base.y, base.z-new_base.z)*result; + result = Matrix::translation(base-new_base)*result; return result; }