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:
zhenyan121
2026-07-17 18:08:51 +08:00
committed by GitHub
parent d6e1e4a50e
commit 2b75c510af
43 changed files with 1883 additions and 1934 deletions

View File

@@ -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);
};

View File

@@ -6,7 +6,9 @@ struct Argument {
std::optional<int> port;
std::optional<std::string> ip;
std::optional<std::string> player;
std::optional<bool> debug_on;
std::optional<bool> no_debug;
std::optional<std::string> language;
std::optional<std::string> video_driver;
std::optional<bool> enable_exclusive;
};
} // namespace Cubed

View File

@@ -1,8 +1,7 @@
#pragma once
#include "Cubed/input/event.hpp"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
@@ -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

View File

@@ -4,6 +4,8 @@
#include "Cubed/ui/label.hpp"
#include "Cubed/ui/widget.hpp"
#include <format>
#include <memory>
#include <unordered_map>
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<std::string, Label*> m_component;
static std::unique_ptr<DebugCollector>& get_ptr();
};
template <typename... Args>
void d_rep(const std::string& key, std::format_string<Args...> fmt,
Args&&... args) {
std::string msg = std::vformat(fmt.get(), std::make_format_args(args...));
DebugCollector::get().report(key, msg);
}
} // namespace Cubed

View File

@@ -101,6 +101,7 @@ public:
AudioEngine& get_audio();
Config& get_config();
WorldScene& world_scene();
void set_direct_exit();
template <typename Fn>
void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) {
m_ticktimers.emplace(
@@ -153,7 +154,7 @@ private:
tbb::concurrent_unordered_map<std::string, TickTimer> m_ticktimers;
std::unordered_map<std::string, Timer> m_timers;
std::atomic<bool> m_exit_direct{false};
std::atomic<bool> m_game_running{false};
std::atomic<bool> m_receive_exit{false};
std::atomic<int> m_rendering_distance{24};

View File

@@ -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 {

View File

@@ -1,7 +1,5 @@
#pragma once
#include <GLFW/glfw3.h>
namespace Cubed {
struct MoveState {

View File

@@ -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
*/
};
}

View File

@@ -50,7 +50,6 @@ public:
const Texture* get_pbr_texture() const;
const std::vector<std::unique_ptr<Texture>>& item_textures() const;
const Texture* get_skin() const;
// Must call after MapTable::init_map() and glfwMakeContextCurrent(window);
void init_texture();
void need_reload();

View File

@@ -0,0 +1,14 @@
#pragma once
#include <cstdlib> // 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

View File

@@ -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<Font>& get_ptr();
};
} // namespace Cubed

View File

@@ -1,6 +1,6 @@
#pragma once
#include "Cubed/tools/log.hpp"
#include "Cubed/tools/log.hpp" // IWYU pragma: keep
#include <string>
@@ -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

View File

@@ -0,0 +1,28 @@
#pragma once
#include "Cubed/tools/log.hpp"
#include <cstdlib>
#include <string>
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

View File

@@ -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;

View File

@@ -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 <typename F> 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<Image> m_background;
std::unique_ptr<Label> m_foreground;
std::unique_ptr<Rect> m_cursor;
@@ -69,5 +69,6 @@ private:
void on_render(Renderer& renderer) override;
void on_update(float dt) override;
void update_show_text();
void update_input_area();
};
} // namespace Cubed

View File

@@ -25,12 +25,10 @@ public:
Widget& operator=(const Widget&) = delete;
Widget& operator=(Widget&&) = delete;
Widget(const std::string& id, Widget* parent);
Widget(Widget* parent);
virtual ~Widget() = default;
virtual void update(float dt);
virtual void render(Renderer& renderer);
virtual const std::string& id() const;
virtual Widget& set_anchor(Anchor anchor);
virtual Widget& set_offset(glm::ivec2 offset);
virtual Widget& set_window_size(int width, int height);
@@ -58,7 +56,6 @@ public:
protected:
Widget* m_parent = nullptr;
std::string m_id;
float m_window_height = 0;
float m_window_width = 0;
// Center is at the top-left corner, position is at the top-left corner

View File

@@ -1,10 +1,10 @@
#pragma once
#include "Cubed/argument.hpp"
#include "Cubed/config.hpp"
#include "Cubed/input/event.hpp"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <SDL3/SDL.h>
namespace Cubed {
class Camera;
class Renderer;
@@ -14,9 +14,9 @@ public:
~Window();
bool is_mouse_enable() const;
const GLFWwindow* get_glfw_window() const;
GLFWwindow* get_glfw_window();
void init();
const SDL_Window* get_window() const;
SDL_Window* get_window();
void init(const Argument& argument);
void imgui_init();
// end of frame to reload!
@@ -25,7 +25,7 @@ public:
void reload_config();
void toggle_fullscreen();
void set_fullscreen(bool full);
void enable_mouse();
void disable_mouse();
@@ -40,19 +40,31 @@ public:
void set_imgui_enabled(bool enable);
void set_vsync(bool enable);
int width() const;
int height() const;
private:
bool m_mouse_enable = true;
bool m_imgui_init = false;
bool m_game_running = false;
GLFWwindow* m_window;
int m_window_width;
int m_window_height;
bool m_enable_exclusive = false;
SDL_Window* m_window;
SDL_GLContext m_context;
int m_window_width = 0;
int m_window_height = 0;
SDL_DisplayID m_windowed_display = 0;
bool m_fullscreen = false;
Config& m_config;
Camera* m_camera = nullptr;
bool m_imgui_enable = false;
bool handle_key_event(const KeyEvent& e);
bool handle_window_resize_event(const WindowResizeEvent& e);
bool handle_mouse_button_event(const MouseButtonEvent& e);
void set_exclusive_fullscreen(bool full);
void set_borderless_fullscreen(bool full);
};
} // namespace Cubed