]> git.tdb.fi Git - libs/demoscene.git/blob - source/sequencer.h
Allow stages to define actions
[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         void define_action(const std::string &, Action &);
112
113         void set_beats_per_minute(float);
114         float get_beats_per_minute() const { return Msp::Time::min/secs_per_beat; }
115         void add_static_action(Action &);
116         void add_action(Action &, float, float);
117
118         void start();
119         void seek(float);
120         void tick(const Msp::Time::TimeDelta &);
121 private:
122         void advance_to(float);
123         void update_next_event();
124 public:
125         float get_current_beat() const { return beat; }
126 };
127
128 template<typename T>
129 inline void Sequencer::register_action_type(const std::string &n)
130 {
131         action_registry.register_type<T>(n);
132 }
133
134 template<typename T>
135 void Sequencer::ActionDefLoader::action_def()
136 {
137         if(action)
138                 throw std::runtime_error("Only one action per definition is allowed");
139
140         Msp::RefPtr<T> act = new T;
141         load_sub(*act, demo);
142         act->validate();
143         action = act.release();
144         action_loaded();
145 }
146
147 } // namespace DemoScene
148 } // namespace Msp
149
150 #endif