From 553f3ec4fbe28a37978ee53b9b6e22fedb691e1d Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 11 Jun 2019 11:15:09 +0300 Subject: [PATCH] Animate only those components which are present in Transforms This allows different components to have different keyframes, matching the functionality of various animation software packages. --- source/animation.cpp | 98 +++++++++++++++++++++++++++++++++++--------- source/animation.h | 22 ++++++++-- 2 files changed, 98 insertions(+), 22 deletions(-) diff --git a/source/animation.cpp b/source/animation.cpp index aa3e1b86..0d0ce75e 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -162,26 +162,51 @@ void Animation::create_curves() delete *i; curves.clear(); - curves.reserve(3+uniforms.size()); - create_curve<3>(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; @@ -225,7 +250,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) @@ -270,14 +295,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)) { } @@ -287,6 +313,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 { @@ -295,9 +344,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); @@ -315,6 +364,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 { @@ -371,7 +431,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; } @@ -382,7 +442,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; } diff --git a/source/animation.h b/source/animation.h index 011c8558..616d0e74 100644 --- a/source/animation.h +++ b/source/animation.h @@ -69,8 +69,9 @@ private: { protected: CurveTarget target; + int component; - Curve(CurveTarget); + Curve(CurveTarget, int); public: virtual ~Curve() { } @@ -88,12 +89,25 @@ private: Interpolate::Spline spline; public: - ValueCurve(CurveTarget, const std::vector &); + ValueCurve(CurveTarget, int, const std::vector &); virtual void apply(float, Matrix &) const; virtual void apply(float, KeyFrame::AnimatedUniform &) const; }; + struct ExtractComponent + { + typedef bool (*Extract)(const KeyFrame &, Vector3 &); + + Extract extract; + unsigned index; + Transform::ComponentMask mask; + + ExtractComponent(Extract e, unsigned i, Transform::ComponentMask m): extract(e), index(i), mask(m) { } + + bool operator()(const KeyFrame &, float &) const; + }; + template struct ExtractUniform { @@ -154,6 +168,7 @@ private: bool looping; std::vector uniforms; std::vector curves; + unsigned uniform_curve_offset; public: Animation(); @@ -175,8 +190,9 @@ private: void add_keyframe(const Time::TimeDelta &, const KeyFrame *, bool, bool); void prepare_keyframe(TimedKeyFrame &); void create_curves(); + void create_curve(CurveTarget, Transform::ComponentMask, ExtractComponent::Extract); template - void create_curve(CurveTarget target, const T &); + void create_curve(CurveTarget target, int, const T &); static bool extract_position(const KeyFrame &, Vector3 &); static bool extract_euler(const KeyFrame &, Vector3 &); static bool extract_scale(const KeyFrame &, Vector3 &); -- 2.43.0