From 2b75c510af9a6992a7a55f705a218216d5ec2d02 Mon Sep 17 00:00:00 2001 From: zhenyan121 <104683324+zhenyan121@users.noreply.github.com> Date: Fri, 17 Jul 2026 18:08:51 +0800 Subject: [PATCH] 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 --- .github/workflows/release-build.yml | 13 +- CMakeLists.txt | 2 +- cmake/Dependencies.cmake | 18 +- include/Cubed/app.hpp | 50 +- include/Cubed/argument.hpp | 4 +- include/Cubed/camera.hpp | 6 +- include/Cubed/debug_collector.hpp | 11 + include/Cubed/gameplay/client_world.hpp | 3 +- include/Cubed/input/event.hpp | 6 +- include/Cubed/input/input.hpp | 2 - include/Cubed/input/mouse.hpp | 3 +- include/Cubed/texture_manager.hpp | 1 - include/Cubed/tools/env_tools.hpp | 14 + include/Cubed/tools/font.hpp | 3 + include/Cubed/tools/system_info.hpp | 42 +- include/Cubed/tools/system_window_manager.hpp | 28 + include/Cubed/ui/label.hpp | 1 - include/Cubed/ui/text_field.hpp | 5 +- include/Cubed/ui/widget.hpp | 3 - include/Cubed/window.hpp | 30 +- src/app.cpp | 842 +++++++------ src/camera.cpp | 60 +- src/debug_collector.cpp | 85 +- src/dev_panel.cpp | 95 +- src/gameplay/client_player.cpp | 12 +- src/gameplay/client_world.cpp | 4 +- src/main.cpp | 4 +- src/render/renderer.cpp | 8 +- src/render/world_renderer.cpp | 9 +- src/scene/world_scene.cpp | 4 +- src/tools/font.cpp | 10 +- src/ui/credits_ui.cpp | 1 + src/ui/image.cpp | 4 +- src/ui/label.cpp | 1 - src/ui/text_field.cpp | 30 +- src/ui/widget.cpp | 3 - src/window.cpp | 280 +++-- third_party/imgui/CMakeLists.txt | 4 +- third_party/imgui/imgui_impl_glfw.cpp | 1098 ----------------- third_party/imgui/imgui_impl_glfw.h | 71 -- third_party/imgui/imgui_impl_sdl3.cpp | 887 +++++++++++++ third_party/imgui/imgui_impl_sdl3.h | 54 + vcpkg.json | 6 +- 43 files changed, 1883 insertions(+), 1934 deletions(-) create mode 100644 include/Cubed/tools/env_tools.hpp create mode 100644 include/Cubed/tools/system_window_manager.hpp delete mode 100644 third_party/imgui/imgui_impl_glfw.cpp delete mode 100644 third_party/imgui/imgui_impl_glfw.h create mode 100644 third_party/imgui/imgui_impl_sdl3.cpp create mode 100644 third_party/imgui/imgui_impl_sdl3.h diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 3dbc82f..6c66744 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -27,7 +27,8 @@ jobs: runs-on: ${{ matrix.os }} - + env: + VCPKG_BINARY_SOURCES: clear;files,${{ github.workspace }}/.vcpkg-cache,readwrite steps: - uses: actions/checkout@v4 @@ -48,12 +49,18 @@ jobs: - name: Setup MSVC if: matrix.platform == 'windows' uses: ilammy/msvc-dev-cmd@v1 - + - name: Cache vcpkg + uses: actions/cache@v4 + with: + path: .vcpkg-cache + key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }} + restore-keys: | + ${{ runner.os }}-vcpkg- - name: Bootstrap vcpkg run: | git clone https://github.com/microsoft/vcpkg.git ./vcpkg/bootstrap-vcpkg.bat - + - name: Configure if: matrix.platform == 'windows' run: > diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e9751d..c414dbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,7 +128,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE - glfw + SDL3::SDL3 glad glm::glm OpenGL::GL diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 6a938c1..7ff0006 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -8,9 +8,7 @@ find_package(zstd REQUIRED) find_package(OpenAL REQUIRED) find_package(harfbuzz REQUIRED) find_package(Freetype REQUIRED) -if (UNIX AND NOT APPLE) - find_package(glfw3 REQUIRED) -endif() +find_package(SDL3 REQUIRED) # Third-party libraries @@ -37,20 +35,6 @@ FetchContent_MakeAvailable(tomlplusplus) if (WIN32) - FetchContent_Declare( - glfw - GIT_REPOSITORY https://github.com/glfw/glfw.git - GIT_TAG 3.4 - ) - - set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) - set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) - set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) - set(GLFW_INSTALL OFF CACHE BOOL "" FORCE) - set(GLFW_VULKAN_STATIC ON CACHE BOOL "" FORCE) - set(BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE) - - FetchContent_MakeAvailable(glfw) set(_BUILD_SHARED_LIBS_SAVED ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS ON) diff --git a/include/Cubed/app.hpp b/include/Cubed/app.hpp index cd4a506..abd550f 100644 --- a/include/Cubed/app.hpp +++ b/include/Cubed/app.hpp @@ -1,7 +1,6 @@ #pragma once -#include "Cubed/audio/audio_engine.hpp" -#define GLFW_INCLUDE_NONE #include "Cubed/argument.hpp" +#include "Cubed/audio/audio_engine.hpp" #include "Cubed/config.hpp" #include "Cubed/dev_panel.hpp" #include "Cubed/render/renderer.hpp" @@ -14,21 +13,15 @@ class App { public: App(); ~App(); - static void cursor_position_callback(GLFWwindow* window, double xpos, - double ypos); - static void key_callback(GLFWwindow* window, int key, int scancode, - int action, int mods); - static void mouse_button_callback(GLFWwindow* window, int button, - int action, int mods); - static void window_focus_callback(GLFWwindow* window, int focused); - static void window_reshape_callback(GLFWwindow* window, int new_width, - int new_height); - static void framebuffer_size_callback(GLFWwindow* window, int new_width, - int new_height); - static void mouse_scroll_callback(GLFWwindow* window, double xoffset, - double yoffset); - static void cursor_enter_callback(GLFWwindow* window, int entered); - static void char_callback(GLFWwindow* window, unsigned int ch); + void handle_mouse_move(float xpos, float ypos, float xrel, float yrel); + void handle_sdl_key(SDL_Event& e); + void handle_sdl_mouse_button(SDL_Event& e); + void handle_window_focus(bool focused); + void handle_window_resize(int new_width, int new_height); + void handle_framebuffer_resize(int new_width, int new_height); + void handle_mouse_scroll(float xoffset, float yoffset); + void handle_text_input(const char* text); + static int start_cubed_application(int argc, char** argv); static unsigned int seed(); @@ -43,29 +36,34 @@ public: const Argument& argument() const; AudioEngine& audio(); - const char* get_clipboard_text(); + std::string get_clipboard_text(); + + void start_text_input(); + void stop_text_input(); + void update_text_input_area(const glm::vec4& textbox, + float cursor_position_x); private: Config m_game_config; + Window m_window; + TextureManager m_texture_manager; AudioEngine m_audio; Renderer m_renderer; - Window m_window; - SceneManager m_scene_manager; - inline static double last_time = glfwGetTime(); - inline static double current_time = glfwGetTime(); - inline static double dt = 0.0f; - inline static double fps_time_count = 0.0f; + inline static uint64_t last_tick = 0; + inline static uint64_t current_tick = 0; + inline static float dt = 0.0f; + inline static float fps_time_count = 0.0f; inline static int frame_count = 0; inline static int fps = 0; Argument m_argument; - + bool m_running = true; void init(int argc, char** argv); void handle_argument(int argc, char** argv); auto init_camera(); @@ -76,6 +74,8 @@ private: void run(); void update(); + void handle_sdl_event(SDL_Event& e); + void dispatch_event(const Event& e); }; diff --git a/include/Cubed/argument.hpp b/include/Cubed/argument.hpp index 2b0c4fd..0df551b 100644 --- a/include/Cubed/argument.hpp +++ b/include/Cubed/argument.hpp @@ -6,7 +6,9 @@ struct Argument { std::optional port; std::optional ip; std::optional player; - std::optional debug_on; + std::optional no_debug; std::optional language; + std::optional video_driver; + std::optional enable_exclusive; }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/camera.hpp b/include/Cubed/camera.hpp index dfe6149..2e2ea98 100644 --- a/include/Cubed/camera.hpp +++ b/include/Cubed/camera.hpp @@ -1,8 +1,7 @@ #pragma once #include "Cubed/input/event.hpp" -#define GLFW_INCLUDE_NONE -#include + #include #include #include @@ -40,7 +39,7 @@ public: void camera_init(ClientPlayer* player); void hot_reload(); void reset_camera(); - void update_cursor_position_camera(double xpos, double ypos); + void update_cursor_position_camera(float offset_x, float offset_y); const glm::mat4 get_camera_lookat() const; const glm::vec3& get_camera_pos() const; @@ -50,6 +49,7 @@ public: void change_perspective(); bool is_first_person() const; bool handle_event(const Event& e); + ClientPlayer* player(); }; } // namespace Cubed diff --git a/include/Cubed/debug_collector.hpp b/include/Cubed/debug_collector.hpp index 5aeaca7..5de74fd 100644 --- a/include/Cubed/debug_collector.hpp +++ b/include/Cubed/debug_collector.hpp @@ -4,6 +4,8 @@ #include "Cubed/ui/label.hpp" #include "Cubed/ui/widget.hpp" +#include +#include #include namespace Cubed { @@ -11,6 +13,7 @@ namespace Cubed { class DebugCollector { public: static DebugCollector& get(); + static void distory(); DebugCollector(); void report(const std::string& name, std::string_view content); @@ -21,6 +24,14 @@ public: private: ColumnLayout m_widget; std::unordered_map m_component; + static std::unique_ptr& get_ptr(); }; +template +void d_rep(const std::string& key, std::format_string fmt, + Args&&... args) { + std::string msg = std::vformat(fmt.get(), std::make_format_args(args...)); + DebugCollector::get().report(key, msg); +} + } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index 4e0dd32..adcb07e 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -101,6 +101,7 @@ public: AudioEngine& get_audio(); Config& get_config(); WorldScene& world_scene(); + void set_direct_exit(); template void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) { m_ticktimers.emplace( @@ -153,7 +154,7 @@ private: tbb::concurrent_unordered_map m_ticktimers; std::unordered_map m_timers; - + std::atomic m_exit_direct{false}; std::atomic m_game_running{false}; std::atomic m_receive_exit{false}; std::atomic m_rendering_distance{24}; diff --git a/include/Cubed/input/event.hpp b/include/Cubed/input/event.hpp index 13b8535..efe26fb 100644 --- a/include/Cubed/input/event.hpp +++ b/include/Cubed/input/event.hpp @@ -11,8 +11,10 @@ namespace Cubed { struct MouseMoveEvent { float xpos; float ypos; - - MouseMoveEvent(float x, float y) : xpos(x), ypos(y) {} + float xrel; + float yrel; + MouseMoveEvent(float x, float y, float dx, float dy) + : xpos(x), ypos(y), xrel(dx), yrel(dy) {} }; struct MouseButtonEvent { diff --git a/include/Cubed/input/input.hpp b/include/Cubed/input/input.hpp index 51d65a0..ef3e549 100644 --- a/include/Cubed/input/input.hpp +++ b/include/Cubed/input/input.hpp @@ -1,7 +1,5 @@ #pragma once -#include - namespace Cubed { struct MoveState { diff --git a/include/Cubed/input/mouse.hpp b/include/Cubed/input/mouse.hpp index 1643513..27a1ad6 100644 --- a/include/Cubed/input/mouse.hpp +++ b/include/Cubed/input/mouse.hpp @@ -9,7 +9,7 @@ enum class MouseKey { BACK_BUTTON, // Side button back FORWARD_BUTTON, // Side button forward - + /* WHEEL_UP, WHEEL_DOWN, WHEEL_LEFT, @@ -20,6 +20,7 @@ enum class MouseKey { EXTRA_BUTTON_3, EXTRA_BUTTON_4, EXTRA_BUTTON_5 + */ }; } diff --git a/include/Cubed/texture_manager.hpp b/include/Cubed/texture_manager.hpp index 3c5fbb4..98f7694 100644 --- a/include/Cubed/texture_manager.hpp +++ b/include/Cubed/texture_manager.hpp @@ -50,7 +50,6 @@ public: const Texture* get_pbr_texture() const; const std::vector>& item_textures() const; const Texture* get_skin() const; - // Must call after MapTable::init_map() and glfwMakeContextCurrent(window); void init_texture(); void need_reload(); diff --git a/include/Cubed/tools/env_tools.hpp b/include/Cubed/tools/env_tools.hpp new file mode 100644 index 0000000..fd22932 --- /dev/null +++ b/include/Cubed/tools/env_tools.hpp @@ -0,0 +1,14 @@ +#pragma once +#include // IWYU pragma: keep +namespace Cubed { +namespace Tools { + +inline void set_env(const char* name, const char* value) { +#ifdef _WIN32 + _putenv_s(name, value); +#else + setenv(name, value, 1); +#endif +} +} // namespace Tools +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/tools/font.hpp b/include/Cubed/tools/font.hpp index 6aad63e..55d6d7f 100644 --- a/include/Cubed/tools/font.hpp +++ b/include/Cubed/tools/font.hpp @@ -51,6 +51,8 @@ public: Font(); ~Font(); static Font& get(); + + static void destroy(); TextMesh vertices(const std::string& text); const Texture* text_texture(); static const std::string& font_path(); @@ -70,6 +72,7 @@ private: int m_max_layers = 0; Glyph& load_glyph(uint32_t glyph_index); void upload_glyph(Glyph& glyph, const unsigned char* buffer); + static std::unique_ptr& get_ptr(); }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/tools/system_info.hpp b/include/Cubed/tools/system_info.hpp index 851cba2..5e103f0 100644 --- a/include/Cubed/tools/system_info.hpp +++ b/include/Cubed/tools/system_info.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Cubed/tools/log.hpp" +#include "Cubed/tools/log.hpp" // IWYU pragma: keep #include @@ -157,6 +157,46 @@ inline std::string get_cpu_info() { #endif } +inline std::string get_compiler_info() { + std::string result; + +#if defined(__clang__) + result = "Clang "; + result += __clang_version__; + +#elif defined(__GNUC__) + result = "GCC "; + result += std::to_string(__GNUC__); + result += "."; + result += std::to_string(__GNUC_MINOR__); + result += "."; + result += std::to_string(__GNUC_PATCHLEVEL__); + +#elif defined(_MSC_VER) + int major = _MSC_VER / 100; + int minor = _MSC_VER % 100; + + result = "MSVC "; + result += std::to_string(major); + result += "."; + result += std::to_string(minor); + +#else + result = "Unknown Compiler"; +#endif + constexpr long CPP_VERSION = +#ifdef _MSC_VER + _MSVC_LANG; +#else + __cplusplus; +#endif + result += " (C++"; + result += std::to_string(CPP_VERSION); + result += ")"; + + return result; +} + } // namespace Tools } // namespace Cubed diff --git a/include/Cubed/tools/system_window_manager.hpp b/include/Cubed/tools/system_window_manager.hpp new file mode 100644 index 0000000..7251ac3 --- /dev/null +++ b/include/Cubed/tools/system_window_manager.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Cubed/tools/log.hpp" + +#include +#include +namespace Cubed { + +namespace Tools { +inline std::string detect_wm() { +#ifdef _WIN32 + return "Windows"; +#endif +#ifdef __linux__ + + const char* desktop = getenv("XDG_CURRENT_DESKTOP"); + if (!desktop) { + return "Unknown"; + } + Logger::info("XDG_CURRENT_DESKTOP: {}", desktop); + return std::string(desktop); +#endif + + return "Unknown"; +} +} // namespace Tools + +} // namespace Cubed diff --git a/include/Cubed/ui/label.hpp b/include/Cubed/ui/label.hpp index b88e96d..734fa8f 100644 --- a/include/Cubed/ui/label.hpp +++ b/include/Cubed/ui/label.hpp @@ -10,7 +10,6 @@ public: Label& operator=(const Label&) = delete; Label& operator=(Label&&) = delete; - Label(const std::string& id, Widget* parent); Label(Widget* parent); virtual ~Label() = default; diff --git a/include/Cubed/ui/text_field.hpp b/include/Cubed/ui/text_field.hpp index 87e12c5..7f98d5e 100644 --- a/include/Cubed/ui/text_field.hpp +++ b/include/Cubed/ui/text_field.hpp @@ -31,7 +31,7 @@ public: bool handle_mouse_button_event(const MouseButtonEvent& e) override; bool handle_text_input_event(const TextInputEvent& e) override; bool handle_key_event(const KeyEvent& e) override; - + bool handle_window_resize_event(const WindowResizeEvent& e) override; const std::string& input_text() const; template TextField& set_on_finish(F&& f) { @@ -47,7 +47,7 @@ private: static constexpr const char* DEFAULT_TEXT_FIELD_IMAGE = "texture/ui/textfield001.png"; - App* m_app; + App* m_app = nullptr; std::unique_ptr m_background; std::unique_ptr