X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fanimation.cpp;h=aa3e1b86893b43258ccc6059e62d69ee8c6a0f33;hp=dbdd05bafd741262910b1832a10a8590dd1ce88b;hb=77ad5a1a89aa43d9a3c8c58abff1ae184510cec6;hpb=025016d7628be9c43b20999325dcbaae5cb3c3b8 diff --git a/source/animation.cpp b/source/animation.cpp index dbdd05ba..aa3e1b86 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "animation.h" #include "animationeventobserver.h" #include "armature.h" @@ -46,24 +46,78 @@ 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); + add_keyframe(t, &kf, false, false); + create_curves(); } void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope) { - add_keyframe(t, kf, slope, slope); + add_keyframe(t, &kf, slope, slope, false); + create_curves(); } 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); + add_keyframe(t, &kf, ss, es, false); create_curves(); } -void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr &kf, float ss, float es) +void Animation::add_control_keyframe(const KeyFrame &kf) +{ + if(keyframes.empty()) + throw invalid_operation("Animation::add_control_keyframe"); + + add_keyframe(keyframes.back().time, &kf, true, false); +} + +void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame *kf, float ss, float es, bool owned) { + if(keyframes.empty()) + return add_keyframe(t, kf, false, owned); + + if(keyframes.back().control) + throw invalid_operation("Animation::add_keyframe"); + + const KeyFrame &last = *keyframes.back().keyframe; + const Transform &trn = kf->get_transform(); + const Transform &last_trn = last.get_transform(); + const KeyFrame::UniformMap &kf_unis = kf->get_uniforms(); + const KeyFrame::UniformMap &last_unis = last.get_uniforms(); + for(unsigned i=1; i<=2; ++i) + { + float x = (i==1 ? ss/3 : 1-es/3); + KeyFrame *ckf = new KeyFrame; + Transform ctrn; + ctrn.set_position(last_trn.get_position()*(1-x)+trn.get_position()*x); + const Transform::AngleVector3 &e1 = last_trn.get_euler(); + const Transform::AngleVector3 &e2 = trn.get_euler(); + ctrn.set_euler(Transform::AngleVector3(e1.x*(1-x)+e2.x*x, e1.y*(1-x)+e2.y*x, e1.z*(1-x)+e2.z*x)); + ctrn.set_scale(last_trn.get_scale()*(1-x)+trn.get_scale()*x); + ckf->set_transform(ctrn); + + for(KeyFrame::UniformMap::const_iterator j=kf_unis.begin(); j!=kf_unis.end(); ++j) + { + KeyFrame::UniformMap::const_iterator k = last_unis.find(j->first); + if(k==last_unis.end()) + continue; + + KeyFrame::AnimatedUniform uni(j->second.size, 0.0f); + for(unsigned c=0; csecond.values[c]*(1-x)+j->second.values[c]*x; + + ckf->set_uniform(j->first, uni); + } + + add_keyframe(t, ckf, true, true); + } + + add_keyframe(t, kf, false, owned); +} + +void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame *kf, bool c, bool owned) +{ + if(c && keyframes.empty()) + throw invalid_argument("Animation::add_keyframe"); if(keyframes.empty() && t!=Time::zero) throw invalid_argument("Animation::add_keyframe"); if(!keyframes.empty() && t::Knot Knot; - vector positions; - vector eulers; - vector scales; - for(vector::const_iterator i=keyframes.begin(); i!=keyframes.end(); ++i) - { - positions.push_back(Knot(i->time/Time::sec, i->keyframe->get_transform().get_position())); - const Transform::AngleVector3 &euler = i->keyframe->get_transform().get_euler(); - eulers.push_back(Knot(i->time/Time::sec, Vector3(euler.x.radians(), euler.y.radians(), euler.z.radians()))); - scales.push_back(Knot(i->time/Time::sec, i->keyframe->get_transform().get_scale())); - } - curves.reserve(3+uniforms.size()); - curves.push_back(new ValueCurve<3>(POSITION, positions)); - curves.push_back(new ValueCurve<3>(EULER, eulers)); - curves.push_back(new ValueCurve<3>(SCALE, scales)); + create_curve<3>(POSITION, &extract_position); + create_curve<3>(EULER, &extract_euler); + create_curve<3>(SCALE, &extract_scale); for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) { if(i->size==1) - create_uniform_curve<1>(i->name); + create_curve<1>(UNIFORM, ExtractUniform<1>(i->name)); else if(i->size==2) - create_uniform_curve<2>(i->name); + create_curve<2>(UNIFORM, ExtractUniform<2>(i->name)); else if(i->size==3) - create_uniform_curve<3>(i->name); + create_curve<3>(UNIFORM, ExtractUniform<3>(i->name)); else if(i->size==4) - create_uniform_curve<4>(i->name); + create_curve<4>(UNIFORM, ExtractUniform<4>(i->name)); } } -template -void Animation::create_uniform_curve(const string &name) +template +void Animation::create_curve(CurveTarget target, const T &extract) { typedef typename ValueCurve::Knot Knot; vector knots; + unsigned n_control = 0; for(vector::const_iterator i=keyframes.begin(); i!=keyframes.end(); ++i) { - const KeyFrame::UniformMap &kf_uniforms = i->keyframe->get_uniforms(); - const KeyFrame::UniformMap::const_iterator j = kf_uniforms.find(name); - if(j!=kf_uniforms.end()) - knots.push_back(Knot(i->time/Time::sec, Interpolate::SplineValue::make(j->second.values))); + if(i->control && knots.empty()) + continue; + + typename Interpolate::SplineValue::Type value; + if(extract(*i->keyframe, value)) + { + float x = i->time/Time::sec; + if(i->control) + { + ++n_control; + if(n_control>2) + throw logic_error("too many control keyframes"); + } + else + { + if(n_control==1) + { + typename Knot::Value cv = knots.back().y; + knots.back().y = (knots[knots.size()-2].y+cv*2.0f)/3.0f; + knots.push_back(Knot(x, (value+cv*2.0f)/3.0f)); + } + else if(n_control==0 && !knots.empty()) + { + typename Knot::Value prev = knots.back().y; + knots.push_back(Knot(knots.back().x, (prev*2.0f+value)/3.0f)); + knots.push_back(Knot(x, (prev+value*2.0f)/3.0f)); + } + n_control = 0; + } + knots.push_back(Knot(x, value)); + } } + + while(n_control--) + knots.pop_back(); + + curves.push_back(new ValueCurve(target, knots)); +} - curves.push_back(new ValueCurve(UNIFORM, knots)); +bool Animation::extract_position(const KeyFrame &kf, Vector3 &value) +{ + value = kf.get_transform().get_position(); + return true; +} + +bool Animation::extract_euler(const KeyFrame &kf, Vector3 &value) +{ + const Transform::AngleVector3 &euler = kf.get_transform().get_euler(); + value = Vector3(euler.x.radians(), euler.y.radians(), euler.z.radians()); + return true; +} + +bool Animation::extract_scale(const KeyFrame &kf, Vector3 &value) +{ + value = kf.get_transform().get_scale(); + return true; } void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v) @@ -185,7 +278,7 @@ Animation::Curve::Curve(CurveTarget t): template Animation::ValueCurve::ValueCurve(CurveTarget t, const vector &k): Curve(t), - spline(Interpolate::LinearSpline(k)) + spline(Interpolate::BezierSpline(k)) { } template @@ -222,6 +315,19 @@ void Animation::ValueCurve::apply(float x, KeyFrame::AnimatedUniform &uni) co } +template +bool Animation::ExtractUniform::operator()(const KeyFrame &kf, typename Interpolate::SplineValue::Type &value) const +{ + const KeyFrame::UniformMap &kf_uniforms = kf.get_uniforms(); + const KeyFrame::UniformMap::const_iterator i = kf_uniforms.find(name); + if(i==kf_uniforms.end()) + return false; + + value = Interpolate::SplineValue::make(i->second.values); + return true; +} + + Animation::UniformInfo::UniformInfo(const string &n, unsigned s): name(n), size(s) @@ -307,7 +413,10 @@ void Animation::Loader::init() { start_slope = 1; end_slope = 1; + slopes_set = 0; add("armature", &Animation::armature); + add("control_keyframe", &Loader::control_keyframe); + add("control_keyframe", &Loader::control_keyframe_inline); add("event", &Loader::event); add("event", &Loader::event1i); add("event", &Loader::event1f); @@ -326,6 +435,55 @@ void Animation::Loader::finish() obj.create_curves(); } +void Animation::Loader::check_slopes_and_control(bool s, bool c) +{ + if(s && c) + throw logic_error("can't use both slopes and control keyframes in same segment"); +} + +void Animation::Loader::add_kf(const KeyFrame *kf, bool c, bool owned) +{ + if(slopes_set && !c) + obj.add_keyframe(current_time, kf, start_slope, end_slope, owned); + else + obj.add_keyframe(current_time, kf, c, owned); + + start_slope = end_slope; + end_slope = 1; + slopes_set = (slopes_set<<1)&3; +} + +void Animation::Loader::load_kf(const string &n, bool c) +{ + add_kf(&get_collection().get(n), c, false); +} + +void Animation::Loader::load_kf_inline(bool c) +{ + RefPtr kf = new KeyFrame; + if(coll) + load_sub(*kf, get_collection()); + else + load_sub(*kf); + + add_kf(kf.get(), c, true); + kf.release(); +} + +void Animation::Loader::control_keyframe(const string &n) +{ + slopes_set &= 1; + check_slopes_and_control(slopes_set, true); + load_kf(n, true); +} + +void Animation::Loader::control_keyframe_inline() +{ + slopes_set &= 1; + check_slopes_and_control(slopes_set, true); + load_kf_inline(true); +} + void Animation::Loader::event(const string &n) { obj.add_event(current_time, n); @@ -363,28 +521,21 @@ void Animation::Loader::interval(float t) void Animation::Loader::keyframe(const string &n) { - obj.add_keyframe(current_time, get_collection().get(n), start_slope, end_slope); - start_slope = end_slope; - end_slope = 1; + load_kf(n, false); } void Animation::Loader::keyframe_inline() { - RefPtr kf = new KeyFrame; - if(coll) - load_sub(*kf, get_collection()); - else - load_sub(*kf); - - obj.add_keyframe(current_time, kf, start_slope, end_slope); - start_slope = end_slope; - end_slope = 1; + load_kf_inline(false); } void Animation::Loader::slopes(float s, float e) { + check_slopes_and_control(true, (!obj.keyframes.empty() && obj.keyframes.back().control)); + start_slope = s; end_slope = e; + slopes_set = 1; } } // namespace GL