mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
refactor: window (#34)
* build: add SDL3 dependency * refactor(window): migrate from GLFW to SDL3 for window and input * refactor: remove unused GLFW includes and commented-out code * refactor(input): use relative mouse motion and simplify camera mouse update * refactor(event-handling): guard input events with imgui state Move mouse enable/disable logic into set_imgui_enabled and check imgui_enable before forwarding non-ImGui events to handlers. This prevents duplicate processing and ensures proper mouse state when toggling ImGui. * fix(camera): reset camera on resize events and fix input handling on imgui toggle - Add Camera::player() accessor. - Handle WindowResizeEvent and FrameBufferResizeEvent to reset camera. - Fix escape key handling to disable mouse before toggling imgui. - Fix left alt handling to toggle mouse state correctly. - Reset player key status when toggling imgui. * fix(client_world): add direct exit flag to break connection error loop * refactor(debug): add d_rep template and remove widget ID * feat(debug_collector): add video driver display to debug UI * fix: invert debug flag logic and rename to no_debug The previous 'debug_on' field was never set to true by default, causing debug mode to never be enabled. Now renamed to 'no_debug' and the renderer initializes with debug enabled unless the --no-debug flag is given. * feat(window): add video driver selection via config and --video-driver argument * ci: add vcpkg cache * fix: mscv cpp version show * fix: context delete too early * fix: ci build fail * fix: opengl resource delete error * fix: add // NOLINT for NvOptimusEnablement and AmdPowerXpressRequestHighPerformance * fix: windows ime fail on fullscreen * feat(ui): update text input area on field changes and window resize * fix(ui): initialize m_app pointer to nullptr * feat(window): add exclusive fullscreen support with WM detection * refactor: simplify WM detection and exclusive fullscreen default Removed WindowManager enum; detect_wm() now returns string directly. Default exclusive fullscreen based on platform (true on Linux). Added WM info to debug overlay. * feat: add Alt key to close ImGui; clarify debug log * refactor(dev-panel): remove direct settings UI from settings tab
This commit is contained in:
280
src/window.cpp
280
src/window.cpp
@@ -1,25 +1,27 @@
|
||||
#include "Cubed/window.hpp"
|
||||
|
||||
#include "Cubed/camera.hpp"
|
||||
#include "Cubed/gameplay/client_player.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/env_tools.hpp"
|
||||
#include "Cubed/tools/font.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <imgui_impl_sdl3.h>
|
||||
|
||||
namespace Cubed {
|
||||
|
||||
static int windowed_xpos = 0, windowed_ypos = 0;
|
||||
static int windowed_width = 800, windowed_height = 600;
|
||||
static int windowed_width = 1280, windowed_height = 720;
|
||||
|
||||
Window::Window(Config& config) : m_config(config) {}
|
||||
|
||||
Window::~Window() {
|
||||
if (m_imgui_init) {
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
}
|
||||
|
||||
if (ImGui::GetCurrentContext() != nullptr) {
|
||||
@@ -27,18 +29,17 @@ Window::~Window() {
|
||||
}
|
||||
|
||||
if (m_window) {
|
||||
glfwDestroyWindow(m_window);
|
||||
m_window = nullptr;
|
||||
SDL_GL_DestroyContext(m_context);
|
||||
SDL_DestroyWindow(m_window);
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
bool Window::is_mouse_enable() const { return m_mouse_enable; }
|
||||
|
||||
const GLFWwindow* Window::get_glfw_window() const { return m_window; }
|
||||
const SDL_Window* Window::get_window() const { return m_window; }
|
||||
|
||||
GLFWwindow* Window::get_glfw_window() { return m_window; }
|
||||
SDL_Window* Window::get_window() { return m_window; }
|
||||
|
||||
bool Window::handle_event(const Event& e) {
|
||||
return std::visit(
|
||||
@@ -109,85 +110,149 @@ bool Window::handle_mouse_button_event(const MouseButtonEvent& e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Window::init() {
|
||||
if (!glfwInit()) {
|
||||
Logger::error("glfw init fail");
|
||||
void Window::set_exclusive_fullscreen(bool full) {
|
||||
|
||||
if (full) {
|
||||
SDL_GetWindowPosition(m_window, &windowed_xpos, &windowed_ypos);
|
||||
SDL_GetWindowSize(m_window, &windowed_width, &windowed_height);
|
||||
SDL_SetWindowFullscreen(m_window, true);
|
||||
m_fullscreen = true;
|
||||
m_config.set("window.fullscreen", true);
|
||||
} else {
|
||||
SDL_SetWindowFullscreen(m_window, false);
|
||||
SDL_SetWindowPosition(m_window, windowed_xpos, windowed_ypos);
|
||||
SDL_SetWindowSize(m_window, windowed_width, windowed_height);
|
||||
m_fullscreen = false;
|
||||
m_config.set("window.fullscreen", false);
|
||||
}
|
||||
}
|
||||
void Window::set_borderless_fullscreen(bool full) {
|
||||
if (full) {
|
||||
// If the window is maximized, restore it first.
|
||||
if (SDL_GetWindowFlags(m_window) & SDL_WINDOW_MAXIMIZED) {
|
||||
SDL_RestoreWindow(m_window);
|
||||
}
|
||||
|
||||
SDL_GetWindowPosition(m_window, &windowed_xpos, &windowed_ypos);
|
||||
|
||||
SDL_GetWindowSize(m_window, &windowed_width, &windowed_height);
|
||||
|
||||
m_windowed_display = SDL_GetDisplayForWindow(m_window);
|
||||
|
||||
SDL_Rect display_bounds{};
|
||||
if (!SDL_GetDisplayBounds(m_windowed_display, &display_bounds)) {
|
||||
|
||||
Logger::error("SDL_GetDisplayBounds failed: {}", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_SetWindowBordered(m_window, false);
|
||||
|
||||
SDL_SetWindowPosition(m_window, display_bounds.x, display_bounds.y);
|
||||
|
||||
SDL_SetWindowSize(m_window, display_bounds.w, display_bounds.h);
|
||||
|
||||
SDL_RaiseWindow(m_window);
|
||||
|
||||
m_fullscreen = true;
|
||||
m_config.set("window.fullscreen", true);
|
||||
} else {
|
||||
|
||||
SDL_SetWindowBordered(m_window, true);
|
||||
|
||||
SDL_SetWindowSize(m_window, windowed_width, windowed_height);
|
||||
|
||||
SDL_SetWindowPosition(m_window, windowed_xpos, windowed_ypos);
|
||||
|
||||
SDL_RaiseWindow(m_window);
|
||||
|
||||
m_fullscreen = false;
|
||||
m_config.set("window.fullscreen", false);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::init(const Argument& argument) {
|
||||
auto video_driver = m_config.get("video_driver", std::string("auto"));
|
||||
if (argument.video_driver) {
|
||||
video_driver = *argument.video_driver;
|
||||
}
|
||||
if (video_driver == "wayland") {
|
||||
Tools::set_env("SDL_VIDEO_DRIVER", "wayland");
|
||||
} else if (video_driver == "x11") {
|
||||
Tools::set_env("SDL_VIDEO_DRIVER", "x11");
|
||||
} else if (video_driver == "auto") {
|
||||
|
||||
} else {
|
||||
Logger::warn("Unknow Vider Driver {}", video_driver);
|
||||
}
|
||||
|
||||
bool default_exclusive = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
default_exclusive = false;
|
||||
#else
|
||||
default_exclusive = true;
|
||||
#endif
|
||||
|
||||
m_enable_exclusive =
|
||||
m_config.get("enable_exclusive_fullscreen", default_exclusive);
|
||||
|
||||
if (argument.enable_exclusive) {
|
||||
m_enable_exclusive = *argument.enable_exclusive;
|
||||
}
|
||||
|
||||
Logger::info("Exclusive Fullscreen {}", m_enable_exclusive);
|
||||
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
Logger::error("sdl3 init fail");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
|
||||
SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
m_window_width = m_config.get("window.width", 800);
|
||||
m_window_height = m_config.get("window.height", 600);
|
||||
m_window_width = m_config.get("window.width", 1280);
|
||||
m_window_height = m_config.get("window.height", 720);
|
||||
m_window = SDL_CreateWindow("Cubed", m_window_width, m_window_height,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE |
|
||||
SDL_WINDOW_HIGH_PIXEL_DENSITY);
|
||||
|
||||
if (m_config.get("window.fullscreen", false)) {
|
||||
GLFWmonitor* primary_monitor = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(primary_monitor);
|
||||
m_window = glfwCreateWindow(mode->width, mode->height, "Cubed",
|
||||
primary_monitor, NULL);
|
||||
} else {
|
||||
m_window = glfwCreateWindow(m_window_width, m_window_height, "Cubed",
|
||||
NULL, NULL);
|
||||
set_fullscreen(m_config.get("window.fullscreen", false));
|
||||
|
||||
m_context = SDL_GL_CreateContext(m_window);
|
||||
SDL_GL_MakeCurrent(m_window, m_context);
|
||||
|
||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||
Logger::error("Failed to initialize glad");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
set_vsync(m_config.get("window.V-Sync", true));
|
||||
|
||||
glfwMakeContextCurrent(m_window);
|
||||
if (m_config.get("window.V-Sync", true)) {
|
||||
glfwSwapInterval(1);
|
||||
} else {
|
||||
glfwSwapInterval(0);
|
||||
}
|
||||
if (m_game_running) {
|
||||
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
}
|
||||
|
||||
if (glfwRawMouseMotionSupported()) {
|
||||
glfwSetInputMode(m_window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
|
||||
SDL_SetWindowRelativeMouseMode(m_window, true);
|
||||
} else {
|
||||
Logger::warn("Don,t support Raw Mouse Motion");
|
||||
SDL_SetWindowRelativeMouseMode(m_window, false);
|
||||
}
|
||||
|
||||
GLFWmonitor* primary = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(primary);
|
||||
glfwSetWindowPos(m_window, static_cast<int>(mode->width / 2.0f) - 400,
|
||||
static_cast<int>(mode->height / 2.0f) - 300);
|
||||
SDL_SetWindowPosition(m_window, SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED);
|
||||
}
|
||||
|
||||
void Window::reload_config() {
|
||||
// V-Sync
|
||||
if (m_config.get("window.V-Sync", true)) {
|
||||
glfwSwapInterval(1);
|
||||
} else {
|
||||
glfwSwapInterval(0);
|
||||
}
|
||||
set_vsync(m_config.get("window.V-Sync", true));
|
||||
// Window
|
||||
windowed_width = m_config.get("window.width", 800);
|
||||
windowed_height = m_config.get("window.height", 600);
|
||||
windowed_width = m_config.get("window.width", 1280);
|
||||
windowed_height = m_config.get("window.height", 720);
|
||||
|
||||
if (m_config.get("window.fullscreen", false)) {
|
||||
glfwGetWindowPos(m_window, &windowed_xpos, &windowed_ypos);
|
||||
glfwGetWindowSize(m_window, &windowed_width, &windowed_height);
|
||||
set_fullscreen(m_config.get("window.fullscreen", false));
|
||||
|
||||
GLFWmonitor* primary = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(primary);
|
||||
|
||||
glfwSetWindowMonitor(m_window, primary, 0, 0, mode->width, mode->height,
|
||||
GL_DONT_CARE);
|
||||
} else {
|
||||
GLFWmonitor* monitor = glfwGetWindowMonitor(m_window);
|
||||
if (monitor != nullptr) {
|
||||
glfwSetWindowMonitor(m_window, nullptr, windowed_xpos,
|
||||
windowed_ypos, windowed_width, windowed_height,
|
||||
0);
|
||||
} else {
|
||||
Logger::error("Can't Find Monitor");
|
||||
}
|
||||
}
|
||||
if (!m_mouse_enable) {
|
||||
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
disable_mouse();
|
||||
} else {
|
||||
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
enable_mouse();
|
||||
}
|
||||
m_config.set("window.width", windowed_width);
|
||||
m_config.set("window.height", windowed_height);
|
||||
@@ -195,33 +260,44 @@ void Window::reload_config() {
|
||||
|
||||
void Window::toggle_fullscreen() {
|
||||
|
||||
GLFWmonitor* monitor = glfwGetWindowMonitor(m_window);
|
||||
if (monitor != nullptr) {
|
||||
glfwSetWindowMonitor(m_window, nullptr, windowed_xpos, windowed_ypos,
|
||||
windowed_width, windowed_height, 0);
|
||||
|
||||
m_config.set("window.fullscreen", false);
|
||||
if (m_fullscreen) {
|
||||
set_fullscreen(false);
|
||||
} else {
|
||||
glfwGetWindowPos(m_window, &windowed_xpos, &windowed_ypos);
|
||||
glfwGetWindowSize(m_window, &windowed_width, &windowed_height);
|
||||
|
||||
GLFWmonitor* primary = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(primary);
|
||||
|
||||
glfwSetWindowMonitor(m_window, primary, 0, 0, mode->width, mode->height,
|
||||
GL_DONT_CARE);
|
||||
m_config.set("window.fullscreen", true);
|
||||
set_fullscreen(true);
|
||||
}
|
||||
|
||||
m_config.set("window.width", windowed_width);
|
||||
m_config.set("window.height", windowed_height);
|
||||
}
|
||||
void Window::set_fullscreen(bool full) {
|
||||
if (full == m_fullscreen)
|
||||
return;
|
||||
if (m_enable_exclusive) {
|
||||
set_exclusive_fullscreen(full);
|
||||
} else {
|
||||
set_borderless_fullscreen(full);
|
||||
}
|
||||
int w, h;
|
||||
SDL_GetWindowSize(m_window, &w, &h);
|
||||
|
||||
SDL_Event event{};
|
||||
event.type = SDL_EVENT_WINDOW_RESIZED;
|
||||
event.window.data1 = w;
|
||||
event.window.data2 = h;
|
||||
event.window.windowID = SDL_GetWindowID(m_window);
|
||||
|
||||
SDL_PushEvent(&event);
|
||||
SDL_Rect ime_rect{0, 0, 1, 1};
|
||||
|
||||
SDL_SetTextInputArea(m_window, &ime_rect, 0);
|
||||
}
|
||||
void Window::enable_mouse() {
|
||||
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
SDL_WarpMouseInWindow(m_window, width() / 2, height() / 2);
|
||||
SDL_SetWindowRelativeMouseMode(m_window, false);
|
||||
m_mouse_enable = true;
|
||||
}
|
||||
void Window::disable_mouse() {
|
||||
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
SDL_SetWindowRelativeMouseMode(m_window, true);
|
||||
if (m_camera) {
|
||||
m_camera->reset_camera();
|
||||
}
|
||||
@@ -240,18 +316,34 @@ void Window::set_game_running(bool running) {
|
||||
set_imgui_enabled(false);
|
||||
}
|
||||
|
||||
void Window::should_close_window() { glfwSetWindowShouldClose(m_window, true); }
|
||||
void Window::should_close_window() {
|
||||
SDL_Event quit_event;
|
||||
quit_event.type = SDL_EVENT_QUIT;
|
||||
SDL_PushEvent(&quit_event);
|
||||
}
|
||||
|
||||
bool Window::is_enable_imgui() const { return m_imgui_enable; }
|
||||
|
||||
void Window::set_imgui_enabled(bool enable) { m_imgui_enable = enable; }
|
||||
void Window::set_imgui_enabled(bool enable) {
|
||||
m_imgui_enable = enable;
|
||||
if (m_camera) {
|
||||
auto player = m_camera->player();
|
||||
if (player) {
|
||||
player->reset_key_status();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::set_vsync(bool enable) {
|
||||
if (!SDL_GL_SetSwapInterval(static_cast<int>(enable))) {
|
||||
Logger::error("VSync Fail: {}", SDL_GetError());
|
||||
}
|
||||
}
|
||||
int Window::width() const { return m_window_width; }
|
||||
int Window::height() const { return m_window_height; }
|
||||
void Window::imgui_init() {
|
||||
float dpi_scale_x, dpi_scale_y;
|
||||
glfwGetWindowContentScale(m_window, &dpi_scale_x, &dpi_scale_y);
|
||||
// float main_scale =
|
||||
// ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor());
|
||||
float main_scale = dpi_scale_x;
|
||||
float main_scale = SDL_GetWindowDisplayScale(m_window);
|
||||
|
||||
Logger::info("Main Scale {}", main_scale);
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
@@ -288,8 +380,8 @@ void Window::imgui_init() {
|
||||
ImFont* font = io.Fonts->AddFontFromFileTTF(Font::font_path().c_str());
|
||||
ASSERT_MSG(font != nullptr, "Font Load Fail");
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplGlfw_InitForOpenGL(m_window, false);
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
ImGui_ImplSDL3_InitForOpenGL(m_window, m_context);
|
||||
ImGui_ImplOpenGL3_Init("#version 460");
|
||||
|
||||
m_imgui_init = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user