mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
feature: UI (#31)
* refactor(ui): replace Text with Label/Widget component system Replace the old `Text` class with a new component-based UI system consisting of `Widget` and `Label` classes. Key changes: - Remove `Text` class and its GPU upload logic; introduce `Label` as a `Widget` subclass with dirty-flag vertex update. - Add `UIVertexData` struct to manage per-label vertex buffer/array and memory. - Refactor `DebugCollector` to store labels in a `Widget` tree, removing hash-based lookup. - Simplify `Font::vertices()` signature by removing position/scale parameters; scaling is now applied in the renderer’s model matrix. - Update `Renderer` with `render_label()` and move UI rendering to a `render_ui()` that renders the widget tree. - Add new source files `label.cpp`, `widget.cpp`, `ui_vertex_data.cpp` and update CMakeLists. * refactor(render): replace UI shaders with image shaders and Image widget * refactor(core): add event system and scene management - Introduce Event variant and Overloaded helper for input handling - Move game state (camera, client_world, dev_panel) from App to WorldScene - Add SceneManager with push/pop/change operations for scene stack - Refactor input callbacks to dispatch events through scene hierarchy - Extract Argument struct to separate header - Update Renderer and WorldRenderer to accept world reference - Replace global input state with event-driven processing in ClientPlayer, Camera, etc. * refactor: add framebuffer resize event and separate UI management * fix(font): use correct texture format and clamp to edge for font atlas * feat(input): add KeyAction::REPEAT for key repeat events Add a new REPEAT value to the KeyAction enum and update the input callbacks to map GLFW_REPEAT actions to the new value instead of treating them as press. * feat(client-player): add block cooldown and track mouse state Introduce a time-based cooldown for block placement (PLACE_BLOCK_INTERVAL) to prevent rapid clicking. Replace the global InputState with per-player MouseState tracking in ClientPlayer. Rename place_block() to get_current_block() for clarity. Remove the old src/input.cpp and the Cubed/input.hpp header, moving input structures to Cubed/input/input.hpp. * ui: add main menu scene and interactive button widget - Implement MainMenuScene with a "Start Game" button that pushes the WorldScene. - Extend Button class with background/foreground, hover detection, and size queries. - Add virtual width/height and event handlers to Widget base class. - Update WorldUIManager to propagate mouse move events. - Adjust Window mouse mode based on game running state. * feat(ui): add button scaling and change square vertices to top-left origin * refactor(font): return TextMesh from Font::vertices to include bounding box Replace the plain vertex vector with a TextMesh struct that carries width, height, and min coordinates. Update Label to compute and store these values immediately on text change (removing lazy dirty update). Fix Button's width/height to factor in scale and use concrete widget types for background and foreground. * feat(ui): support scaling of labels and images Modify width() and height() methods to multiply by m_scale for both Label and Image. Rename internal dimensions to m_real_width and m_real_height for clarity. Adjust Button foreground position to vertically center when label is scaled. * refactor(ui): move scale property to subclasses and fix resize event handling Remove scale from base Widget class and add per-type set_scale/scale methods to Button, Image, and Label. Dispatch separate WindowResizeEvent alongside existing FrameBufferResizeEvent. Correct centering calculations from `+` to `-` in main menu and world UI managers. * fix(render): remove duplicate scaling in render_image model matrix * feat(ui): introduce anchor-based widget positioning system Replace set_position with anchor and offset for relative positioning. Add parent pointer to widget hierarchy. Remove manual resize logic in UI managers. * feat(ui): introduce ColumnLayout widget and refactor widget parenting - Add ColumnLayout widget that arranges children vertically with spacing. - Refactor Widget::add_child to automatically pass `this` as parent. - Update DebugCollector to use ColumnLayout for consistent spacing. - Expose children() accessor in Widget for layout management. * feat(main_menu): add exit button and refactor layout with ColumnLayout - Add `should_close_window()` method to force window close from UI. - Replace standalone button with ColumnLayout for proper centering. - Add "Exit" button that calls `should_close_window()`. - Update ESC key handling to only close window when game is not running. - Fix ColumnLayout to respect parent's anchor instead of hardcoded TOP_LEFT. - Remove unused parameter name in Image::update for consistency. * feat(ui): add Rect widget with fill, color, and parent-relative sizing * refactor(ui): extract common UI manager logic into base class * refactor: move server logic to WorldScene and refactor UI methods * feat(scene): implement pause menu with UI manager and escape key toggling Add PauseMenuUIManager class and integrate pause state into WorldScene. Escape key toggles pause in ClientPlayer and PauseMenuUIManager. Refactor Window mouse and imgui control to support pause state. * refactor(scene): dispatch events via typed handlers and move pause toggle to WorldScene * feat(ui): add HUD visibility toggle and image fill features * refactor(app): remove redundant ImGui WantCaptureMouse check in cursor callback * feat(scene): add credits scene and UI * feat(credits): add ESC key handling; remove about tab from dev panel * feat(ui): add Slider widget for value selection * refactor(ui/slider): improve track/thumb initialization and validation Rename track/thumb accessors from set_track/set_thumb to get_track/get_thumb. Add private init methods and a constant THUMB_WIDTH. Add validation to set_width with log and assert. Modify set_height to assume non-null m_thumb. * refactor(ui): simplify Button API with property setters * feat(ui): add label and image support to slider - Add `set_text()`, `set_track_image()`, `set_thumb_image()` methods. - Include label rendering and auto-scaling based on slider dimensions. - Replace static `THUMB_WIDTH` with dynamic thumb sizing. - Add slider thumb and track texture assets. * feat(ui): add int slider support and fix update_text_scale calls * refactor(config): rename hot_reload to reload_config and add settings scene * feat(ui): add auto-scaling option for button and slider text * feat(ui): add button enable/disable and reset on re-enter Prevent double-clicking on buttons that push new scenes by disabling them on click and re-enabling when the UI manager's on_re_enter is called. * fix(input): reset key status on pause * feat(ui): add ComboButton widget and integrate into settings Introduce ComboButton, a button that cycles through options on click. Used in SettingsUI for fullscreen, V-Sync, and anisotropic filtering. Adds texture reload support in SettingsScene and makes Button methods virtual to allow overriding. Also fixes default mouse_enable to true. * feat(ui): add child anchor and content sizing to column layout * feat(ui): add TextField widget with UTF-8 text input support * feat(scene): add host game scene and world parameter handling * feat(scene): add join game scene and UI * feat(ui): add clipboard paste to TextField * feat(ui): add blinking cursor to text field * feat(ui): add error UI for connection failures and network errors Introduce ErrorUI to display error messages in-world when the client encounters connection failures or network errors. The network client now stores error strings thread-safely and exposes them via `get_error_string()`. The world scene suspends normal update/render when an error is active and shows the error overlay, allowing the user to return to the previous scene. Additionally, the client world checks for connection errors during exit to avoid hanging, and the join game UI is fixed to correctly default to client mode. * refactor: move connect error check to WorldScene and add UI titles * feat(ui): add error display in host and join game screens * feat(ui): add configurable child traversal order for event handling Add TraversalOrder enum to Widget, allowing event handlers to iterate children in back-to-front (default) or front-to-back order. Set ColumnLayout to front-to-back order. Change TextField mouse button handler to return false, enabling event propagation. * fix: window build fail * style(ui): remove extra blank line
This commit is contained in:
591
src/app.cpp
591
src/app.cpp
@@ -1,11 +1,13 @@
|
||||
#include "Cubed/app.hpp"
|
||||
|
||||
#include "Cubed/camera.hpp"
|
||||
#include "Cubed/config.hpp"
|
||||
#include "Cubed/debug_collector.hpp"
|
||||
#include "Cubed/tools/arg_parser.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/system_info.hpp"
|
||||
#include "Cubed/tools/text_tools.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#include <exception>
|
||||
@@ -16,30 +18,22 @@ App::App()
|
||||
|
||||
: m_game_config(ASSETS_PATH "config.toml"),
|
||||
m_texture_manager(m_game_config), m_audio(m_game_config),
|
||||
m_client_world(m_audio, m_game_config), m_dev_panel(*this),
|
||||
m_renderer(m_camera, m_client_world, m_texture_manager, m_dev_panel,
|
||||
m_game_config),
|
||||
m_window(m_renderer, m_game_config) {}
|
||||
m_renderer(m_texture_manager, m_game_config), m_window(m_game_config),
|
||||
m_scene_manager(*this) {}
|
||||
|
||||
App::~App() {
|
||||
if (m_client) {
|
||||
m_client->stop();
|
||||
}
|
||||
}
|
||||
App::~App() {}
|
||||
void App::cursor_position_callback(GLFWwindow* window, double xpos,
|
||||
double ypos) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) {
|
||||
if (app->m_window.is_enable_imgui()) {
|
||||
ImGui_ImplGlfw_CursorPosCallback(window, xpos, ypos);
|
||||
return;
|
||||
}
|
||||
if (!app->m_window.is_mouse_enable()) {
|
||||
app->m_camera.update_cursor_position_camera(xpos, ypos);
|
||||
}
|
||||
|
||||
app->m_scene_manager.handle_event(
|
||||
MouseMoveEvent{static_cast<float>(xpos), static_cast<float>(ypos)});
|
||||
}
|
||||
void App::init(int argc, char** argv) {
|
||||
handle_toml();
|
||||
@@ -60,6 +54,8 @@ void App::init(int argc, char** argv) {
|
||||
window_focus_callback);
|
||||
glfwSetWindowSizeCallback(m_window.get_glfw_window(),
|
||||
window_reshape_callback);
|
||||
glfwSetFramebufferSizeCallback(m_window.get_glfw_window(),
|
||||
framebuffer_size_callback);
|
||||
glfwSetKeyCallback(m_window.get_glfw_window(), key_callback);
|
||||
glfwSetScrollCallback(m_window.get_glfw_window(), mouse_scroll_callback);
|
||||
glfwSetCursorEnterCallback(m_window.get_glfw_window(),
|
||||
@@ -67,29 +63,26 @@ void App::init(int argc, char** argv) {
|
||||
glfwSetCharCallback(m_window.get_glfw_window(), char_callback);
|
||||
|
||||
m_audio.init();
|
||||
|
||||
ChunkGenerator::init();
|
||||
BlockManager::init();
|
||||
m_renderer.init(m_argument.debug_on);
|
||||
Logger::info("Renderer Init Success");
|
||||
m_window.update_viewport();
|
||||
// MapTable::init_map();
|
||||
m_texture_manager.init_texture();
|
||||
Logger::info("Texture Load Success");
|
||||
if (!m_argument.is_client) {
|
||||
m_server.start_server(m_argument.port);
|
||||
|
||||
m_scene_manager.request_push(SceneType::MAIN_MENU);
|
||||
|
||||
{
|
||||
int w, h;
|
||||
glfwGetWindowSize(m_window.get_glfw_window(), &w, &h);
|
||||
window_reshape_callback(m_window.get_glfw_window(), w, h);
|
||||
}
|
||||
|
||||
m_client = std::make_shared<NetworkClient>(m_client_world);
|
||||
|
||||
m_client->start(m_argument.ip, m_argument.port);
|
||||
// init will send packet
|
||||
m_client_world.init(m_argument.player, m_client);
|
||||
|
||||
Logger::info("World Init Success");
|
||||
|
||||
m_camera.camera_init(&m_client_world.get_player());
|
||||
m_dev_panel.init();
|
||||
{
|
||||
int w, h;
|
||||
glfwGetFramebufferSize(m_window.get_glfw_window(), &w, &h);
|
||||
framebuffer_size_callback(m_window.get_glfw_window(), w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void App::handle_argument(int argc, char** argv) {
|
||||
@@ -178,50 +171,358 @@ void App::key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
// ImGui_ImplGlfw_CursorEnterCallback(window,
|
||||
// !app->m_window.is_mouse_enable());
|
||||
if (io.WantCaptureKeyboard && app->m_window.is_mouse_enable()) {
|
||||
if ((key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_ESCAPE) &&
|
||||
action == GLFW_PRESS) {
|
||||
app->m_window.toggle_mouse_able();
|
||||
app->m_camera.reset_camera();
|
||||
if (io.WantCaptureKeyboard && app->m_window.is_enable_imgui()) {
|
||||
if ((key == GLFW_KEY_LEFT_ALT) && action == GLFW_PRESS) {
|
||||
app->dispatch_event(KeyEvent{Key::LEFT_ALT, KeyAction::PRESS});
|
||||
return;
|
||||
}
|
||||
ImGui_ImplGlfw_KeyCallback(window, key, scancode, action, mods);
|
||||
return;
|
||||
}
|
||||
Key pkey;
|
||||
KeyAction act;
|
||||
switch (key) {
|
||||
// Letter keys
|
||||
case GLFW_KEY_A:
|
||||
pkey = Key::A;
|
||||
break;
|
||||
case GLFW_KEY_B:
|
||||
pkey = Key::B;
|
||||
break;
|
||||
case GLFW_KEY_C:
|
||||
pkey = Key::C;
|
||||
break;
|
||||
case GLFW_KEY_D:
|
||||
pkey = Key::D;
|
||||
break;
|
||||
case GLFW_KEY_E:
|
||||
pkey = Key::E;
|
||||
break;
|
||||
case GLFW_KEY_F:
|
||||
pkey = Key::F;
|
||||
break;
|
||||
case GLFW_KEY_G:
|
||||
pkey = Key::G;
|
||||
break;
|
||||
case GLFW_KEY_H:
|
||||
pkey = Key::H;
|
||||
break;
|
||||
case GLFW_KEY_I:
|
||||
pkey = Key::I;
|
||||
break;
|
||||
case GLFW_KEY_J:
|
||||
pkey = Key::J;
|
||||
break;
|
||||
case GLFW_KEY_K:
|
||||
pkey = Key::K;
|
||||
break;
|
||||
case GLFW_KEY_L:
|
||||
pkey = Key::L;
|
||||
break;
|
||||
case GLFW_KEY_M:
|
||||
pkey = Key::M;
|
||||
break;
|
||||
case GLFW_KEY_N:
|
||||
pkey = Key::N;
|
||||
break;
|
||||
case GLFW_KEY_O:
|
||||
pkey = Key::O;
|
||||
break;
|
||||
case GLFW_KEY_P:
|
||||
pkey = Key::P;
|
||||
break;
|
||||
case GLFW_KEY_Q:
|
||||
if (action == GLFW_PRESS) {
|
||||
}
|
||||
break;
|
||||
case GLFW_KEY_ESCAPE:
|
||||
if (action == GLFW_PRESS) {
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
}
|
||||
break;
|
||||
case GLFW_KEY_F11:
|
||||
if (action == GLFW_PRESS) {
|
||||
app->m_window.toggle_fullscreen();
|
||||
}
|
||||
pkey = Key::Q;
|
||||
break;
|
||||
case GLFW_KEY_R:
|
||||
if (action == GLFW_PRESS) {
|
||||
app->m_texture_manager.need_reload();
|
||||
}
|
||||
pkey = Key::R;
|
||||
break;
|
||||
case GLFW_KEY_LEFT_ALT:
|
||||
if (action == GLFW_PRESS) {
|
||||
app->m_window.toggle_mouse_able();
|
||||
app->m_camera.reset_camera();
|
||||
}
|
||||
case GLFW_KEY_S:
|
||||
pkey = Key::S;
|
||||
break;
|
||||
case GLFW_KEY_T:
|
||||
pkey = Key::T;
|
||||
break;
|
||||
case GLFW_KEY_U:
|
||||
pkey = Key::U;
|
||||
break;
|
||||
case GLFW_KEY_V:
|
||||
pkey = Key::V;
|
||||
break;
|
||||
case GLFW_KEY_W:
|
||||
pkey = Key::W;
|
||||
break;
|
||||
case GLFW_KEY_X:
|
||||
pkey = Key::X;
|
||||
break;
|
||||
case GLFW_KEY_Y:
|
||||
pkey = Key::Y;
|
||||
break;
|
||||
case GLFW_KEY_Z:
|
||||
pkey = Key::Z;
|
||||
break;
|
||||
|
||||
// Digit keys (main keyboard area)
|
||||
case GLFW_KEY_0:
|
||||
pkey = Key::DIGIT_0;
|
||||
break;
|
||||
case GLFW_KEY_1:
|
||||
pkey = Key::DIGIT_1;
|
||||
break;
|
||||
case GLFW_KEY_2:
|
||||
pkey = Key::DIGIT_2;
|
||||
break;
|
||||
case GLFW_KEY_3:
|
||||
pkey = Key::DIGIT_3;
|
||||
break;
|
||||
case GLFW_KEY_4:
|
||||
pkey = Key::DIGIT_4;
|
||||
break;
|
||||
case GLFW_KEY_5:
|
||||
pkey = Key::DIGIT_5;
|
||||
break;
|
||||
case GLFW_KEY_6:
|
||||
pkey = Key::DIGIT_6;
|
||||
break;
|
||||
case GLFW_KEY_7:
|
||||
pkey = Key::DIGIT_7;
|
||||
break;
|
||||
case GLFW_KEY_8:
|
||||
pkey = Key::DIGIT_8;
|
||||
break;
|
||||
case GLFW_KEY_9:
|
||||
pkey = Key::DIGIT_9;
|
||||
break;
|
||||
|
||||
// Function keys
|
||||
case GLFW_KEY_F1:
|
||||
pkey = Key::F1;
|
||||
break;
|
||||
case GLFW_KEY_F2:
|
||||
pkey = Key::F2;
|
||||
break;
|
||||
case GLFW_KEY_F3:
|
||||
pkey = Key::F3;
|
||||
break;
|
||||
case GLFW_KEY_F4:
|
||||
pkey = Key::F4;
|
||||
break;
|
||||
case GLFW_KEY_F5:
|
||||
if (action == GLFW_PRESS) {
|
||||
app->m_camera.change_perspective();
|
||||
}
|
||||
pkey = Key::F5;
|
||||
break;
|
||||
case GLFW_KEY_F6:
|
||||
pkey = Key::F6;
|
||||
break;
|
||||
case GLFW_KEY_F7:
|
||||
pkey = Key::F7;
|
||||
break;
|
||||
case GLFW_KEY_F8:
|
||||
pkey = Key::F8;
|
||||
break;
|
||||
case GLFW_KEY_F9:
|
||||
pkey = Key::F9;
|
||||
break;
|
||||
case GLFW_KEY_F10:
|
||||
pkey = Key::F10;
|
||||
break;
|
||||
case GLFW_KEY_F11:
|
||||
pkey = Key::F11;
|
||||
break;
|
||||
case GLFW_KEY_F12:
|
||||
pkey = Key::F12;
|
||||
break;
|
||||
|
||||
// Control keys
|
||||
case GLFW_KEY_BACKSPACE:
|
||||
pkey = Key::BACKSPACE;
|
||||
break;
|
||||
case GLFW_KEY_TAB:
|
||||
pkey = Key::TAB;
|
||||
break;
|
||||
case GLFW_KEY_ENTER:
|
||||
pkey = Key::ENTER;
|
||||
break;
|
||||
case GLFW_KEY_ESCAPE:
|
||||
pkey = Key::ESCAPE;
|
||||
break;
|
||||
case GLFW_KEY_SPACE:
|
||||
pkey = Key::SPACE;
|
||||
break;
|
||||
case GLFW_KEY_CAPS_LOCK:
|
||||
pkey = Key::CAPS_LOCK;
|
||||
break;
|
||||
case GLFW_KEY_NUM_LOCK:
|
||||
pkey = Key::NUM_LOCK;
|
||||
break;
|
||||
case GLFW_KEY_SCROLL_LOCK:
|
||||
pkey = Key::SCROLL_LOCK;
|
||||
break;
|
||||
|
||||
// Modifier keys
|
||||
case GLFW_KEY_LEFT_SHIFT:
|
||||
pkey = Key::LEFT_SHIFT;
|
||||
break;
|
||||
case GLFW_KEY_RIGHT_SHIFT:
|
||||
pkey = Key::RIGHT_SHIFT;
|
||||
break;
|
||||
case GLFW_KEY_LEFT_CONTROL:
|
||||
pkey = Key::LEFT_CTRL;
|
||||
break;
|
||||
case GLFW_KEY_RIGHT_CONTROL:
|
||||
pkey = Key::RIGHT_CTRL;
|
||||
break;
|
||||
case GLFW_KEY_LEFT_ALT:
|
||||
pkey = Key::LEFT_ALT;
|
||||
break;
|
||||
case GLFW_KEY_RIGHT_ALT:
|
||||
pkey = Key::RIGHT_ALT;
|
||||
break;
|
||||
case GLFW_KEY_LEFT_SUPER:
|
||||
pkey = Key::LEFT_SUPER;
|
||||
break;
|
||||
case GLFW_KEY_RIGHT_SUPER:
|
||||
pkey = Key::RIGHT_SUPER;
|
||||
break;
|
||||
|
||||
// Navigation keys
|
||||
case GLFW_KEY_INSERT:
|
||||
pkey = Key::INSERT;
|
||||
break;
|
||||
case GLFW_KEY_DELETE:
|
||||
pkey = Key::DELETE;
|
||||
break;
|
||||
case GLFW_KEY_HOME:
|
||||
pkey = Key::HOME;
|
||||
break;
|
||||
case GLFW_KEY_END:
|
||||
pkey = Key::END;
|
||||
break;
|
||||
case GLFW_KEY_PAGE_UP:
|
||||
pkey = Key::PAGE_UP;
|
||||
break;
|
||||
case GLFW_KEY_PAGE_DOWN:
|
||||
pkey = Key::PAGE_DOWN;
|
||||
break;
|
||||
case GLFW_KEY_LEFT:
|
||||
pkey = Key::LEFT;
|
||||
break;
|
||||
case GLFW_KEY_RIGHT:
|
||||
pkey = Key::RIGHT;
|
||||
break;
|
||||
case GLFW_KEY_UP:
|
||||
pkey = Key::UP;
|
||||
break;
|
||||
case GLFW_KEY_DOWN:
|
||||
pkey = Key::DOWN;
|
||||
break;
|
||||
|
||||
// Lock and system keys
|
||||
case GLFW_KEY_PRINT_SCREEN:
|
||||
pkey = Key::PRINT_SCREEN;
|
||||
break;
|
||||
case GLFW_KEY_PAUSE:
|
||||
pkey = Key::PAUSE;
|
||||
break;
|
||||
|
||||
// Main keyboard area symbol keys
|
||||
case GLFW_KEY_GRAVE_ACCENT:
|
||||
pkey = Key::GRAVE_ACCENT;
|
||||
break;
|
||||
case GLFW_KEY_MINUS:
|
||||
pkey = Key::MINUS;
|
||||
break;
|
||||
case GLFW_KEY_EQUAL:
|
||||
pkey = Key::EQUALS;
|
||||
break;
|
||||
case GLFW_KEY_LEFT_BRACKET:
|
||||
pkey = Key::LEFT_BRACKET;
|
||||
break;
|
||||
case GLFW_KEY_RIGHT_BRACKET:
|
||||
pkey = Key::RIGHT_BRACKET;
|
||||
break;
|
||||
case GLFW_KEY_BACKSLASH:
|
||||
pkey = Key::BACKSLASH;
|
||||
break;
|
||||
case GLFW_KEY_SEMICOLON:
|
||||
pkey = Key::SEMICOLON;
|
||||
break;
|
||||
case GLFW_KEY_APOSTROPHE:
|
||||
pkey = Key::APOSTROPHE;
|
||||
break;
|
||||
case GLFW_KEY_COMMA:
|
||||
pkey = Key::COMMA;
|
||||
break;
|
||||
case GLFW_KEY_PERIOD:
|
||||
pkey = Key::PERIOD;
|
||||
break;
|
||||
case GLFW_KEY_SLASH:
|
||||
pkey = Key::SLASH;
|
||||
break;
|
||||
|
||||
// Numpad area
|
||||
case GLFW_KEY_KP_0:
|
||||
pkey = Key::NUMPAD_0;
|
||||
break;
|
||||
case GLFW_KEY_KP_1:
|
||||
pkey = Key::NUMPAD_1;
|
||||
break;
|
||||
case GLFW_KEY_KP_2:
|
||||
pkey = Key::NUMPAD_2;
|
||||
break;
|
||||
case GLFW_KEY_KP_3:
|
||||
pkey = Key::NUMPAD_3;
|
||||
break;
|
||||
case GLFW_KEY_KP_4:
|
||||
pkey = Key::NUMPAD_4;
|
||||
break;
|
||||
case GLFW_KEY_KP_5:
|
||||
pkey = Key::NUMPAD_5;
|
||||
break;
|
||||
case GLFW_KEY_KP_6:
|
||||
pkey = Key::NUMPAD_6;
|
||||
break;
|
||||
case GLFW_KEY_KP_7:
|
||||
pkey = Key::NUMPAD_7;
|
||||
break;
|
||||
case GLFW_KEY_KP_8:
|
||||
pkey = Key::NUMPAD_8;
|
||||
break;
|
||||
case GLFW_KEY_KP_9:
|
||||
pkey = Key::NUMPAD_9;
|
||||
break;
|
||||
case GLFW_KEY_KP_ADD:
|
||||
pkey = Key::NUMPAD_ADD;
|
||||
break;
|
||||
case GLFW_KEY_KP_SUBTRACT:
|
||||
pkey = Key::NUMPAD_SUBTRACT;
|
||||
break;
|
||||
case GLFW_KEY_KP_MULTIPLY:
|
||||
pkey = Key::NUMPAD_MULTIPLY;
|
||||
break;
|
||||
case GLFW_KEY_KP_DIVIDE:
|
||||
pkey = Key::NUMPAD_DIVIDE;
|
||||
break;
|
||||
case GLFW_KEY_KP_DECIMAL:
|
||||
pkey = Key::NUMPAD_DECIMAL;
|
||||
break;
|
||||
case GLFW_KEY_KP_ENTER:
|
||||
pkey = Key::NUMPAD_ENTER;
|
||||
break;
|
||||
|
||||
default:
|
||||
Logger::error("Unknown Key {}", key);
|
||||
return;
|
||||
}
|
||||
|
||||
app->m_client_world.get_player().update_player_move_state(key, action);
|
||||
if (action == GLFW_PRESS) {
|
||||
act = KeyAction::PRESS;
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
act = KeyAction::RELEASE;
|
||||
} else {
|
||||
act = KeyAction::REPEAT;
|
||||
}
|
||||
|
||||
app->dispatch_event(KeyEvent{pkey, act});
|
||||
}
|
||||
|
||||
void App::mouse_button_callback(GLFWwindow* window, int button, int action,
|
||||
@@ -229,75 +530,102 @@ void App::mouse_button_callback(GLFWwindow* window, int button, int action,
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) {
|
||||
if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) {
|
||||
ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods);
|
||||
return;
|
||||
}
|
||||
MouseKey key;
|
||||
KeyAction act;
|
||||
switch (button) {
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
if (action == GLFW_PRESS) {
|
||||
if (app->m_window.is_mouse_enable()) {
|
||||
app->m_window.toggle_mouse_able();
|
||||
app->m_camera.reset_camera();
|
||||
break;
|
||||
;
|
||||
}
|
||||
Input::get_input_state().mouse_state.left = true;
|
||||
}
|
||||
if (action == GLFW_RELEASE) {
|
||||
Input::get_input_state().mouse_state.left = false;
|
||||
}
|
||||
key = MouseKey::LEFT_BUTTON;
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_RIGHT:
|
||||
if (action == GLFW_PRESS) {
|
||||
Input::get_input_state().mouse_state.right = true;
|
||||
}
|
||||
if (action == GLFW_RELEASE) {
|
||||
Input::get_input_state().mouse_state.right = false;
|
||||
}
|
||||
key = MouseKey::RIGHT_BUTTON;
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_MIDDLE:
|
||||
key = MouseKey::MIDDLE_BUTTON;
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_4:
|
||||
key = MouseKey::BACK_BUTTON;
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_5:
|
||||
key = MouseKey::FORWARD_BUTTON;
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_6:
|
||||
key = MouseKey::EXTRA_BUTTON_1;
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_7:
|
||||
key = MouseKey::EXTRA_BUTTON_2;
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_8:
|
||||
key = MouseKey::EXTRA_BUTTON_3;
|
||||
break;
|
||||
default:
|
||||
Logger::error("Unknown Mouse Button {}", button);
|
||||
return;
|
||||
}
|
||||
if (action == GLFW_PRESS) {
|
||||
act = KeyAction::PRESS;
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
act = KeyAction::RELEASE;
|
||||
} else {
|
||||
act = KeyAction::REPEAT;
|
||||
}
|
||||
|
||||
app->dispatch_event(MouseButtonEvent{key, act});
|
||||
}
|
||||
|
||||
void App::window_focus_callback(GLFWwindow* window, int focused) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) {
|
||||
if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) {
|
||||
ImGui_ImplGlfw_WindowFocusCallback(window, focused);
|
||||
return;
|
||||
}
|
||||
if (focused) {
|
||||
app->m_camera.reset_camera();
|
||||
auto camera = app->m_window.camera();
|
||||
if (camera) {
|
||||
camera->reset_camera();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void App::window_reshape_callback(GLFWwindow* window, int, int) {
|
||||
void App::window_reshape_callback(GLFWwindow* window, int width, int height) {
|
||||
|
||||
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
app->m_window.update_viewport();
|
||||
}
|
||||
|
||||
app->dispatch_event(WindowResizeEvent{width, height});
|
||||
|
||||
Logger::info("Window Reshape W: {} H: {}", width, height);
|
||||
}
|
||||
void App::framebuffer_size_callback(GLFWwindow* window, int width, int height) {
|
||||
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
app->dispatch_event(FrameBufferResizeEvent{width, height});
|
||||
|
||||
Logger::info("Frame Buffer Reshape W: {} H: {}", width, height);
|
||||
}
|
||||
void App::mouse_scroll_callback(GLFWwindow* window, double xoffset,
|
||||
double yoffset) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) {
|
||||
if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) {
|
||||
ImGui_ImplGlfw_ScrollCallback(window, xoffset, yoffset);
|
||||
return;
|
||||
}
|
||||
auto& player = app->m_client_world.get_player();
|
||||
player.update_scroll(yoffset);
|
||||
app->dispatch_event(MouseWheelEvent(static_cast<float>(yoffset)));
|
||||
}
|
||||
|
||||
void App::cursor_enter_callback(GLFWwindow* window, int entered) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) {
|
||||
if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) {
|
||||
ImGui_ImplGlfw_CursorEnterCallback(window, entered);
|
||||
return;
|
||||
}
|
||||
@@ -307,9 +635,11 @@ void App::char_callback(GLFWwindow* window, unsigned int c) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||
ASSERT_MSG(app, "nullptr");
|
||||
if (io.WantCaptureKeyboard && app->m_window.is_mouse_enable()) {
|
||||
if (io.WantCaptureKeyboard && app->m_window.is_enable_imgui()) {
|
||||
ImGui_ImplGlfw_CharCallback(window, c);
|
||||
return;
|
||||
}
|
||||
app->dispatch_event(TextInputEvent{codepoint_to_utf8(c)});
|
||||
}
|
||||
|
||||
void App::render() {
|
||||
@@ -318,8 +648,9 @@ void App::render() {
|
||||
ImGui_ImplGlfw_Sleep(10);
|
||||
return;
|
||||
}
|
||||
m_renderer.render();
|
||||
|
||||
m_renderer.begin_frame();
|
||||
m_scene_manager.render(m_renderer);
|
||||
m_renderer.end_frame();
|
||||
glfwSwapBuffers(m_window.get_glfw_window());
|
||||
}
|
||||
|
||||
@@ -327,20 +658,33 @@ void App::run() {
|
||||
|
||||
last_time = glfwGetTime();
|
||||
while (!glfwWindowShouldClose(m_window.get_glfw_window())) {
|
||||
if (m_client_world.is_receive_exit()) {
|
||||
break;
|
||||
}
|
||||
// if (m_client_world.is_receive_exit()) {
|
||||
// break;
|
||||
// }
|
||||
update();
|
||||
render();
|
||||
}
|
||||
m_client_world.request_exit();
|
||||
if (!m_argument.is_client) {
|
||||
m_server.server_world().stop();
|
||||
}
|
||||
}
|
||||
static Gait player_gait = Gait::WALK;
|
||||
// static Gait player_gait = Gait::WALK;
|
||||
void App::update() {
|
||||
glfwPollEvents();
|
||||
{
|
||||
int w, h;
|
||||
glfwGetFramebufferSize(m_window.get_glfw_window(), &w, &h);
|
||||
|
||||
if (w != m_renderer.frame_width() || h != m_renderer.frame_height()) {
|
||||
dispatch_event(FrameBufferResizeEvent{w, h});
|
||||
}
|
||||
}
|
||||
{
|
||||
int w, h;
|
||||
glfwGetWindowSize(m_window.get_glfw_window(), &w, &h);
|
||||
|
||||
if (w != m_renderer.window_width() || h != m_renderer.window_height()) {
|
||||
dispatch_event(WindowResizeEvent{w, h});
|
||||
}
|
||||
}
|
||||
|
||||
current_time = glfwGetTime();
|
||||
dt = current_time - last_time;
|
||||
last_time = current_time;
|
||||
@@ -359,23 +703,34 @@ void App::update() {
|
||||
std::format("RSS: {}mb", Tools::get_current_rss() / (1024 * 1024)));
|
||||
}
|
||||
m_texture_manager.update();
|
||||
m_client_world.update(dt);
|
||||
m_camera.update_move_camera();
|
||||
const auto& player = m_client_world.get_player();
|
||||
if (player_gait != player.get_gait()) {
|
||||
player_gait = player.get_gait();
|
||||
float fov = m_game_config.get("player.fov", 70.0f);
|
||||
if (player_gait == Gait::WALK) {
|
||||
m_renderer.update_fov(fov);
|
||||
}
|
||||
if (player_gait == Gait::RUN) {
|
||||
m_renderer.update_fov(fov + 5.0f);
|
||||
}
|
||||
}
|
||||
m_audio.update_listener(m_camera.get_camera_pos(),
|
||||
m_camera.get_camera_front(), glm::vec3(0, 1, 0));
|
||||
|
||||
m_audio.update();
|
||||
DebugCollector::get().get_widget().update(dt);
|
||||
m_renderer.update(dt);
|
||||
|
||||
m_scene_manager.update(dt);
|
||||
}
|
||||
|
||||
void App::dispatch_event(const Event& e) {
|
||||
if (m_window.handle_event(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_texture_manager.handle_event(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_renderer.handle_event(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DebugCollector::get().handle_event(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_scene_manager.handle_event(e)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int App::start_cubed_application(int argc, char** argv) {
|
||||
@@ -401,14 +756,14 @@ float App::delta_time() { return dt; }
|
||||
|
||||
float App::get_fps() { return fps; }
|
||||
|
||||
Camera& App::camera() { return m_camera; }
|
||||
DevPanel& App::dev_panel() { return m_dev_panel; }
|
||||
Renderer& App::renderer() { return m_renderer; }
|
||||
TextureManager& App::texture_manager() { return m_texture_manager; }
|
||||
Window& App::window() { return m_window; }
|
||||
ClientWorld& App::client_world() { return m_client_world; }
|
||||
ServerWorld& App::server_world() { return m_server.server_world(); }
|
||||
|
||||
Config& App::config() { return m_game_config; }
|
||||
const App::Argument& App::argument() const { return m_argument; }
|
||||
const Argument& App::argument() const { return m_argument; }
|
||||
AudioEngine& App::audio() { return m_audio; }
|
||||
const char* App::get_clipboard_text() {
|
||||
return glfwGetClipboardString(m_window.get_glfw_window());
|
||||
}
|
||||
} // namespace Cubed
|
||||
Reference in New Issue
Block a user