ge211
ge211_engine.cpp
1 #include "ge211_engine.h"
2 #include "ge211_base.h"
3 #include "ge211_render.h"
4 #include "ge211_sprites.h"
5 
6 #include <SDL.h>
7 #include "../3rdparty/utf8-cpp/utf8.h"
8 
9 #include <algorithm>
10 #include <cstring>
11 
12 namespace ge211 {
13 
14 namespace detail {
15 
16 // Used to control the frame rate if we have to fallback to
17 // software rendering, or for when the window is hidden (and
18 // vsync stops working).
19 static const int software_fps = 60;
20 static const Duration software_frame_length = Duration(1) / software_fps;
21 static const Duration min_frame_length = software_frame_length / 2;
22 
23 Engine::Engine(Abstract_game& game)
24  : game_{game},
25  window_{game_.initial_window_title(), game_.initial_window_dimensions()},
26  renderer_{window_}
27 {
28  game_.engine_ = this;
29 }
30 
31 Engine::~Engine()
32 {
33  game_.engine_ = nullptr;
34 }
35 
36 void Engine::prepare(const sprites::Sprite& sprite) const
37 {
38  sprite.prepare(renderer_);
39 }
40 
41 void Engine::run()
42 {
43  SDL_Event e;
44  Sprite_set sprites;
45 
46  bool has_vsync = renderer_.is_vsync();
47 
48  try {
49  game_.on_start();
50 
51  while (!game_.quit_) {
52  handle_events_(e);
53  game_.on_frame(game_.get_prev_frame_length().seconds());
54  if (game_.mixer_) game_.mixer_->poll_channels_();
55  game_.draw(sprites);
56 
57  renderer_.set_color(game_.background_color);
58  renderer_.clear();
59  paint_sprites_(sprites);
60  renderer_.present();
61 
62  Duration allowed_frame_length =
63  (is_focused_ && has_vsync)?
64  min_frame_length : software_frame_length;
65 
66  auto frame_length = game_.frame_start_.elapsed_time();
67  if (frame_length < allowed_frame_length) {
68  auto duration = allowed_frame_length - frame_length;
69  duration.sleep_for();
70  game_.mark_frame_();
71  debug() << "Software vsync slept for "
72  << duration.seconds() << " s";
73  } else {
74  game_.mark_frame_();
75  }
76  }
77 
78  game_.on_quit();
79  } catch (const Exception_base& e) {
80  fatal() << "Uncaught exception:\n " << e.what();
81  exit(1);
82  }
83 }
84 
85 void Engine::handle_events_(SDL_Event& e)
86 {
87  while (SDL_PollEvent(&e) != 0) {
88  switch (e.type) {
89  case SDL_QUIT:
90  game_.quit();
91  break;
92 
93  case SDL_TEXTINPUT: {
94  const char* str = e.text.text;
95  const char* end = str + std::strlen(str);
96 
97  while (str < end) {
98  uint32_t code = utf8::next(str, end);
99  if (code) game_.on_key(Key{code});
100  }
101 
102  break;
103  }
104 
105  case SDL_KEYDOWN: {
106  Key key(e.key);
107  if (!e.key.repeat) {
108  game_.on_key_down(key);
109  }
110  if (!key.is_textual()) {
111  game_.on_key(key);
112  }
113  break;
114  }
115 
116  case SDL_KEYUP:
117  game_.on_key_up(Key{e.key});
118  break;
119 
120  case SDL_MOUSEBUTTONDOWN: {
121  Mouse_button button;
122  if (map_button(e.button.button, button))
123  game_.on_mouse_down(button, {e.button.x, e.button.y});
124  break;
125  }
126 
127  case SDL_MOUSEBUTTONUP: {
128  Mouse_button button;
129  if (map_button(e.button.button, button))
130  game_.on_mouse_up(button, {e.button.x, e.button.y});
131  break;
132  }
133 
134  case SDL_MOUSEMOTION:
135  game_.on_mouse_move({e.motion.x, e.motion.y});
136  break;
137 
138  case SDL_WINDOWEVENT:
139  switch (e.window.event) {
140  case SDL_WINDOWEVENT_FOCUS_GAINED:
141  is_focused_ = true;
142  break;
143 
144  case SDL_WINDOWEVENT_FOCUS_LOST:
145  is_focused_ = false;
146  break;
147 
148  default:
149  ;
150  }
151  break;
152 
153  default:
154  ;
155  }
156  }
157 }
158 
159 void Engine::paint_sprites_(Sprite_set& sprite_set)
160 {
161  auto& sprites = sprite_set.sprites_;
162  std::make_heap(sprites.begin(), sprites.end());
163 
164  while (!sprites.empty()) {
165  std::pop_heap(sprites.begin(), sprites.end());
166  sprites.back().render(renderer_);
167  sprites.pop_back();
168  }
169 }
170 
171 Window& Engine::get_window() noexcept
172 {
173  return window_;
174 }
175 
176 } // end namespace detail
177 
178 }
Mouse_button
A representation of a mouse button.
Definition: ge211_event.h:18
The game engine namespace.
Definition: ge211.h:17