19 #ifndef SCENE_MANAGER_H
20 #define SCENE_MANAGER_H
22 #include <unordered_map>
25 #include "../threads/future.h"
28 #include "../generic/managed.h"
29 #include "../signals/signal.h"
31 #include "../generic/static_if.h"
32 #include "../coroutines/helpers.h"
38 typedef std::shared_ptr<Scene> ScenePtr;
39 typedef std::function<ScenePtr (Window*)> SceneFactory;
41 typedef sig::signal<void (std::string, Scene*)> SceneActivatedSignal;
42 typedef sig::signal<void (std::string, Scene*)> SceneDeactivatedSignal;
45 enum ActivateBehaviour {
46 ACTIVATE_BEHAVIOUR_UNLOAD_FIRST,
47 ACTIVATE_BEHAVIOUR_UNLOAD_AFTER
60 static void unpack(std::vector<any>& output, T&& arg) {
61 output.push_back(std::forward<T>(arg));
64 template<
typename T,
typename... Args>
65 static void unpack(std::vector<any>& output, T&& t, Args&& ...args) {
66 output.push_back(std::forward<T>(t));
67 unpack(output, std::forward<Args>(args)...);
70 template<
typename... Args>
71 static void unpack(std::vector<any>&) {}
73 struct ConnectionHolder {
77 template<
typename... Args>
80 ActivateBehaviour behaviour,
83 auto new_scene = get_or_create_route(route);
84 if(new_scene != current_scene_) {
85 if(behaviour == ACTIVATE_BEHAVIOUR_UNLOAD_AFTER) {
86 if(!new_scene->is_loaded()) {
87 new_scene->load_args.clear();
88 unpack(new_scene->load_args, std::forward<Args>(args)...);
92 auto previous = current_scene_;
95 previous->deactivate();
96 signal_scene_deactivated_(previous->name(), previous.get());
99 std::swap(current_scene_, new_scene);
100 current_scene_->activate();
102 if(previous && previous->unload_on_deactivate()) {
104 unload(previous->name());
108 auto previous = current_scene_;
111 previous->deactivate();
112 signal_scene_deactivated_(previous->name(), previous.get());
113 if(previous->unload_on_deactivate()) {
114 unload(previous->name());
118 if(!new_scene->is_loaded()) {
119 new_scene->load_args.clear();
120 unpack(new_scene->load_args, std::forward<Args>(args)...);
124 std::swap(current_scene_, new_scene);
125 current_scene_->activate();
128 signal_scene_activated_(route, new_scene.get());
132 template<
typename D,
typename T,
typename...Args>
133 static ScenePtr make_scene(
const D& deleter, Args&&... args) {
134 return std::shared_ptr<T>(
new T(std::forward<Args>(args)...), deleter);
138 static void deleter(T* obj) {
147 bool has_scene(
const std::string& route)
const;
148 ScenePtr resolve_scene(
const std::string& route);
150 template<
typename... Args>
152 const std::string& route, ActivateBehaviour behaviour,
155 scene_activation_trigger_ = std::bind(
156 &SceneManager::do_activate<Args&...>,
157 this, route, behaviour, std::forward<Args>(args)...
161 template<
typename... Args>
162 void activate(
const std::string& route, Args&& ...args) {
163 activate(route, ACTIVATE_BEHAVIOUR_UNLOAD_FIRST, std::forward<Args>(args)...);
166 template<
typename ...Args>
167 void preload(
const std::string& route, Args&& ...args) {
168 auto scene = get_or_create_route(route);
170 if(scene->is_loaded()) {
174 scene->load_args.clear();
175 unpack(scene->load_args, std::forward<Args>(args)...);
180 template<
typename ...Args>
181 void _preload_in_background(ScenePtr scene, Args&& ...args) {
182 if(scene->is_loaded()) {
186 scene->load_args.clear();
187 unpack(scene->load_args, std::forward<Args>(args)...);
191 template<
typename ...Args>
193 const std::string& route,
197 auto scene = get_or_create_route(route);
201 &SceneManager::_preload_in_background<Args&...>,
204 std::forward<Args>(args)...
209 void unload(
const std::string& route);
213 void clean_destroyed_scenes();
215 bool is_loaded(
const std::string& route)
const;
218 ScenePtr active_scene()
const;
220 bool scene_queued_for_activation()
const;
222 template<
typename T,
typename... Args>
223 void register_scene(
const std::string& name, Args&&... args) {
224 SceneFactory func = std::bind(
225 &SceneManager::make_scene<decltype(&SceneManager::deleter<T>), T,
Window*,
typename std::decay<Args>::type&...>,
226 &SceneManager::deleter<T>, std::placeholders::_1, std::forward<Args>(args)...
229 _store_scene_factory(name, [=](
Window* window) -> ScenePtr {
230 auto ret = func(window);
232 S_ERROR(
"Failed to initialize the Scene");
237 ret->scene_manager_ =
this;
243 void register_scene(
const std::string& name) {
244 _store_scene_factory(name, [=](
Window* window) -> ScenePtr {
245 auto ret = SceneManager::make_scene<decltype(&SceneManager::deleter<T>), T>(&SceneManager::deleter, window);
247 ret->scene_manager_ =
this;
250 S_ERROR(
"Failed to initialize the Scene");
259 std::shared_ptr<T> resolve_scene_as(
const std::string& route) {
260 return std::dynamic_pointer_cast<T>(resolve_scene(route));
263 void _store_scene_factory(
const std::string& name, SceneFactory func) {
264 scene_factories_[name] = func;
269 std::unordered_map<std::string, SceneFactory> scene_factories_;
270 std::unordered_map<std::string, ScenePtr> routes_;
272 ScenePtr current_scene_;
273 ScenePtr get_or_create_route(
const std::string& route);
275 struct BackgroundTask {
284 void update(
float dt);
285 void late_update(
float dt);
286 void fixed_update(
float step);
288 std::function<void ()> scene_activation_trigger_;
289 std::set<std::string> routes_queued_for_destruction_;
294 #endif // SCENE_MANAGER_H