add event system

This commit is contained in:
ouczbs 2024-12-13 11:32:34 +08:00
parent 0166774b26
commit 38cbff3c55
17 changed files with 276 additions and 24 deletions

View File

@ -1,4 +1,6 @@
#include "app.h"
#include "data/global.h" #include "data/global.h"
namespace api { namespace api {
APP_API EngineConfig gEngineConfig{}; APP_API EngineConfig gEngineConfig{};
IMPLEMENT_STATIC_MODULE(APP_API, AppModule, app)
} }

View File

@ -0,0 +1,17 @@
#include "event/event_system.h"
namespace api {
SINGLETON_DEFINE(EventSystem)
inline EventSystem::EventSystem()
{
SINGLETON_PTR();
}
inline void EventSystem::Initialize()
{
}
inline void EventSystem::Finalize()
{
}
}

View File

@ -1,6 +1,14 @@
#pragma once #pragma once
#include "module/module.h"
#include "data/engine_config.h" #include "data/engine_config.h"
namespace api{ namespace api{
class APP_API AppModule : public IStaticModule
{
public:
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
void InitMetaData(void) override {};
};
template<typename T> template<typename T>
class AppImpl; class AppImpl;
class App { class App {

View File

@ -1,3 +1,4 @@
#pragma once
#include "engine_config.h" #include "engine_config.h"
#include "project_config.h" #include "project_config.h"
namespace api { namespace api {

View File

@ -0,0 +1,187 @@
#pragma once
#include "pmr/name.h"
#include <functional>
#include <unordered_map>
namespace api{
using pmr::Name;
//* Utility functions to create std::functions without std::placeholder
template <class>
class Event;
/**
* @brief Event that can call all of its subscribers
*
* @tparam R Return type
* @tparam Args Function arguments
*/
template <class R, class... Args>
class Event<R(Args...)> {
private:
using Delegate = std::function<R(Args...)>;
using FuncMap = std::unordered_map<Name, Delegate>;
std::unordered_map<void*, FuncMap> listeners;
//std::unordered_map<const void*, FuncMap> constListeners;
template<typename Type>
static consteval auto add_const(R(Type::* ptr)(Args...)) {
using MethodType = R(Type::*)(Args...)const;
return (MethodType)ptr;
}
template<class Type>
static std::function<R(Args...)> EasyBind(R(Type::* func)(Args... args) const, const Type* invoker) {
return [=](auto&&... args) {
return (invoker->*func)(std::forward<decltype(args)>(args)...);
};
}
public:
Event() = default;
/**
* @brief Subscribes a member function to the event.
*
* @tparam Invoker The instance type to call the member function
* @tparam Type The type containing the member function
* @param id Unique identifier of the subscribing function
* @param func The function to call when the event is raised
* @param invoker The instance owning the member function
*/
template <class Invoker, class Type>
void Subscribe(const Name& id, R(Type::*func)(Args... args),const Invoker* invoker) {
Subscribe<Invoker, Type>(id, add_const(func), invoker);
}
/**
* @brief Subscribes a const member function to the event.
*
* @tparam Invoker The instance type to call the member function
* @tparam Type The type containing the member function
* @param id Unique identifier of the subscribing function
* @param func The const function to call when the event is raised
* @param invoker The instance owning the member function
*/
template <class Invoker, class Type>
void Subscribe(const Name& id, R (Type::*func)(Args... args) const, const Invoker* invoker) {
Delegate deleg{ std::move(EasyBind(func, invoker)) };
auto found{ listeners.find(invoker) };
if (found != listeners.end()) {
auto iter{ found->second.find(id) };
if (iter != found->second.end()) {
iter->second = std::move(deleg);
}
else {
found->second.emplace(id, std::move(deleg));
}
}
else {
listeners.emplace(invoker, FuncMap{ {id, {std::move(deleg)}} });
}
}
/**
* @brief Subscribes a free function or a std::function reference to the event
*
* @param id Unique identifier of the subscribing function
* @param func The function to call when the event is raised
*/
void Subscribe(const Name& id,const std::function<R(Args...)>& func) {
auto found{listeners.find(nullptr)};
if (found != listeners.end()) {
auto iter{found->second.find(id)};
if (iter != found->second.end()) {
iter->second = func;
}
else {
found->second.emplace(id, func);
}
} else {
listeners.emplace(nullptr, FuncMap{{id, {func}}});
}
}
/**
* @brief Unsubscribes a member function from an event
*
* @tparam Invoker
* @param id Unique identifier of the subscribed function
* @param invoker The instance owning the member function
*/
template <class Invoker>
void Unsubscribe(const Name& id,const Invoker* invoker) {
auto found {listeners.find(invoker)};
if (found != listeners.end()) {
auto iter {found->second.find(id)};
if (iter != found->second.end()) {
found->second.erase(iter);
}
if (found->second.empty()) {
listeners.erase(found);
}
}
}
/**
* @brief Unsubscribes a free function/lambda from an event
*
* @param id Unique identifier of the subscribed function/lambda
*/
void Unsubscribe(const Name& id) {
auto found{listeners.find(nullptr)};
if (found != listeners.end()) {
auto iter{found->second.find(id)};
if (iter != found->second.end()) {
found->second.erase(iter);
}
if (found->second.empty()) {
listeners.erase(found);
}
}
}
/**
* @brief Unsubscribes all functions owned by the invoker const instance from this event
*
* @param invoker Const instance subscribed to this event
*/
template <class Invoker>
void RemoveListener(const Invoker* invoker) {
auto found{ listeners.find(invoker)};
if (found != listeners.end()) {
listeners.erase(found);
}
}
/**
* @brief Unsubscribes all free functions/lambdas from this event
*/
void RemoveFreeFunctions() {
auto found{listeners.find(nullptr)};
if (found != listeners.end()) {
listeners.erase(found);
}
}
// TODO: Check if args should be lvalues or not.
/**
* @brief Calls all subscribed functions
*
* @param args
*/
void Invoke(Args... args) {
for (auto& listener : listeners) {
for (auto& func : listener.second) {
func.second(std::forward<decltype(args)>(args)...);
}
}
}
/**
* @brief Calls all subscribed functions (this is equivalent to Invoke())
*
* @param args
*/
void operator()(Args... args) {
Invoke(std::forward<decltype(args)>(args)...);
}
};
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "event.h"
#include "module/module.h"
namespace api {
class APP_API EventSystem : public ISystem{
SINGLETON_IMPL(EventSystem)
public:
EventSystem();
void Initialize() override;
void Finalize() override;
Event<void()> BeginRenderFrame;
};
}

View File

@ -1,4 +1,13 @@
#include "data/engine_config.h" #include "data/engine_config.h"
#include "event/event_system.h"
#include "app.h"
namespace api { namespace api {
void AppModule::OnLoad(int argc, char** argv)
{
AddSystem<EventSystem>();
}
void AppModule::OnUnload()
{
}
} }

View File

@ -1,3 +1,4 @@
#pragma once
#include "package_path.h" #include "package_path.h"
#include <vector> #include <vector>
#include <fstream> #include <fstream>

View File

@ -6,10 +6,12 @@
#include "vkn/thread/command_worker.h" #include "vkn/thread/command_worker.h"
#include "vkn/loader/vulkan_glsl_loader.h" #include "vkn/loader/vulkan_glsl_loader.h"
#include "render/asset/mesh.h" #include "render/asset/mesh.h"
#include "event/event_system.h"
#include "meta/enum.h" #include "meta/enum.h"
#include "tinyimageformat/tinyimageformat_apis.h" #include "tinyimageformat/tinyimageformat_apis.h"
#include "zlog.h" #include "zlog.h"
namespace vkn { namespace vkn {
using api::EventSystem;
inline bool operator==(const FramebufferKey& k1, const FramebufferKey& k2) { inline bool operator==(const FramebufferKey& k1, const FramebufferKey& k2) {
if (k1.pass != k2.pass) return false; if (k1.pass != k2.pass) return false;
if (k1.attachmentCount != k2.attachmentCount) return false; if (k1.attachmentCount != k2.attachmentCount) return false;
@ -344,6 +346,7 @@ namespace vkn {
window.Aquire(ctx); window.Aquire(ctx);
ctx.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); ctx.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
graph.mSurface = ctx.surface; graph.mSurface = ctx.surface;
EventSystem::Ptr()->BeginRenderFrame.Invoke();
} }
void VulkanAPI::EndFrame() void VulkanAPI::EndFrame()
{ {

View File

@ -1,5 +1,4 @@
#include "engine/api.h" #include "engine/api.h"
#include "app_impl.inl"
#include "os/file_manager.h" #include "os/file_manager.h"
#include "xmalloc_new_delete.h" #include "xmalloc_new_delete.h"
class ENGINE_API EngineModule : public api::IDynamicModule class ENGINE_API EngineModule : public api::IDynamicModule
@ -14,6 +13,7 @@ public:
}; };
void InitMetaData(void) override { void InitMetaData(void) override {
mInfo.dependencies = { mInfo.dependencies = {
{"app","1.0.1", "static"},
{"core", "1.0.1", "static" }, {"core", "1.0.1", "static" },
{"asset", "1.0.1", "static" }, {"asset", "1.0.1", "static" },
{"render", "1.0.1", "static" }, {"render", "1.0.1", "static" },

View File

@ -1,5 +0,0 @@
#ifndef ASSET_API_VAL
#define ASSET_API_VAL 1
#include "resource_system_impl.inl"
#include "asset_visit_impl.inl"
#endif // !ASSET_API_VAL

View File

@ -1,6 +0,0 @@
#ifndef CORE_API_VAL
#define CORE_API_VAL 1
#include "zlog.h"
#include "module_manager_impl.inl"
#include "file_manager_impl.inl"
#endif // !CORE_API_VAL

View File

@ -0,0 +1,30 @@
#ifndef ZLIB_API_VAL
#define ZLIB_API_VAL 1
#include "pmr/name.h"
#include "pmr/frame_allocator.h"
#endif // !ZLIB_API_VAL
#ifndef CORE_API_VAL
#define CORE_API_VAL 1
#include "zlog.h"
#include "module_manager_impl.inl"
#include "file_manager_impl.inl"
#endif // !CORE_API_VAL
#ifndef ASSET_API_VAL
#define ASSET_API_VAL 1
#include "resource_system_impl.inl"
#include "asset_visit_impl.inl"
#endif // !ASSET_API_VAL
#ifndef RENDER_API_VAL
#define RENDER_API_VAL 1
#include "renderapi_impl.inl"
#include "window_impl.inl"
#endif // !RENDER_API_VAL
#ifndef APP_API_VAL
#define APP_API_VAL 1
#include "app_impl.inl"
#include "event_system_impl.inl"
#endif // !APP_API_VAL

View File

@ -1,5 +0,0 @@
#ifndef RENDER_API_VAL
#define RENDER_API_VAL 1
#include "renderapi_impl.inl"
#include "window_impl.inl"
#endif // !RENDER_API_VAL

View File

@ -1,6 +0,0 @@
#ifndef ZLIB_API_VAL
#define ZLIB_API_VAL 1
#include "pmr/name.h"
#include "pmr/frame_allocator.h"
#include "refl/detail/uclass.inl"
#endif // !ZLIB_API_VAL

View File

@ -1,6 +1,7 @@
#include "zlog.h" #include "zlog.h"
#include "zworld.h" #include "zworld.h"
#include "data/global.h" #include "data/global.h"
#include "event/event_system.h"
#include "vkn/vulkan_window.h" #include "vkn/vulkan_window.h"
#include "vkn/vulkan_api.h" #include "vkn/vulkan_api.h"
#ifdef WITH_EDITOR #ifdef WITH_EDITOR
@ -26,6 +27,9 @@ void ZWorldModule::OnLoad(int argc, char** argv)
#ifdef WITH_EDITOR //绑定窗口交互 #ifdef WITH_EDITOR //绑定窗口交互
ImGui_ImplSDL2_InitForVulkan(window->GetPtr()); ImGui_ImplSDL2_InitForVulkan(window->GetPtr());
#endif #endif
EventSystem::Ptr()->BeginRenderFrame.Subscribe("zworld", []() {
API->graph.AddRenderPass<DemoPass>();
});
} }
void ZWorldModule::Initialize() void ZWorldModule::Initialize()
{ {
@ -46,7 +50,6 @@ void ZWorldModule::MainLoop()
} }
} }
API->BeginFrame(); API->BeginFrame();
API->graph.AddRenderPass<DemoPass>();
API->Render(); API->Render();
API->EndFrame(); API->EndFrame();
FramePool()->reset(); FramePool()->reset();