]> git.tdb.fi Git - libs/demoscene.git/blob - source/sequencer.h
Allow specifying one-off actions inside segments
[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/objectloader.h>
9 #include <msp/time/timedelta.h>
10 #include <msp/time/timestamp.h>
11 #include "action.h"
12
13 class Demo;
14
15 class Sequencer
16 {
17 public:
18         class Loader: public Msp::DataFile::ObjectLoader<Sequencer>
19         {
20         private:
21                 Demo &demo;
22
23         public:
24                 Loader(Sequencer &, Demo &);
25
26         private:
27                 void define_action(const std::string &);
28                 void instant(float);
29                 void segment(float, float);
30         };
31
32 private:
33         class ActionDefLoader;
34         class SegmentLoader;
35
36         class RegisteredAction
37         {
38         public:
39                 typedef void (ActionDefLoader::*DefLoaderFunc)();
40                 typedef void (SegmentLoader::*LoaderFunc)();
41
42                 virtual ~RegisteredAction() { }
43                 virtual DefLoaderFunc get_def_loader_func() const = 0;
44                 virtual LoaderFunc get_loader_func() const = 0;
45         };
46
47         template<typename T>
48         class RegisteredActionType: public RegisteredAction
49         {
50         public:
51                 virtual DefLoaderFunc get_def_loader_func() const;
52                 virtual LoaderFunc get_loader_func() const;
53         };
54
55         class ActionDefLoader: public Msp::DataFile::ObjectLoader<Sequencer>
56         {
57         private:
58                 Demo &demo;
59                 Msp::RefPtr<Action> action;
60
61         public:
62                 ActionDefLoader(Sequencer &, Demo &);
63
64                 Action *get_action() { return action.release(); }
65
66         private:
67                 virtual void finished();
68
69                 template<typename T>
70                 void action_def();
71
72                 template<typename T>
73                 friend class RegisteredActionType;
74         };
75
76         struct Segment
77         {
78                 Action *action;
79                 float start_beat;
80                 float end_beat;
81         };
82
83         class SegmentLoader: public Msp::DataFile::ObjectLoader<Sequencer>
84         {
85         private:
86                 float start_beat;
87                 float end_beat;
88                 Demo &demo;
89
90         public:
91                 SegmentLoader(Sequencer &, float, float, Demo &);
92
93         private:
94                 template<typename T>
95                 void action();
96
97                 void apply(const std::string &);
98
99                 template<typename T>
100                 friend class RegisteredActionType;
101         };
102
103 public:
104         sigc::signal<void> signal_finished;
105
106 private:
107         std::map<std::string, RegisteredAction *> action_types;
108         std::map<std::string, Action *> named_actions;
109         std::vector<Action *> anonymous_actions;
110
111         Msp::Time::TimeDelta secs_per_beat;
112         std::vector<Action *> static_actions;
113         std::vector<Segment> segments;
114         std::vector<Segment>::const_iterator begin;
115         std::vector<Segment>::const_iterator end;
116         bool started;
117         float beat;
118         float next_event;
119
120 public:
121         Sequencer(float = 120.0f);
122
123         template<typename T>
124         void register_action_type(const std::string &);
125
126         void set_beats_per_minute(float);
127         float get_beats_per_minute() const { return Msp::Time::min/secs_per_beat; }
128         void add_static_action(Action &);
129         void add_action(Action &, float, float);
130
131         void start();
132         void seek(float);
133         void tick(const Msp::Time::TimeDelta &);
134 private:
135         void advance_to(float);
136         void update_next_event();
137 public:
138         float get_current_beat() const { return beat; }
139 };
140
141 template<typename T>
142 inline void Sequencer::register_action_type(const std::string &n)
143 {
144         if(action_types.count(n))
145                 throw Msp::key_error(n);
146
147         action_types[n] = new RegisteredActionType<T>;
148 }
149
150 template<typename T>
151 Sequencer::RegisteredAction::DefLoaderFunc Sequencer::RegisteredActionType<T>::get_def_loader_func() const
152 {
153         return &ActionDefLoader::action_def<T>;
154 }
155
156 template<typename T>
157 Sequencer::RegisteredAction::LoaderFunc Sequencer::RegisteredActionType<T>::get_loader_func() const
158 {
159         return &SegmentLoader::action<T>;
160 }
161
162 template<typename T>
163 void Sequencer::ActionDefLoader::action_def()
164 {
165         if(action)
166                 throw std::runtime_error("Only one action per definition is allowed");
167
168         Msp::RefPtr<T> act = new T;
169         load_sub(*act, demo);
170         action = act;
171 }
172
173 template<typename T>
174 void Sequencer::SegmentLoader::action()
175 {
176         Msp::RefPtr<T> act = new T;
177         load_sub(*act, demo);
178         obj.add_action(*act, start_beat, end_beat);
179         obj.anonymous_actions.push_back(act.release());
180 }
181
182 #endif