|
|
- /*
- * Copyright (C) 2023 Christopher J. Howard
- *
- * This file is part of Antkeeper source code.
- *
- * Antkeeper source code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Antkeeper source code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
- */
-
- #include "application.hpp"
- #include "config.hpp"
- #include "debug/log.hpp"
- #include "input/scancode.hpp"
- #include "math/map.hpp"
- #include <SDL2/SDL.h>
- #include <glad/glad.h>
- #include <stdexcept>
- #include <utility>
-
- application::application
- (
- const std::string& window_title,
- int window_x,
- int window_y,
- int window_w,
- int window_h,
- bool maximized,
- bool fullscreen,
- bool v_sync
- ):
- closed(false),
- maximized(false),
- fullscreen(true),
- v_sync(false),
- cursor_visible(true),
- display_size({0, 0}),
- display_dpi(0.0f),
- windowed_position({-1, -1}),
- windowed_size({-1, -1}),
- viewport_size({-1, -1}),
- mouse_position({0, 0}),
- sdl_window(nullptr),
- sdl_gl_context(nullptr)
- {
- // Log SDL info
- // SDL_version sdl_compiled_version;
- // SDL_version sdl_linked_version;
- // SDL_VERSION(&sdl_compiled_version);
- // SDL_GetVersion(&sdl_linked_version);
- // debug::log::info
- // (
- // "SDL compiled version: {}.{}.{}; linked version: {}.{}.{}",
- // sdl_compiled_version.major,
- // sdl_compiled_version.minor,
- // sdl_compiled_version.patch,
- // sdl_linked_version.major,
- // sdl_linked_version.minor,
- // sdl_linked_version.patch
- // );
-
- // Init SDL events and video subsystems
- debug::log::trace("Initializing SDL events and video subsystems...");
- if (SDL_InitSubSystem(SDL_INIT_EVENTS | SDL_INIT_VIDEO) != 0)
- {
- debug::log::fatal("Failed to initialize SDL events and video subsystems: {}", SDL_GetError());
- throw std::runtime_error("Failed to initialize SDL events and video subsystems");
- }
- debug::log::trace("Initialized SDL events and video subsystems");
-
- // Query displays
- debug::log::trace("Querying displays...");
-
- const int sdl_display_count = SDL_GetNumVideoDisplays();
- if (sdl_display_count < 1)
- {
- debug::log::fatal("No displays detected: {}", SDL_GetError());
- throw std::runtime_error("No displays detected");
- }
-
- debug::log::info("Display count: {}", sdl_display_count);
-
- for (int i = 0; i < sdl_display_count; ++i)
- {
- // Query display mode
- SDL_DisplayMode sdl_display_mode;
- if (SDL_GetDesktopDisplayMode(i, &sdl_display_mode) != 0)
- {
- debug::log::error("Failed to get mode of display {}: {}", i, SDL_GetError());
- SDL_ClearError();
- continue;
- }
-
- // Query display name
- const char* sdl_display_name = SDL_GetDisplayName(i);
- if (!sdl_display_name)
- {
- debug::log::warning("Failed to get name of display {}: {}", i, SDL_GetError());
- SDL_ClearError();
- sdl_display_name = "";
- }
-
- // Query display DPI
- float sdl_display_dpi;
- if (SDL_GetDisplayDPI(i, &sdl_display_dpi, nullptr, nullptr) != 0)
- {
- const float default_dpi = 96.0f;
- debug::log::warning("Failed to get DPI of display {}: {}; Defaulting to {} DPI", i, SDL_GetError(), default_dpi);
- SDL_ClearError();
- }
-
- // Log display information
- debug::log::info("Display {} name: \"{}\"; resolution: {}x{}; refresh rate: {}Hz; DPI: {}", i, sdl_display_name, sdl_display_mode.w, sdl_display_mode.h, sdl_display_mode.refresh_rate, sdl_display_dpi);
- }
-
- debug::log::trace("Queried displays");
-
- // Detect display dimensions
- SDL_DisplayMode sdl_desktop_display_mode;
- if (SDL_GetDesktopDisplayMode(0, &sdl_desktop_display_mode) != 0)
- {
- debug::log::fatal("Failed to detect desktop display mode: {}", SDL_GetError());
- throw std::runtime_error("Failed to detect desktop display mode");
- }
- display_size = {sdl_desktop_display_mode.w, sdl_desktop_display_mode.h};
-
- // Detect display DPI
- if (SDL_GetDisplayDPI(0, &display_dpi, nullptr, nullptr) != 0)
- {
- debug::log::fatal("Failed to detect display DPI: {}", SDL_GetError());
- throw std::runtime_error("Failed to detect display DPI");
- }
-
- // Log display properties
- debug::log::info("Detected {}x{}@{}Hz display with {} DPI", sdl_desktop_display_mode.w, sdl_desktop_display_mode.h, sdl_desktop_display_mode.refresh_rate, display_dpi);
-
- // Load OpenGL library
- debug::log::trace("Loading OpenGL library...");
- if (SDL_GL_LoadLibrary(nullptr) != 0)
- {
- debug::log::fatal("Failed to load OpenGL library: {}", SDL_GetError());
- throw std::runtime_error("Failed to load OpenGL library");
- }
- debug::log::trace("Loaded OpenGL library");
-
- // Set OpenGL-related window creation hints
- SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, config::opengl_version_major);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, config::opengl_version_minor);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, config::opengl_min_red_size);
- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, config::opengl_min_green_size);
- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, config::opengl_min_blue_size);
- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, config::opengl_min_alpha_size);
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, config::opengl_min_depth_size);
- SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, config::opengl_min_stencil_size);
-
- Uint32 sdl_window_flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
- if (fullscreen)
- {
- sdl_window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
- }
- if (maximized)
- {
- sdl_window_flags |= SDL_WINDOW_MAXIMIZED;
- }
- if (window_x == -1 && window_y == -1)
- {
- window_x = SDL_WINDOWPOS_CENTERED;
- window_y = SDL_WINDOWPOS_CENTERED;
- }
- if (window_w <= 0 || window_h <= 0)
- {
- window_w = sdl_desktop_display_mode.w / 2;
- window_h = sdl_desktop_display_mode.h / 2;
- }
-
- // Create a hidden fullscreen window
- debug::log::trace("Creating window...");
- sdl_window = SDL_CreateWindow
- (
- window_title.c_str(),
- window_x,
- window_y,
- window_w,
- window_h,
- sdl_window_flags
- );
- if (!sdl_window)
- {
- debug::log::fatal("Failed to create {}x{} window: {}", display_size[0], display_size[1], SDL_GetError());
- throw std::runtime_error("Failed to create SDL window");
- }
- debug::log::trace("Created window");
-
-
- if (window_x != SDL_WINDOWPOS_CENTERED && window_y != SDL_WINDOWPOS_CENTERED)
- {
- this->windowed_position = {window_x, window_y};
- }
- this->windowed_size = {window_w, window_h};
- this->maximized = maximized;
- this->fullscreen = fullscreen;
-
- // Set hard window minimum size
- SDL_SetWindowMinimumSize(sdl_window, 160, 120);
-
- // Create OpenGL context
- debug::log::trace("Creating OpenGL {}.{} context...", config::opengl_version_major, config::opengl_version_minor);
- sdl_gl_context = SDL_GL_CreateContext(sdl_window);
- if (!sdl_gl_context)
- {
- debug::log::fatal("Failed to create OpenGL context: {}", SDL_GetError());
- throw std::runtime_error("Failed to create OpenGL context");
- }
-
- // Log version of created OpenGL context
- int opengl_context_version_major = -1;
- int opengl_context_version_minor = -1;
- SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &opengl_context_version_major);
- SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &opengl_context_version_minor);
- debug::log::info("Created OpenGL {}.{} context", opengl_context_version_major, opengl_context_version_minor);
-
- // Compare OpenGL context version with requested version
- if (opengl_context_version_major != config::opengl_version_major ||
- opengl_context_version_minor != config::opengl_version_minor)
- {
- debug::log::warning("Requested OpenGL {}.{} context but created OpenGL {}.{} context", config::opengl_version_major, config::opengl_version_minor, opengl_context_version_major, opengl_context_version_minor);
- }
-
- // Log format of OpenGL context default framebuffer
- int opengl_context_red_size = -1;
- int opengl_context_green_size = -1;
- int opengl_context_blue_size = -1;
- int opengl_context_alpha_size = -1;
- int opengl_context_depth_size = -1;
- int opengl_context_stencil_size = -1;
- SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &opengl_context_red_size);
- SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &opengl_context_green_size);
- SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &opengl_context_blue_size);
- SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &opengl_context_alpha_size);
- SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &opengl_context_depth_size);
- SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &opengl_context_stencil_size);
- debug::log::info("OpenGL context format: R{}G{}B{}A{}D{}S{}", opengl_context_red_size, opengl_context_green_size, opengl_context_blue_size, opengl_context_alpha_size, opengl_context_depth_size, opengl_context_stencil_size);
-
- // Compare OpenGL context default framebuffer format with request format
- if (opengl_context_red_size < config::opengl_min_red_size ||
- opengl_context_green_size < config::opengl_min_green_size ||
- opengl_context_blue_size < config::opengl_min_blue_size ||
- opengl_context_alpha_size < config::opengl_min_alpha_size ||
- opengl_context_depth_size < config::opengl_min_depth_size ||
- opengl_context_stencil_size < config::opengl_min_stencil_size)
- {
- debug::log::warning
- (
- "OpenGL context format (R{}G{}B{}A{}D{}S{}) does not meet minimum requested format (R{}G{}B{}A{}D{}S{})",
- opengl_context_red_size, opengl_context_green_size, opengl_context_blue_size, opengl_context_alpha_size, opengl_context_depth_size, opengl_context_stencil_size,
- config::opengl_min_red_size, config::opengl_min_green_size, config::opengl_min_blue_size, config::opengl_min_alpha_size, config::opengl_min_depth_size, config::opengl_min_stencil_size
- );
- }
-
- // Load OpenGL functions via GLAD
- debug::log::trace("Loading OpenGL functions...");
- if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
- {
- debug::log::fatal("Failed to load OpenGL functions", SDL_GetError());
- throw std::runtime_error("Failed to load OpenGL functions");
- }
- debug::log::trace("Loaded OpenGL functions");
-
- // Log OpenGL context information
- debug::log::info
- (
- "OpenGL vendor: {}; renderer: {}; version: {}; shading language version: {}",
- reinterpret_cast<const char*>(glGetString(GL_VENDOR)),
- reinterpret_cast<const char*>(glGetString(GL_RENDERER)),
- reinterpret_cast<const char*>(glGetString(GL_VERSION)),
- reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION))
- );
-
- // Clear window color
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- swap_buffers();
-
- // Set v-sync mode
- set_v_sync(v_sync);
-
- // Update viewport size
- SDL_GL_GetDrawableSize(sdl_window, &viewport_size[0], &viewport_size[1]);
-
- // Init SDL joystick and controller subsystems
- debug::log::trace("Initializing SDL joystick and controller subsystems...");
- if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) != 0)
- {
- debug::log::error("Failed to initialize SDL joystick and controller subsytems: {}", SDL_GetError());
- }
- else
- {
- debug::log::trace("Initialized SDL joystick and controller subsystems");
- }
-
- // Setup rasterizer
- rasterizer = new gl::rasterizer();
- rasterizer->context_resized(viewport_size[0], viewport_size[1]);
-
- // Register keyboard and mouse with input device manager
- device_manager.register_device(keyboard);
- device_manager.register_device(mouse);
-
- // Generate keyboard and mouse device connected events
- keyboard.connect();
- mouse.connect();
-
- // Connect gamepads
- process_events();
- }
-
- application::~application()
- {
- // Destroy the OpenGL context
- SDL_GL_DeleteContext(sdl_gl_context);
-
- // Destroy the SDL window
- SDL_DestroyWindow(sdl_window);
-
- // Shutdown SDL
- SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
- SDL_Quit();
- }
-
- void application::close()
- {
- closed = true;
- }
-
- void application::set_title(const std::string& title)
- {
- SDL_SetWindowTitle(sdl_window, title.c_str());
- }
-
- void application::set_cursor_visible(bool visible)
- {
- SDL_ShowCursor((visible) ? SDL_ENABLE : SDL_DISABLE);
- cursor_visible = visible;
- }
-
- void application::set_relative_mouse_mode(bool enabled)
- {
- if (enabled)
- {
- SDL_GetMouseState(&mouse_position[0], &mouse_position[1]);
- SDL_ShowCursor(SDL_DISABLE);
- SDL_SetRelativeMouseMode(SDL_TRUE);
- }
- else
- {
- SDL_SetRelativeMouseMode(SDL_FALSE);
- SDL_WarpMouseInWindow(sdl_window, mouse_position[0], mouse_position[1]);
- if (cursor_visible)
- {
- SDL_ShowCursor(SDL_ENABLE);
- }
- }
- }
-
- void application::resize_window(int width, int height)
- {
- int x = (display_size[0] >> 1) - (width >> 1);
- int y = (display_size[1] >> 1) - (height >> 1);
-
- // Resize and center window
- SDL_SetWindowPosition(sdl_window, x, y);
- SDL_SetWindowSize(sdl_window, width, height);
- }
-
- void application::set_fullscreen(bool fullscreen)
- {
- if (this->fullscreen != fullscreen)
- {
- this->fullscreen = fullscreen;
-
- if (fullscreen)
- {
- SDL_SetWindowFullscreen(sdl_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
- }
- else
- {
- SDL_SetWindowFullscreen(sdl_window, 0);
- }
- }
- }
-
- void application::set_v_sync(bool v_sync)
- {
- if (v_sync)
- {
- debug::log::trace("Enabling adaptive v-sync...");
- if (SDL_GL_SetSwapInterval(-1) != 0)
- {
- debug::log::error("Failed to enable adaptive v-sync: {}", SDL_GetError());
- debug::log::trace("Enabling synchronized v-sync...");
- if (SDL_GL_SetSwapInterval(1) != 0)
- {
- debug::log::error("Failed to enable synchronized v-sync: {}", SDL_GetError());
- }
- else
- {
- this->v_sync = v_sync;
- debug::log::debug("Enabled synchronized v-sync");
- }
- }
- else
- {
- this->v_sync = v_sync;
- debug::log::debug("Enabled adaptive v-sync");
- }
- }
- else
- {
- debug::log::trace("Disabling v-sync...");
- if (SDL_GL_SetSwapInterval(0) != 0)
- {
- debug::log::error("Failed to disable v-sync: {}", SDL_GetError());
- }
- else
- {
- this->v_sync = v_sync;
- debug::log::debug("Disabled v-sync");
- }
- }
- }
-
- void application::set_window_opacity(float opacity)
- {
- SDL_SetWindowOpacity(sdl_window, opacity);
- }
-
- void application::swap_buffers()
- {
- SDL_GL_SwapWindow(sdl_window);
- }
-
- void application::show_window()
- {
- SDL_ShowWindow(sdl_window);
- //SDL_GL_MakeCurrent(sdl_window, sdl_gl_context);
- }
-
- void application::hide_window()
- {
- SDL_HideWindow(sdl_window);
- }
-
- void application::add_game_controller_mappings(const void* mappings, std::size_t size)
- {
- debug::log::trace("Adding SDL game controller mappings...");
- int mapping_count = SDL_GameControllerAddMappingsFromRW(SDL_RWFromConstMem(mappings, static_cast<int>(size)), 0);
- if (mapping_count == -1)
- {
- debug::log::error("Failed to add SDL game controller mappings: {}", SDL_GetError());
- }
- else
- {
- debug::log::debug("Added {} SDL game controller mappings", mapping_count);
- }
- }
-
- void application::process_events()
- {
- // Active modifier keys
- std::uint16_t sdl_key_mod = KMOD_NONE;
- std::uint16_t modifier_keys = input::modifier_key::none;
-
- // Mouse motion event accumulators
- // bool mouse_motion = false;
- // std::int32_t mouse_x;
- // std::int32_t mouse_y;
- // std::int32_t mouse_dx = 0;
- // std::int32_t mouse_dy = 0;
-
- SDL_Event sdl_event;
- while (SDL_PollEvent(&sdl_event))
- {
- switch (sdl_event.type)
- {
- [[likely]] case SDL_MOUSEMOTION:
- {
- // More than one mouse motion event is often generated per frame, and may be a source of lag.
- // Mouse events can be accumulated here to prevent excessive function calls and allocations
- // mouse_motion = true;
- // mouse_x = sdl_event.motion.x;
- // mouse_y = sdl_event.motion.y;
- // mouse_dx += sdl_event.motion.xrel;
- // mouse_dy += sdl_event.motion.yrel;
-
- mouse.move({sdl_event.motion.x, sdl_event.motion.y}, {sdl_event.motion.xrel, sdl_event.motion.yrel});
- break;
- }
-
- case SDL_KEYDOWN:
- case SDL_KEYUP:
- {
- // Get scancode of key
- const input::scancode scancode = static_cast<input::scancode>(sdl_event.key.keysym.scancode);
-
- // Rebuild modifier keys bit mask
- if (sdl_event.key.keysym.mod != sdl_key_mod)
- {
- sdl_key_mod = sdl_event.key.keysym.mod;
-
- modifier_keys = input::modifier_key::none;
- if (sdl_key_mod & KMOD_LSHIFT)
- modifier_keys |= input::modifier_key::left_shift;
- if (sdl_key_mod & KMOD_RSHIFT)
- modifier_keys |= input::modifier_key::right_shift;
- if (sdl_key_mod & KMOD_LCTRL)
- modifier_keys |= input::modifier_key::left_ctrl;
- if (sdl_key_mod & KMOD_RCTRL)
- modifier_keys |= input::modifier_key::right_ctrl;
- if (sdl_key_mod & KMOD_LGUI)
- modifier_keys |= input::modifier_key::left_gui;
- if (sdl_key_mod & KMOD_RGUI)
- modifier_keys |= input::modifier_key::right_gui;
- if (sdl_key_mod & KMOD_NUM)
- modifier_keys |= input::modifier_key::num_lock;
- if (sdl_key_mod & KMOD_CAPS)
- modifier_keys |= input::modifier_key::caps_lock;
- if (sdl_key_mod & KMOD_SCROLL)
- modifier_keys |= input::modifier_key::scroll_lock;
- if (sdl_key_mod & KMOD_MODE)
- modifier_keys |= input::modifier_key::alt_gr;
- }
-
- // Determine if event was generated from a key repeat
- const bool repeat = sdl_event.key.repeat > 0;
-
- if (sdl_event.type == SDL_KEYDOWN)
- {
- keyboard.press(scancode, repeat, modifier_keys);
- }
- else
- {
- keyboard.release(scancode, repeat, modifier_keys);
- }
-
- break;
- }
-
- case SDL_MOUSEWHEEL:
- {
- const float flip = (sdl_event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) ? -1.0f : 1.0f;
- mouse.scroll({sdl_event.wheel.preciseX * flip, sdl_event.wheel.preciseY * flip});
- break;
- }
-
- case SDL_MOUSEBUTTONDOWN:
- {
- mouse.press(static_cast<input::mouse_button>(sdl_event.button.button));
- break;
- }
-
- case SDL_MOUSEBUTTONUP:
- {
- mouse.release(static_cast<input::mouse_button>(sdl_event.button.button));
- break;
- }
-
- [[likely]] case SDL_CONTROLLERAXISMOTION:
- {
- if (sdl_event.caxis.axis != SDL_CONTROLLER_AXIS_INVALID)
- {
- if (auto it = gamepad_map.find(sdl_event.cdevice.which); it != gamepad_map.end())
- {
- // Map axis position onto `[-1, 1]`.
- const float position = math::map
- (
- static_cast<float>(sdl_event.caxis.value),
- static_cast<float>(std::numeric_limits<decltype(sdl_event.caxis.value)>::min()),
- static_cast<float>(std::numeric_limits<decltype(sdl_event.caxis.value)>::max()),
- -1.0f,
- 1.0f
- );
-
- // Generate gamepad axis moved event
- it->second->move(static_cast<input::gamepad_axis>(sdl_event.caxis.axis), position);
- }
- }
- break;
- }
-
- case SDL_CONTROLLERBUTTONDOWN:
- {
- if (sdl_event.cbutton.button != SDL_CONTROLLER_BUTTON_INVALID)
- {
- if (auto it = gamepad_map.find(sdl_event.cdevice.which); it != gamepad_map.end())
- {
- it->second->press(static_cast<input::gamepad_button>(sdl_event.cbutton.button));
- }
- }
- break;
- }
-
- case SDL_CONTROLLERBUTTONUP:
- {
- if (sdl_event.cbutton.button != SDL_CONTROLLER_BUTTON_INVALID)
- {
- if (auto it = gamepad_map.find(sdl_event.cdevice.which); it != gamepad_map.end())
- {
- it->second->release(static_cast<input::gamepad_button>(sdl_event.cbutton.button));
- }
- }
- break;
- }
-
- case SDL_WINDOWEVENT:
- {
- switch (sdl_event.window.event)
- {
- case SDL_WINDOWEVENT_SIZE_CHANGED:
- {
- // Query SDL window parameters
- SDL_Window* sdl_window = SDL_GetWindowFromID(sdl_event.window.windowID);
- const auto sdl_window_flags = SDL_GetWindowFlags(sdl_window);
- int sdl_window_drawable_w = 0;
- int sdl_window_drawable_h = 0;
- SDL_GL_GetDrawableSize(sdl_window, &sdl_window_drawable_w, &sdl_window_drawable_h);
-
- // Build window resized event
- input::event::window_resized event;
- event.window = nullptr;
- event.size.x() = static_cast<std::int32_t>(sdl_event.window.data1);
- event.size.y() = static_cast<std::int32_t>(sdl_event.window.data2);
- event.maximized = sdl_window_flags & SDL_WINDOW_MAXIMIZED;
- event.fullscreen = sdl_window_flags & SDL_WINDOW_FULLSCREEN;
- event.viewport_size.x() = static_cast<std::int32_t>(sdl_window_drawable_w);
- event.viewport_size.y() = static_cast<std::int32_t>(sdl_window_drawable_h);
-
- // Update windowed size
- if (!event.maximized && !event.fullscreen)
- {
- windowed_size = event.size;
- }
-
- // Update GL context size
- rasterizer->context_resized(event.viewport_size.x(), event.viewport_size.y());
-
- // Publish window resized event
- window_resized_publisher.publish(event);
- break;
- }
-
- case SDL_WINDOWEVENT_MOVED:
- {
- // Query SDL window parameters
- SDL_Window* sdl_window = SDL_GetWindowFromID(sdl_event.window.windowID);
- const auto sdl_window_flags = SDL_GetWindowFlags(sdl_window);
-
- // Build window moved event
- input::event::window_moved event;
- event.window = nullptr;
- event.position.x() = static_cast<std::int32_t>(sdl_event.window.data1);
- event.position.y() = static_cast<std::int32_t>(sdl_event.window.data2);
- event.maximized = sdl_window_flags & SDL_WINDOW_MAXIMIZED;
- event.fullscreen = sdl_window_flags & SDL_WINDOW_FULLSCREEN;
-
- // Update windowed position
- if (!event.maximized && !event.fullscreen)
- {
- windowed_position = event.position;
- }
-
- // Publish window moved event
- window_moved_publisher.publish(event);
- break;
- }
-
- case SDL_WINDOWEVENT_FOCUS_GAINED:
- // Build and publish window focused gained event
- window_focus_changed_publisher.publish({nullptr, true});
- break;
-
- case SDL_WINDOWEVENT_FOCUS_LOST:
- // Build and publish window focused lost event
- window_focus_changed_publisher.publish({nullptr, false});
- break;
-
- case SDL_WINDOWEVENT_MAXIMIZED:
- // Update window maximized
- maximized = true;
-
- // Build and publish window maximized event
- window_maximized_publisher.publish({nullptr});
- break;
-
- case SDL_WINDOWEVENT_RESTORED:
- // Update window maximized
- maximized = false;
-
- // Build and publish window restored event
- window_restored_publisher.publish({nullptr});
- break;
-
- case SDL_WINDOWEVENT_MINIMIZED:
- // Build and publish window minimized event
- window_minimized_publisher.publish({nullptr});
- break;
-
- [[unlikely]] case SDL_WINDOWEVENT_CLOSE:
- // Build and publish window closed event
- window_closed_publisher.publish({nullptr});
- break;
-
- default:
- break;
- }
- break;
- }
-
- [[unlikely]] case SDL_CONTROLLERDEVICEADDED:
- {
- if (SDL_IsGameController(sdl_event.cdevice.which))
- {
- SDL_GameController* sdl_controller = SDL_GameControllerOpen(sdl_event.cdevice.which);
- const char* controller_name = SDL_GameControllerNameForIndex(sdl_event.cdevice.which);
-
- if (sdl_controller)
- {
- if (auto it = gamepad_map.find(sdl_event.cdevice.which); it != gamepad_map.end())
- {
- // Gamepad reconnected
- debug::log::info("Reconnected gamepad \"{}\"", controller_name);
- it->second->connect();
- }
- else
- {
- // Get gamepad GUID
- SDL_Joystick* sdl_joystick = SDL_GameControllerGetJoystick(sdl_controller);
- SDL_JoystickGUID sdl_guid = SDL_JoystickGetGUID(sdl_joystick);
-
- // Copy into UUID struct
- ::uuid gamepad_uuid;
- std::memcpy(gamepad_uuid.data.data(), sdl_guid.data, gamepad_uuid.data.size());
-
- debug::log::info("Connected gamepad \"{}\" with UUID {}", controller_name, gamepad_uuid.string());
-
- // Create new gamepad
- input::gamepad* gamepad = new input::gamepad();
- gamepad->set_uuid(gamepad_uuid);
-
- // Add gamepad to gamepad map
- gamepad_map[sdl_event.cdevice.which] = gamepad;
-
- // Register gamepad with device manager
- device_manager.register_device(*gamepad);
-
- // Generate gamepad connected event
- gamepad->connect();
- }
- }
- else
- {
- debug::log::error("Failed to connected gamepad \"{}\": {}", controller_name, SDL_GetError());
- }
- }
-
- break;
- }
-
- [[unlikely]] case SDL_CONTROLLERDEVICEREMOVED:
- {
- SDL_GameController* sdl_controller = SDL_GameControllerFromInstanceID(sdl_event.cdevice.which);
-
- if (sdl_controller)
- {
- const char* controller_name = SDL_GameControllerNameForIndex(sdl_event.cdevice.which);
-
- SDL_GameControllerClose(sdl_controller);
- if (auto it = gamepad_map.find(sdl_event.cdevice.which); it != gamepad_map.end())
- {
- it->second->disconnect();
- }
-
- debug::log::info("Disconnected gamepad \"{}\"", controller_name);
- }
-
- break;
- }
-
- [[unlikely]] case SDL_QUIT:
- {
- debug::log::info("Quit requested");
- close();
- break;
- }
-
- default:
- break;
- }
- }
-
- // Process accumulated mouse motion events
- // if (mouse_motion)
- // {
- // mouse.move(mouse_x, mouse_y, mouse_dx, mouse_dy);
- // }
- }
|