X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fanimation.cpp;h=0e4bd3e6ff26c26a4e4b7204c487fa6715148be7;hp=c58a33d818f5d588a4ced081d35c1ec56ba2f23c;hb=f88bce7df357cf12ce20b7dc8c7d179d2ae95920;hpb=49f1812b3e5ad73748015df52d0e4dee17246036 diff --git a/source/animation.cpp b/source/animation.cpp index c58a33d8..0e4bd3e6 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -46,20 +46,26 @@ const string &Animation::get_uniform_name(unsigned i) const void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf) { - RefPtr kfr(&kf); - kfr.keep(); - add_keyframe(t, kfr, false); + add_keyframe(t, &kf, false, false); + create_curves(); +} + +void Animation::add_keyframe_owned(const Time::TimeDelta &t, const KeyFrame *kf) +{ + add_keyframe(t, kf, false, true); 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, float) +void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es) { - add_keyframe(t, kf); + add_keyframe(t, &kf, ss, es, false); + create_curves(); } void Animation::add_control_keyframe(const KeyFrame &kf) @@ -67,12 +73,62 @@ void Animation::add_control_keyframe(const KeyFrame &kf) if(keyframes.empty()) throw invalid_operation("Animation::add_control_keyframe"); - RefPtr kfr(&kf); - kfr.keep(); - add_keyframe(keyframes.back().time, kfr, true); + add_keyframe(keyframes.back().time, &kf, true, false); +} + +void Animation::add_control_keyframe_owned(const KeyFrame *kf) +{ + if(keyframes.empty()) + throw invalid_operation("Animation::add_control_keyframe_owned"); + + add_keyframe(keyframes.back().time, kf, true, true); +} + +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 RefPtr &kf, bool c) +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"); @@ -97,6 +153,8 @@ void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr(POSITION, &extract_position); - create_curve<3>(EULER, &extract_euler); - create_curve<3>(SCALE, &extract_scale); + curves.reserve(6+uniforms.size()); + create_curve(POSITION, Transform::POSITION, &extract_position); + create_curve(EULER, Transform::EULER, &extract_euler); + create_curve(SCALE, Transform::SCALE, &extract_scale); + uniform_curve_offset = curves.size(); for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) { if(i->size==1) - create_curve<1>(UNIFORM, ExtractUniform<1>(i->name)); + create_curve<1>(UNIFORM, -1, ExtractUniform<1>(i->name)); else if(i->size==2) - create_curve<2>(UNIFORM, ExtractUniform<2>(i->name)); + create_curve<2>(UNIFORM, -1, ExtractUniform<2>(i->name)); else if(i->size==3) - create_curve<3>(UNIFORM, ExtractUniform<3>(i->name)); + create_curve<3>(UNIFORM, -1, ExtractUniform<3>(i->name)); else if(i->size==4) - create_curve<4>(UNIFORM, ExtractUniform<4>(i->name)); + create_curve<4>(UNIFORM, -1, ExtractUniform<4>(i->name)); + } +} + +void Animation::create_curve(CurveTarget target, Transform::ComponentMask mask, ExtractComponent::Extract extract) +{ + Transform::ComponentMask all = mask; + Transform::ComponentMask any = Transform::NONE; + for(vector::const_iterator i=keyframes.begin(); i!=keyframes.end(); ++i) + { + all = all&i->keyframe->get_transform().get_mask(); + any = any|i->keyframe->get_transform().get_mask(); + } + + if(all==mask) + create_curve<3>(target, -1, extract); + else if(any&mask) + { + unsigned low_bit = mask&(mask>>2); + for(unsigned i=3; i-->0; ) + { + Transform::ComponentMask bit = static_cast(low_bit<(target, i, ExtractComponent(extract, i, bit)); + } } } template -void Animation::create_curve(CurveTarget target, const T &extract) +void Animation::create_curve(CurveTarget target, int component, const T &extract) { typedef typename ValueCurve::Knot Knot; @@ -181,7 +264,7 @@ void Animation::create_curve(CurveTarget target, const T &extract) while(n_control--) knots.pop_back(); - curves.push_back(new ValueCurve(target, knots)); + curves.push_back(new ValueCurve(target, component, knots)); } bool Animation::extract_position(const KeyFrame &kf, Vector3 &value) @@ -226,14 +309,15 @@ void Animation::set_looping(bool l) } -Animation::Curve::Curve(CurveTarget t): - target(t) +Animation::Curve::Curve(CurveTarget t, int c): + target(t), + component(c) { } template -Animation::ValueCurve::ValueCurve(CurveTarget t, const vector &k): - Curve(t), +Animation::ValueCurve::ValueCurve(CurveTarget t, int c, const vector &k): + Curve(t, c), spline(Interpolate::BezierSpline(k)) { } @@ -243,6 +327,29 @@ void Animation::ValueCurve::apply(float, Matrix &) const throw invalid_operation("ValueCurve::apply"); } +template<> +void Animation::ValueCurve<1>::apply(float x, Matrix &matrix) const +{ + float value = spline(x); + if(target==POSITION || target==SCALE) + { + Vector3 vec; + vec[component] = value; + if(target==POSITION) + matrix.translate(vec); + else + matrix.scale(vec); + } + else if(target==EULER) + { + Vector3 vec; + vec[component] = 1.0f; + matrix.rotate(Geometry::Angle::from_radians(value), vec); + } + else + throw invalid_operation("ValueCurve::apply"); +} + template<> void Animation::ValueCurve<3>::apply(float x, Matrix &matrix) const { @@ -251,9 +358,9 @@ void Animation::ValueCurve<3>::apply(float x, Matrix &matrix) const matrix.translate(value); else if(target==EULER) { - matrix.rotate(value.z, Vector3(0, 0, 1)); - matrix.rotate(value.y, Vector3(0, 1, 0)); - matrix.rotate(value.x, Vector3(1, 0, 0)); + matrix.rotate(Geometry::Angle::from_radians(value.z), Vector3(0, 0, 1)); + matrix.rotate(Geometry::Angle::from_radians(value.y), Vector3(0, 1, 0)); + matrix.rotate(Geometry::Angle::from_radians(value.x), Vector3(1, 0, 0)); } else if(target==SCALE) matrix.scale(value); @@ -271,6 +378,17 @@ void Animation::ValueCurve::apply(float x, KeyFrame::AnimatedUniform &uni) co } +bool Animation::ExtractComponent::operator()(const KeyFrame &kf, float &value) const +{ + Vector3 vec; + if(!extract(kf, vec)) + return false; + + value = vec[index]; + return kf.get_transform().get_mask()&mask; +} + + template bool Animation::ExtractUniform::operator()(const KeyFrame &kf, typename Interpolate::SplineValue::Type &value) const { @@ -327,7 +445,7 @@ void Animation::Iterator::dispatch_events(AnimationEventObserver &observer) Matrix Animation::Iterator::get_matrix() const { Matrix matrix; - for(unsigned i=0; i<3; ++i) + for(unsigned i=0; iuniform_curve_offset; ++i) animation->curves[i]->apply(elapsed/Time::sec, matrix); return matrix; } @@ -338,7 +456,7 @@ KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const throw out_of_range("Animation::Iterator::get_uniform"); KeyFrame::AnimatedUniform uni(animation->uniforms[i].size, 0.0f); - animation->curves[3+i]->apply(elapsed/Time::sec, uni); + animation->curves[animation->uniform_curve_offset+i]->apply(elapsed/Time::sec, uni); return uni; } @@ -369,6 +487,7 @@ 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); @@ -390,9 +509,27 @@ 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) { - obj.add_keyframe(current_time, get_collection().get(n), c); + add_kf(&get_collection().get(n), c, false); } void Animation::Loader::load_kf_inline(bool c) @@ -403,16 +540,21 @@ void Animation::Loader::load_kf_inline(bool c) else load_sub(*kf); - obj.add_keyframe(current_time, kf, c); + 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); } @@ -463,8 +605,11 @@ void Animation::Loader::keyframe_inline() 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