From c6d1fd8910c4a5e45945e664873e19582700b974 Mon Sep 17 00:00:00 2001 From: sebastian Date: Sun, 2 Aug 2026 21:04:34 +0200 Subject: [PATCH] ADD: Basic UI --- CMakeLists.txt | 2 ++ engine/src/core/Application.cpp | 5 +++ engine/src/core/Application.h | 3 ++ .../core/inputsOutputs/inputs/Keyboard.cpp | 3 ++ .../src/core/inputsOutputs/inputs/Mouse.cpp | 17 +++++++++ engine/src/core/inputsOutputs/inputs/Mouse.h | 3 +- engine/src/ui/ImGuiContext.cpp | 36 +++++++++++++++++++ engine/src/ui/ImGuiContext.h | 26 ++++++++++++++ game/src/GameLayer.cpp | 28 +++++++++++++++ game/src/GameLayer.h | 3 ++ game/src/ludo/LudoGameMode.h | 3 +- 11 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 engine/src/ui/ImGuiContext.cpp create mode 100644 engine/src/ui/ImGuiContext.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 374fec9..daca027 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,6 +156,8 @@ add_library(Engine STATIC engine/src/ecs/standardComponents/PickableComponent.h engine/src/ecs/systems/PickingSystem.cpp engine/src/ecs/systems/PickingSystem.h + engine/src/ui/ImGuiContext.cpp + engine/src/ui/ImGuiContext.h ) target_include_directories(Engine PUBLIC engine/src) target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui spdlog::spdlog tinyobjloader stb_image) diff --git a/engine/src/core/Application.cpp b/engine/src/core/Application.cpp index 34ed369..673ab34 100644 --- a/engine/src/core/Application.cpp +++ b/engine/src/core/Application.cpp @@ -28,6 +28,10 @@ namespace engine { lastTime = currentTime; m_window->pollEvents(); + m_keyboard.update(); + m_mouse.update(); + + m_imguiContext.beginFrame(); onUpdate(deltaTime); @@ -35,6 +39,7 @@ namespace engine { onRender(); + m_imguiContext.endFrame(); m_window->swapBuffers(); } } diff --git a/engine/src/core/Application.h b/engine/src/core/Application.h index bbd9434..da38366 100644 --- a/engine/src/core/Application.h +++ b/engine/src/core/Application.h @@ -8,11 +8,13 @@ #include #include "EngineConfig.h" + #include "Window.h" #include "inputsOutputs/context/InputContextStack.h" #include "inputsOutputs/inputs/Keyboard.h" #include "inputsOutputs/inputs/Mouse.h" #include "layer/SceneManager.h" +#include "ui/ImGuiContext.h" namespace engine { @@ -38,6 +40,7 @@ namespace engine { Keyboard m_keyboard{*m_window}; // braucht Window& im Konstruktor Mouse m_mouse{*m_window}; SceneManager m_sceneManager{m_inputContextStack}; + ImGuiContext m_imguiContext{*m_window}; // neu }; diff --git a/engine/src/core/inputsOutputs/inputs/Keyboard.cpp b/engine/src/core/inputsOutputs/inputs/Keyboard.cpp index e1fe426..204710e 100644 --- a/engine/src/core/inputsOutputs/inputs/Keyboard.cpp +++ b/engine/src/core/inputsOutputs/inputs/Keyboard.cpp @@ -4,6 +4,7 @@ #include "Keyboard.h" +#include "imgui_impl_glfw.h" #include "core/Window.h" #include "GLFW/glfw3.h" @@ -42,6 +43,7 @@ bool engine::Keyboard::keyReleaseEvent(const int key) const { void engine::Keyboard::addTextListener(Window &window) { glfwSetCharCallback(window.getHandle(), [](GLFWwindow* handle, unsigned int key) { + ImGui_ImplGlfw_CharCallback(handle, key); auto* target = static_cast(glfwGetWindowUserPointer(handle)); if (!target || !target->keyboard) return; @@ -51,6 +53,7 @@ void engine::Keyboard::addTextListener(Window &window) { void engine::Keyboard::addKeyListener(Window &window) { glfwSetKeyCallback(window.getHandle(), [](GLFWwindow* handle, int key, int scancode, int action, int mods) { + ImGui_ImplGlfw_KeyCallback(handle, key, scancode, action, mods); auto* target = static_cast(glfwGetWindowUserPointer(handle)); if (!target || !target->keyboard) return; diff --git a/engine/src/core/inputsOutputs/inputs/Mouse.cpp b/engine/src/core/inputsOutputs/inputs/Mouse.cpp index 06e9a2f..f2dc204 100644 --- a/engine/src/core/inputsOutputs/inputs/Mouse.cpp +++ b/engine/src/core/inputsOutputs/inputs/Mouse.cpp @@ -4,6 +4,7 @@ #include "Mouse.h" +#include "imgui_impl_glfw.h" #include "core/Window.h" #include "GLFW/glfw3.h" @@ -77,6 +78,8 @@ void engine::Mouse::updateDetlas() { void engine::Mouse::addMoveListener(Window &window) { glfwSetCursorPosCallback(window.getHandle(), [](GLFWwindow* handle, double xPos, double yPos) { + ImGui_ImplGlfw_CursorPosCallback(handle, xPos, yPos); + auto* target = static_cast(glfwGetWindowUserPointer(handle)); if (!target || !target->mouse) return; @@ -89,6 +92,8 @@ void engine::Mouse::addMoveListener(Window &window) { void engine::Mouse::addScrollListener(Window &window) { glfwSetScrollCallback(window.getHandle(), [](GLFWwindow* handle, double xoff, double yoff) { + ImGui_ImplGlfw_ScrollCallback(handle, xoff, yoff); + auto* target = static_cast(glfwGetWindowUserPointer(handle)); if (target && target->mouse) target->mouse->scroll = static_cast(yoff); }); @@ -96,6 +101,8 @@ void engine::Mouse::addScrollListener(Window &window) { void engine::Mouse::addClickListener(Window &window) { glfwSetMouseButtonCallback(window.getHandle(), [](GLFWwindow* handle, int button, int action, int mods) { + ImGui_ImplGlfw_MouseButtonCallback(handle, button, action, mods); + auto* target = static_cast(glfwGetWindowUserPointer(handle)); if (!target || !target->mouse) return; @@ -103,3 +110,13 @@ void engine::Mouse::addClickListener(Window &window) { else if (action == GLFW_RELEASE) target->mouse->reportButtonRelease(button); }); } + +int engine::Mouse::MouseButtonToInt(MouseButton button) { + int glfwButton = 0; + switch (button) { + case MouseButton::LEFT: glfwButton = GLFW_MOUSE_BUTTON_LEFT; break; + case MouseButton::RIGHT: glfwButton = GLFW_MOUSE_BUTTON_RIGHT; break; + case MouseButton::MIDDLE: glfwButton = GLFW_MOUSE_BUTTON_MIDDLE; break; + } + return glfwButton; +} diff --git a/engine/src/core/inputsOutputs/inputs/Mouse.h b/engine/src/core/inputsOutputs/inputs/Mouse.h index 84c513b..af2d28c 100644 --- a/engine/src/core/inputsOutputs/inputs/Mouse.h +++ b/engine/src/core/inputsOutputs/inputs/Mouse.h @@ -44,8 +44,7 @@ namespace engine { static void addScrollListener(Window& window); static void addClickListener(Window& window); - static int MouseButtonToInt(MouseButton button) { - } + static int MouseButtonToInt(MouseButton button); }; } diff --git a/engine/src/ui/ImGuiContext.cpp b/engine/src/ui/ImGuiContext.cpp new file mode 100644 index 0000000..570b03a --- /dev/null +++ b/engine/src/ui/ImGuiContext.cpp @@ -0,0 +1,36 @@ +// +// Created by sebastian on 02.08.26. +// + +#include "ImGuiContext.h" + +#include "imgui.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_opengl3.h" + +engine::ImGuiContext::ImGuiContext(Window &window) { + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGui::StyleColorsDark(); + ImGui::GetIO().IniFilename = nullptr; // keine imgui.ini neben der exe, optional + + ImGui_ImplGlfw_InitForOpenGL(window.getHandle(), /* install_callbacks = */ false); + ImGui_ImplOpenGL3_Init("#version 460"); +} + +engine::ImGuiContext::~ImGuiContext() { + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); +} + +void engine::ImGuiContext::beginFrame() const { + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); +} + +void engine::ImGuiContext::endFrame() const { + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} diff --git a/engine/src/ui/ImGuiContext.h b/engine/src/ui/ImGuiContext.h new file mode 100644 index 0000000..b1591f3 --- /dev/null +++ b/engine/src/ui/ImGuiContext.h @@ -0,0 +1,26 @@ +// +// Created by sebastian on 02.08.26. +// + +#ifndef COLORRACE_IMGUICONTEXT_H +#define COLORRACE_IMGUICONTEXT_H + + +#pragma once +#include "core/Window.h" + +namespace engine { + class ImGuiContext { + public: + explicit ImGuiContext(Window& window); + ~ImGuiContext(); + + ImGuiContext(const ImGuiContext&) = delete; + ImGuiContext& operator=(const ImGuiContext&) = delete; + + void beginFrame() const; + void endFrame() const; + }; +} + +#endif //COLORRACE_IMGUICONTEXT_H diff --git a/game/src/GameLayer.cpp b/game/src/GameLayer.cpp index c5e0b5d..0637f33 100644 --- a/game/src/GameLayer.cpp +++ b/game/src/GameLayer.cpp @@ -30,6 +30,29 @@ void GameLayer::onDetachImpl() { } +void GameLayer::renderHud() { + const auto& state = m_gameMode->getState(); + bool isMyTurn = m_gameMode->getCurrentPlayer() == m_localPlayer; + + ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver); + ImGui::Begin("Ludo", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize); + + ImGui::Text("Am Zug: %s", toString(m_gameMode->getColorOf(m_gameMode->getCurrentPlayer())).data()); + ImGui::Text("Wuerfel: %d", state.getDiceValue()); + + ImGui::BeginDisabled(!isMyTurn || state.getPhase() != ludo::TurnPhase::AwaitingRoll); + if (ImGui::Button("Wuerfeln")) { + m_gameMode->sendCommand(ludo::RollDiceCommand{m_localPlayer}); + } + + if (!m_lastEventMessage.empty()) ImGui::Text("%s", m_lastEventMessage.c_str()); + + ImGui::EndDisabled(); + + ImGui::End(); + +} + void GameLayer::onUpdate(float deltaTime) { Layer::onUpdate(deltaTime); m_cameraController->update(getKeyboard(), *m_camera, deltaTime); @@ -39,6 +62,9 @@ void GameLayer::onUpdate(float deltaTime) { if constexpr (std::is_same_v) { m_piecePresenter.onPieceMoved(e, m_gameMode->getState()); } + if constexpr (std::is_same_v) { + m_lastEventMessage = std::format("Wuerfel geworfen: {}", e.diceValue); + } // DiceRolledEvent/TurnChangedEvent -> ImGui-State aktualisieren }, event); } @@ -58,4 +84,6 @@ void GameLayer::onRender() { MeshRenderSystem meshRenderSystem; meshRenderSystem.update(m_entityRegistry, m_renderQueue); m_renderer->render(m_renderQueue, *m_camera, *m_pointLight); + + renderHud(); } diff --git a/game/src/GameLayer.h b/game/src/GameLayer.h index 90b4aef..e5ef097 100644 --- a/game/src/GameLayer.h +++ b/game/src/GameLayer.h @@ -44,6 +44,9 @@ private: engine::PlayerID m_localPlayer = 0; std::shared_ptr m_gameMode; engine::PickingSystem m_pickingSystem; + std::string m_lastEventMessage; + + void renderHud(); }; diff --git a/game/src/ludo/LudoGameMode.h b/game/src/ludo/LudoGameMode.h index 6373dae..7c4f598 100644 --- a/game/src/ludo/LudoGameMode.h +++ b/game/src/ludo/LudoGameMode.h @@ -21,6 +21,7 @@ namespace ludo { [[nodiscard]] const LudoGameState& getState() const override { return m_gameState; } + [[nodiscard]] PlayerColor getColorOf(engine::PlayerID playerID) const; private: struct MoveResult { int fromPosition; @@ -33,7 +34,7 @@ namespace ludo { void handle(const RollDiceCommand &command); - [[nodiscard]] PlayerColor getColorOf(engine::PlayerID playerID) const; + void handle(const MovePieceCommand &command); void finishTurn();