X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fanimation.cpp;h=e82a92a87ce4811b3e465b345e6f5477d1c61f27;hp=1e2dda900fafc0d580bf84cb648772ccf7747ac3;hb=9319f1c8ed99866966f20fbab952da673af2257e;hpb=e3abc10ca3fb04d58db22b01f44981841ae39182 diff --git a/source/animation.cpp b/source/animation.cpp index 1e2dda90..e82a92a8 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -3,6 +3,7 @@ #include #include #include "animation.h" +#include "animationeventobserver.h" #include "armature.h" #include "error.h" #include "pose.h" @@ -43,26 +44,51 @@ 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, ss, es); +} + +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() && t=keyframes.capacity()); + + keyframes.push_back(TimedKeyFrame()); + TimedKeyFrame &tkf = keyframes.back(); tkf.time = t; - tkf.keyframe = &kf; - tkf.keyframe.keep(); - prepare_keyframe(tkf); - keyframes.push_back(tkf); -} + tkf.start_slope = ss; + tkf.end_slope = es; + tkf.keyframe = kf; -void Animation::set_looping(bool l) -{ - looping = l; + if(realloc) + { + for(unsigned i=1; i1 && t>(&tkf-1)->time) + tkf.prev = &tkf-1; + + prepare_keyframe(tkf); } void Animation::prepare_keyframe(TimedKeyFrame &tkf) { - tkf.prev = (keyframes.empty() ? 0 : &keyframes.back()); - const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms(); for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i) { @@ -79,7 +105,29 @@ void Animation::prepare_keyframe(TimedKeyFrame &tkf) uniforms.push_back(UniformInfo(i->first, i->second.size)); } - tkf.prepare(); + tkf.prepare(*this); +} + +void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v) +{ + Event event; + event.time = t; + event.name = n; + event.value = v; + 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; } @@ -91,18 +139,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; @@ -170,12 +219,13 @@ Matrix Animation::MatrixInterpolation::get(float t) const } -Animation::TimedKeyFrame::TimedKeyFrame(const Animation &a): - animation(a), - prev(0) +Animation::TimedKeyFrame::TimedKeyFrame(): + prev(0), + start_slope(1), + end_slope(1) { } -void Animation::TimedKeyFrame::prepare() +void Animation::TimedKeyFrame::prepare(const Animation &animation) { const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms(); for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i) @@ -218,22 +268,27 @@ Animation::UniformInfo::UniformInfo(const string &n, unsigned s): Animation::Iterator::Iterator(const Animation &a): - animation(a), - iter(animation.keyframes.begin()), + 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) { time_since_keyframe += t; while(time_since_keyframe>iter->delta_t) { - KeyFrameList::const_iterator next = iter; + vector::const_iterator next = iter; ++next; - if(next==animation.keyframes.end()) + if(next==animation->keyframes.end()) { - if(animation.looping) - next = animation.keyframes.begin(); + if(animation->looping) + next = animation->keyframes.begin(); else { end = true; @@ -246,15 +301,36 @@ 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; } +void Animation::Iterator::dispatch_events(AnimationEventObserver &observer) +{ + vector::const_iterator events_end = animation->events.end(); + if(end) + { + for(; event_iter!=events_end; ++event_iter) + observer.animation_event(0, event_iter->name, event_iter->value); + } + else if(event_iter!=events_end) + { + Time::TimeDelta t = time_since_keyframe; + if(iter->prev) + t += iter->prev->time; + for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter) + observer.animation_event(0, event_iter->name, event_iter->value); + } +} + 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 @@ -264,22 +340,21 @@ KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const if(iter->uniforms.size()>i) return iter->uniforms[i]; else - return KeyFrame::AnimatedUniform(animation.uniforms[i].size, 0.0f); + return KeyFrame::AnimatedUniform(animation->uniforms[i].size, 0.0f); } - unsigned size = animation.uniforms[i].size; - float t = time_since_keyframe/iter->delta_t; + unsigned size = animation->uniforms[i].size; 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; } Matrix Animation::Iterator::get_pose_matrix(unsigned link) const { - if(!animation.armature) + if(!animation->armature) throw invalid_operation("Animation::Iterator::get_pose_matrix"); - if(link>animation.armature->get_max_link_index()) + if(link>animation->armature->get_max_link_index()) throw out_of_range("Animation::Iterator::get_pose_matrix"); if(!iter->prev) @@ -290,10 +365,10 @@ Matrix Animation::Iterator::get_pose_matrix(unsigned link) const return Matrix(); } - // We must redo the base point correction since interpolation throws if off + // 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); - const Vector3 &base = animation.armature->get_link(link).get_base(); + 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; return result; @@ -314,16 +389,62 @@ 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); + add("event", &Loader::event1f); + add("event", &Loader::event2f); + add("event", &Loader::event3f); + add("event", &Loader::event4f); add("interval", &Loader::interval); add("keyframe", &Loader::keyframe); add("keyframe", &Loader::keyframe_inline); add("looping", &Animation::looping); + add("slopes", &Loader::slopes); +} + +void Animation::Loader::event(const string &n) +{ + obj.add_event(current_time, n); +} + +void Animation::Loader::event1i(const string &n, int v) +{ + obj.add_event(current_time, n, v); +} + +void Animation::Loader::event1f(const string &n, float v) +{ + obj.add_event(current_time, n, v); +} + +void Animation::Loader::event2f(const string &n, float v0, float v1) +{ + obj.add_event(current_time, n, LinAl::Vector(v0, v1)); +} + +void Animation::Loader::event3f(const string &n, float v0, float v1, float v2) +{ + obj.add_event(current_time, n, Vector3(v0, v1, v2)); +} + +void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3) +{ + obj.add_event(current_time, n, Vector4(v0, v1, v2, v3)); +} + +void Animation::Loader::interval(float t) +{ + current_time += t*Time::sec; } 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() @@ -334,16 +455,15 @@ void Animation::Loader::keyframe_inline() else load_sub(*kf); - TimedKeyFrame tkf(obj); - tkf.time = current_time; - tkf.keyframe = kf; - obj.prepare_keyframe(tkf); - obj.keyframes.push_back(tkf); + obj.add_keyframe(current_time, kf, start_slope, end_slope); + start_slope = end_slope; + end_slope = 1; } -void Animation::Loader::interval(float t) +void Animation::Loader::slopes(float s, float e) { - current_time += t*Time::sec; + start_slope = s; + end_slope = e; } } // namespace GL