From 5712ba0600ae5becd7f8a750c6e8bbde052b485a Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sun, 12 Jul 2026 16:05:59 +0800 Subject: [PATCH] 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. --- include/Cubed/app.hpp | 24 +- include/Cubed/argument.hpp | 11 + include/Cubed/camera.hpp | 5 + include/Cubed/dev_panel.hpp | 6 +- include/Cubed/gameplay/client_player.hpp | 18 +- include/Cubed/gameplay/client_world.hpp | 8 +- include/Cubed/input/event.hpp | 52 +++ include/Cubed/input/key.hpp | 127 ++++++ include/Cubed/input/mouse.hpp | 25 ++ include/Cubed/render/player_renderer.hpp | 6 +- include/Cubed/render/renderer.hpp | 24 +- include/Cubed/render/texture.hpp | 8 +- include/Cubed/render/world_renderer.hpp | 25 +- include/Cubed/scene/scene.hpp | 17 +- include/Cubed/scene/scene_manager.hpp | 47 +++ include/Cubed/scene/world_scene.hpp | 38 ++ include/Cubed/texture_manager.hpp | 9 +- include/Cubed/ui/button.hpp | 19 + include/Cubed/ui/image.hpp | 11 +- include/Cubed/ui/ui_manager.hpp | 13 + include/Cubed/ui/widget.hpp | 1 + include/Cubed/window.hpp | 11 +- src/CMakeLists.txt | 3 + src/app.cpp | 496 ++++++++++++++++++----- src/camera.cpp | 37 ++ src/dev_panel.cpp | 22 +- src/gameplay/client_player.cpp | 130 +++--- src/gameplay/client_world.cpp | 33 +- src/render/player_renderer.cpp | 21 +- src/render/renderer.cpp | 44 +- src/render/texture.cpp | 11 +- src/render/world_renderer.cpp | 107 ++--- src/scene/scene_manager.cpp | 96 +++++ src/scene/world_scene.cpp | 78 ++++ src/texture_manager.cpp | 60 ++- src/ui/button.cpp | 0 src/ui/image.cpp | 32 +- src/window.cpp | 54 ++- 38 files changed, 1383 insertions(+), 346 deletions(-) create mode 100644 include/Cubed/argument.hpp create mode 100644 include/Cubed/input/event.hpp create mode 100644 include/Cubed/input/key.hpp create mode 100644 include/Cubed/input/mouse.hpp create mode 100644 include/Cubed/scene/scene_manager.hpp create mode 100644 include/Cubed/scene/world_scene.hpp create mode 100644 include/Cubed/ui/button.hpp create mode 100644 include/Cubed/ui/ui_manager.hpp create mode 100644 src/scene/scene_manager.cpp create mode 100644 src/scene/world_scene.cpp create mode 100644 src/ui/button.cpp diff --git a/include/Cubed/app.hpp b/include/Cubed/app.hpp index bde0f9c..f68aeac 100644 --- a/include/Cubed/app.hpp +++ b/include/Cubed/app.hpp @@ -1,27 +1,19 @@ #pragma once #include "Cubed/audio/audio_engine.hpp" -#include "Cubed/gameplay/client_world.hpp" #include "Cubed/gameplay/network_server.hpp" #include "Cubed/gameplay/server_world.hpp" #define GLFW_INCLUDE_NONE -#include "Cubed/camera.hpp" +#include "Cubed/argument.hpp" #include "Cubed/config.hpp" #include "Cubed/dev_panel.hpp" #include "Cubed/render/renderer.hpp" +#include "Cubed/scene/scene_manager.hpp" #include "Cubed/texture_manager.hpp" #include "Cubed/window.hpp" namespace Cubed { class App { public: - struct Argument { - bool is_client = false; - int port = 25530; - std::string ip{"127.0.0.1"}; - std::string player{"Unknown"}; - bool debug_on = true; - }; - App(); ~App(); static void cursor_position_callback(GLFWwindow* window, double xpos, @@ -43,12 +35,9 @@ public: static float delta_time(); static float get_fps(); - Camera& camera(); - DevPanel& dev_panel(); Renderer& renderer(); TextureManager& texture_manager(); Window& window(); - ClientWorld& client_world(); ServerWorld& server_world(); Config& config(); const Argument& argument() const; @@ -56,18 +45,17 @@ public: private: Config m_game_config; - Camera m_camera; + TextureManager m_texture_manager; NetworkServer m_server; - std::shared_ptr m_client; AudioEngine m_audio; - ClientWorld m_client_world; - DevPanel m_dev_panel; 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; @@ -86,6 +74,8 @@ private: void render(); void run(); void update(); + + void dispatch_event(const Event& e); }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/argument.hpp b/include/Cubed/argument.hpp new file mode 100644 index 0000000..88a1ee0 --- /dev/null +++ b/include/Cubed/argument.hpp @@ -0,0 +1,11 @@ +#pragma once +#include +namespace Cubed { +struct Argument { + bool is_client = false; + int port = 25530; + std::string ip{"127.0.0.1"}; + std::string player{"Unknown"}; + bool debug_on = true; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/camera.hpp b/include/Cubed/camera.hpp index aa1a649..dfe6149 100644 --- a/include/Cubed/camera.hpp +++ b/include/Cubed/camera.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Cubed/input/event.hpp" #define GLFW_INCLUDE_NONE #include #include @@ -28,6 +29,9 @@ private: glm::vec3 camera_collision(glm::vec3 start, glm::vec3 end, float radius = 0.2f); + bool handle_key_event(const KeyEvent& e); + bool handle_mouse_move_event(const MouseMoveEvent& e); + public: Camera(); @@ -45,6 +49,7 @@ public: glm::vec3 get_camera_front() const; void change_perspective(); bool is_first_person() const; + bool handle_event(const Event& e); }; } // namespace Cubed diff --git a/include/Cubed/dev_panel.hpp b/include/Cubed/dev_panel.hpp index 1f927fd..3d98bcb 100644 --- a/include/Cubed/dev_panel.hpp +++ b/include/Cubed/dev_panel.hpp @@ -6,8 +6,9 @@ namespace Cubed { -class App; +class WorldScene; class ClientPlayer; +class App; class DevPanel { struct ConfigView { float fov = 70.0f; @@ -32,12 +33,13 @@ class DevPanel { }; public: - DevPanel(App& app); + DevPanel(WorldScene& app); void init(); void render(); private: App& m_app; + WorldScene& m_world_scene; Config& m_config; ConfigView m_config_view; ClientPlayer* m_player; diff --git a/include/Cubed/gameplay/client_player.hpp b/include/Cubed/gameplay/client_player.hpp index 9baaecc..7bb1e3a 100644 --- a/include/Cubed/gameplay/client_player.hpp +++ b/include/Cubed/gameplay/client_player.hpp @@ -7,6 +7,7 @@ #include "Cubed/gameplay/game_time.hpp" #include "Cubed/gameplay/player.hpp" #include "Cubed/input.hpp" +#include "Cubed/input/event.hpp" #include #include @@ -23,6 +24,14 @@ public: ClientPlayer(ClientWorld& world); ~ClientPlayer(); + bool handle_mouse_button_event(const MouseButtonEvent& e); + bool handle_key_event(const KeyEvent& e); + bool handle_mouse_wheel_event(const MouseWheelEvent& e); + + void update_front_vec(float offset_x, float offset_y); + bool update_player_move_state(Key key, KeyAction action); + bool update_scroll(float yoffset); + void update_chunk_set(const ChunkPosSet& set); const ChunkPosSet& get_chunk_pos_set() const; ChunkPosSet get_chunk_pos_set(); @@ -40,9 +49,6 @@ public: void set_player_pos(const glm::vec3& pos); void set_place_block(unsigned id); void update(float delta_time); - void update_front_vec(float offset_x, float offset_y); - void update_player_move_state(int key, int action); - void update_scroll(double yoffset); float& max_walk_speed(); float& max_run_speed(); @@ -137,11 +143,17 @@ private: void update_direction(); void update_lookup_block(); + + bool place_block(MouseKey key); + void update_move(float delta_time); + void update_x_move(glm::vec3& player_pos); void update_y_move(glm::vec3& player_pos); void update_z_move(glm::vec3& player_pos); + void update_player_chunk(); + void play_walk_sound(float dt); Gait compute_gait() const; }; diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index 2ec0596..5bf58a5 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -7,6 +7,7 @@ #include "Cubed/gameplay/client_player.hpp" #include "Cubed/gameplay/game_time.hpp" #include "Cubed/gameplay/network_client.hpp" +#include "Cubed/input/event.hpp" #include "Cubed/tools/cubed_random.hpp" #include "Cubed/tools/priority_thread_pool.hpp" @@ -41,14 +42,15 @@ struct PlayerRenderData { Gait gait; float angle; }; - +class WorldScene; class ClientWorld { public: - ClientWorld(AudioEngine& auido, Config& config); + ClientWorld(AudioEngine& auido, Config& config, WorldScene& scene); ~ClientWorld(); void init(std::string_view player_name, std::shared_ptr client); void update(float delta_time); + bool handle_event(const Event& e); const std::optional& get_look_block_pos() const; ClientPlayer& get_player(); const ClientPlayer& get_player() const; @@ -97,6 +99,7 @@ public: static AABB get_block_aabb(const glm::ivec3& pos); AudioEngine& get_audio(); Config& get_config(); + WorldScene& world_scene(); template void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) { m_ticktimers.emplace( @@ -133,6 +136,7 @@ private: ChunkHashMap m_chunks; AudioEngine& m_audio; Config& m_config; + WorldScene& m_world_scene; std::vector m_planes; std::jthread m_client_thread; diff --git a/include/Cubed/input/event.hpp b/include/Cubed/input/event.hpp new file mode 100644 index 0000000..30d00a9 --- /dev/null +++ b/include/Cubed/input/event.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "Cubed/input/key.hpp" +#include "Cubed/input/mouse.hpp" + +#include +#include + +namespace Cubed { + +struct MouseMoveEvent { + float xpos; + float ypos; + + MouseMoveEvent(float x, float y) : xpos(x), ypos(y) {} +}; + +struct MouseButtonEvent { + MouseKey key; + KeyAction action; + + MouseButtonEvent(MouseKey k, KeyAction a) : key(k), action(a) {} +}; + +struct MouseWheelEvent { + float offset; + + MouseWheelEvent(float o) : offset(o) {} +}; + +struct KeyEvent { + Key key; + KeyAction action; + + KeyEvent(Key k, KeyAction a) : key(k), action(a) {} +}; + +struct TextInputEvent { + std::string text; + + TextInputEvent(std::string t) : text(std::move(t)) {} +}; + +using Event = std::variant; + +template struct Overloaded : T... { + using T::operator()...; +}; +template Overloaded(T...) -> Overloaded; + +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/input/key.hpp b/include/Cubed/input/key.hpp new file mode 100644 index 0000000..847ce60 --- /dev/null +++ b/include/Cubed/input/key.hpp @@ -0,0 +1,127 @@ +#pragma once + +namespace Cubed { +enum class Key { + // Letter keys + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T, + U, + V, + W, + X, + Y, + Z, + + // Digit keys (main keyboard area) + DIGIT_0, + DIGIT_1, + DIGIT_2, + DIGIT_3, + DIGIT_4, + DIGIT_5, + DIGIT_6, + DIGIT_7, + DIGIT_8, + DIGIT_9, + + // Function keys + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + + // Control keys + BACKSPACE, + TAB, + ENTER, + ESCAPE, + SPACE, + CAPS_LOCK, + NUM_LOCK, + SCROLL_LOCK, + + // Modifier keys + LEFT_SHIFT, + RIGHT_SHIFT, + LEFT_CTRL, + RIGHT_CTRL, + LEFT_ALT, + RIGHT_ALT, + LEFT_SUPER, + RIGHT_SUPER, // Windows / Command 键 + + // Navigation keys + INSERT, + DELETE, + HOME, + END, + PAGE_UP, + PAGE_DOWN, + LEFT, + RIGHT, + UP, + DOWN, + + // Lock and system keys + PRINT_SCREEN, + PAUSE, + + // Main keyboard area symbol keys + GRAVE_ACCENT, // ` + MINUS, // - + EQUALS, // = + LEFT_BRACKET, // [ + RIGHT_BRACKET, // ] + BACKSLASH, // \ / + SEMICOLON, // ; + APOSTROPHE, // ' + COMMA, // , + PERIOD, // . + SLASH, // / + + // Numpad area + NUMPAD_0, + NUMPAD_1, + NUMPAD_2, + NUMPAD_3, + NUMPAD_4, + NUMPAD_5, + NUMPAD_6, + NUMPAD_7, + NUMPAD_8, + NUMPAD_9, + NUMPAD_ADD, // + + NUMPAD_SUBTRACT, // - + NUMPAD_MULTIPLY, // * + NUMPAD_DIVIDE, // / + NUMPAD_DECIMAL, // . + NUMPAD_ENTER +}; +enum class KeyAction { PRESS, RELEASE }; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/input/mouse.hpp b/include/Cubed/input/mouse.hpp new file mode 100644 index 0000000..1643513 --- /dev/null +++ b/include/Cubed/input/mouse.hpp @@ -0,0 +1,25 @@ +#pragma once + +namespace Cubed { + +enum class MouseKey { + LEFT_BUTTON, + RIGHT_BUTTON, + MIDDLE_BUTTON, + + BACK_BUTTON, // Side button back + FORWARD_BUTTON, // Side button forward + + WHEEL_UP, + WHEEL_DOWN, + WHEEL_LEFT, + WHEEL_RIGHT, + + EXTRA_BUTTON_1, // Additional programmable buttons + EXTRA_BUTTON_2, + EXTRA_BUTTON_3, + EXTRA_BUTTON_4, + EXTRA_BUTTON_5 +}; + +} diff --git a/include/Cubed/render/player_renderer.hpp b/include/Cubed/render/player_renderer.hpp index 4d2cc85..4ac66ad 100644 --- a/include/Cubed/render/player_renderer.hpp +++ b/include/Cubed/render/player_renderer.hpp @@ -5,6 +5,7 @@ #include namespace Cubed { +class ClientWorld; class Renderer; class PlayerRenderer { public: @@ -12,8 +13,9 @@ public: PlayerRenderer(Renderer& renderer); ~PlayerRenderer(); void init(); - void render(const Shader& shader); - void shadow_render(const Shader& shader, glm::mat4& light_matrix); + void render(const Shader& shader, ClientWorld& world); + void shadow_render(const Shader& shader, glm::mat4& light_matrix, + ClientWorld& world); private: struct PlayerVertex { diff --git a/include/Cubed/render/renderer.hpp b/include/Cubed/render/renderer.hpp index afaea89..745e779 100644 --- a/include/Cubed/render/renderer.hpp +++ b/include/Cubed/render/renderer.hpp @@ -15,8 +15,6 @@ #include #include namespace Cubed { - -class Camera; class TextureManager; class ClientWorld; class DevPanel; @@ -24,15 +22,15 @@ class Renderer { public: constexpr static int NUM_VAO = 7; - Renderer(const Camera& camera, ClientWorld& world, - const TextureManager& texture_manager, DevPanel& dev_panel, - Config& config); + Renderer(TextureManager& texture_manager, Config& config); ~Renderer(); void hot_reload(); void init(bool debug_on); const Shader& get_shader(const std::string& name) const; + void begin_frame(); + void end_frame(); void render(); - + void render_world(ClientWorld& world); void render_lable(const Label& label); void render_image(const Image& image); @@ -63,9 +61,6 @@ public: float& underwater_fog_density(); float& water_density(); - const Camera& camera() const; - const ClientWorld& world() const; - ClientWorld& world(); const glm::mat4& world_proj_matrix() const; const TextureManager& texture_mamger() const; float delta_time() const; @@ -75,12 +70,10 @@ public: const glm::mat4& p_mat() const; const std::vector& vao() const; + void render_dev_panel(DevPanel& dev_panel); private: - const Camera& m_camera; - DevPanel& m_dev_panel; - const TextureManager& m_texture_manager; - ClientWorld& m_world; + TextureManager& m_texture_manager; bool m_init = false; @@ -121,13 +114,8 @@ private: void init_quad(); void init_text(); - void day_night_calculation(); - - void render_sky(); - void render_ui(); void render_crosshair(); - void render_dev_panel(); }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/render/texture.hpp b/include/Cubed/render/texture.hpp index 25b9180..b19bb7a 100644 --- a/include/Cubed/render/texture.hpp +++ b/include/Cubed/render/texture.hpp @@ -60,12 +60,12 @@ public: void tex_image_2d(TextureFormat internalformat, TextureFormat format, GLenum type, const void* data, GLsizei width, - GLsizei height, GLint level = 0, GLint border = 0) const; + GLsizei height, GLint level = 0, GLint border = 0); void tex_image_3d(TextureFormat internalformat, TextureFormat format, GLenum type, const void* data, GLsizei width, GLsizei height, GLsizei depth, GLint level = 0, - GLint border = 0) const; + GLint border = 0); void tex_sub_image_3d(TextureFormat format, GLenum type, const void* data, GLint xoffset, GLint yoffset, GLint zoffset, @@ -84,9 +84,13 @@ public: void set_clamp_to_edge(bool r = true, bool s = true, bool t = true) const; TextureType type() const; + float width() const; + float height() const; private: GLuint m_id = 0; + float m_width = 0; + float m_height = 0; const TextureType M_TYPE; GLenum get_gl_texture_type() const; }; diff --git a/include/Cubed/render/world_renderer.hpp b/include/Cubed/render/world_renderer.hpp index 3a54141..40cd118 100644 --- a/include/Cubed/render/world_renderer.hpp +++ b/include/Cubed/render/world_renderer.hpp @@ -39,7 +39,7 @@ public: WorldRenderer& operator=(const WorldRenderer&) = delete; WorldRenderer& operator=(WorldRenderer&&) = delete; void init(); - void render(); + void render(ClientWorld& world); void updata_framebuffer(int width, int height); float& ambient_strength(); @@ -121,27 +121,26 @@ private: glm::mat4 view_matrix; - ClientWorld& m_world; - const Camera& m_camera; const TextureManager& m_texture_manager; - void day_night_calculation(); + void day_night_calculation(ClientWorld& world); - void render_sky(); + void render_sky(ClientWorld& world); - void render_world(); + void render_world(ClientWorld& world); - void shadow_map_generate(); + void shadow_map_generate(ClientWorld& world); - void render_underwater(); - void render_outline(); - void render_player(); + void render_underwater(ClientWorld& world); + void render_outline(ClientWorld& world); + void render_player(ClientWorld& world); void render_normal_block(const glm::mat4& model_mat, - const glm::mat4& mv_mat, - const glm::mat4& norm_mat); + const glm::mat4& mv_mat, const glm::mat4& norm_mat, + ClientWorld& world); void render_transparent_block(const glm::mat4& mv_mat, - const glm::mat4& norm_mat); + const glm::mat4& norm_mat, + ClientWorld& world); glm::vec3 quantize_sun_direction(const glm::vec3& sundir, float angle_step_deg) const; diff --git a/include/Cubed/scene/scene.hpp b/include/Cubed/scene/scene.hpp index 76b3d92..d869fee 100644 --- a/include/Cubed/scene/scene.hpp +++ b/include/Cubed/scene/scene.hpp @@ -1,11 +1,24 @@ #pragma once - +#include "Cubed/input/event.hpp" namespace Cubed { +class Renderer; + +enum class SceneType { MAIN_MENU, WORLD }; + class Scene { public: Scene() = default; + + Scene(const Scene&) = delete; + Scene(Scene&&) = delete; + Scene& operator=(const Scene&) = delete; + Scene& operator=(Scene&&) = delete; + virtual ~Scene() = default; virtual void update(float dt) = 0; - virtual void render() = 0; + virtual void render(Renderer& renderer) = 0; + virtual bool handle_event(const Event& e) = 0; + virtual void on_enter() {}; + virtual void on_leave() {}; }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/scene/scene_manager.hpp b/include/Cubed/scene/scene_manager.hpp new file mode 100644 index 0000000..09dbbda --- /dev/null +++ b/include/Cubed/scene/scene_manager.hpp @@ -0,0 +1,47 @@ +#pragma once +#include "Cubed/scene/scene.hpp" + +#include +#include +#include +namespace Cubed { +class App; +class SceneManager { +public: + SceneManager(const SceneManager&) = delete; + SceneManager(SceneManager&&) = delete; + SceneManager& operator=(const SceneManager&) = delete; + SceneManager& operator=(SceneManager&&) = delete; + SceneManager(App& app); + ~SceneManager(); + + void update(float dt); + void render(Renderer& renderer); + + bool handle_event(const Event& e); + + void request_change(SceneType type); + void request_push(SceneType type); + void request_pop(); + + App& app(); + +private: + enum class OperationType { PUSH, POP, CHANGE }; + struct SceneOperation { + OperationType type; + std::optional scene; + }; + + App& m_app; + std::vector> m_pending_delete_scene; + std::optional m_operation; + std::stack> m_scenes; + void process_operation(); + void change(SceneType type); + void push(SceneType type); + void pop(); + + std::unique_ptr create_scene(SceneType); +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/scene/world_scene.hpp b/include/Cubed/scene/world_scene.hpp new file mode 100644 index 0000000..06b0a58 --- /dev/null +++ b/include/Cubed/scene/world_scene.hpp @@ -0,0 +1,38 @@ +#pragma once +#include "Cubed/argument.hpp" +#include "Cubed/camera.hpp" +#include "Cubed/dev_panel.hpp" +#include "Cubed/gameplay/client_world.hpp" +#include "Cubed/scene/scene.hpp" +namespace Cubed { +class SceneManager; +class WorldScene : public Scene { +public: + WorldScene(const WorldScene&) = delete; + WorldScene(WorldScene&&) = delete; + WorldScene& operator=(const WorldScene&) = delete; + WorldScene& operator=(WorldScene&&) = delete; + + WorldScene(SceneManager& scene_manager); + ~WorldScene(); + + void update(float dt) override; + void render(Renderer& renderer) override; + bool handle_event(const Event& e) override; + void on_enter() override; + void on_leave() override; + + Camera& camera(); + SceneManager& scene_manager(); + ClientWorld& client_world(); + +private: + SceneManager& m_scene_manager; + DevPanel m_dev_panel; + Camera m_camera; + std::shared_ptr m_client; + ClientWorld m_client_world; + + const Argument& m_argument; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/texture_manager.hpp b/include/Cubed/texture_manager.hpp index edd31f2..3c5fbb4 100644 --- a/include/Cubed/texture_manager.hpp +++ b/include/Cubed/texture_manager.hpp @@ -1,6 +1,7 @@ #pragma once #include "Cubed/config.hpp" #include "Cubed/gameplay/block.hpp" +#include "Cubed/input/event.hpp" #include "Cubed/render/texture.hpp" #include @@ -15,10 +16,10 @@ private: std::unique_ptr m_block_status_array; std::unique_ptr m_texture_array; std::unique_ptr m_cross_plane_array; - std::unique_ptr m_ui_array; std::unique_ptr m_normal_texture_array; std::unique_ptr m_skin; std::vector> m_item_textures; + std::unordered_map> m_ui_map; GLfloat m_max_aniso = 0.0f; Config& m_config; int m_aniso = 1; @@ -27,7 +28,7 @@ private: void load_block_texture(unsigned block_id); void load_block_item_texture(unsigned id); void load_cross_plane_texture(unsigned id); - void load_ui_texture(unsigned id); + const Texture* load_image_texture(const std::string& path); void load_pbr_texture(unsigned id); void init_item(); void init_block(); @@ -35,6 +36,7 @@ private: void init_block_status(); void init_skin(); void hot_reload(); + bool handle_key_event(const KeyEvent& e); public: TextureManager(Config& config); @@ -44,7 +46,7 @@ public: const Texture* get_block_status_array() const; const Texture* get_texture_array() const; const Texture* get_cross_plane_array() const; - const Texture* get_ui_array() const; + const Texture* get_image_texture(const std::string& path); const Texture* get_pbr_texture() const; const std::vector>& item_textures() const; const Texture* get_skin() const; @@ -54,6 +56,7 @@ public: void need_reload(); void update(); int max_aniso() const; + bool handle_event(const Event& e); }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/ui/button.hpp b/include/Cubed/ui/button.hpp new file mode 100644 index 0000000..9feb638 --- /dev/null +++ b/include/Cubed/ui/button.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "Cubed/ui/widget.hpp" + +#include + +namespace Cubed { +class Button : public Widget { +public: + Button(); + + template Button& set_clicked(F&& f) { + m_clicked = std::move(f); + } + +private: + std::function m_clicked; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/ui/image.hpp b/include/Cubed/ui/image.hpp index 44e122e..65560c2 100644 --- a/include/Cubed/ui/image.hpp +++ b/include/Cubed/ui/image.hpp @@ -4,24 +4,21 @@ #include "Cubed/ui/widget.hpp" #include "glm/ext/vector_float2.hpp" -#include - namespace Cubed { +class TextureManager; class Image : public Widget { public: Image(); void update(float dt) override; void render(Renderer& renderer) override; - Image& set_image(std::filesystem::path path); + Image& set_image(const std::string& path, TextureManager& texture_manager); float width() const; float height() const; - const Texture& texture() const; + const Texture* texture() const; private: - Texture m_texture; - int m_width = 0; - int m_height = 0; + const Texture* m_texture = nullptr; glm::vec2 m_pos{0.0f, 0.0f}; float m_scale = 1.0f; }; diff --git a/include/Cubed/ui/ui_manager.hpp b/include/Cubed/ui/ui_manager.hpp new file mode 100644 index 0000000..3016f0b --- /dev/null +++ b/include/Cubed/ui/ui_manager.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace Cubed { +class UIManager { +public: + UIManager(const UIManager&) = delete; + UIManager(UIManager&&) = delete; + UIManager& operator=(const UIManager&) = delete; + UIManager& operator=(UIManager&&) = delete; + +private: +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/ui/widget.hpp b/include/Cubed/ui/widget.hpp index 608839a..e781657 100644 --- a/include/Cubed/ui/widget.hpp +++ b/include/Cubed/ui/widget.hpp @@ -19,6 +19,7 @@ public: virtual Widget& set_scale(float scale); virtual const glm::vec2& pos() const; virtual float scale() const; + template T& add_child(Args&&... args) { auto widget = std::make_unique(std::forward(args)...); T& ref = *widget; diff --git a/include/Cubed/window.hpp b/include/Cubed/window.hpp index d1de2e2..663976b 100644 --- a/include/Cubed/window.hpp +++ b/include/Cubed/window.hpp @@ -1,11 +1,12 @@ #pragma once #include "Cubed/config.hpp" +#include "Cubed/input/event.hpp" #define GLFW_INCLUDE_NONE #include namespace Cubed { - +class Camera; class Renderer; class Window { public: @@ -19,11 +20,16 @@ public: void imgui_init(); void update_viewport(); // end of frame to reload! + bool handle_event(const Event& e); + void hot_reload(); void toggle_fullscreen(); void toggle_mouse_able(); + void set_camera(Camera* camera); + Camera* camera(); + private: bool m_mouse_enable = false; bool m_imgui_init = false; @@ -33,6 +39,9 @@ private: int m_height; Renderer& m_renderer; Config& m_config; + Camera* m_camera = nullptr; + bool handle_key_event(const KeyEvent& e); + bool handle_mouse_button_event(const MouseButtonEvent& e); }; } // namespace Cubed \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5d78f70..74999a6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,4 +62,7 @@ target_sources(${PROJECT_NAME} ui/label.cpp ui/ui_vertex_data.cpp ui/image.cpp + ui/button.cpp + scene/world_scene.cpp + scene/scene_manager.cpp ) \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index 62e3966..3446411 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,5 +1,6 @@ #include "Cubed/app.hpp" +#include "Cubed/camera.hpp" #include "Cubed/config.hpp" #include "Cubed/debug_collector.hpp" #include "Cubed/tools/arg_parser.hpp" @@ -16,16 +17,10 @@ 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_renderer, 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(); @@ -38,7 +33,8 @@ void App::cursor_position_callback(GLFWwindow* window, double xpos, 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(xpos), static_cast(ypos)}); } } void App::init(int argc, char** argv) { @@ -80,16 +76,7 @@ void App::init(int argc, char** argv) { m_server.start_server(m_argument.port); } - m_client = std::make_shared(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(); + m_scene_manager.request_push(SceneType::WORLD); } void App::handle_argument(int argc, char** argv) { @@ -179,49 +166,355 @@ void App::key_callback(GLFWwindow* window, int key, int scancode, int action, // 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 ((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 || action == GLFW_REPEAT) { + act = KeyAction::PRESS; + } else { + act = KeyAction::RELEASE; + } + + app->dispatch_event(KeyEvent{pkey, act}); } void App::mouse_button_callback(GLFWwindow* window, int button, int action, @@ -233,30 +526,44 @@ void App::mouse_button_callback(GLFWwindow* window, int button, int action, 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 || action == GLFW_REPEAT) { + act = KeyAction::PRESS; + } else { + act = KeyAction::RELEASE; + } + + app->dispatch_event(MouseButtonEvent{key, act}); } void App::window_focus_callback(GLFWwindow* window, int focused) { @@ -268,7 +575,10 @@ void App::window_focus_callback(GLFWwindow* window, int focused) { return; } if (focused) { - app->m_camera.reset_camera(); + auto camera = app->m_window.camera(); + if (camera) { + camera->reset_camera(); + } } } @@ -289,8 +599,7 @@ void App::mouse_scroll_callback(GLFWwindow* window, double xoffset, 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(yoffset))); } void App::cursor_enter_callback(GLFWwindow* window, int entered) { @@ -318,8 +627,10 @@ void App::render() { ImGui_ImplGlfw_Sleep(10); return; } + m_renderer.begin_frame(); + m_scene_manager.render(m_renderer); m_renderer.render(); - + m_renderer.end_frame(); glfwSwapBuffers(m_window.get_glfw_window()); } @@ -327,18 +638,18 @@ 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(); current_time = glfwGetTime(); @@ -359,24 +670,24 @@ 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_scene_manager.handle_event(e)) { + return; + } } int App::start_cubed_application(int argc, char** argv) { @@ -402,14 +713,11 @@ 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; } } // namespace Cubed \ No newline at end of file diff --git a/src/camera.cpp b/src/camera.cpp index c4cfdeb..07910dd 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -115,6 +115,27 @@ bool Camera::is_first_person() const { return m_perspective == Perspective::FIRST_PERSON; } +bool Camera::handle_event(const Event& e) { + return std::visit( + Overloaded{[this](const MouseMoveEvent& e) { + if (handle_mouse_move_event(e)) { + return true; + } + + return false; + }, + [](const MouseButtonEvent& e) { return false; }, + [](const MouseWheelEvent& e) { return false; }, + [this](const KeyEvent& e) { + if (handle_key_event(e)) { + return true; + } + return false; + }, + [](const TextInputEvent& e) { return false; }}, + e); +} + glm::vec3 Camera::camera_collision(glm::vec3 start, glm::vec3 end, float radius) { constexpr float STEP = 0.05f; @@ -136,4 +157,20 @@ glm::vec3 Camera::camera_collision(glm::vec3 start, glm::vec3 end, return end; } +bool Camera::handle_key_event(const KeyEvent& e) { + if (e.key == Key::LEFT_ALT && e.action == KeyAction::PRESS) { + reset_camera(); + return true; + } + if (e.key == Key::F5 && e.action == KeyAction::PRESS) { + change_perspective(); + return true; + } + return false; +} +bool Camera::handle_mouse_move_event(const MouseMoveEvent& e) { + update_cursor_position_camera(e.xpos, e.ypos); + return true; +} + } // namespace Cubed diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index a01faf8..1a6d451 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -5,6 +5,7 @@ #include "Cubed/gameplay/cave_path.hpp" #include "Cubed/gameplay/client_player.hpp" #include "Cubed/gameplay/river.path.hpp" +#include "Cubed/scene/world_scene.hpp" #include "Cubed/tools/log.hpp" #include @@ -46,10 +47,12 @@ constexpr float DELTA_ANGLE_MAX = 30.0f; constexpr int PATH_STEP_MIN = 1; constexpr int PATH_STEP_MAX = 1000; -DevPanel::DevPanel(App& app) : m_app(app), m_config(app.config()) {} +DevPanel::DevPanel(WorldScene& world_scene) + : m_app(world_scene.scene_manager().app()), m_world_scene(world_scene), + m_config(m_app.config()) {} void DevPanel::init() { - m_player = &m_app.client_world().get_player(); + m_player = &m_world_scene.client_world().get_player(); update_config_view(); update_player_profile(); } @@ -383,7 +386,7 @@ void DevPanel::show_settings_tab_item() { 128)) { m_config.set("world.rendering_distance", m_config_view.rendering_distance); - m_app.client_world().hot_reload(); + m_world_scene.client_world().hot_reload(); } if (ImGui::Checkbox("Fullscreen", &m_config_view.fullscreen)) { m_config.set("window.fullscreen", m_config_view.fullscreen); @@ -551,20 +554,23 @@ void DevPanel::show_server_world_table_bar() { } void DevPanel::show_client_world_table_bar() { - static int rendering_distance = m_app.client_world().rendering_distance(); + static int rendering_distance = + m_world_scene.client_world().rendering_distance(); if (ImGui::SliderInt("Render Distance", &rendering_distance, 2, 128)) { - m_app.client_world().rendering_distance(rendering_distance); + m_world_scene.client_world().rendering_distance(rendering_distance); // Config::get().set("world.rendering_distance", rendering_distance); } if (ImGui::Button("Rebuild World")) { - m_app.client_world().rebuild_world(); + m_world_scene.client_world().rebuild_world(); } ImGui::SameLine(); if (ImGui::Button("Spawn Point")) { m_player->set_player_pos({0.0f, 255.0f, 0.0f}); } - ImGui::Text("Chunk Task Id %d", m_app.client_world().get_chunk_task_id()); - ImGui::Text("Client World Chunk %d", m_app.client_world().chunk_size()); + ImGui::Text("Chunk Task Id %d", + m_world_scene.client_world().get_chunk_task_id()); + ImGui::Text("Client World Chunk %d", + m_world_scene.client_world().chunk_size()); } void DevPanel::show_player_tab_item() { diff --git a/src/gameplay/client_player.cpp b/src/gameplay/client_player.cpp index 0e0acab..00cef97 100644 --- a/src/gameplay/client_player.cpp +++ b/src/gameplay/client_player.cpp @@ -141,48 +141,42 @@ void ClientPlayer::update(float delta_time) { DebugCollector::get().report("speed", std::format("Speed: {:.2} m/s", m_xz_speed)); } -void ClientPlayer::update_player_move_state(int key, int action) { - switch (key) { - case GLFW_KEY_W: - if (action == GLFW_PRESS) { +bool ClientPlayer::update_player_move_state(Key key, KeyAction action) { + if (key == Key::W) { + if (action == KeyAction::PRESS) { m_move_state.forward = true; } - if (action == GLFW_RELEASE) { + if (action == KeyAction::RELEASE) { m_move_state.forward = false; - m_sprinting = false; } - break; - case GLFW_KEY_S: - if (action == GLFW_PRESS) { + } else if (key == Key::S) { + if (action == KeyAction::PRESS) { m_move_state.back = true; } - if (action == GLFW_RELEASE) { + if (action == KeyAction::RELEASE) { m_move_state.back = false; } - break; - case GLFW_KEY_A: - if (action == GLFW_PRESS) { + } else if (key == Key::A) { + if (action == KeyAction::PRESS) { m_move_state.left = true; } - if (action == GLFW_RELEASE) { + if (action == KeyAction::RELEASE) { m_move_state.left = false; } - break; - case GLFW_KEY_D: - if (action == GLFW_PRESS) { + } else if (key == Key::D) { + if (action == KeyAction::PRESS) { m_move_state.right = true; } - if (action == GLFW_RELEASE) { + if (action == KeyAction::RELEASE) { m_move_state.right = false; } - break; - case GLFW_KEY_SPACE: - if (action == GLFW_PRESS) { + } else if (key == Key::SPACE) { + if (action == KeyAction::PRESS) { m_move_state.up = true; if (space_on) { if (m_game_mode == CREATIVE) { - is_fly = !is_fly ? true : false; + is_fly = !is_fly; m_y_speed = 0.0f; } space_on = false; @@ -191,35 +185,39 @@ void ClientPlayer::update_player_move_state(int key, int action) { space_on = true; } } - if (action == GLFW_RELEASE) { + if (action == KeyAction::RELEASE) { m_move_state.up = false; } - break; - case GLFW_KEY_LEFT_SHIFT: - if (action == GLFW_PRESS) { + } else if (key == Key::LEFT_SHIFT) { + if (action == KeyAction::PRESS) { m_move_state.down = true; } - if (action == GLFW_RELEASE) { + if (action == KeyAction::RELEASE) { m_move_state.down = false; } - break; - case GLFW_KEY_LEFT_CONTROL: - if (action == GLFW_PRESS) { + } else if (key == Key::LEFT_CTRL) { + if (action == KeyAction::PRESS) { m_sprinting = true; } - break; - case GLFW_KEY_F4: - if (action == GLFW_PRESS) { + /* + if (action == KeyAction::RELEASE) { + m_sprinting = false; + }*/ + } else if (key == Key::F4) { + if (action == KeyAction::PRESS) { if (m_game_mode == CREATIVE) { change_mode(SPECTATOR); } else { change_mode(CREATIVE); } } - break; + } else { + return false; } + m_moving = m_move_state.forward || m_move_state.back || m_move_state.left || m_move_state.right; + return true; } void ClientPlayer::update_front_vec(float offset_x, float offset_y) { @@ -275,28 +273,32 @@ void ClientPlayer::update_lookup_block() { } else { m_look_block = std::nullopt; } +} +bool ClientPlayer::place_block(MouseKey key) { - if (m_look_block != std::nullopt) { - if (Input::get_input_state().mouse_state.left) { - if (m_world.is_solid(m_look_block->pos)) { - m_world.report_block_change(m_look_block->pos, 0); - } - Input::get_input_state().mouse_state.left = false; - } - if (Input::get_input_state().mouse_state.right) { - glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal; - if (!m_world.is_solid(near_pos)) { - AABB block_box = ClientWorld::get_block_aabb(near_pos); - AABB player_box = get_aabb(get_player_pos()); - if (!player_box.intersects(block_box)) { - m_world.report_block_change(near_pos, m_place_block); - } - } - Input::get_input_state().mouse_state.right = false; + if (m_look_block == std::nullopt) { + return false; + } + bool placeed = false; + if (key == MouseKey::LEFT_BUTTON) { + if (m_world.is_solid(m_look_block->pos)) { + m_world.report_block_change(m_look_block->pos, 0); + placeed = true; } } + if (key == MouseKey::RIGHT_BUTTON) { + glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal; + if (!m_world.is_solid(near_pos)) { + AABB block_box = ClientWorld::get_block_aabb(near_pos); + AABB player_box = get_aabb(get_player_pos()); + if (!player_box.intersects(block_box)) { + m_world.report_block_change(near_pos, m_place_block); + placeed = true; + } + } + } + return placeed; } - void ClientPlayer::update_move(float delta_time) { // if frame rate less than 1 frame per second, don't update if (delta_time > 1.0f) { @@ -523,7 +525,7 @@ Gait ClientPlayer::compute_gait() const { return Gait::WALK; } -void ClientPlayer::update_scroll(double yoffset) { +bool ClientPlayer::update_scroll(float yoffset) { if (m_game_mode == SPECTATOR) { if (yoffset > 0) { if (m_max_speed < 500.0f) { @@ -548,6 +550,28 @@ void ClientPlayer::update_scroll(double yoffset) { } } } + return true; +} + +bool ClientPlayer::handle_mouse_button_event(const MouseButtonEvent& e) { + if (e.action == KeyAction::PRESS) { + return place_block(e.key); + } + return false; +} + +bool ClientPlayer::handle_key_event(const KeyEvent& e) { + if (update_player_move_state(e.key, e.action)) { + return true; + } + + return false; +} +bool ClientPlayer::handle_mouse_wheel_event(const MouseWheelEvent& e) { + if (update_scroll(e.offset)) { + return true; + } + return false; } void ClientPlayer::update_chunk_set(const ChunkPosSet& set) { diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index d44e5de..9e19610 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -21,8 +21,8 @@ struct ChunkRenderData { }; } // namespace -ClientWorld::ClientWorld(AudioEngine& auido, Config& config) - : m_player(*this), m_audio(auido), m_config(config) {} +ClientWorld::ClientWorld(AudioEngine& auido, Config& config, WorldScene& scene) + : m_player(*this), m_audio(auido), m_config(config), m_world_scene(scene) {} ClientWorld::~ClientWorld() { m_client->close(); @@ -718,6 +718,7 @@ AABB ClientWorld::get_block_aabb(const glm::ivec3& pos) { AudioEngine& ClientWorld::get_audio() { return m_audio; } Config& ClientWorld::get_config() { return m_config; } +WorldScene& ClientWorld::world_scene() { return m_world_scene; } void ClientWorld::request_exit() { if (m_receive_exit) { @@ -905,6 +906,34 @@ void ClientWorld::update(float delta_time) { } } +bool ClientWorld::handle_event(const Event& e) { + return std::visit( + Overloaded{[this](const MouseButtonEvent& e) { + if (m_player.handle_mouse_button_event(e)) { + return true; + } + return false; + }, + [](const MouseMoveEvent& e) { return false; }, + [this](const MouseWheelEvent& e) { + if (m_player.handle_mouse_wheel_event(e)) { + return true; + } + return false; + }, + [this](const KeyEvent& e) { + if (m_player.handle_key_event(e)) { + return true; + } + + return false; + }, + [](const TextInputEvent& e) { return false; } + + }, + e); +} + glm::vec3 ClientWorld::sunlight_dir() const { float altitude = sin((m_day_tick - 6 * PER_HOUR) / static_cast(DAY_TIME / 2) * std::numbers::pi) * diff --git a/src/render/player_renderer.cpp b/src/render/player_renderer.cpp index 58b937e..27dd5fa 100644 --- a/src/render/player_renderer.cpp +++ b/src/render/player_renderer.cpp @@ -4,6 +4,7 @@ #include "Cubed/gameplay/client_world.hpp" #include "Cubed/primitive_data.hpp" #include "Cubed/render/renderer.hpp" +#include "Cubed/scene/world_scene.hpp" #include "Cubed/texture_manager.hpp" #include @@ -188,24 +189,24 @@ void PlayerRenderer::init() { m_inited = true; } -void PlayerRenderer::render(const Shader& shader) { +void PlayerRenderer::render(const Shader& shader, ClientWorld& world) { if (!m_inited) { Logger::error("Player Renderer isn't init"); return; } - auto& m_camera = m_renderer.camera(); - auto& m_world = m_renderer.world(); - auto& m_player = m_world.get_player(); - glm::mat4 m_v_mat = m_camera.get_camera_lookat(); + + auto& camera = world.world_scene().camera(); + auto& m_player = world.get_player(); + glm::mat4 m_v_mat = camera.get_camera_lookat(); glm::mat4 m_p_mat = m_renderer.world_proj_matrix(); - auto& players = m_world.render_player_data(); + auto& players = world.render_player_data(); shader.set_loc("proj_matrix", m_p_mat); for (auto& player : players) { if (player.uuid == m_player.get_uuid()) { - if (m_camera.is_first_person()) { + if (camera.is_first_person()) { continue; } } @@ -302,15 +303,15 @@ void PlayerRenderer::render(const Shader& shader) { } void PlayerRenderer::shadow_render(const Shader& shader, - glm::mat4& light_matrix) { + glm::mat4& light_matrix, + ClientWorld& world) { if (!m_inited) { Logger::error("Player Renderer isn't init"); return; } shader.use(); shader.set_loc("lightSpaceMatrix", light_matrix); - auto& m_world = m_renderer.world(); - auto& players = m_world.render_player_data(); + auto& players = world.render_player_data(); for (auto& player : players) { glm::mat4 model(1.0f); diff --git a/src/render/renderer.cpp b/src/render/renderer.cpp index a9c25a2..b1bbbed 100644 --- a/src/render/renderer.cpp +++ b/src/render/renderer.cpp @@ -1,11 +1,8 @@ #include "Cubed/render/renderer.hpp" -#include "Cubed/camera.hpp" #include "Cubed/config.hpp" #include "Cubed/debug_collector.hpp" #include "Cubed/dev_panel.hpp" -#include "Cubed/gameplay/client_player.hpp" -#include "Cubed/gameplay/client_world.hpp" #include "Cubed/primitive_data.hpp" #include "Cubed/render/renderer_constants.hpp" #include "Cubed/texture_manager.hpp" @@ -19,12 +16,9 @@ namespace Cubed { -Renderer::Renderer(const Camera& camera, ClientWorld& world, - const TextureManager& texture_manager, DevPanel& dev_panel, - Config& config) - : m_camera(camera), m_dev_panel(dev_panel), - m_texture_manager(texture_manager), m_world(world), - m_world_renderer(*this), m_config(config) {} +Renderer::Renderer(TextureManager& texture_manager, Config& config) + : m_texture_manager(texture_manager), m_world_renderer(*this), + m_config(config) {} Renderer::~Renderer() { if (m_init) { @@ -121,7 +115,7 @@ void Renderer::init(bool debug_on) { VertexBuffer::unbind(); m_crosshair_image = std::make_unique(); - m_crosshair_image->set_image("texture/ui/0.png"); + m_crosshair_image->set_image("texture/ui/0.png", m_texture_manager); m_crosshair_image ->set_position(m_width / 2 + m_crosshair_image->width() / 2, m_height / 2 + m_crosshair_image->height() / 2) @@ -148,14 +142,14 @@ void Renderer::init_text() { DebugCollector::get().init_text(); } - -void Renderer::render() { +void Renderer::begin_frame() { glDisable(GL_FRAMEBUFFER_SRGB); // clear screen glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - m_world_renderer.render(); +} +void Renderer::end_frame() {} +void Renderer::render() { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -164,10 +158,13 @@ void Renderer::render() { render_ui(); - render_dev_panel(); glEnable(GL_DEPTH_TEST); } +void Renderer::render_world(ClientWorld& world) { + m_world_renderer.render(world); +} + void Renderer::render_lable(const Label& label) { const auto& shader = get_shader("text"); @@ -194,6 +191,10 @@ void Renderer::render_lable(const Label& label) { } void Renderer::render_image(const Image& image) { + if (!image.texture()) { + Logger::error("Image id {} not set image!", image.id()); + return; + } const auto& shader = get_shader("image"); shader.use(); auto& pos = image.pos(); @@ -206,7 +207,8 @@ void Renderer::render_image(const Image& image) { shader.set_loc("proj_matrix", m_ui_proj_matrix); m_vao[3].bind(); - image.texture().bind(0); + + image.texture()->bind(0); glDrawArrays(GL_TRIANGLES, 0, 6); Tools::check_opengl_error(); } @@ -254,10 +256,11 @@ void Renderer::updata_framebuffer(int width, int height) { m_height = height; } -void Renderer::render_dev_panel() { - +void Renderer::render_dev_panel(DevPanel& dev_panel) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); - m_dev_panel.render(); + dev_panel.render(); glEnable(GL_DEPTH_TEST); } @@ -298,9 +301,6 @@ float& Renderer::underwater_fog_density() { } float& Renderer::water_density() { return m_world_renderer.water_density(); } -const Camera& Renderer::camera() const { return m_camera; } -const ClientWorld& Renderer::world() const { return m_world; } -ClientWorld& Renderer::world() { return m_world; } const glm::mat4& Renderer::world_proj_matrix() const { return m_world_proj_matrix; } diff --git a/src/render/texture.cpp b/src/render/texture.cpp index 2830472..411c590 100644 --- a/src/render/texture.cpp +++ b/src/render/texture.cpp @@ -48,8 +48,10 @@ void Texture::parameterfv(TexturePname pname, const float* param) const { } void Texture::tex_image_2d(TextureFormat internalformat, TextureFormat format, GLenum type, const void* data, GLsizei width, - GLsizei height, GLint level, GLint border) const { + GLsizei height, GLint level, GLint border) { bind(); + m_width = static_cast(width); + m_height = static_cast(height); glTexImage2D(get_gl_texture_type(), level, std::to_underlying(internalformat), width, height, border, std::to_underlying(format), type, data); @@ -58,8 +60,10 @@ void Texture::tex_image_2d(TextureFormat internalformat, TextureFormat format, void Texture::tex_image_3d(TextureFormat internalformat, TextureFormat format, GLenum type, const void* data, GLsizei width, GLsizei height, GLsizei depth, GLint level, - GLint border) const { + GLint border) { bind(); + m_width = static_cast(width); + m_height = static_cast(height); glTexImage3D(get_gl_texture_type(), level, std::to_underlying(internalformat), width, height, depth, border, std::to_underlying(format), type, data); @@ -135,7 +139,8 @@ void Texture::set_clamp_to_edge(bool r, bool s, bool t) const { } TextureType Texture::type() const { return M_TYPE; } - +float Texture::width() const { return m_width; } +float Texture::height() const { return m_height; } void Texture::unbind() { glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D_ARRAY, 0); diff --git a/src/render/world_renderer.cpp b/src/render/world_renderer.cpp index c699205..e1f857d 100644 --- a/src/render/world_renderer.cpp +++ b/src/render/world_renderer.cpp @@ -5,12 +5,12 @@ #include "Cubed/gameplay/client_world.hpp" #include "Cubed/render/renderer.hpp" #include "Cubed/render/renderer_constants.hpp" +#include "Cubed/scene/world_scene.hpp" #include "Cubed/texture_manager.hpp" #include "Cubed/tools/math_tools.hpp" namespace Cubed { WorldRenderer::WorldRenderer(Renderer& renderer) : m_renderer(renderer), m_player_renderer(renderer), - m_world(renderer.world()), m_camera(renderer.camera()), m_texture_manager(renderer.texture_mamger()) {} WorldRenderer::~WorldRenderer() { m_accum_texture.reset(); @@ -30,21 +30,21 @@ WorldRenderer::~WorldRenderer() { void WorldRenderer::init() { m_player_renderer.init(); } -void WorldRenderer::render() { +void WorldRenderer::render(ClientWorld& world) { // update view matrix; - view_matrix = m_renderer.camera().get_camera_lookat(); + view_matrix = world.world_scene().camera().get_camera_lookat(); m_world_fbo->bind(); // clear world framebuffer glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - day_night_calculation(); + day_night_calculation(world); - render_sky(); - render_world(); - render_outline(); - render_player(); + render_sky(world); + render_world(world); + render_outline(world); + render_player(world); FrameBuffer::unbind(); @@ -55,13 +55,13 @@ void WorldRenderer::render() { glClearColor(0.0f, 0.0f, 0.0f, 1.0); glClear(GL_COLOR_BUFFER_BIT); - render_underwater(); + render_underwater(world); glDisable(GL_FRAMEBUFFER_SRGB); } -void WorldRenderer::day_night_calculation() { +void WorldRenderer::day_night_calculation(ClientWorld& world) { - m_parallel_light.sundir = glm::normalize(m_renderer.world().sunlight_dir()); + m_parallel_light.sundir = glm::normalize(world.sunlight_dir()); m_parallel_light.sun_height = (-m_parallel_light.sundir).y; m_parallel_light.lightdir = m_parallel_light.sundir; @@ -92,7 +92,9 @@ void WorldRenderer::day_night_calculation() { m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor); } -void WorldRenderer::render_sky() { +void WorldRenderer::render_sky(ClientWorld& world) { + + auto& camera = world.world_scene().camera(); glm::vec3 zenith = {0.20f, 0.45f, 0.95f}; @@ -142,9 +144,8 @@ void WorldRenderer::render_sky() { sky_shader.use(); - glm::mat4 model_mat = - glm::translate(glm::mat4(1.0f), - m_camera.get_camera_pos() - glm::vec3(0.5f, 0.5f, 0.5f)); + glm::mat4 model_mat = glm::translate( + glm::mat4(1.0f), camera.get_camera_pos() - glm::vec3(0.5f, 0.5f, 0.5f)); glm::mat4 mv_mat = view_matrix * model_mat; @@ -195,20 +196,22 @@ void WorldRenderer::render_sky() { glDrawArrays(GL_TRIANGLES, 0, 6); }; // draw sun - glm::vec3 sun_pos = m_camera.get_camera_pos() + - normalize(-m_world.sunlight_dir()) * (FAR_PLANE * 0.9f); + glm::vec3 sun_pos = + camera.get_camera_pos() + + normalize(-m_parallel_light.sundir) * (FAR_PLANE * 0.9f); billboard_drawer(sun_pos, SUN_SIZE, SUN_COLOR); // draw moon - glm::vec3 moon_pos = m_camera.get_camera_pos() + - normalize(m_world.sunlight_dir()) * (FAR_PLANE * 0.9f); + glm::vec3 moon_pos = + camera.get_camera_pos() + + normalize(m_parallel_light.sundir) * (FAR_PLANE * 0.9f); billboard_drawer(moon_pos, MOON_SIZE, MOON_COLOR); glDepthMask(GL_TRUE); } -void WorldRenderer::render_world() { +void WorldRenderer::render_world(ClientWorld& world) { // shader map @@ -223,7 +226,7 @@ void WorldRenderer::render_world() { glm::mat4 norm_mat = glm::transpose(glm::inverse(mv_mat)); if (m_shader_on) { - shadow_map_generate(); + shadow_map_generate(world); } m_world_fbo->bind(); @@ -231,7 +234,7 @@ void WorldRenderer::render_world() { glCullFace(GL_BACK); glViewport(0, 0, m_width, m_height); - render_normal_block(model_mat, mv_mat, norm_mat); + render_normal_block(model_mat, mv_mat, norm_mat, world); // copy depth buffer m_world_fbo->bind(FrameBufferType::READ_FRAMEBUFFER); @@ -256,14 +259,14 @@ void WorldRenderer::render_world() { glBlendFunci(0, GL_ONE, GL_ONE); glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - render_transparent_block(mv_mat, norm_mat); + render_transparent_block(mv_mat, norm_mat, world); } -void WorldRenderer::render_outline() { +void WorldRenderer::render_outline(ClientWorld& world) { const auto& shader = m_renderer.get_shader("outline"); shader.use(); - const auto& block_pos = m_renderer.world().get_look_block_pos(); + const auto& block_pos = world.get_look_block_pos(); if (block_pos != std::nullopt) { @@ -285,24 +288,24 @@ void WorldRenderer::render_outline() { } } -void WorldRenderer::shadow_map_generate() { +void WorldRenderer::shadow_map_generate(ClientWorld& world) { float texels_per_unit = 0.0f; const auto& lightdir = m_parallel_light.lightdir; auto m_delta_time = m_renderer.delta_time(); - + auto& camera = world.world_scene().camera(); // shader map glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix; - auto& m_render_snapshots = m_world.render_snapshots(); - auto& camera_pos = m_camera.get_camera_pos(); + auto& m_render_snapshots = world.render_snapshots(); + auto& camera_pos = camera.get_camera_pos(); const auto& depth_shader = m_renderer.get_shader("depth_shader"); depth_shader.use(); - glm::vec3 cam_pos = m_camera.get_camera_pos(); - glm::vec3 cam_fwd = m_camera.get_camera_front(); + glm::vec3 cam_pos = camera.get_camera_pos(); + glm::vec3 cam_fwd = camera.get_camera_front(); float half_extent = 128.0f; glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f); @@ -389,13 +392,13 @@ void WorldRenderer::shadow_map_generate() { } // player auto& player_shadow = m_renderer.get_shader("player_depth"); - m_player_renderer.shadow_render(player_shadow, light_space_matrix); + m_player_renderer.shadow_render(player_shadow, light_space_matrix, world); } -void WorldRenderer::render_underwater() { +void WorldRenderer::render_underwater(ClientWorld& world) { const auto& shader = m_renderer.get_shader("under_water"); - + auto& camera = world.world_scene().camera(); shader.use(); auto& m_vao = m_renderer.vao(); @@ -406,10 +409,10 @@ void WorldRenderer::render_underwater() { shader.set_loc("u_sceneTexture", 0); shader.set_loc("u_time", static_cast(glfwGetTime())); - shader.set_loc("u_underwater", m_camera.is_under_water()); + shader.set_loc("u_underwater", camera.is_under_water()); shader.set_loc("u_waterColor", glm::vec3(0.1f, 0.25f, 0.35f)); shader.set_loc("u_fogDensity", m_underwater_fog_density); - shader.set_loc("cameraPos", m_camera.get_camera_pos()); + shader.set_loc("cameraPos", camera.get_camera_pos()); shader.set_loc("sunDir", -m_parallel_light.sundir); shader.set_loc("waterDensity", m_water_density); shader.set_loc("InverseViewProjection", @@ -427,13 +430,14 @@ void WorldRenderer::render_underwater() { void WorldRenderer::render_normal_block(const glm::mat4& model_mat, const glm::mat4& mv_mat, - const glm::mat4& norm_mat) { + const glm::mat4& norm_mat, + ClientWorld& world) { // shader map glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix; - - auto& m_render_snapshots = m_world.render_snapshots(); - auto& camera_pos = m_camera.get_camera_pos(); + auto& camera = world.world_scene().camera(); + auto& m_render_snapshots = world.render_snapshots(); + auto& camera_pos = camera.get_camera_pos(); const auto& lightdir = m_parallel_light.lightdir; @@ -467,14 +471,14 @@ void WorldRenderer::render_normal_block(const glm::mat4& model_mat, normal_block_shader.set_loc("maxRadius", m_max_radius); normal_block_shader.set_loc("samples", m_samples); normal_block_shader.set_loc("specularStrength", m_specular_strength); - normal_block_shader.set_loc("cameraPos", m_camera.get_camera_pos()); + normal_block_shader.set_loc("cameraPos", camera.get_camera_pos()); normal_block_shader.set_loc("flipY", m_flip_y); - normal_block_shader.set_loc("renderDistance", m_world.rendering_distance()); + normal_block_shader.set_loc("renderDistance", world.rendering_distance()); normal_block_shader.set_loc("skyColor", m_sky_uniform.sky_top); glm::mat4 mvp_mat = proj_mat * mv_mat; - auto& m_planes = m_world.planes(); + auto& m_planes = world.planes(); Math::extract_frustum_planes(mvp_mat, m_planes); @@ -545,10 +549,11 @@ void WorldRenderer::render_normal_block(const glm::mat4& model_mat, } void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat, - const glm::mat4& norm_mat) { - - auto& m_render_snapshots = m_world.render_snapshots(); + const glm::mat4& norm_mat, + ClientWorld& world) { + auto& m_render_snapshots = world.render_snapshots(); + auto& camera = world.world_scene().camera(); const auto& lightdir = m_parallel_light.lightdir; glm::vec3 light_dir_view = glm::normalize(glm::mat3(view_matrix) * lightdir); @@ -573,11 +578,11 @@ void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat, accum_shader.use(); set_accum_loc(accum_shader); - accum_shader.set_loc("cameraPos", m_camera.get_camera_pos()); + accum_shader.set_loc("cameraPos", camera.get_camera_pos()); m_texture_manager.get_texture_array()->bind(0); - auto& m_planes = m_world.planes(); + auto& m_planes = world.planes(); for (const auto& snapshot : m_render_snapshots) { if (!snapshot) { @@ -619,7 +624,7 @@ void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat, water_shader.set_loc("cloudWhiteMix", m_sky_uniform.cloud_white_mix); water_shader.set_loc("cloudThresholdLow", m_cloud_threshold_low); water_shader.set_loc("cloudThresholdHigh", m_cloud_threshold_high); - water_shader.set_loc("underwater", m_camera.is_under_water()); + water_shader.set_loc("underwater", camera.is_under_water()); water_shader.set_loc("refractStrength", m_refract_strength); water_shader.set_loc("enablePerturb", m_water_perturb); water_shader.set_loc("enableDepthFade", m_water_depth_fade); @@ -670,7 +675,7 @@ void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat, glBindVertexArray(0); } -void WorldRenderer::render_player() { +void WorldRenderer::render_player(ClientWorld& world) { auto& shader = m_renderer.get_shader("player"); shader.use(); glm::vec3 light_dir_view = @@ -692,7 +697,7 @@ void WorldRenderer::render_player() { // shader.set_loc("skyColor", m_sky_uniform.sky_top); m_depth_map_texture->bind(0); - m_player_renderer.render(shader); + m_player_renderer.render(shader, world); } glm::vec3 WorldRenderer::quantize_sun_direction(const glm::vec3& lightdir, diff --git a/src/scene/scene_manager.cpp b/src/scene/scene_manager.cpp new file mode 100644 index 0000000..f4f02ab --- /dev/null +++ b/src/scene/scene_manager.cpp @@ -0,0 +1,96 @@ +#include "Cubed/scene/scene_manager.hpp" + +#include "Cubed/scene/world_scene.hpp" + +namespace Cubed { +SceneManager::SceneManager(App& app) : m_app(app) {} +SceneManager::~SceneManager() {} + +void SceneManager::update(float dt) { + m_pending_delete_scene.clear(); + + if (!m_scenes.empty()) { + m_scenes.top()->update(dt); + } + process_operation(); +} +void SceneManager::render(Renderer& renderer) { + if (m_scenes.empty()) { + return; + } + m_scenes.top()->render(renderer); +} + +bool SceneManager::handle_event(const Event& e) { + return m_scenes.top()->handle_event(e); +} + +void SceneManager::request_change(SceneType type) { + ASSERT(!m_operation.has_value()); + m_operation = {OperationType::CHANGE, type}; +} +void SceneManager::request_push(SceneType type) { + ASSERT(!m_operation.has_value()); + m_operation = {OperationType::PUSH, type}; +} +void SceneManager::request_pop() { + ASSERT(!m_operation.has_value()); + m_operation = {OperationType::POP, std::nullopt}; +} + +void SceneManager::process_operation() { + while (m_operation) { + auto op = std::move(*m_operation); + m_operation.reset(); + + switch (op.type) { + case OperationType::PUSH: + push(*op.scene); + break; + case OperationType::POP: + pop(); + break; + case OperationType::CHANGE: + change(*op.scene); + break; + } + } +} + +void SceneManager::change(SceneType type) { + if (!m_scenes.empty()) { + pop(); + } + + push(type); +} +void SceneManager::push(SceneType type) { + auto scene = create_scene(type); + scene->on_enter(); + m_scenes.push(std::move(scene)); +} +void SceneManager::pop() { + if (m_scenes.empty()) { + return; + } + auto scene = std::move(m_scenes.top()); + m_scenes.pop(); + scene->on_leave(); + m_pending_delete_scene.push_back(std::move(scene)); +} + +std::unique_ptr SceneManager::create_scene(SceneType type) { + switch (type) { + case SceneType::WORLD: + return std::make_unique(*this); + case SceneType::MAIN_MENU: + return nullptr; + } + + std::string err = std::format("Unknown Scene"); + ASSERT_MSG(false, err); + throw std::runtime_error(err); +} + +App& SceneManager::app() { return m_app; } +} // namespace Cubed \ No newline at end of file diff --git a/src/scene/world_scene.cpp b/src/scene/world_scene.cpp new file mode 100644 index 0000000..45272da --- /dev/null +++ b/src/scene/world_scene.cpp @@ -0,0 +1,78 @@ +#include "Cubed/scene/world_scene.hpp" + +#include "Cubed/app.hpp" +#include "Cubed/render/renderer.hpp" +#include "Cubed/scene/scene_manager.hpp" +namespace Cubed { +WorldScene::WorldScene(SceneManager& scene_manager) + : m_scene_manager(scene_manager), m_dev_panel(*this), + m_client_world(scene_manager.app().audio(), scene_manager.app().config(), + *this), + m_argument(scene_manager.app().argument()) {} + +WorldScene::~WorldScene() { + if (m_client) { + m_client->stop(); + } +} + +void WorldScene::update(float dt) { + m_client_world.update(dt); + m_camera.update_move_camera(); + m_client_world.get_audio().update_listener(m_camera.get_camera_pos(), + m_camera.get_camera_front(), + glm::vec3(0, 1, 0)); + /* + const auto& player = m_client_world.get_player(); + if (player_gait != player.get_gait()) { + player_gait = player.get_gait(); + float fov = m_client_world.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); + } + }*/ +} + +void WorldScene::render(Renderer& renderer) { + Logger::info("World Scene Render Start !"); + renderer.render_world(m_client_world); + Logger::info("Client World Render Finish"); + renderer.render_dev_panel(m_dev_panel); + Logger::info("DevPanel Render Finish!"); +} +bool WorldScene::handle_event(const Event& e) { + if (m_camera.handle_event(e)) { + return true; + } + // world event needs to be processed last + if (m_client_world.handle_event(e)) { + return true; + } + return false; +} +void WorldScene::on_enter() { + + m_client = std::make_shared(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_scene_manager.app().window().set_camera(&m_camera); + m_dev_panel.init(); +} +void WorldScene::on_leave() { + m_client_world.request_exit(); + + m_scene_manager.app().window().set_camera(nullptr); +} + +Camera& WorldScene::camera() { return m_camera; } +SceneManager& WorldScene::scene_manager() { return m_scene_manager; } +ClientWorld& WorldScene::client_world() { return m_client_world; } +} // namespace Cubed \ No newline at end of file diff --git a/src/texture_manager.cpp b/src/texture_manager.cpp index d59383b..b83e696 100644 --- a/src/texture_manager.cpp +++ b/src/texture_manager.cpp @@ -11,7 +11,6 @@ constexpr int BLOCK_SIZE = 16; constexpr int BLOCK_NORMAL_SIZE = 128; constexpr int CROSS_PLANE_SIZE = 16; constexpr int BLOCK_ITEM_SIZE = 16; -constexpr int UI_SIZE = 16; constexpr int BLOCK_STATUS_SIZE = 16; constexpr int SKIN_SIZE = 64; @@ -58,7 +57,13 @@ const Texture* TextureManager::get_texture_array() const { const Texture* TextureManager::get_cross_plane_array() const { return m_cross_plane_array.get(); } -const Texture* TextureManager::get_ui_array() const { return m_ui_array.get(); } +const Texture* TextureManager::get_image_texture(const std::string& path) { + auto it = m_ui_map.find(path); + if (it != m_ui_map.end()) { + return it->second.get(); + } + return load_image_texture(path); +} const Texture* TextureManager::get_pbr_texture() const { return m_normal_texture_array.get(); @@ -146,13 +151,19 @@ void TextureManager::load_cross_plane_texture(unsigned id) { CROSS_PLANE_SIZE, CROSS_PLANE_SIZE); } -void TextureManager::load_ui_texture(unsigned id) { - ASSERT_MSG(id < MAX_UI_NUM, "Exceed the max ui sum limit"); +const Texture* TextureManager::load_image_texture(const std::string& path) { - std::string path = "texture/ui/" + std::to_string(id) + ".png"; auto image_data = (Tools::load_image_data(path)); - m_ui_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE, - image_data.data, 0, 0, id, UI_SIZE, UI_SIZE); + std::unique_ptr image = + std::make_unique(TextureType::TEXTURE_2D); + image->tex_image_2d(RGBA, RGBA, GL_UNSIGNED_BYTE, image_data.data, + image_data.width, image_data.height); + image->set_nearest(); + auto [it, inserted] = m_ui_map.try_emplace(path, std::move(image)); + if (!inserted) { + Logger::error("Path {} already exist!", path); + } + return it->second.get(); } void TextureManager::load_pbr_texture(unsigned id) { @@ -232,17 +243,7 @@ void TextureManager::init_block() { Logger::info("Block Texture Load Success"); } -void TextureManager::init_ui() { - m_ui_array = std::make_unique(TextureType::TEXTURE_2D_ARRAY); - m_ui_array->tex_image_3d(TextureFormat::RGBA, TextureFormat::RGBA, - GL_UNSIGNED_BYTE, nullptr, UI_SIZE, UI_SIZE, - MAX_UI_NUM); - for (int i = 0; i < MAX_UI_NUM; i++) { - load_ui_texture(i); - } - - m_ui_array->set_nearest(); -} +void TextureManager::init_ui() {} void TextureManager::init_skin() { m_skin = std::make_unique(TextureType::TEXTURE_2D); @@ -304,4 +305,27 @@ void TextureManager::hot_reload() { int TextureManager::max_aniso() const { return static_cast(m_max_aniso); } +bool TextureManager::handle_event(const Event& e) { + return std::visit( + Overloaded{[](const MouseMoveEvent& e) { return false; }, + [](const MouseButtonEvent& e) { return false; }, + [](const MouseWheelEvent& e) { return false; }, + [this](const KeyEvent& e) { + if (handle_key_event(e)) { + return true; + } + return false; + }, + [](const TextInputEvent& e) { return false; }}, + e); +} + +bool TextureManager::handle_key_event(const KeyEvent& e) { + if (e.key == Key::R && e.action == KeyAction::PRESS) { + need_reload(); + return true; + } + + return false; +} } // namespace Cubed \ No newline at end of file diff --git a/src/ui/button.cpp b/src/ui/button.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ui/image.cpp b/src/ui/image.cpp index ac09eda..f13ddcc 100644 --- a/src/ui/image.cpp +++ b/src/ui/image.cpp @@ -1,27 +1,35 @@ #include "Cubed/ui/image.hpp" #include "Cubed/render/renderer.hpp" -#include "Cubed/tools/shader_tools.hpp" +#include "Cubed/texture_manager.hpp" namespace Cubed { -Image::Image() : m_texture(TextureType::TEXTURE_2D) {} +Image::Image() {} void Image::update(float dt) { (void)dt; } void Image::render(Renderer& renderer) { renderer.render_image(*this); } -Image& Image::set_image(std::filesystem::path path) { - auto data = Tools::load_image_data(path); - m_texture.tex_image_2d(RGBA, RGBA, GL_UNSIGNED_BYTE, data.data, data.width, - data.height); - m_height = data.height; - m_width = data.width; - m_texture.set_nearest(); +Image& Image::set_image(const std::string& path, + TextureManager& texture_manager) { + m_texture = texture_manager.get_image_texture(path); return *this; } -float Image::height() const { return m_height; } +float Image::height() const { + if (!m_texture) { + Logger::error("Image id {} not set image!", m_id); + return 0.0f; + } + return m_texture->height(); +} -float Image::width() const { return m_width; } +float Image::width() const { + if (!m_texture) { + Logger::error("Image id {} not set image!", m_id); + return 0.0f; + } + return m_texture->width(); +} -const Texture& Image::texture() const { return m_texture; } +const Texture* Image::texture() const { return m_texture; } } // namespace Cubed \ No newline at end of file diff --git a/src/window.cpp b/src/window.cpp index 3343231..6dde85e 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,5 +1,6 @@ #include "Cubed/window.hpp" +#include "Cubed/camera.hpp" #include "Cubed/render/renderer.hpp" #include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/font.hpp" @@ -51,6 +52,52 @@ void Window::update_viewport() { m_config.set("window.height", windowed_height); } +bool Window::handle_event(const Event& e) { + return std::visit(Overloaded{[](const MouseMoveEvent& e) { return false; }, + [this](const MouseButtonEvent& e) { + if (handle_mouse_button_event(e)) { + return true; + } + return false; + }, + [](const MouseWheelEvent& e) { return false; }, + [this](const KeyEvent& e) { + if (handle_key_event(e)) { + return true; + } + return false; + }, + [](const TextInputEvent& e) { return false; }}, + e); +} + +bool Window::handle_key_event(const KeyEvent& e) { + if (e.key == Key::F11 && e.action == KeyAction::PRESS) { + toggle_fullscreen(); + return true; + } + if (e.key == Key::ESCAPE && e.action == KeyAction::PRESS) { + glfwSetWindowShouldClose(m_window, GLFW_TRUE); + return true; + } + if (e.key == Key::LEFT_ALT && e.action == KeyAction::PRESS) { + toggle_mouse_able(); + return true; + } + + return false; +} + +bool Window::handle_mouse_button_event(const MouseButtonEvent& e) { + if (e.key == MouseKey::LEFT_BUTTON && e.action == KeyAction::PRESS) { + if (is_mouse_enable()) { + toggle_mouse_able(); + return true; + } + } + return false; +} + void Window::init() { if (!glfwInit()) { Logger::error("glfw init fail"); @@ -166,8 +213,13 @@ void Window::toggle_mouse_able() { glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); m_mouse_enable = true; } -} + if (m_camera) { + m_camera->reset_camera(); + } +} +void Window::set_camera(Camera* camera) { m_camera = camera; } +Camera* Window::camera() { return m_camera; } void Window::imgui_init() { float dpi_scale_x, dpi_scale_y; glfwGetWindowContentScale(m_window, &dpi_scale_x, &dpi_scale_y);