23 #include <engine/config.hpp>
33 if (SDL_InitSubSystem(SDL_INIT_EVENTS | SDL_INIT_VIDEO) != 0)
35 debug::log_fatal(
"Failed to initialize SDL events and video subsystems: {}", SDL_GetError());
36 throw std::runtime_error(
"Failed to initialize SDL events and video subsystems");
41 const int display_count = SDL_GetNumVideoDisplays();
42 if (display_count < 1)
49 m_displays.resize(display_count);
52 for (
int i = 0; i < display_count; ++i)
66 if (SDL_GL_LoadLibrary(
nullptr) != 0)
69 throw std::runtime_error(
"Failed to load OpenGL library");
74 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
75 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
76 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, config::opengl_version_major);
77 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, config::opengl_version_minor);
80 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG | SDL_GL_CONTEXT_DEBUG_FLAG);
82 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
85 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
86 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, config::opengl_min_red_size);
87 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, config::opengl_min_green_size);
88 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, config::opengl_min_blue_size);
89 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, config::opengl_min_alpha_size);
90 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, config::opengl_min_depth_size);
91 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, config::opengl_min_stencil_size);
98 SDL_QuitSubSystem(SDL_INIT_VIDEO);
104 const std::string& title,
113 std::shared_ptr<app::sdl_window>
window = std::make_shared<app::sdl_window>
138 int status = SDL_PeepEvents(&
event, 1, SDL_GETEVENT, SDL_DISPLAYEVENT, SDL_SYSWMEVENT);
147 throw std::runtime_error(
"Failed to peep SDL events");
151 if (
event.type == SDL_WINDOWEVENT)
153 switch (
event.window.event)
155 case SDL_WINDOWEVENT_SIZE_CHANGED:
158 SDL_Window* internal_window = SDL_GetWindowFromID(
event.window.windowID);
162 window->
m_size = {
event.window.data1,
event.window.data2};
163 const auto window_flags = SDL_GetWindowFlags(internal_window);
164 if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)))
171 window->m_graphics_pipeline->defaut_framebuffer_resized
185 case SDL_WINDOWEVENT_MOVED:
188 SDL_Window* internal_window = SDL_GetWindowFromID(
event.window.windowID);
193 const auto window_flags = SDL_GetWindowFlags(internal_window);
194 if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)))
207 case SDL_WINDOWEVENT_FOCUS_GAINED:
210 SDL_Window* internal_window = SDL_GetWindowFromID(
event.window.windowID);
221 case SDL_WINDOWEVENT_FOCUS_LOST:
224 SDL_Window* internal_window = SDL_GetWindowFromID(
event.window.windowID);
235 case SDL_WINDOWEVENT_MAXIMIZED:
238 SDL_Window* internal_window = SDL_GetWindowFromID(
event.window.windowID);
252 case SDL_WINDOWEVENT_RESTORED:
255 SDL_Window* internal_window = SDL_GetWindowFromID(
event.window.windowID);
269 case SDL_WINDOWEVENT_MINIMIZED:
272 SDL_Window* internal_window = SDL_GetWindowFromID(
event.window.windowID);
283 [[unlikely]]
case SDL_WINDOWEVENT_CLOSE:
286 SDL_Window* internal_window = SDL_GetWindowFromID(
event.window.windowID);
301 else if (
event.type == SDL_DISPLAYEVENT)
303 switch (
event.display.event)
305 case SDL_DISPLAYEVENT_CONNECTED:
306 if (
event.display.display < m_displays.size())
320 else if (
event.display.display == m_displays.size())
323 m_displays.resize(m_displays.size() + 1);
327 update_display(
event.display.display);
342 case SDL_DISPLAYEVENT_DISCONNECTED:
343 if (
event.display.display < m_displays.size())
363 case SDL_DISPLAYEVENT_ORIENTATION:
364 if (
event.display.display < m_displays.size())
370 switch (
event.display.data1)
372 case SDL_ORIENTATION_LANDSCAPE:
375 case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
378 case SDL_ORIENTATION_PORTRAIT:
381 case SDL_ORIENTATION_PORTRAIT_FLIPPED:
408 sdl_window* sdl_window_manager::get_window(SDL_Window* internal_window)
410 if (
auto i = m_window_map.find(internal_window); i != m_window_map.end())
416 throw std::runtime_error(
"SDL window unrecognized by SDL window manager");
424 return m_displays.size();
429 return m_displays[index];
432 void sdl_window_manager::update_display(
int sdl_display_index)
435 SDL_DisplayMode sdl_display_mode;
436 if (SDL_GetDesktopDisplayMode(sdl_display_index, &sdl_display_mode) != 0)
438 debug::log_error(
"Failed to get mode of display {}: {}", sdl_display_index, SDL_GetError());
440 sdl_display_mode = {0, 0, 0, 0,
nullptr};
444 const char* sdl_display_name = SDL_GetDisplayName(sdl_display_index);
445 if (!sdl_display_name)
447 debug::log_warning(
"Failed to get name of display {}: {}", sdl_display_index, SDL_GetError());
449 sdl_display_name =
nullptr;
453 SDL_Rect sdl_display_bounds;
454 if (SDL_GetDisplayBounds(sdl_display_index, &sdl_display_bounds) != 0)
456 debug::log_warning(
"Failed to get bounds of display {}: {}", sdl_display_index, SDL_GetError());
458 sdl_display_bounds = {0, 0, sdl_display_mode.w, sdl_display_mode.h};
462 SDL_Rect sdl_display_usable_bounds;
463 if (SDL_GetDisplayUsableBounds(sdl_display_index, &sdl_display_usable_bounds) != 0)
465 debug::log_warning(
"Failed to get usable bounds of display {}: {}", sdl_display_index, SDL_GetError());
467 sdl_display_usable_bounds = sdl_display_bounds;
471 float sdl_display_dpi;
472 if (SDL_GetDisplayDPI(sdl_display_index, &sdl_display_dpi,
nullptr,
nullptr) != 0)
474 debug::log_warning(
"Failed to get DPI of display {}: {}", sdl_display_index, SDL_GetError());
476 sdl_display_dpi = 0.0f;
480 SDL_DisplayOrientation sdl_display_orientation = SDL_GetDisplayOrientation(sdl_display_index);
483 display& display = m_displays[sdl_display_index];
484 display.set_index(
static_cast<std::size_t
>(sdl_display_index));
485 display.set_name(sdl_display_name ? sdl_display_name : std::string());
486 display.set_bounds({{sdl_display_bounds.x, sdl_display_bounds.y}, {sdl_display_bounds.x + sdl_display_bounds.w, sdl_display_bounds.y + sdl_display_bounds.h}});
487 display.set_usable_bounds({{sdl_display_usable_bounds.x, sdl_display_usable_bounds.y}, {sdl_display_usable_bounds.x + sdl_display_usable_bounds.w, sdl_display_usable_bounds.y + sdl_display_usable_bounds.h}});
488 display.set_refresh_rate(sdl_display_mode.refresh_rate);
489 display.set_dpi(sdl_display_dpi);
490 switch (sdl_display_orientation)
492 case SDL_ORIENTATION_LANDSCAPE:
495 case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
498 case SDL_ORIENTATION_PORTRAIT:
501 case SDL_ORIENTATION_PORTRAIT_FLIPPED:
508 display.m_connected =
true;
const geom::rectangle< int > & get_bounds() const noexcept
Returns the bounds of the display, in display units.
const std::string & get_name() const noexcept
Returns the name of the display.
const int & get_refresh_rate() const noexcept
Returns the refresh rate of the display, in Hz.
const display_orientation & get_orientation() const noexcept
Returns the current orientation of the display.
void set_orientation(display_orientation orientation) noexcept
Sets the orientation of the display.
const float & get_dpi() const noexcept
Returns the DPI of the display.
const display & get_display(std::size_t index) const override
Returns the display with the given index.
std::shared_ptr< window > create_window(const std::string &title, const math::ivec2 &windowed_position, const math::ivec2 &windowed_size, bool maximized, bool fullscreen, bool v_sync) override
std::size_t get_display_count() const override
Returns the number of available displays.
~sdl_window_manager() override
Destructs an SDL window manager.
sdl_window_manager()
Constructs an SDL window manager.
void update() override
Updates all managed windows.
event::publisher< window_restored_event > m_restored_publisher
event::publisher< window_maximized_event > m_maximized_publisher
event::publisher< window_closed_event > m_closed_publisher
math::ivec2 m_viewport_size
math::ivec2 m_windowed_position
math::ivec2 m_windowed_size
event::publisher< window_focus_changed_event > m_focus_changed_publisher
event::publisher< window_moved_event > m_moved_publisher
event::publisher< window_minimized_event > m_minimized_publisher
event::publisher< window_resized_event > m_resized_publisher
status
Behavior tree node return status enumerations.
@ landscape
Display is in landscape mode, with the right side up, relative to portrait mode.
@ unknown
Display orientation unknown.
@ portrait
Display is in portrait mode.
@ portrait_flipped
Display is in portrait mode, upside down.
@ landscape_flipped
Display is in landscape mode, with the left side up, relative to portrait mode.
log_message< log_message_severity::fatal, Args... > log_fatal
Formats and logs a fatal error message.
log_message< log_message_severity::warning, Args... > log_warning
Formats and logs a warning message.
log_message< log_message_severity::trace, Args... > log_trace
Formats and logs a trace message.
log_message< log_message_severity::debug, Args... > log_debug
Formats and logs a debug message.
log_message< log_message_severity::error, Args... > log_error
Formats and logs an error message.
log_message< log_message_severity::info, Args... > log_info
Formats and logs an info message.
Publish-subscribe messaging.
constexpr element_type & x() noexcept
Returns a reference to the first element.
constexpr element_type & y() noexcept
Returns a reference to the second element.