]> git.tdb.fi Git - libs/demoscene.git/blobdiff - source/sequencer.h
Allow specifying one-off actions inside segments
[libs/demoscene.git] / source / sequencer.h
index 028c5d5161d5094ffb92bbd0f59b333ecfbabd6b..f8137177bbd73c31d792a5f59299187a49d99fdd 100644 (file)
@@ -3,42 +3,76 @@
 
 #include <vector>
 #include <sigc++/signal.h>
+#include <msp/core/maputils.h>
+#include <msp/core/refptr.h>
+#include <msp/datafile/objectloader.h>
 #include <msp/time/timedelta.h>
 #include <msp/time/timestamp.h>
+#include "action.h"
+
+class Demo;
 
 class Sequencer
 {
 public:
-       class Action
+       class Loader: public Msp::DataFile::ObjectLoader<Sequencer>
        {
-       protected:
-               Action() { }
+       private:
+               Demo &demo;
+
        public:
-               virtual ~Action() { }
+               Loader(Sequencer &, Demo &);
 
-               virtual void start(float, float) { }
-               virtual void beat(int) { }
-               virtual void tick(float, float) { }
-               virtual void end(float) { }
+       private:
+               void define_action(const std::string &);
+               void instant(float);
+               void segment(float, float);
        };
 
-       class InterpolationAction: public Action
+private:
+       class ActionDefLoader;
+       class SegmentLoader;
+
+       class RegisteredAction
        {
-       protected:
-               bool hermite;
-               float start_beat;
-               float duration;
+       public:
+               typedef void (ActionDefLoader::*DefLoaderFunc)();
+               typedef void (SegmentLoader::*LoaderFunc)();
 
-               InterpolationAction(bool = false);
+               virtual ~RegisteredAction() { }
+               virtual DefLoaderFunc get_def_loader_func() const = 0;
+               virtual LoaderFunc get_loader_func() const = 0;
+       };
 
+       template<typename T>
+       class RegisteredActionType: public RegisteredAction
+       {
        public:
-               virtual void start(float, float);
-               virtual void tick(float, float);
-               virtual void end(float);
-               virtual void interpolate(float, float) { }
+               virtual DefLoaderFunc get_def_loader_func() const;
+               virtual LoaderFunc get_loader_func() const;
+       };
+
+       class ActionDefLoader: public Msp::DataFile::ObjectLoader<Sequencer>
+       {
+       private:
+               Demo &demo;
+               Msp::RefPtr<Action> action;
+
+       public:
+               ActionDefLoader(Sequencer &, Demo &);
+
+               Action *get_action() { return action.release(); }
+
+       private:
+               virtual void finished();
+
+               template<typename T>
+               void action_def();
+
+               template<typename T>
+               friend class RegisteredActionType;
        };
 
-private:
        struct Segment
        {
                Action *action;
@@ -46,10 +80,34 @@ private:
                float end_beat;
        };
 
+       class SegmentLoader: public Msp::DataFile::ObjectLoader<Sequencer>
+       {
+       private:
+               float start_beat;
+               float end_beat;
+               Demo &demo;
+
+       public:
+               SegmentLoader(Sequencer &, float, float, Demo &);
+
+       private:
+               template<typename T>
+               void action();
+
+               void apply(const std::string &);
+
+               template<typename T>
+               friend class RegisteredActionType;
+       };
+
 public:
        sigc::signal<void> signal_finished;
 
 private:
+       std::map<std::string, RegisteredAction *> action_types;
+       std::map<std::string, Action *> named_actions;
+       std::vector<Action *> anonymous_actions;
+
        Msp::Time::TimeDelta secs_per_beat;
        std::vector<Action *> static_actions;
        std::vector<Segment> segments;
@@ -62,6 +120,9 @@ private:
 public:
        Sequencer(float = 120.0f);
 
+       template<typename T>
+       void register_action_type(const std::string &);
+
        void set_beats_per_minute(float);
        float get_beats_per_minute() const { return Msp::Time::min/secs_per_beat; }
        void add_static_action(Action &);
@@ -77,4 +138,45 @@ public:
        float get_current_beat() const { return beat; }
 };
 
+template<typename T>
+inline void Sequencer::register_action_type(const std::string &n)
+{
+       if(action_types.count(n))
+               throw Msp::key_error(n);
+
+       action_types[n] = new RegisteredActionType<T>;
+}
+
+template<typename T>
+Sequencer::RegisteredAction::DefLoaderFunc Sequencer::RegisteredActionType<T>::get_def_loader_func() const
+{
+       return &ActionDefLoader::action_def<T>;
+}
+
+template<typename T>
+Sequencer::RegisteredAction::LoaderFunc Sequencer::RegisteredActionType<T>::get_loader_func() const
+{
+       return &SegmentLoader::action<T>;
+}
+
+template<typename T>
+void Sequencer::ActionDefLoader::action_def()
+{
+       if(action)
+               throw std::runtime_error("Only one action per definition is allowed");
+
+       Msp::RefPtr<T> act = new T;
+       load_sub(*act, demo);
+       action = act;
+}
+
+template<typename T>
+void Sequencer::SegmentLoader::action()
+{
+       Msp::RefPtr<T> act = new T;
+       load_sub(*act, demo);
+       obj.add_action(*act, start_beat, end_beat);
+       obj.anonymous_actions.push_back(act.release());
+}
+
 #endif