X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fanimation.cpp;h=6c9e179dc749dc16642b5b755f6afd7e36fecf2b;hp=e633aae502dfc0fa59f938b3add23e5ef5357604;hb=a9c375e17065bcc429b430bd8211a9ee845159a5;hpb=00cc52f21b5ae29fb1b25c162552c851a0559e66 diff --git a/source/animation.cpp b/source/animation.cpp index e633aae5..6c9e179d 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include "animation.h" #include "animationeventobserver.h" #include "armature.h" @@ -24,6 +23,8 @@ Animation::~Animation() void Animation::set_armature(const Armature &a) { + if(!keyframes.empty() && &a!=armature) + throw invalid_operation("Animation::set_armature"); armature = &a; } @@ -43,30 +44,50 @@ const string &Animation::get_uniform_name(unsigned i) const } void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf) +{ + add_keyframe(t, kf, 1.0f, 1.0f); +} + +void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope) +{ + add_keyframe(t, kf, slope, slope); +} + +void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es) { RefPtr kfr(&kf); kfr.keep(); - add_keyframe(t, kfr); + add_keyframe(t, kfr, ss, es); } -void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr &kf) +void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr &kf, float ss, float es) { + if(keyframes.empty() && t!=Time::zero) + throw invalid_argument("Animation::add_keyframe"); if(!keyframes.empty() && tget_pose() && armature && kf->get_pose()->get_armature()!=armature) + throw invalid_argument("Animation::add_keyframe"); bool realloc = (keyframes.size()>=keyframes.capacity()); + if(kf->get_pose() && !armature) + armature = kf->get_pose()->get_armature(); + keyframes.push_back(TimedKeyFrame()); TimedKeyFrame &tkf = keyframes.back(); tkf.time = t; + tkf.start_slope = ss; + tkf.end_slope = es; tkf.keyframe = kf; if(realloc) { for(unsigned i=1; i1) + if(keyframes.size()>1 && t>(&tkf-1)->time) tkf.prev = &tkf-1; prepare_keyframe(tkf); @@ -102,6 +123,14 @@ void Animation::add_event(const Time::TimeDelta &t, const string &n, const Varia events.push_back(event); } +const Time::TimeDelta &Animation::get_duration() const +{ + if(keyframes.empty()) + return Time::zero; + + return keyframes.back().time; +} + void Animation::set_looping(bool l) { looping = l; @@ -116,18 +145,19 @@ Animation::AxisInterpolation::AxisInterpolation(): Animation::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2) { // Compute a normalized vector halfway between the two endpoints - float half[3]; float a1_len = 0; float h_len = 0; + float cos_half = 0; for(unsigned i=0; i<3; ++i) { - half[i] = (axis1[i]+axis2[i])/2; + float half_i = (axis1[i]+axis2[i])/2; + cos_half += axis1[i]*half_i; a1_len += axis1[i]*axis1[i]; - h_len += half[i]*half[i]; + h_len += half_i*half_i; } // Compute correction factors for smooth interpolation - float cos_half = (axis1[0]*half[0]+axis1[1]*half[1]+axis1[2]*half[2])/sqrt(a1_len*h_len); + cos_half = min(max(cos_half/sqrt(a1_len*h_len), -1.0f), 1.0f); float angle = acos(cos_half); slope = (angle ? angle/tan(angle) : 1); scale = cos_half; @@ -196,7 +226,9 @@ Matrix Animation::MatrixInterpolation::get(float t) const Animation::TimedKeyFrame::TimedKeyFrame(): - prev(0) + prev(0), + start_slope(1), + end_slope(1) { } void Animation::TimedKeyFrame::prepare(const Animation &animation) @@ -245,8 +277,12 @@ Animation::Iterator::Iterator(const Animation &a): animation(&a), iter(animation->keyframes.begin()), event_iter(animation->events.begin()), + x(0), end(false) -{ } +{ + if(iter==animation->keyframes.end()) + throw invalid_argument("Animation::Iterator::Iterator"); +} Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t) { @@ -271,6 +307,9 @@ Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t) iter = next; } + x = time_since_keyframe/iter->delta_t; + x += (iter->start_slope-1)*((x-2)*x+1)*x + (1-iter->end_slope)*(1-x)*x*x; + return *this; } @@ -297,7 +336,7 @@ Matrix Animation::Iterator::get_matrix() const if(!iter->prev) return iter->keyframe->get_matrix(); - return iter->matrix.get(time_since_keyframe/iter->delta_t); + return iter->matrix.get(x); } KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const @@ -311,10 +350,9 @@ KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const } 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; + result.values[j] = iter->prev->uniforms[i].values[j]*(1-x)+iter->uniforms[i].values[j]*x; return result; } @@ -335,7 +373,7 @@ Matrix Animation::Iterator::get_pose_matrix(unsigned link) const // We must redo the base point correction since interpolation throws it off // XXX This should probably be done on local matrices - Matrix result = iter->pose_matrices[link].get(time_since_keyframe/iter->delta_t); + Matrix result = iter->pose_matrices[link].get(x); const Vector3 &base = animation->armature->get_link(link).get_base(); Vector3 new_base = result*base; result = Matrix::translation(base-new_base)*result; @@ -357,6 +395,8 @@ Animation::Loader::Loader(Animation &a, Collection &c): void Animation::Loader::init() { + start_slope = 1; + end_slope = 1; add("armature", &Animation::armature); add("event", &Loader::event); add("event", &Loader::event1i); @@ -368,6 +408,7 @@ void Animation::Loader::init() add("keyframe", &Loader::keyframe); add("keyframe", &Loader::keyframe_inline); add("looping", &Animation::looping); + add("slopes", &Loader::slopes); } void Animation::Loader::event(const string &n) @@ -407,7 +448,9 @@ void Animation::Loader::interval(float t) void Animation::Loader::keyframe(const string &n) { - obj.add_keyframe(current_time, get_collection().get(n)); + obj.add_keyframe(current_time, get_collection().get(n), start_slope, end_slope); + start_slope = end_slope; + end_slope = 1; } void Animation::Loader::keyframe_inline() @@ -418,7 +461,15 @@ void Animation::Loader::keyframe_inline() else load_sub(*kf); - obj.add_keyframe(current_time, kf); + obj.add_keyframe(current_time, kf, start_slope, end_slope); + start_slope = end_slope; + end_slope = 1; +} + +void Animation::Loader::slopes(float s, float e) +{ + start_slope = s; + end_slope = e; } } // namespace GL