ST_engine  0.3-ALPHA
window_manager.cpp
1 /* This file is part of the "ST" project.
2  * You may use, distribute or modify this code under the terms
3  * of the GNU General Public License version 2.
4  * See LICENCE.txt in the root directory of the project.
5  *
6  * Author: Maxim Atanasov
7  * E-mail: maxim.atanasov@protonmail.com
8  */
9 
10 #include <window_manager.hpp>
11 #include <SDL.h>
12 #include <SDL_image.h>
13 
14 static bool singleton_initialized = false;
15 
21  singleton_initialized = false;
22  SDL_FreeSurface(icon);
23  SDL_DestroyWindow(window);
24  window = nullptr;
25  SDL_Quit();
26 }
27 
33 window_manager::window_manager(message_bus &gMessageBus, task_manager &gTask_manager, const std::string &window_name)
34  : gMessage_bus(gMessageBus), gTask_manager(gTask_manager) {
35 
36  if (singleton_initialized) {
37  throw std::runtime_error("The window manager cannot be initialized more than once!");
38  } else {
39  singleton_initialized = true;
40  }
41 
42  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
43  fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
44  exit(1);
45  }
46  if (IMG_Init(IMG_INIT_PNG | IMG_INIT_WEBP) < 0) { // NOLINT(hicpp-signed-bitwise)
47  fprintf(stderr, "Failed to initialize SDL_IMG: %s\n", IMG_GetError());
48  exit(1);
49  }
50  //TODO: Max res reported by my 4K TV => 4096x2160 => not widescreen
51  //TODO: List all modes in a dropdown in the UI and allow the player to select the appropriate one.
52  //TODO: Default res, should be the one the OS is currently using
53  SDL_GetDisplayMode(0, 0, &DM);
54  width = static_cast<int16_t>(DM.w);
55  height = static_cast<int16_t>(DM.h);
56  window = SDL_CreateWindow(window_name.c_str(), 0, 0, width, height, SDL_WINDOW_OPENGL);
57  gMessage_bus.send_msg(new message(LOG_INFO, make_data<std::string>(
58  "Current screen resolution is " + std::to_string(width) + "x" + std::to_string(height))));
59  uint32_t screen_width_height = width | (height << 16U); // NOLINT(hicpp-signed-bitwise)
60  gMessage_bus.send_msg(new message(REAL_SCREEN_COORDINATES, screen_width_height));
61 
62  //Load and set icon
63  icon = IMG_Load("levels/icon.png");
64  SDL_SetWindowIcon(window, icon);
65 
66  gMessage_bus.subscribe(SET_FULLSCREEN, &msg_sub);
67  gMessage_bus.subscribe(SET_WINDOW_RESOLUTION, &msg_sub);
68 }
69 
75 void window_manager::update_task(void *mngr) {
76  auto self = static_cast<window_manager *>(mngr);
77  self->handle_messages();
78 }
79 
84 void window_manager::handle_messages() {
85  message *temp = msg_sub.get_next_message();
86  while (temp != nullptr) {
87  switch (temp->msg_name) {
88  case SET_FULLSCREEN: {
89  auto arg = static_cast<bool>(temp->base_data0);
90  set_fullscreen(arg);
91  gMessage_bus.send_msg(new message(FULLSCREEN_STATUS, arg));
92  break;
93  }
94  case SET_WINDOW_BRIGHTNESS: {
95  auto arg = *static_cast<float *>(temp->get_data());
96  set_brightness(arg);
97  gMessage_bus.send_msg(
98  new message(LOG_SUCCESS, make_data<std::string>("Brightness set to: " + std::to_string(arg))));
99  break;
100  }
101  case SET_WINDOW_RESOLUTION: {
102  auto data = temp->base_data0;
103  int16_t new_width = data & 0x0000ffffU;
104  int16_t new_height = (data >> 16U) & 0x0000ffffU;
105  if (new_width != width && new_height != height) {
106  uint32_t screen_width_height = new_width | (new_height << 16U); // NOLINT(hicpp-signed-bitwise)
107  gMessage_bus.send_msg(new message(REAL_SCREEN_COORDINATES, screen_width_height));
108  SDL_SetWindowSize(window, new_width, new_height);
109  width = new_width;
110  height = new_height;
111  SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED,
112  SDL_WINDOWPOS_CENTERED); // NOLINT(hicpp-signed-bitwise)
113  }
114  break;
115  }
116  }
117  delete temp;
118  temp = msg_sub.get_next_message();
119  }
120 }
121 
127  return window;
128 }
129 
134 void window_manager::set_fullscreen(bool arg) {
135 #ifdef _MSC_VER
136  if (arg && !(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)) { // NOLINT(hicpp-signed-bitwise)
137  SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
138  SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
139  } else if (!arg && (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)) { // NOLINT(hicpp-signed-bitwise)
140  SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
141  SDL_SetWindowFullscreen(window, 0);
142  SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
143  SDL_SetWindowFullscreen(window, 0);
144  SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); // NOLINT(hicpp-signed-bitwise)
145  }
146 #else
147  if(arg && !(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)) {
148  SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
149  }
150  else if(!arg && (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)){
151  SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
152  SDL_SetWindowFullscreen(window, 0);
153  SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); // NOLINT(hicpp-signed-bitwise)
154  }
155 #endif
156 }
157 
163 void window_manager::set_brightness(float arg) {
164  SDL_SetWindowBrightness(this->window, arg);
165 }
166 
171  gTask_manager.start_task_lockfree(new ST::task(update_task, this, nullptr));
172 }
An object representing a task to be run by the task manager.
Definition: task.hpp:24
The central messaging system of the engine. All subsystem make extensive use of it.
Definition: message_bus.hpp:29
void subscribe(uint8_t msg, subscriber *sub)
Definition: message_bus.cpp:71
void send_msg(message *msg)
Definition: message_bus.cpp:19
A message object passed around in the message bus. Holds anything created with make_data<>().
Definition: message.hpp:21
void * get_data() const
Definition: message.hpp:80
message * get_next_message()
Definition: subscriber.hpp:39
The Task Manager handles all things multi-threaded in the engine.
void start_task_lockfree(ST::task *arg)
This object is responsible for managing the window.
SDL_Window * get_window()
window_manager(message_bus &gMessageBus, task_manager &gTask_manager, const std::string &window_name)