Simulant  21.12-1292
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
window.h
1 /* * Copyright (c) 2011-2017 Luke Benstead https://simulant-engine.appspot.com
2  *
3  * This file is part of Simulant.
4  *
5  * Simulant is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Simulant is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with Simulant. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef SIMULANT_WINDOW_BASE_H
20 #define SIMULANT_WINDOW_BASE_H
21 
22 #include <memory>
23 
24 #include "logging.h"
25 
26 #include "generic/property.h"
27 #include "generic/object_manager.h"
28 #include "generic/data_carrier.h"
29 
30 #include "input/input_state.h"
31 #include "types.h"
32 #include "loader.h"
33 #include "event_listener.h"
34 #include "stats_recorder.h"
35 #include "screen.h"
36 
37 namespace smlt {
38 
39 class AssetManager;
40 class InputManager;
41 
42 namespace ui {
43  class Interface;
44 }
45 
46 namespace scenes {
47  class Loading;
48 }
49 
50 class Application;
51 class InputState;
52 class Compositor;
53 class SceneImpl;
54 class Renderer;
55 class Panel;
56 class SoundDriver;
57 class StageNode;
58 
59 typedef sig::signal<void (std::string, Screen*)> ScreenAddedSignal;
60 typedef sig::signal<void (std::string, Screen*)> ScreenRemovedSignal;
61 
62 typedef sig::signal<void ()> FocusLostSignal;
63 typedef sig::signal<void ()> FocusGainedSignal;
64 
65 class Window :
66  public Loadable,
67  public RenderTarget,
68  public EventListenerManager {
69 
70  DEFINE_SIGNAL(ScreenAddedSignal, signal_screen_added);
71  DEFINE_SIGNAL(ScreenRemovedSignal, signal_screen_removed);
72 
73  DEFINE_SIGNAL(FocusLostSignal, signal_focus_lost);
74  DEFINE_SIGNAL(FocusGainedSignal, signal_focus_gained);
75 
76  friend class Screen; /* Screen needs to call render_screen */
77  friend class Application; /* ContextLock stuff */
78 public:
79  typedef std::shared_ptr<Window> ptr;
80 
81  template<typename T>
82  static std::shared_ptr<Window> create(Application* app) {
83  auto window = std::make_shared<T>();
84  window->set_application(app);
85  return window;
86  }
87 
88  virtual ~Window();
89 
90  virtual bool create_window(
91  uint16_t width,
92  uint16_t height,
93  uint8_t bpp,
94  bool fullscreen,
95  bool enable_vsync
96  );
97 
98  virtual void set_title(const std::string& title) = 0;
99  virtual void cursor_position(int32_t& mouse_x, int32_t& mouse_y) = 0;
100  virtual void show_cursor(bool cursor_shown=true) = 0;
101  virtual void lock_cursor(bool cursor_locked=true) = 0;
102 
103  virtual void check_events() = 0;
104 
105  void swap_buffers();
106 
107  uint16_t width() const override { return width_; }
108  uint16_t height() const override { return height_; }
109  bool is_fullscreen() const { return fullscreen_; }
110  bool vsync_enabled() const { return vsync_enabled_; }
111 
112  float aspect_ratio() const;
113 
114  // FIXME: these should be on Application, not Window!
115  void set_logging_level(LogLevel level);
116  LogLevel logging_level() const;
117 
118  void reset();
119 
120  Vec2 coordinate_from_normalized(Ratio rx, Ratio ry) {
121  return Vec2(
122  uint16_t(float(width()) * rx),
123  uint16_t(float(height()) * ry)
124  );
125  }
126 
127  void on_finger_down(
128  TouchPointID touch_id,
129  float normalized_x, float normalized_y, float pressure=1.0
130  );
131 
132  void on_finger_up(
133  TouchPointID touch_id,
134  float normalized_x, float normalized_y
135  );
136 
137  void on_finger_motion(
138  TouchPointID touch_id,
139  float normalized_x, float normalized_y,
140  float dx, float dy // Between -1.0 and +1.0
141  );
142 
143  void on_key_down(KeyboardCode code, ModifierKeyState modifiers);
144  void on_key_up(KeyboardCode code, ModifierKeyState modifiers);
145 
146  void on_game_controller_button_down(GameControllerIndex index, JoystickButton button);
147  void on_game_controller_button_up(GameControllerIndex index, JoystickButton button);
148 
149  void on_mouse_down(MouseID id, uint8_t mouse_button, int32_t x, int32_t y, bool touch_device);
150  void on_mouse_up(MouseID id, uint8_t mouse_button, int32_t x, int32_t y, bool touch_device);
151  void on_mouse_move(MouseID id, int32_t x, int32_t y, bool touch_device);
152 
153  /* Return the number of screens connected */
154  std::size_t screen_count() const;
155 
156  /* Return a specific screen given its name */
157  Screen* screen(const std::string& name) const;
158 
159  void each_screen(std::function<void (std::string, Screen*)> callback);
160 
161  /* Private API for Window subclasses (public for testing)
162  don't call this directly
163  */
164  Screen* _create_screen(
165  const std::string& name,
166  uint16_t width,
167  uint16_t height,
168  ScreenFormat format,
169  uint16_t refresh_rate);
170 
171  void _destroy_screen(const std::string& name);
172 
173  /* Creates the window, but doesn't do any context initialisation */
174  virtual bool _init_window() = 0;
175 
176  /* Initialises any renderer context */
177  virtual bool _init_renderer(Renderer* renderer) = 0;
178 
179  bool initialize_assets_and_devices();
180  void _clean_up();
181 
182  /* Audio listener stuff */
183 
184  /* Returns the current audio listener, or NULL if there
185  * is no explicit audio listener set, and there are no current
186  * render pipelines.
187  *
188  * Behaviour is:
189  *
190  * - Explictly set listener
191  * - Or, First camera of first render pipeline
192  * - Or, NULL
193  */
194  StageNode* audio_listener();
195 
196  /* Sets a stage node explicitly as the audio listener */
197  void set_audio_listener(StageNode* node);
198 
199  /* Returns true if an explicit audio listener is being used */
200  bool has_explicit_audio_listener() const;
201 
203  bool has_context() const { return has_context_; }
204 
206  bool has_focus() const { return has_focus_; }
207 
210  void set_has_focus(bool v=true);
211 
212 protected:
213  std::shared_ptr<Renderer> renderer_;
214 
215  void set_vsync_enabled(bool vsync) {
216  vsync_enabled_ = vsync;
217  }
218 
219  void set_width(uint16_t width) {
220  width_ = width;
221  }
222 
223  void set_height(uint16_t height) {
224  height_ = height;
225  }
226 
227  void set_bpp(uint16_t bpp) {
228  bpp_ = bpp;
229  }
230 
231  void set_fullscreen(bool val) {
232  fullscreen_ = val;
233  }
234 
235  virtual void destroy_window() = 0;
236  virtual void on_application_set(Application* app);
237 
238  Window();
239 
240  void set_has_context(bool value=true);
241  thread::Mutex& context_lock() { return context_lock_; }
242 
243  void set_application(Application* app);
244 
245  void update_screens(float dt);
246  sig::Connection update_conn_;
247 public:
248  void set_escape_to_quit(bool value=true) { escape_to_quit_ = value; }
249  bool escape_to_quit_enabled() const { return escape_to_quit_; }
250 
251 protected:
252  InputState* get_input_state() {
253  return input_state_.get();
254  }
255 
256 private:
257  Application* application_ = nullptr;
258 
259  void create_defaults();
260  virtual void initialize_input_controller(InputState& controller) = 0;
261 
262  bool can_attach_sound_by_id() const { return false; }
263 
264  bool initialized_ = false;
265 
266  uint16_t width_ = 0;
267  uint16_t height_ = 0;
268  uint16_t bpp_ = 0;
269  bool fullscreen_ = false;
270  bool vsync_enabled_ = false;
271 
272  bool escape_to_quit_ = true;
273 
274  bool has_context_ = false;
275  bool has_focus_ = false;
276 
277  /*
278  * Sometimes we need to destroy or recreate the GL context, if that happens while we are rendering in the
279  * main thread, then bad things happen. This lock exists so that we don't destroy the context while we are rendering.
280  * We obtain the lock before rendering, and release it after. Likewise we obtain the lock while destroying the context
281  * (we can use has_context to make sure we don't start rendering when there is no context) */
282  thread::Mutex context_lock_;
283 
284  void destroy() {}
285 
286  std::shared_ptr<smlt::Compositor> compositor_;
287  generic::DataCarrier data_carrier_;
288 
289  virtual std::shared_ptr<SoundDriver> create_sound_driver(const std::string& from_config) = 0;
290 
291  std::shared_ptr<InputState> input_state_;
292  std::shared_ptr<InputManager> input_manager_;
293 
294  std::unordered_map<std::string, Screen::ptr> screens_;
295 
296  /* This is called by Screens to render themselves to devices. Default behaviour is a no-op */
297  virtual void render_screen(Screen* screen, const uint8_t* data, int row_stride) {
298  _S_UNUSED(screen);
299  _S_UNUSED(data);
300  _S_UNUSED(row_stride);
301  }
302 
303  /* To be overridden by subclasses if external screens need some kind of initialization/clean_up */
304  virtual bool initialize_screen(Screen* screen) {
305  _S_UNUSED(screen);
306  return true;
307  }
308 
309  virtual void shutdown_screen(Screen* screen) {
310  _S_UNUSED(screen);
311  }
312 
313  virtual void do_swap_buffers() {}
314 
315  StageNode* audio_listener_ = nullptr;
316 protected:
317  friend class GameController;
318 
319  InputState* _input_state() const { return input_state_.get(); }
320 
321  virtual void game_controller_start_rumble(GameController *controller, RangeValue<0, 1> low_rumble, RangeValue<0, 1> high_rumble, const smlt::Seconds& duration) {
322  _S_UNUSED(controller);
323  _S_UNUSED(low_rumble);
324  _S_UNUSED(high_rumble);
325  _S_UNUSED(duration);
326  }
327 
328  virtual void game_controller_stop_rumble(GameController *controller) {
329  _S_UNUSED(controller);
330  }
331 
332 public:
333  //Read only properties
334  S_DEFINE_PROPERTY(app, &Window::application_);
335  S_DEFINE_PROPERTY(renderer, &Window::renderer_);
336  S_DEFINE_PROPERTY(data, &Window::data_carrier_);
337  S_DEFINE_PROPERTY(input, &Window::input_manager_);
338  S_DEFINE_PROPERTY(input_state, &Window::input_state_);
339  S_DEFINE_PROPERTY(compositor, &Window::compositor_);
340 };
341 
342 }
343 
344 #endif
smlt::Application
Definition: application.h:160
smlt
Definition: animation.cpp:25
smlt::Window
Definition: window.h:68
smlt::Window::reset
void reset()
Window::reset.
Definition: window.cpp:270
smlt::Window::set_has_focus
void set_has_focus(bool v=true)
Definition: window.cpp:153
smlt::RenderTarget
Definition: interfaces.h:27
smlt::Window::has_context
bool has_context() const
Definition: window.h:203
smlt::Loadable
Definition: loadable.h:26
smlt::ModifierKeyState
Definition: event_listener.h:40
smlt::StageNode
Definition: stage_node.h:442
smlt::Screen
Definition: screen.h:20
smlt::Seconds
Definition: types.h:55
smlt::Renderer
Definition: renderer.h:40
smlt::EventListenerManager
Definition: event_listener.h:157
smlt::Window::has_focus
bool has_focus() const
Definition: window.h:206
smlt::Vec2
Definition: vec2.h:16
smlt::sig::signal
Definition: signal.h:330