Animate only those components which are present in Transforms
authorMikko Rasa <tdb@tdb.fi>
Tue, 11 Jun 2019 08:15:09 +0000 (11:15 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 11 Jun 2019 08:15:09 +0000 (11:15 +0300)
This allows different components to have different keyframes, matching
the functionality of various animation software packages.

source/animation.cpp
source/animation.h

index aa3e1b86893b43258ccc6059e62d69ee8c6a0f33..0d0ce75e951176dc3444b29c1b231b7f8c530735 100644 (file)
@@ -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<UniformInfo>::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<TimedKeyFrame>::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<Transform::ComponentMask>(low_bit<<i);
+                       if(any&bit)
+                               create_curve<1>(target, i, ExtractComponent(extract, i, bit));
+               }
        }
 }
 
 template<unsigned N, typename T>
-void Animation::create_curve(CurveTarget target, const T &extract)
+void Animation::create_curve(CurveTarget target, int component, const T &extract)
 {
        typedef typename ValueCurve<N>::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<N>(target, knots));
+       curves.push_back(new ValueCurve<N>(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<unsigned N>
-Animation::ValueCurve<N>::ValueCurve(CurveTarget t, const vector<Knot> &k):
-       Curve(t),
+Animation::ValueCurve<N>::ValueCurve(CurveTarget t, int c, const vector<Knot> &k):
+       Curve(t, c),
        spline(Interpolate::BezierSpline<float, 3, N>(k))
 { }
 
@@ -287,6 +313,29 @@ void Animation::ValueCurve<N>::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<float>::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<float>::from_radians(value.z), Vector3(0, 0, 1));
+               matrix.rotate(Geometry::Angle<float>::from_radians(value.y), Vector3(0, 1, 0));
+               matrix.rotate(Geometry::Angle<float>::from_radians(value.x), Vector3(1, 0, 0));
        }
        else if(target==SCALE)
                matrix.scale(value);
@@ -315,6 +364,17 @@ void Animation::ValueCurve<N>::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<unsigned N>
 bool Animation::ExtractUniform<N>::operator()(const KeyFrame &kf, typename Interpolate::SplineValue<float, N>::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; i<animation->uniform_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;
 }
 
index 011c8558ca52f32659247c263b7cdb17f46359c5..616d0e74e9ab8beadc2c39b4010786d2f57082cb 100644 (file)
@@ -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<float, 3, N> spline;
 
        public:
-               ValueCurve(CurveTarget, const std::vector<Knot> &);
+               ValueCurve(CurveTarget, int, const std::vector<Knot> &);
 
                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<unsigned N>
        struct ExtractUniform
        {
@@ -154,6 +168,7 @@ private:
        bool looping;
        std::vector<UniformInfo> uniforms;
        std::vector<Curve *> 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<unsigned N, typename T>
-       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 &);