X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fanimation.cpp;h=53543d1b89b8426f576305604c046651cea156a7;hp=eb22ab29f0462fa5c686b2542b9b21ba155f5a6e;hb=1eed7ffeb576674535661a09d298cff62f2cf96a;hpb=b37c25fb969b3fb6936ac456a07bd69c4c10cd00 diff --git a/source/animation.cpp b/source/animation.cpp index eb22ab29..53543d1b 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -20,7 +20,7 @@ void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf) if(!keyframes.empty() && ttime; + tkf.prepare(); - const double *m1_data = tkf.prev->keyframe->get_matrix().data(); - const double *m2_data = tkf.keyframe->get_matrix().data(); +} + + +Animation::AxisInterpolation::AxisInterpolation(): + slope(0), + scale(0) +{ } + +Animation::AxisInterpolation::AxisInterpolation(const double *axis1, const double *axis2) +{ + // Compute a normalized vector halfway between the two endpoints + double half[3]; + double len = 0; for(unsigned i=0; i<3; ++i) { - const double *m1_col = m1_data+i*4; - const double *m2_col = m2_data+i*4; - - // Compute a normalized vector halfway between the two endpoints - double half[3]; - double len = 0; - for(unsigned j=0; j<3; ++j) - { - half[j] = (m1_col[j]+m2_col[j])/2; - len += half[j]*half[j]; - } - len = sqrt(len); - for(unsigned j=0; j<3; ++j) - half[j] /= len; - - // Compute correction factors for smooth interpolation - double cos_half = m1_col[0]*half[0]+m1_col[1]*half[1]+m1_col[2]*half[2]; - double angle = acos(cos_half); - tkf.axes[i].slope = (angle ? angle/tan(angle) : 1); - tkf.axes[i].scale = cos_half; + half[i] = (axis1[i]+axis2[i])/2; + 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); + slope = (angle ? angle/tan(angle) : 1); + scale = cos_half; } -Matrix Animation::compute_matrix(const TimedKeyFrame &tkf, const Time::TimeDelta &dt) const + +Animation::MatrixInterpolation::MatrixInterpolation(): + matrix1(0), + matrix2(0) +{ } + +Animation::MatrixInterpolation::MatrixInterpolation(const Matrix &m1, const Matrix &m2): + matrix1(&m1), + matrix2(&m2) { - if(!dt) - return tkf.keyframe->get_matrix(); - if(!tkf.prev) - throw invalid_argument("Animation::compute_matrix"); - const TimedKeyFrame &prev = *tkf.prev; + const double *m1_data = matrix1->data(); + const double *m2_data = matrix2->data(); + for(unsigned i=0; i<3; ++i) + axes[i] = AxisInterpolation(m1_data+i*4, m2_data+i*4); +} - float t = dt/tkf.delta_t; +Matrix Animation::MatrixInterpolation::get(float t) const +{ float u = t*2.0f-1.0f; double matrix[16]; - const double *m1_data = prev.keyframe->get_matrix().data(); - const double *m2_data = tkf.keyframe->get_matrix().data(); for(unsigned i=0; i<4; ++i) { - const double *m1_col = m1_data+i*4; - const double *m2_col = m2_data+i*4; + const double *m1_col = matrix1->data()+i*4; + const double *m2_col = matrix2->data()+i*4; double *out_col = matrix+i*4; if(i<3) @@ -91,13 +100,13 @@ Matrix Animation::compute_matrix(const TimedKeyFrame &tkf, const Time::TimeDelta around the halfway point and computing its tangent. This is approximated by a third degree polynomial, scaled so that the result will be in the range [-1, 1]. */ - float w = (tkf.axes[i].slope+(1-tkf.axes[i].slope)*u*u)*u*0.5f+0.5f; + 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 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. */ - float n = (tkf.axes[i].scale+(1-tkf.axes[i].scale)*u*u); + float n = (axes[i].scale+(1-axes[i].scale)*u*u); for(unsigned j=0; j<3; ++j) out_col[j] = ((1-w)*m1_col[j]+w*m2_col[j])/n; @@ -118,11 +127,17 @@ Matrix Animation::compute_matrix(const TimedKeyFrame &tkf, const Time::TimeDelta } -Animation::AxisInterpolation::AxisInterpolation(): - slope(0), - scale(0) +Animation::TimedKeyFrame::TimedKeyFrame(const Animation &a): + animation(a), + prev(0) { } +void Animation::TimedKeyFrame::prepare() +{ + delta_t = time-prev->time; + matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix()); +} + Animation::Iterator::Iterator(const Animation &a): animation(a), @@ -158,7 +173,10 @@ Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t) Matrix Animation::Iterator::get_matrix() const { - return animation.compute_matrix(*iter, time_since_keyframe); + if(!iter->prev) + return iter->keyframe->get_matrix(); + + return iter->matrix.get(time_since_keyframe/iter->delta_t); } @@ -192,7 +210,7 @@ void Animation::Loader::keyframe_inline() RefPtr kf = new KeyFrame; load_sub(*kf); - TimedKeyFrame tkf; + TimedKeyFrame tkf(obj); tkf.time = current_time; tkf.keyframe = kf; obj.prepare_keyframe(tkf);