]> git.tdb.fi Git - libs/demoscene.git/blob - source/sequencer.h
Use LoadableTypeRegistry to manage action types in Sequencer
[libs/demoscene.git] / source / sequencer.h
1 #ifndef MSP_DEMOSCENE_SEQUENCER_H_
2 #define MSP_DEMOSCENE_SEQUENCER_H_
3
4 #include <vector>
5 #include <sigc++/signal.h>
6 #include <msp/core/maputils.h>
7 #include <msp/core/refptr.h>
8 #include <msp/datafile/loadabletyperegistry.h>
9 #include <msp/datafile/objectloader.h>
10 #include <msp/time/timedelta.h>
11 #include <msp/time/timestamp.h>
12 #include "action.h"
13
14 namespace Msp {
15 namespace DemoScene {
16
17 class Demo;
18
19 class Sequencer
20 {
21 public:
22         class Loader: public Msp::DataFile::ObjectLoader<Sequencer>
23         {
24         private:
25                 Demo &demo;
26                 float base_beat;
27
28         public:
29                 Loader(Sequencer &, Demo &);
30
31         private:
32                 void base(float);
33                 void define_action(const std::string &);
34                 void instant(float);
35                 void repeat(float, float, unsigned);
36                 void segment(float, float);
37         };
38
39 private:
40         class ActionDefLoader: public Msp::DataFile::ObjectLoader<Sequencer>
41         {
42         protected:
43                 template<typename T>
44                 struct AddAction
45                 {
46                         static void add(ActionDefLoader &ldr, const std::string &kw) { ldr.add(kw, &ActionDefLoader::action_def<T>); }
47                 };
48
49                 Demo &demo;
50                 Msp::RefPtr<Action> action;
51
52         public:
53                 ActionDefLoader(Sequencer &, Demo &);
54
55                 Action *get_action() { return action.release(); }
56
57         protected:
58                 virtual void action_loaded() { }
59
60         private:
61                 template<typename T>
62                 void action_def();
63
64                 friend class Sequencer;
65         };
66
67         struct Segment
68         {
69                 Action *action;
70                 float start_beat;
71                 float end_beat;
72         };
73
74         class SegmentLoader: public ActionDefLoader
75         {
76         private:
77                 float start_beat;
78                 float end_beat;
79
80         public:
81                 SegmentLoader(Sequencer &, float, float, Demo &);
82
83         private:
84                 virtual void action_loaded();
85
86                 void apply(const std::string &);
87         };
88
89 public:
90         sigc::signal<void> signal_finished;
91
92 private:
93         DataFile::LoadableTypeRegistry<ActionDefLoader, ActionDefLoader::AddAction> action_registry;
94         std::map<std::string, Action *> named_actions;
95         std::vector<Action *> anonymous_actions;
96
97         Msp::Time::TimeDelta secs_per_beat;
98         std::vector<Action *> static_actions;
99         std::vector<Segment> segments;
100         std::vector<Segment>::const_iterator begin;
101         std::vector<Segment>::const_iterator end;
102         bool started;
103         float beat;
104         float next_event;
105
106 public:
107         Sequencer(float = 120.0f);
108
109         template<typename T>
110         void register_action_type(const std::string &);
111
112         void set_beats_per_minute(float);
113         float get_beats_per_minute() const { return Msp::Time::min/secs_per_beat; }
114         void add_static_action(Action &);
115         void add_action(Action &, float, float);
116
117         void start();
118         void seek(float);
119         void tick(const Msp::Time::TimeDelta &);
120 private:
121         void advance_to(float);
122         void update_next_event();
123 public:
124         float get_current_beat() const { return beat; }
125 };
126
127 template<typename T>
128 inline void Sequencer::register_action_type(const std::string &n)
129 {
130         action_registry.register_type<T>(n);
131 }
132
133 template<typename T>
134 void Sequencer::ActionDefLoader::action_def()
135 {
136         if(action)
137                 throw std::runtime_error("Only one action per definition is allowed");
138
139         Msp::RefPtr<T> act = new T;
140         load_sub(*act, demo);
141         act->validate();
142         action = act.release();
143         action_loaded();
144 }
145
146 } // namespace DemoScene
147 } // namespace Msp
148
149 #endif