diff --git a/assets/texture/ui/button001.png b/assets/texture/ui/button001.png new file mode 100644 index 0000000..d235658 Binary files /dev/null and b/assets/texture/ui/button001.png differ diff --git a/include/Cubed/scene/main_menu_scene.hpp b/include/Cubed/scene/main_menu_scene.hpp new file mode 100644 index 0000000..5abb913 --- /dev/null +++ b/include/Cubed/scene/main_menu_scene.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Cubed/scene/scene.hpp" +#include "Cubed/ui/main_menu_ui_manager.hpp" +namespace Cubed { +class SceneManager; +class MainMenuScene : public Scene { +public: + MainMenuScene(const MainMenuScene&) = delete; + MainMenuScene(MainMenuScene&&) = delete; + MainMenuScene& operator=(const MainMenuScene&) = delete; + MainMenuScene& operator=(MainMenuScene&&) = delete; + MainMenuScene(SceneManager& scene_manager); + ~MainMenuScene(); + + 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; + + SceneManager& scene_manager(); + +private: + SceneManager& m_scene_manager; + MainMenuUIManager m_ui_manager; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/ui/button.hpp b/include/Cubed/ui/button.hpp index 9feb638..ec63074 100644 --- a/include/Cubed/ui/button.hpp +++ b/include/Cubed/ui/button.hpp @@ -9,11 +9,48 @@ class Button : public Widget { public: Button(); + Button(const Button&) = delete; + Button(Button&&) = delete; + Button& operator=(const Button&) = delete; + Button& operator=(Button&&) = delete; + + void render(Renderer& renderer) override; + void update(float dt) override; + + bool handle_mouse_move_event(const MouseMoveEvent& e) override; + bool handle_mouse_button_event(const MouseButtonEvent& e) override; + + Widget& set_position(const glm::vec2& pos) override; + Widget& set_position(float x, float y) override; + + float width() const override; + float height() const override; + template Button& set_clicked(F&& f) { - m_clicked = std::move(f); + m_clicked = std::forward(f); + return *this; + } + + template T& set_background(Args&&... args) { + auto w = std::make_unique(std::forward(args)...); + T& ref = *w; + m_background = std::move(w); + return ref; + } + + template T& set_foreground(Args&&... args) { + auto w = std::make_unique(std::forward(args)...); + T& ref = *w; + m_foreground = std::move(w); + return ref; } private: std::function m_clicked; + std::unique_ptr m_background; + std::unique_ptr m_foreground; + bool m_hovered = false; + glm::vec2 m_min_pos; + glm::vec2 m_max_pos; }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/ui/image.hpp b/include/Cubed/ui/image.hpp index 65560c2..4a414b0 100644 --- a/include/Cubed/ui/image.hpp +++ b/include/Cubed/ui/image.hpp @@ -13,8 +13,8 @@ public: void render(Renderer& renderer) override; Image& set_image(const std::string& path, TextureManager& texture_manager); - float width() const; - float height() const; + float width() const override; + float height() const override; const Texture* texture() const; private: diff --git a/include/Cubed/ui/label.hpp b/include/Cubed/ui/label.hpp index 788820a..7aae6ed 100644 --- a/include/Cubed/ui/label.hpp +++ b/include/Cubed/ui/label.hpp @@ -12,6 +12,7 @@ public: Label& operator=(Label&&) = delete; Label(const std::string& id); + Label(); virtual ~Label() = default; Label& set_text(std::string_view text); diff --git a/include/Cubed/ui/main_menu_ui_manager.hpp b/include/Cubed/ui/main_menu_ui_manager.hpp new file mode 100644 index 0000000..c278c99 --- /dev/null +++ b/include/Cubed/ui/main_menu_ui_manager.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "Cubed/input/event.hpp" +#include "Cubed/ui/widget.hpp" + +#include +#include +namespace Cubed { +class Renderer; +class MainMenuScene; +class MainMenuUIManager { +public: + MainMenuUIManager(MainMenuScene& m_scene); + MainMenuUIManager(const MainMenuUIManager&) = delete; + MainMenuUIManager(MainMenuUIManager&&) = delete; + MainMenuUIManager& operator=(const MainMenuUIManager&) = delete; + MainMenuUIManager& operator=(MainMenuUIManager&&) = delete; + ~MainMenuUIManager(); + + void init(); + void render(Renderer& renderer); + void update(float dt); + + bool handle_event(const Event& e); + +private: + MainMenuScene& m_scene; + std::unordered_map> m_widgets; + bool handle_mouse_move_event(const MouseMoveEvent& e); + bool handle_mouse_button_event(const MouseButtonEvent& e); + bool handle_window_resize_event(const WindowResizeEvent& e); + bool handle_mouse_wheel_event(const MouseWheelEvent& e); + bool handle_key_event(const KeyEvent& e); +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/ui/widget.hpp b/include/Cubed/ui/widget.hpp index e781657..d9af1a6 100644 --- a/include/Cubed/ui/widget.hpp +++ b/include/Cubed/ui/widget.hpp @@ -1,10 +1,12 @@ #pragma once +#include "Cubed/input/event.hpp" #include "glm/ext/vector_float2.hpp" #include #include namespace Cubed { class Renderer; + class Widget { public: @@ -17,9 +19,17 @@ public: virtual Widget& set_position(const glm::vec2& pos); virtual Widget& set_position(float x, float y); virtual Widget& set_scale(float scale); + virtual float width() const; + virtual float height() const; virtual const glm::vec2& pos() const; virtual float scale() const; + virtual bool handle_key_event(const KeyEvent& e); + virtual bool handle_mouse_button_event(const MouseButtonEvent& e); + virtual bool handle_mouse_wheel_event(const MouseWheelEvent& e); + virtual bool handle_window_resize_event(const WindowResizeEvent& e); + virtual bool handle_mouse_move_event(const MouseMoveEvent& e); + template T& add_child(Args&&... args) { auto widget = std::make_unique(std::forward(args)...); T& ref = *widget; diff --git a/include/Cubed/ui/world_ui_manager.hpp b/include/Cubed/ui/world_ui_manager.hpp index 24f5538..5b1de87 100644 --- a/include/Cubed/ui/world_ui_manager.hpp +++ b/include/Cubed/ui/world_ui_manager.hpp @@ -25,7 +25,7 @@ public: private: WorldScene& m_scene; std::unordered_map> m_widgets; - + bool handle_mouse_move_event(const MouseMoveEvent& e); bool handle_mouse_button_event(const MouseButtonEvent& e); bool handle_window_resize_event(const WindowResizeEvent& e); bool handle_mouse_wheel_event(const MouseWheelEvent& e); diff --git a/include/Cubed/window.hpp b/include/Cubed/window.hpp index 5023e24..66c4d24 100644 --- a/include/Cubed/window.hpp +++ b/include/Cubed/window.hpp @@ -30,9 +30,12 @@ public: void set_camera(Camera* camera); Camera* camera(); + void set_game_running(bool running); + private: bool m_mouse_enable = false; bool m_imgui_init = false; + bool m_game_running = false; GLFWwindow* m_window; int m_window_width; int m_window_height; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f77b03e..dc68bbf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,4 +65,6 @@ target_sources(${PROJECT_NAME} scene/world_scene.cpp scene/scene_manager.cpp ui/world_ui_manager.cpp + ui/main_menu_ui_manager.cpp + scene/main_menu_scene.cpp ) \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index 599b024..2c69610 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -77,7 +77,7 @@ void App::init(int argc, char** argv) { m_server.start_server(m_argument.port); } - m_scene_manager.request_push(SceneType::WORLD); + m_scene_manager.request_push(SceneType::MAIN_MENU); { int w, h; diff --git a/src/scene/main_menu_scene.cpp b/src/scene/main_menu_scene.cpp new file mode 100644 index 0000000..df08ee5 --- /dev/null +++ b/src/scene/main_menu_scene.cpp @@ -0,0 +1,21 @@ +#include "Cubed/scene/main_menu_scene.hpp" + +namespace Cubed { +MainMenuScene::MainMenuScene(SceneManager& scene_manager) + : m_scene_manager(scene_manager), m_ui_manager(*this) {} +MainMenuScene::~MainMenuScene() {} + +void MainMenuScene::update(float dt) { m_ui_manager.update(dt); } +void MainMenuScene::render(Renderer& renderer) { + m_ui_manager.render(renderer); +} +bool MainMenuScene::handle_event(const Event& e) { + if (m_ui_manager.handle_event(e)) { + return true; + } + return false; +} +void MainMenuScene::on_enter() { m_ui_manager.init(); } +void MainMenuScene::on_leave() {} +SceneManager& MainMenuScene::scene_manager() { return m_scene_manager; } +} // namespace Cubed \ No newline at end of file diff --git a/src/scene/scene_manager.cpp b/src/scene/scene_manager.cpp index d726f83..2894988 100644 --- a/src/scene/scene_manager.cpp +++ b/src/scene/scene_manager.cpp @@ -1,5 +1,6 @@ #include "Cubed/scene/scene_manager.hpp" +#include "Cubed/scene/main_menu_scene.hpp" #include "Cubed/scene/world_scene.hpp" namespace Cubed { @@ -8,11 +9,10 @@ SceneManager::~SceneManager() {} void SceneManager::update(float dt) { m_pending_delete_scene.clear(); - + process_operation(); if (!m_scenes.empty()) { m_scenes.top()->update(dt); } - process_operation(); } void SceneManager::render(Renderer& renderer) { if (m_scenes.empty()) { @@ -87,7 +87,7 @@ std::unique_ptr SceneManager::create_scene(SceneType type) { case SceneType::WORLD: return std::make_unique(*this); case SceneType::MAIN_MENU: - return nullptr; + return std::make_unique(*this); } std::string err = std::format("Unknown Scene"); diff --git a/src/scene/world_scene.cpp b/src/scene/world_scene.cpp index 0faa613..2879cbf 100644 --- a/src/scene/world_scene.cpp +++ b/src/scene/world_scene.cpp @@ -72,11 +72,14 @@ void WorldScene::on_enter() { m_scene_manager.app().window().set_camera(&m_camera); m_dev_panel.init(); m_ui_manager.init(); + + m_scene_manager.app().window().set_game_running(true); } void WorldScene::on_leave() { m_client_world.request_exit(); m_scene_manager.app().window().set_camera(nullptr); + m_scene_manager.app().window().set_game_running(false); } Camera& WorldScene::camera() { return m_camera; } diff --git a/src/ui/button.cpp b/src/ui/button.cpp index e69de29..b399a39 100644 --- a/src/ui/button.cpp +++ b/src/ui/button.cpp @@ -0,0 +1,67 @@ +#include "Cubed/ui/button.hpp" + +#include "Cubed/tools/log.hpp" + +namespace Cubed { +Button::Button() {} + +void Button::update(float dt) { + if (m_background) { + m_background->update(dt); + } + if (m_foreground) { + m_foreground->update(dt); + } +} + +void Button::render(Renderer& renderer) { + if (m_background) { + m_background->render(renderer); + } + if (m_foreground) { + m_foreground->render(renderer); + } +} + +bool Button::handle_mouse_move_event(const MouseMoveEvent& e) { + if (e.xpos >= m_min_pos.x && e.xpos <= m_max_pos.x) { + if (e.ypos >= m_min_pos.y && e.ypos <= m_max_pos.y) { + m_hovered = true; + Logger::info("Hovered {}", m_hovered); + return true; + } + } + m_hovered = false; + Logger::info("Hovered {}", m_hovered); + return false; +} +bool Button::handle_mouse_button_event(const MouseButtonEvent& e) { + if (e.action == KeyAction::PRESS && e.key == MouseKey::LEFT_BUTTON) { + if (m_hovered && m_clicked) { + m_clicked(); + Logger::info("Button click!"); + return true; + } + } + return false; +} + +Widget& Button::set_position(const glm::vec2& pos) { + m_pos = pos; + m_background->set_position(pos); + m_foreground->set_position(pos); + m_min_pos = pos; + + m_max_pos.x = m_min_pos.x + m_background->width(); + m_max_pos.y = m_min_pos.y + m_background->height(); + + return *this; +} +Widget& Button::set_position(float x, float y) { + return set_position(glm::vec2{x, y}); +} + +float Button::width() const { return m_background->width(); } +float Button::height() const { return m_background->height(); } + +} // namespace Cubed \ No newline at end of file diff --git a/src/ui/label.cpp b/src/ui/label.cpp index 01b9e31..e9977c2 100644 --- a/src/ui/label.cpp +++ b/src/ui/label.cpp @@ -4,7 +4,7 @@ #include "Cubed/tools/font.hpp" namespace Cubed { Label::Label(const std::string& id) : Widget(id) {} - +Label::Label() {} Label& Label::set_text(std::string_view text) { m_text.text = text; m_dirty = true; diff --git a/src/ui/main_menu_ui_manager.cpp b/src/ui/main_menu_ui_manager.cpp new file mode 100644 index 0000000..3e6156f --- /dev/null +++ b/src/ui/main_menu_ui_manager.cpp @@ -0,0 +1,133 @@ +#include "Cubed/ui/main_menu_ui_manager.hpp" + +#include "Cubed/app.hpp" +#include "Cubed/render/renderer.hpp" +#include "Cubed/scene/main_menu_scene.hpp" +#include "Cubed/scene/scene_manager.hpp" +#include "Cubed/ui/button.hpp" +namespace Cubed { + +MainMenuUIManager::MainMenuUIManager(MainMenuScene& scene) : m_scene(scene) {} +MainMenuUIManager::~MainMenuUIManager() {} + +void MainMenuUIManager::init() { + + auto start_game_button = std::make_unique