--- /dev/null
+#ifndef MSP_GL_ANIMATION_H_
+#define MSP_GL_ANIMATION_H_
+
+#include <msp/core/refptr.h>
+#include <msp/datafile/objectloader.h>
+#include <msp/interpolate/spline.h>
+#include <msp/time/timedelta.h>
+#include "keyframe.h"
+
+namespace Msp {
+namespace GL {
+
+class AnimationEventObserver;
+class Armature;
+class Matrix;
+class Pose;
+
+/**
+An Animation is a sequence of KeyFrames combined with timing information. The
+state at any point in the animation can be interpolated from the keyframes.
+*/
+class Animation
+{
+public:
+ class Loader: public DataFile::CollectionObjectLoader<Animation>
+ {
+ private:
+ Time::TimeDelta current_time;
+ float start_slope;
+ float end_slope;
+ int slopes_set;
+
+ public:
+ Loader(Animation &);
+ Loader(Animation &, Collection &);
+ private:
+ void init();
+ virtual void finish();
+
+ void check_slopes_and_control(bool, bool);
+ void add_kf(const KeyFrame *, bool, bool);
+ void load_kf(const std::string &, bool);
+ void load_kf_inline(bool);
+
+ void control_keyframe(const std::string &);
+ void control_keyframe_inline();
+ void event(const std::string &);
+ void event1i(const std::string &, int);
+ void event1f(const std::string &, float);
+ void event2f(const std::string &, float, float);
+ void event3f(const std::string &, float, float, float);
+ void event4f(const std::string &, float, float, float, float);
+ void interval(float);
+ void keyframe(const std::string &);
+ void keyframe_inline();
+ void slopes(float, float);
+ };
+
+private:
+ enum CurveTarget
+ {
+ POSITION,
+ EULER,
+ SCALE,
+ UNIFORM
+ };
+
+ class Curve
+ {
+ protected:
+ CurveTarget target;
+ int component;
+
+ Curve(CurveTarget, int);
+ public:
+ virtual ~Curve() { }
+
+ virtual void apply(float, Matrix &) const = 0;
+ virtual void apply(float, KeyFrame::AnimatedUniform &) const = 0;
+ };
+
+ template<unsigned N>
+ class ValueCurve: public Curve
+ {
+ public:
+ typedef typename Interpolate::SplineKnot<double, N> Knot;
+
+ private:
+ Interpolate::Spline<double, 3, N> spline;
+
+ public:
+ 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
+ {
+ const std::string &name;
+
+ ExtractUniform(const std::string &n): name(n) { }
+
+ bool operator()(const KeyFrame &, typename Interpolate::SplineValue<float, N>::Type &) const;
+ };
+
+ struct TimedKeyFrame
+ {
+ Time::TimeDelta time;
+ RefPtr<const KeyFrame> keyframe;
+ bool control;
+ };
+
+ struct Event
+ {
+ Time::TimeDelta time;
+ std::string name;
+ Variant value;
+ };
+
+ struct UniformInfo
+ {
+ std::string name;
+ unsigned size;
+
+ UniformInfo(const std::string &, unsigned);
+ };
+
+public:
+ class Iterator
+ {
+ private:
+ const Animation *animation;
+ Time::TimeDelta elapsed;
+ std::vector<Event>::const_iterator event_iter;
+ bool end;
+
+ public:
+ Iterator(const Animation &);
+
+ Iterator &operator+=(const Time::TimeDelta &);
+ void dispatch_events(AnimationEventObserver &);
+
+ bool is_end() const { return end; }
+ Matrix get_matrix() const;
+ KeyFrame::AnimatedUniform get_uniform(unsigned) const;
+ Matrix get_pose_matrix(unsigned) const;
+ };
+
+private:
+ const Armature *armature;
+ std::vector<TimedKeyFrame> keyframes;
+ std::vector<Event> events;
+ bool looping;
+ std::vector<UniformInfo> uniforms;
+ std::vector<Curve *> curves;
+ unsigned uniform_curve_offset;
+
+public:
+ Animation();
+ ~Animation();
+
+ void set_armature(const Armature &);
+ const Armature *get_armature() const { return armature; }
+
+ unsigned get_n_uniforms() const { return uniforms.size(); }
+ unsigned get_slot_for_uniform(const std::string &) const;
+ const std::string &get_uniform_name(unsigned) const;
+
+ void add_keyframe(const Time::TimeDelta &, const KeyFrame &);
+ void add_keyframe_owned(const Time::TimeDelta &, const KeyFrame *);
+ DEPRECATED void add_keyframe(const Time::TimeDelta &, const KeyFrame &, float);
+ DEPRECATED void add_keyframe(const Time::TimeDelta &, const KeyFrame &, float, float);
+ void add_control_keyframe(const KeyFrame &);
+ void add_control_keyframe_owned(const KeyFrame *);
+private:
+ void add_keyframe(const Time::TimeDelta &, const KeyFrame *, float, float, bool);
+ 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, int, const T &);
+ static bool extract_position(const KeyFrame &, Vector3 &);
+ static bool extract_euler(const KeyFrame &, Vector3 &);
+ static bool extract_scale(const KeyFrame &, Vector3 &);
+public:
+ void add_event(const Time::TimeDelta &, const std::string &, const Variant & = Variant());
+
+ const Msp::Time::TimeDelta &get_duration() const;
+
+ void set_looping(bool);
+ bool is_looping() const { return looping; }
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif