Antkeeper  0.0.1
sdl-window.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
21 #include <engine/config.hpp>
22 #include <engine/debug/log.hpp>
23 #include <engine/gl/pipeline.hpp>
24 #include <glad/gl.h>
25 #include <stdexcept>
26 
27 namespace app {
28 
30 (
31  const std::string& title,
32  const math::ivec2& windowed_position,
33  const math::ivec2& windowed_size,
34  bool maximized,
35  bool fullscreen,
36  bool v_sync
37 )
38 {
39  // Determine SDL window creation flags
40  Uint32 window_flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
41  if (maximized)
42  {
43  window_flags |= SDL_WINDOW_MAXIMIZED;
44  }
45  if (fullscreen)
46  {
47  window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
48  }
49 
50  // Create SDL window
51  debug::log_trace("Creating SDL window...");
52  m_internal_window = SDL_CreateWindow
53  (
54  title.c_str(),
55  windowed_position.x(),
56  windowed_position.y(),
57  windowed_size.x(),
58  windowed_size.y(),
59  window_flags
60  );
61  if (!m_internal_window)
62  {
63  debug::log_fatal("Failed to create SDL window: {}", SDL_GetError());
64  throw std::runtime_error("Failed to create SDL window");
65  }
66  debug::log_trace("Created SDL window");
67 
68  // Create OpenGL context
69  debug::log_trace("Creating OpenGL context...");
70  m_internal_context = SDL_GL_CreateContext(m_internal_window);
71  if (!m_internal_context)
72  {
73  debug::log_fatal("Failed to create OpenGL context: {}", SDL_GetError());
74  throw std::runtime_error("Failed to create OpenGL context");
75  }
76  debug::log_trace("Created OpenGL context");
77 
78  // Query OpenGL context info
79  int opengl_context_version_major = -1;
80  int opengl_context_version_minor = -1;
81  int opengl_context_red_size = -1;
82  int opengl_context_green_size = -1;
83  int opengl_context_blue_size = -1;
84  int opengl_context_alpha_size = -1;
85  int opengl_context_depth_size = -1;
86  int opengl_context_stencil_size = -1;
87  SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &opengl_context_version_major);
88  SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &opengl_context_version_minor);
89  SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &opengl_context_red_size);
90  SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &opengl_context_green_size);
91  SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &opengl_context_blue_size);
92  SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &opengl_context_alpha_size);
93  SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &opengl_context_depth_size);
94  SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &opengl_context_stencil_size);
95 
96  // Log OpenGL context info
98  (
99  "OpenGL context version: {}.{}; format: R{}G{}B{}A{}D{}S{}",
100  opengl_context_version_major,
101  opengl_context_version_minor,
102  opengl_context_red_size,
103  opengl_context_green_size,
104  opengl_context_blue_size,
105  opengl_context_alpha_size,
106  opengl_context_depth_size,
107  opengl_context_stencil_size
108  );
109 
110  // Compare OpenGL context version with requested version
111  if (opengl_context_version_major != config::opengl_version_major ||
112  opengl_context_version_minor != config::opengl_version_minor)
113  {
114  debug::log_warning("Requested OpenGL context version {}.{} but got version {}.{}", config::opengl_version_major, config::opengl_version_minor, opengl_context_version_major, opengl_context_version_minor);
115  }
116 
117  // Compare OpenGL context format with requested format
118  if (opengl_context_red_size < config::opengl_min_red_size ||
119  opengl_context_green_size < config::opengl_min_green_size ||
120  opengl_context_blue_size < config::opengl_min_blue_size ||
121  opengl_context_alpha_size < config::opengl_min_alpha_size ||
122  opengl_context_depth_size < config::opengl_min_depth_size ||
123  opengl_context_stencil_size < config::opengl_min_stencil_size)
124  {
126  (
127  "OpenGL context format (R{}G{}B{}A{}D{}S{}) does not meet minimum requested format (R{}G{}B{}A{}D{}S{})",
128  opengl_context_red_size,
129  opengl_context_green_size,
130  opengl_context_blue_size,
131  opengl_context_alpha_size,
132  opengl_context_depth_size,
133  opengl_context_stencil_size,
134  config::opengl_min_red_size,
135  config::opengl_min_green_size,
136  config::opengl_min_blue_size,
137  config::opengl_min_alpha_size,
138  config::opengl_min_depth_size,
139  config::opengl_min_stencil_size
140  );
141  }
142 
143  // Load OpenGL functions via GLAD
144  debug::log_trace("Loading OpenGL functions...");
145  if (!gladLoadGL(reinterpret_cast<GLADloadfunc>(SDL_GL_GetProcAddress)))
146  {
147  debug::log_fatal("Failed to load OpenGL functions", SDL_GetError());
148  throw std::runtime_error("Failed to load OpenGL functions");
149  }
150  debug::log_trace("Loaded OpenGL functions");
151 
152  // Log OpenGL information
154  (
155  "OpenGL vendor: {}; renderer: {}; version: {}; shading language version: {}",
156  reinterpret_cast<const char*>(glGetString(GL_VENDOR)),
157  reinterpret_cast<const char*>(glGetString(GL_RENDERER)),
158  reinterpret_cast<const char*>(glGetString(GL_VERSION)),
159  reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION))
160  );
161 
162  // Allocate graphics pipeline
163  m_graphics_pipeline = std::make_unique<gl::pipeline>();
164 
165  // Clear default framebuffer to black
166  m_graphics_pipeline->clear_attachments(gl::color_clear_bit, {{0.0f, 0.0f, 0.0f, 0.0f}});
167  swap_buffers();
168 
169  // Enable or disable v-sync
170  set_v_sync(v_sync);
171 
172  // Update window state
173  this->m_title = title;
174  this->m_windowed_position = windowed_position;
175  this->m_windowed_size = windowed_size;
176  this->m_maximized = maximized;
177  this->m_fullscreen = fullscreen;
178  SDL_GetWindowPosition(m_internal_window, &this->m_position.x(), &this->m_position.y());
179  SDL_GetWindowSize(m_internal_window, &this->m_size.x(), &this->m_size.y());
180  SDL_GetWindowMinimumSize(m_internal_window, &this->m_minimum_size.x(), &this->m_minimum_size.y());
181  SDL_GetWindowMaximumSize(m_internal_window, &this->m_maximum_size.x(), &this->m_maximum_size.y());
182  SDL_GL_GetDrawableSize(m_internal_window, &this->m_viewport_size.x(), &this->m_viewport_size.y());
183 }
184 
186 {
187  // Deallocate graphics pipeline
188  m_graphics_pipeline.reset();
189 
190  // Destruct the OpenGL context
191  SDL_GL_DeleteContext(m_internal_context);
192 
193  // Destruct the SDL window
194  SDL_DestroyWindow(m_internal_window);
195 }
196 
197 void sdl_window::set_title(const std::string& title)
198 {
199  SDL_SetWindowTitle(m_internal_window, title.c_str());
200  this->m_title = title;
201 }
202 
204 {
205  SDL_SetWindowPosition(m_internal_window, position.x(), position.y());
206 }
207 
209 {
210  SDL_SetWindowSize(m_internal_window, size.x(), size.y());
211 }
212 
214 {
215  SDL_SetWindowMinimumSize(m_internal_window, size.x(), size.y());
216  this->m_minimum_size = size;
217 }
218 
220 {
221  SDL_SetWindowMaximumSize(m_internal_window, size.x(), size.y());
222  this->m_maximum_size = size;
223 }
224 
225 void sdl_window::set_maximized(bool maximized)
226 {
227  if (maximized)
228  {
229  SDL_MaximizeWindow(m_internal_window);
230  }
231  else
232  {
233  SDL_RestoreWindow(m_internal_window);
234  }
235 }
236 
237 void sdl_window::set_fullscreen(bool fullscreen)
238 {
239  //SDL_HideWindow(m_internal_window);
240  SDL_SetWindowFullscreen(m_internal_window, (fullscreen) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
241  //SDL_ShowWindow(m_internal_window);
242  this->m_fullscreen = fullscreen;
243 }
244 
245 void sdl_window::set_v_sync(bool v_sync)
246 {
247  if (v_sync)
248  {
249  debug::log_trace("Enabling adaptive v-sync...");
250  if (SDL_GL_SetSwapInterval(-1) != 0)
251  {
252  debug::log_error("Failed to enable adaptive v-sync: {}", SDL_GetError());
253  debug::log_trace("Enabling synchronized v-sync...");
254  if (SDL_GL_SetSwapInterval(1) != 0)
255  {
256  debug::log_error("Failed to enable synchronized v-sync: {}", SDL_GetError());
257  v_sync = false;
258  }
259  else
260  {
261  debug::log_debug("Enabled synchronized v-sync");
262  }
263  }
264  else
265  {
266  debug::log_debug("Enabled adaptive v-sync");
267  }
268  }
269  else
270  {
271  debug::log_trace("Disabling v-sync...");
272  if (SDL_GL_SetSwapInterval(0) != 0)
273  {
274  debug::log_error("Failed to disable v-sync: {}", SDL_GetError());
275  v_sync = true;
276  }
277  else
278  {
279  debug::log_debug("Disabled v-sync");
280  }
281  }
282 
283  this->m_v_sync = v_sync;
284 }
285 
287 {
288  SDL_GL_MakeCurrent(m_internal_window, m_internal_context);
289 }
290 
292 {
293  SDL_GL_SwapWindow(m_internal_window);
294 }
295 
296 } // namespace app
virtual ~sdl_window()
Definition: sdl-window.cpp:185
sdl_window(const std::string &title, const math::ivec2 &windowed_position, const math::ivec2 &windowed_size, bool maximized, bool fullscreen, bool v_sync)
Definition: sdl-window.cpp:30
void make_current() override
Makes the window's graphics context current.
Definition: sdl-window.cpp:286
void swap_buffers() override
Swaps the front and back buffers of the window's graphics context.
Definition: sdl-window.cpp:291
void set_v_sync(bool v_sync) override
Enables or disables v-sync.
Definition: sdl-window.cpp:245
void set_title(const std::string &title) override
Changes the title of the window.
Definition: sdl-window.cpp:197
void set_position(const math::ivec2 &position) override
Changes the position of the window.
Definition: sdl-window.cpp:203
void set_maximized(bool maximized) override
Maximizes or unmaximizes the window.
Definition: sdl-window.cpp:225
void set_fullscreen(bool fullscreen) override
Enables or disables fullscreen mode.
Definition: sdl-window.cpp:237
void set_minimum_size(const math::ivec2 &size) override
Sets the minimum size of the window.
Definition: sdl-window.cpp:213
void set_size(const math::ivec2 &size) override
Changes the size of the window.
Definition: sdl-window.cpp:208
void set_maximum_size(const math::ivec2 &size) override
Sets the maximum size of the window.
Definition: sdl-window.cpp:219
math::ivec2 m_minimum_size
Definition: window.hpp:232
bool m_v_sync
Definition: window.hpp:237
math::ivec2 m_viewport_size
Definition: window.hpp:234
math::ivec2 m_windowed_position
Definition: window.hpp:228
math::ivec2 m_windowed_size
Definition: window.hpp:230
std::string m_title
Definition: window.hpp:227
math::ivec2 m_size
Definition: window.hpp:231
bool m_maximized
Definition: window.hpp:235
bool m_fullscreen
Definition: window.hpp:236
math::ivec2 m_position
Definition: window.hpp:229
math::ivec2 m_maximum_size
Definition: window.hpp:233
log_message< log_message_severity::fatal, Args... > log_fatal
Formats and logs a fatal error message.
Definition: log.hpp:158
log_message< log_message_severity::warning, Args... > log_warning
Formats and logs a warning message.
Definition: log.hpp:130
log_message< log_message_severity::trace, Args... > log_trace
Formats and logs a trace message.
Definition: log.hpp:88
log_message< log_message_severity::debug, Args... > log_debug
Formats and logs a debug message.
Definition: log.hpp:102
log_message< log_message_severity::error, Args... > log_error
Formats and logs an error message.
Definition: log.hpp:144
log_message< log_message_severity::info, Args... > log_info
Formats and logs an info message.
Definition: log.hpp:116
@ color_clear_bit
Indicates the color buffer should be cleared.
Definition: clear-bits.hpp:31
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180