From 71f1b2c6d236d857ae588202bb16ad51e25af50d Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 22 Oct 2025 11:31:42 +0200 Subject: [PATCH] feat: event emitter --- engine/include/engine/api.h | 3 +- engine/include/engine/app/app.h | 2 +- engine/include/engine/renderer/core.h | 21 +++-- engine/include/engine/window/event.h | 81 ------------------- engine/include/engine/window/event.hpp | 74 +++++++++++++++++ .../engine/window/events/window_events.h | 2 +- engine/include/engine/window/window.h | 4 +- engine/src/renderer/core.cpp | 77 +++++++++++------- engine/src/window/window.cpp | 6 +- 9 files changed, 147 insertions(+), 123 deletions(-) delete mode 100644 engine/include/engine/window/event.h create mode 100644 engine/include/engine/window/event.hpp diff --git a/engine/include/engine/api.h b/engine/include/engine/api.h index c533939..7c5c372 100644 --- a/engine/include/engine/api.h +++ b/engine/include/engine/api.h @@ -12,6 +12,7 @@ extern IApplication* CreateApplication(); int main() { - Engine::Run(std::unique_ptr(CreateApplication())); + auto engine = Engine::GetInstance(); + engine->Run(std::unique_ptr(CreateApplication())); return 0; } \ No newline at end of file diff --git a/engine/include/engine/app/app.h b/engine/include/engine/app/app.h index 14c4fa4..90fb007 100644 --- a/engine/include/engine/app/app.h +++ b/engine/include/engine/app/app.h @@ -2,7 +2,7 @@ #define APPLICATION_H_ #include "engine/scene/scene.h" -#include "engine/window/event.h" +#include "engine/window/event.hpp" #include "engine/export.h" class ENGINE_API IApplication { diff --git a/engine/include/engine/renderer/core.h b/engine/include/engine/renderer/core.h index c9a6031..5871c63 100644 --- a/engine/include/engine/renderer/core.h +++ b/engine/include/engine/renderer/core.h @@ -13,15 +13,22 @@ #include "engine/app/app.h" #include "engine/export.h" -class ENGINE_API Engine { +class ENGINE_API Engine : public EventHandler { public: - static void Run(std::unique_ptr app); + static Engine* GetInstance(); + + void Run(std::unique_ptr app); private: - static std::unique_ptr s_app; - static std::shared_ptr s_window; - static std::unique_ptr s_renderer; - static std::shared_ptr s_scene; - static bool s_running; + Engine() {} + static Engine* s_instance; + + void OnEvent(const Event& event) override; +private: + std::unique_ptr m_app; + std::shared_ptr m_window; + std::unique_ptr m_renderer; + std::shared_ptr m_scene; + bool m_running; }; diff --git a/engine/include/engine/window/event.h b/engine/include/engine/window/event.h deleted file mode 100644 index c97cd10..0000000 --- a/engine/include/engine/window/event.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef EVENT_H_ -#define EVENT_H_ - -#include -#include -#include -#include -#include - -enum class EventType { - WINDOW_RESIZE, - WINDOW_CLOSE, -}; - -class Event { -public: - enum EventCategory { - WINDOW, - // KEYBOARD ... - }; - - Event(EventCategory category) : m_category(category) {} - virtual ~Event() {} - - Event(const Event& event) = default; - - inline const EventCategory GetCategory() const { return m_category; } - - inline const virtual EventType GetType() const = 0; -private: - EventCategory m_category; -}; - -class EventDispatcher { - using Type = std::type_index; - using RawFn = std::function; - - struct Slot { std::size_t id; RawFn fn; }; - - std::unordered_map> subs_; - std::size_t next_id_ = 1; - -public: - struct Handle { - std::type_index type{typeid(void)}; - std::size_t id{0}; - explicit operator bool() const { return id != 0; } - }; - - template - Handle Subscribe(F&& f) { - auto& vec = subs_[Type(typeid(E))]; - Handle h{ Type(typeid(E)), next_id_++ }; - // Wrap strongly typed callback into type-erased RawFn - RawFn wrapper = [fn = std::function(std::forward(f))](const void* p){ - fn(*static_cast(p)); - }; - vec.push_back(Slot{h.id, std::move(wrapper)}); - return h; - } - - // Unsubscribe with handle - void Unsubscribe(const Handle& h) { - auto it = subs_.find(h.type); - if (it == subs_.end()) return; - auto& vec = it->second; - vec.erase(std::remove_if(vec.begin(), vec.end(), - [&](const Slot& s){ return s.id == h.id; }), - vec.end()); - } - - // Publish immediately - template - void Dispatch(const E& e) const { - auto it = subs_.find(Type(typeid(E))); - if (it == subs_.end()) return; - for (auto& slot : it->second) slot.fn(&e); - } -}; - -#endif // EVENT_H_ \ No newline at end of file diff --git a/engine/include/engine/window/event.hpp b/engine/include/engine/window/event.hpp new file mode 100644 index 0000000..599e4fa --- /dev/null +++ b/engine/include/engine/window/event.hpp @@ -0,0 +1,74 @@ +#ifndef EVENT_H_ +#define EVENT_H_ + +#include +#include +#include +#include +#include + +enum class EventType { + WINDOW_RESIZE, + WINDOW_CLOSE, +}; + +class Event { +public: + enum EventCategory { + WINDOW, + // KEYBOARD ... + }; + + Event(EventCategory category) : m_category(category) {} + virtual ~Event() {} + + Event(const Event& event) = default; + + inline const EventCategory GetCategory() const { return m_category; } + + inline const virtual EventType GetType() const = 0; +private: + EventCategory m_category; +}; + +class EventHandler { +public: + EventHandler() = default; + + virtual void OnEvent(const Event& event) = 0; +}; + +class EventEmitter { +public: + struct Handle { + std::size_t id{0}; + explicit operator bool() const { return id != 0; } + }; + + EventEmitter() = default; + + Handle Subscribe2(EventHandler* handler) { + auto slot = Slot{ m_next_id++, handler }; + m_subs.push_back(slot); + return Handle{ slot.id }; + } + + void Unsubscribe2(const Handle& h) { + m_subs.erase(std::remove_if(m_subs.begin(), m_subs.end(), + [&](const Slot& s){ return s.id == h.id; }), + m_subs.end()); + } +protected: + void EmitEvent(const Event& event) { + for (auto &sub : m_subs) { + sub.handler->OnEvent(event); + } + } + +private: + struct Slot { std::size_t id; EventHandler* handler; }; + std::vector m_subs; + std::size_t m_next_id = 1; +}; + +#endif // EVENT_H_ \ No newline at end of file diff --git a/engine/include/engine/window/events/window_events.h b/engine/include/engine/window/events/window_events.h index 6dee04c..7391f20 100644 --- a/engine/include/engine/window/events/window_events.h +++ b/engine/include/engine/window/events/window_events.h @@ -1,7 +1,7 @@ #ifndef WINDOW_EVENTS_H_ #define WINDOW_EVENTS_H_ -#include "engine/window/event.h" +#include "engine/window/event.hpp" class WindowEvent : public Event { public: diff --git a/engine/include/engine/window/window.h b/engine/include/engine/window/window.h index 282946c..179d024 100644 --- a/engine/include/engine/window/window.h +++ b/engine/include/engine/window/window.h @@ -3,7 +3,7 @@ #include #include -#include "engine/window/event.h" +#include "engine/window/event.hpp" #define ENGINE_GL_MAJOR_VERSION 4 #define ENGINE_GL_MINOR_VERSION 6 @@ -13,7 +13,7 @@ #define DEFAULT_WIDTH 1024 #define DEFAULT_HEIGHT 768 -class Window : public EventDispatcher { +class Window : public EventEmitter { friend class Engine; private: Window(); diff --git a/engine/src/renderer/core.cpp b/engine/src/renderer/core.cpp index a07e4cd..8be0b26 100644 --- a/engine/src/renderer/core.cpp +++ b/engine/src/renderer/core.cpp @@ -2,48 +2,67 @@ #include "engine/renderer/core.h" -#include "engine/window/event.h" +#include "engine/window/event.hpp" #include "engine/renderer/wavefront.h" -std::unique_ptr Engine::s_app = nullptr; -std::shared_ptr Engine::s_window = nullptr; -std::unique_ptr Engine::s_renderer = nullptr; -std::shared_ptr Engine::s_scene = nullptr; -bool Engine::s_running = false; +Engine* Engine::s_instance = nullptr; void Engine::Run(std::unique_ptr app) { - s_scene = std::make_shared(); - s_renderer = std::make_unique(s_scene); - s_window = Window::GetInstance(); - s_app = std::move(app); - s_running = true; + m_scene = std::make_shared(); + m_renderer = std::make_unique(m_scene); + m_window = Window::GetInstance(); + m_app = std::move(app); + m_running = true; - s_app->OnInit(s_scene); - s_renderer->Init(); + m_app->OnInit(m_scene); + m_renderer->Init(); - s_window->Subscribe([&](const WindowCloseEvent& e) { - s_running = false; - s_app->OnEvent(e); - }); + // m_window->Subscribe([&](const WindowCloseEvent& e) { + + // m_app->OnEvent(e); + // }); - s_window->Subscribe([&](const WindowResizeEvent& e) { - s_renderer->OnWindowResized(e.GetWidth(), e.GetHeight()); - s_app->OnEvent(e); - }); + // m_window->Subscribe([&](const WindowResizeEvent& e) { + // m_renderer->OnWindowResized(e.GetWidth(), e.GetHeight()); + // m_app->OnEvent(e); + // }); - while (s_running) { - s_window->ProcessEvents(); + m_window->Subscribe2(this); - s_app->OnUpdate(); + while (m_running) { + m_window->ProcessEvents(); - s_renderer->Render(); + m_app->OnUpdate(); - s_window->SwapBuffers(); + m_renderer->Render(); + + m_window->SwapBuffers(); } - s_app->OnShutdown(); + m_app->OnShutdown(); - s_window->Destroy(); - s_app.reset(); + m_window->Destroy(); + m_app.reset(); +} + +void Engine::OnEvent(const Event& event) { + m_app->OnEvent(event); + if (event.GetCategory() == Event::EventCategory::WINDOW) { + if (event.GetType() == EventType::WINDOW_RESIZE) { + auto e = static_cast(event); + m_renderer->OnWindowResized(e.GetWidth(), e.GetHeight()); + } + if (event.GetType() == EventType::WINDOW_CLOSE) { + m_running = false; + } + } +} + +Engine* Engine::GetInstance() { + if (!s_instance) { + s_instance = new Engine(); + } + + return s_instance; } diff --git a/engine/src/window/window.cpp b/engine/src/window/window.cpp index d726778..beb2226 100644 --- a/engine/src/window/window.cpp +++ b/engine/src/window/window.cpp @@ -101,10 +101,12 @@ void Window::ProcessEvents() { case SDL_EVENT_WINDOW_CLOSE_REQUESTED: case SDL_EVENT_QUIT: Dispatch(WindowCloseEvent()); + EmitEvent(WindowCloseEvent{}); break; case SDL_EVENT_KEY_DOWN: if (event.key.scancode == SDL_SCANCODE_ESCAPE) { Dispatch(WindowCloseEvent()); + EmitEvent(WindowCloseEvent{}); } if (event.key.scancode == SDL_SCANCODE_F11) { bool isFullscreen = SDL_GetWindowFlags(m_handle) & SDL_WINDOW_FULLSCREEN; @@ -122,7 +124,9 @@ void Window::ProcessEvents() { 0, width, height); - Dispatch(WindowResizeEvent(static_cast(m_width), static_cast(m_height))); + auto event = WindowResizeEvent(static_cast(m_width), static_cast(m_height)); + Dispatch(event); + EmitEvent(event); SDL_SetWindowRelativeMouseMode(m_handle, true); SDL_Rect boundaries = {0, 0, m_width, m_height}; SDL_SetWindowMouseRect(m_handle, &boundaries);