summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2023-12-21 17:44:03 -0500
committerJonathan Bradley <jcb@pikum.xyz>2023-12-23 11:42:23 -0500
commitfa7fc343a0e444da72938fad58d219cf52228976 (patch)
tree24630be0c54f9768a13f32c5970558768e343543 /src
parent6fa3b137c74536d2bab77f3309ca5b4c60953fe0 (diff)
plugin checkpoint - multiple plugins and collision callbacks
Diffstat (limited to 'src')
-rw-r--r--src/components.hpp3
-rw-r--r--src/ecs.cpp51
-rw-r--r--src/ecs.hpp2
-rw-r--r--src/game.cpp39
-rw-r--r--src/physics.cpp32
-rw-r--r--src/plugins.cpp74
-rw-r--r--src/plugins.hpp22
-rw-r--r--src/project.cpp19
-rw-r--r--src/window.cpp18
9 files changed, 218 insertions, 42 deletions
diff --git a/src/components.hpp b/src/components.hpp
index e99481e..86c5727 100644
--- a/src/components.hpp
+++ b/src/components.hpp
@@ -4,6 +4,7 @@
#include "dynamic-array.hpp"
#include "macros.hpp"
#include "physics.hpp"
+#include "plugins.hpp"
#include <BulletDynamics/Dynamics/btRigidBody.h>
#include <LinearMath/btDefaultMotionState.h>
@@ -65,6 +66,7 @@ struct CompGrBinds {
uint32_t instanceCounter = 0;
uint32_t instanceBufferMaxCount = 0;
VkDeviceSize instanceOffsets = 0;
+ PkeCallback collisionCallback{};
};
struct InstPos {
@@ -84,6 +86,7 @@ struct CompInstance {
PhysicsCollision physicsLayer = PhysicsCollision{1};
PhysicsCollision physicsMask = PhysicsCollision{1};
InstBt bt;
+ PkeCallback collisionCallback{};
bool isNeedingUpdated = false;
};
diff --git a/src/ecs.cpp b/src/ecs.cpp
index 4580abe..c33caaa 100644
--- a/src/ecs.cpp
+++ b/src/ecs.cpp
@@ -327,6 +327,57 @@ void ECS_Tick_Late(double delta) {
}
}
+void FindComponents(EntityHandle handle, Entity *&ent, CompInstance *&compInst, CompGrBinds *&grBinds) {
+ ECS_GetEntity_Inner(handle, ent);
+ if (ent == nullptr)
+ return;
+ GrBindsHandle grBindsHandle = ent->grBindsHandle;
+ if (ent->instanceHandle != InstanceHandle_MAX) {
+ compInst = &Comp_Instance_BucketContainer.buckets[ent->instanceHandle.bucketIndex].instances[ent->instanceHandle.itemIndex];
+ if (grBindsHandle == GrBindsHandle_MAX)
+ grBindsHandle = compInst->grBindsHandle;
+ }
+ if (grBindsHandle != GrBindsHandle_MAX) {
+ grBinds = &Comp_GrBinds_BucketContainer.buckets[grBindsHandle.bucketIndex].compGrBinds[grBindsHandle.itemIndex];
+ }
+}
+
+void ECS_HandleCollision(EntityHandle lhs, EntityHandle rhs) {
+ Entity *lhsEnt = nullptr;
+ CompInstance *lhsInst = nullptr;
+ CompGrBinds *lhsGrBinds = nullptr;
+ FindComponents(lhs, lhsEnt, lhsInst, lhsGrBinds);
+
+ Entity *rhsEnt = nullptr;
+ CompInstance *rhsInst = nullptr;
+ CompGrBinds *rhsGrBinds = nullptr;
+ FindComponents(rhs, rhsEnt, rhsInst, rhsGrBinds);
+
+ void (*lhsColFunc)(EntityHandle, EntityHandle) = nullptr;
+ void (*rhsColFunc)(EntityHandle, EntityHandle) = nullptr;
+
+ if (lhsInst && lhsInst->collisionCallback.func != nullptr) {
+ lhsColFunc = reinterpret_cast<void (*)(EntityHandle, EntityHandle)>(lhsInst->collisionCallback.func);
+ }
+ if (lhsColFunc == nullptr && lhsGrBinds && lhsGrBinds->collisionCallback.func) {
+ lhsColFunc = reinterpret_cast<void (*)(EntityHandle, EntityHandle)>(lhsGrBinds->collisionCallback.func);
+ }
+
+ if (rhsInst && rhsInst->collisionCallback.func != nullptr) {
+ rhsColFunc = reinterpret_cast<void (*)(EntityHandle, EntityHandle)>(rhsInst->collisionCallback.func);
+ }
+ if (rhsColFunc == nullptr && rhsGrBinds && rhsGrBinds->collisionCallback.func) {
+ rhsColFunc = reinterpret_cast<void (*)(EntityHandle, EntityHandle)>(rhsGrBinds->collisionCallback.func);
+ }
+
+ if (lhsColFunc) {
+ lhsColFunc(lhs, rhs);
+ }
+ if (rhsColFunc) {
+ rhsColFunc(lhs, rhs);
+ }
+}
+
CompGrBinds &ECS_CreateGrBinds(EntityHandle entHandle) {
assert(entHandle != EntityHandle_MAX);
diff --git a/src/ecs.hpp b/src/ecs.hpp
index 7ac08e2..4deacaf 100644
--- a/src/ecs.hpp
+++ b/src/ecs.hpp
@@ -27,6 +27,8 @@ void ECS_MarkForRemoval(EntityHandle entHandle);
uint64_t ECS_GetEntities_BucketCount();
Entity *ECS_GetEntities(uint64_t bucketIndex, uint64_t &itemCount);
+void ECS_HandleCollision(EntityHandle lhs, EntityHandle rhs);
+
CompGrBinds &ECS_CreateGrBinds(EntityHandle entHandle);
CompGrBinds *ECS_GetGrBinds(EntityHandle entHandle);
CompGrBinds *ECS_GetGrBinds(GrBindsHandle grBindsHandle);
diff --git a/src/game.cpp b/src/game.cpp
index 20e67a0..5df32a0 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -47,6 +47,7 @@ const char *PKE_FILE_INSTANCE_POS_SCALE = "InstPos::Scale: ";
const char *PKE_FILE_INSTANCE_PHYSICS_MASS = "InstPos::Mass: ";
const char *PKE_FILE_INSTANCE_PHYSICS_COLLISION_LAYER = "InstPos::CollisionLayer: ";
const char *PKE_FILE_INSTANCE_PHYSICS_COLLISION_MASK = "InstPos::CollisionMask: ";
+const char *PKE_FILE_INSTANCE_COLLISION_CALLBACK_SIGNATURE = "Inst::CollisionCallbackSignature: ";
const char *PKE_FILE_CAMERA_POS = "Cam::Pos: ";
const char *PKE_FILE_CAMERA_ROT = "Cam::Rot: ";
@@ -141,6 +142,9 @@ void SerializeInstance(std::ofstream &stream, const CompInstance &comp) {
if (collisionMask != c.physicsMask) {
stream << PKE_FILE_INSTANCE_PHYSICS_COLLISION_MASK << static_cast<PhysicsCollision_T>(collisionMask) << std::endl;
}
+ if (comp.collisionCallback.name[0] != '\0') {
+ stream << PKE_FILE_INSTANCE_COLLISION_CALLBACK_SIGNATURE << comp.collisionCallback.name << std::endl;
+ }
}
void ParseCamera(LevelHandle levelHandle, std::ifstream &stream) {
@@ -238,6 +242,7 @@ void ParseInstance(EntityHandle parentEntHandle, std::ifstream &stream) {
instPos.posRot.setIdentity();
instPos.scale = btVector3(1, 1, 1);
instPos.mass = 1.f;
+ comp.collisionCallback.name[0] = '\0';
char entTypeCode[21];
memset(reinterpret_cast<void *>(entTypeCode), '\0', 21);
while (stream.getline(readLine, readLineLength)) {
@@ -255,6 +260,9 @@ void ParseInstance(EntityHandle parentEntHandle, std::ifstream &stream) {
auto entityHandle = ECS_CreateEntity(parentEntHandle);
auto &compInst = ECS_CreateInstance(entityHandle, et.entityHandle);
+ strncpy(compInst.collisionCallback.name, comp.collisionCallback.name, 16);
+ PkePlugin_SetSignatureFunc(&compInst.collisionCallback);
+
compInst.physicsLayer = comp.physicsLayer;
compInst.physicsMask = comp.physicsMask;
btVector3 localInertia(0, 0, 0);
@@ -356,6 +364,11 @@ void ParseInstance(EntityHandle parentEntHandle, std::ifstream &stream) {
assert(result == STR2NUM_ERROR::SUCCESS);
continue;
}
+ if (strstr(readLine, PKE_FILE_INSTANCE_COLLISION_CALLBACK_SIGNATURE)) {
+ uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_COLLISION_CALLBACK_SIGNATURE);
+ strncpy(comp.collisionCallback.name, readLine + prefixLen, 16);
+ continue;
+ }
}
}
@@ -496,9 +509,11 @@ void Game_Tick(double delta) {
ECS_Tick(delta);
PkeInput_Tick(delta);
- // TODO invoke external ticks here
- if (pkePlugin.OnTick) {
- pkePlugin.OnTick(delta);
+ const auto pluginCount = LoadedPkePlugins.Count();
+ for (long i = 0; i < pluginCount; ++i) {
+ if (LoadedPkePlugins[i].OnTick != nullptr) {
+ LoadedPkePlugins[i].OnTick(delta);
+ }
}
EntityType_Tick_Late(delta);
@@ -517,11 +532,14 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) {
CreateWindow(windowProps);
PkeInput_Init();
EntityType_Init();
- if (pkeSettings.args.pluginPath) {
- Pke_LoadPlugin(pkeSettings.args.pluginPath);
+ if (pkeSettings.args.pluginPath != nullptr) {
+ PkePlugin_Load(pkeSettings.args.pluginPath);
}
- if (pkePlugin.OnInit) {
- pkePlugin.OnInit();
+ const long pluginCount = LoadedPkePlugins.Count();
+ for (long i = 0; i < pluginCount; ++i) {
+ if (LoadedPkePlugins[i].OnInit != nullptr) {
+ LoadedPkePlugins[i].OnInit();
+ }
}
PkeProject_Load(pkeSettings.args.projectPath);
@@ -612,8 +630,11 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) {
#ifndef NDEBUG
Pke_DebugPrint();
#endif
- if (pkePlugin.OnTeardown) {
- pkePlugin.OnTeardown();
+ const auto pluginCount = LoadedPkePlugins.Count();
+ for (long i = 0; i < pluginCount; ++i) {
+ if (LoadedPkePlugins[i].OnTeardown) {
+ LoadedPkePlugins[i].OnTeardown();
+ }
}
Game_Teardown();
Event_Teardown();
diff --git a/src/physics.cpp b/src/physics.cpp
index e960059..4825955 100644
--- a/src/physics.cpp
+++ b/src/physics.cpp
@@ -3,6 +3,7 @@
#include "components.hpp"
#include "dynamic-array.hpp"
+#include "ecs.hpp"
#include "game-settings.hpp"
#include <LinearMath/btAlignedAllocator.h>
@@ -26,6 +27,11 @@ btCollisionDispatcher *btDispatcher = nullptr;
btBroadphaseInterface *btBroadphase = nullptr;
btConstraintSolver *btSolver = nullptr;
+struct EntityCollision {
+ EntityHandle a, b;
+};
+PkeArray<EntityCollision> collisionsThisTick{};
+
void *pke_btAlignedAllocFunc(size_t size, int alignment) {
void *ptr = Pke_New(size, alignment, MemBkt_Bullet);
bulletAllocs->Push({ptr, size});
@@ -68,8 +74,25 @@ void pke_btFreeFunc(void *memBlock) {
struct CollisionHandlerStruct : public btOverlapFilterCallback {
~CollisionHandlerStruct() override {}
bool needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const override {
- return (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) ||
+ auto collided = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) |
(proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
+ if (collided) {
+ const auto *col0 = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ const auto *col1 = static_cast<btCollisionObject *>(proxy1->m_clientObject);
+ if (col0 && col1) {
+ EntityHandle ent0{};
+ ent0.hash = reinterpret_cast<uint64_t>(col0->getUserPointer());
+ EntityHandle ent1{};
+ ent1.hash = reinterpret_cast<uint64_t>(col1->getUserPointer());
+ if (ent0 != EntityHandle_MAX && ent1 != EntityHandle_MAX) {
+ PkeArray_Add<EntityCollision>(&collisionsThisTick, {
+ .a = ent0,
+ .b = ent1,
+ });
+ }
+ }
+ }
+ return collided;
}
} collisionHandlerStruct;
@@ -102,7 +125,12 @@ void Physics_Init() {
int32_t Physics_Tick(double delta) {
if (pkeSettings.isSimulationPaused == true)
return 0;
- return BtDynamicsWorld->stepSimulation(delta, 1);
+ PkeArray_SoftReset(&collisionsThisTick);
+ auto tickCount = BtDynamicsWorld->stepSimulation(delta, 1);
+ for (long i = 0; i < collisionsThisTick.next; ++i) {
+ ECS_HandleCollision(collisionsThisTick.data[i].a, collisionsThisTick.data[i].b);
+ }
+ return tickCount;
}
void Physics_Teardown() {
diff --git a/src/plugins.cpp b/src/plugins.cpp
index bfd2e9b..5b0b817 100644
--- a/src/plugins.cpp
+++ b/src/plugins.cpp
@@ -1,22 +1,24 @@
-#include "macros.hpp"
#include "plugins.hpp"
-#include <cstdio>
-#include <dlfcn.h>
+#include "array.hpp"
+#include "macros.hpp"
-PKEPluginInterface pkePlugin{};
+#include <cassert>
+#include <cstdio>
+#include <cstring>
-void *loadedPlugin = nullptr;
+#ifdef WIN32
+ // TODO
+#else
+ #include <dlfcn.h>
+#endif
-void Pke_UpdatePlugin(const PKEPluginInterface &plugin) {
- pkePlugin.OnInit = plugin.OnInit;
- pkePlugin.OnTick = plugin.OnTick;
- pkePlugin.OnTeardown = plugin.OnTeardown;
- pkePlugin.OnImGuiRender = plugin.OnImGuiRender;
-}
+DynArray<PKEPluginInterface> LoadedPkePlugins;
+PkeArray<PkeCallback> pkePluginCallbacks;
+PkeArray<CallbackSignature> sortedSignatures;
-void Pke_LoadPlugin(const char *path) {
+void PkePlugin_Load(const char *path) {
if (path == nullptr || path == CAFE_BABE(void)) {
return;
}
@@ -33,19 +35,43 @@ void Pke_LoadPlugin(const char *path) {
dlclose(extension);
return;
}
- Pke_UpdatePlugin(*interface);
- loadedPlugin = interface;
+ interface->pluginHandle = extension;
+ LoadedPkePlugins.Push(*interface);
+}
+
+PkeCallback *PkePlugin_FindSignature(const CallbackSignature &sig) {
+ for (long i = 0; i < pkePluginCallbacks.next; ++i) {
+ if (strncmp(sig, pkePluginCallbacks.data[i].name, 16) == 0) {
+ return &pkePluginCallbacks.data[i];
+ }
+ }
+ return nullptr;
}
-void Pke_UnloadPlugin() {
- pkePlugin = {
- .OnInit = nullptr,
- .OnTick= nullptr,
- .OnTeardown= nullptr,
- .OnImGuiRender= nullptr,
- };
- if (loadedPlugin != nullptr && loadedPlugin != CAFE_BABE(void)) {
- dlclose(loadedPlugin);
- loadedPlugin = CAFE_BABE(void);
+void PkePlugin_SetSignatureFunc(PkeCallback *sig) {
+ assert(sig != nullptr);
+ if (sig->name[0] == '\0') {
+ return;
+ }
+ auto *registeredSig = PkePlugin_FindSignature(sig->name);
+ if (registeredSig == nullptr) {
+ fprintf(stdout, "[WARN] [PkePlugin_SetSignatureFunc] Failed to find configured signature: '%s'\n", sig->name);
+ return;
+ }
+ sig->func = registeredSig->func;
+}
+
+int pstrncmp(const void* a, const void* b)
+{
+ return strncmp(static_cast<const CallbackSignature *>(a)[0], static_cast<const CallbackSignature *>(b)[0], 16);
+}
+CallbackSignature *PkePlugin_GetSortedSignatures(long &count) {
+ if (sortedSignatures.next != pkePluginCallbacks.next) {
+ while (sortedSignatures.next != pkePluginCallbacks.next) {
+ PkeArray_Add(&sortedSignatures, pkePluginCallbacks.data[sortedSignatures.next].name);
+ }
+ qsort(sortedSignatures.data, sortedSignatures.next, sizeof(CallbackSignature), pstrncmp);
}
+ count = sortedSignatures.next;
+ return sortedSignatures.data;
}
diff --git a/src/plugins.hpp b/src/plugins.hpp
index 2f34c12..64c19f0 100644
--- a/src/plugins.hpp
+++ b/src/plugins.hpp
@@ -1,16 +1,32 @@
#ifndef PKE_PLUGINS_HPP
#define PKE_PLUGINS_HPP
+#include "array.hpp"
+#include "dynamic-array.hpp"
+
struct PKEPluginInterface {
+ // for internal use only
+ void *pluginHandle = nullptr;
void (*OnInit)() = nullptr;
void (*OnTick)(double delta) = nullptr;
void (*OnTeardown)() = nullptr;
void (*OnImGuiRender)() = nullptr;
};
-extern PKEPluginInterface pkePlugin;
+using CallbackSignature = char[16];
+struct PkeCallback {
+ // the 16 char signature(name) of a function
+ CallbackSignature name = {'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
+ // the address of the function to call - populated on startup
+ void *func = nullptr;
+};
+
+extern DynArray<PKEPluginInterface> LoadedPkePlugins;
+extern PkeArray<PkeCallback> pkePluginCallbacks;
-void Pke_LoadPlugin(const char *path);
-void Pke_UnloadPlugin();
+void PkePlugin_Load(const char *path);
+PkeCallback *PkePlugin_FindSignature(const CallbackSignature &sig);
+void PkePlugin_SetSignatureFunc(PkeCallback *sig);
+CallbackSignature *PkePlugin_GetSortedSignatures(long &count);
#endif /* PKE_PLUGINS_HPP */
diff --git a/src/project.cpp b/src/project.cpp
index e5b5583..08c7c2a 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -27,6 +27,7 @@ const char* const PKE_PROJ_FILE_ENTITY_TYPE_MODELS_DIR = "ModelsDir: ";
const char* const PKE_PROJ_FILE_ENTITY_TYPE_MODEL_FILE = "ModelFile: ";
const char* const PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_TYPE_CODE = "EntityTypeCode: ";
const char* const PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE = "EntityHandle: ";
+const char* const PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE = "CollisionCallbackSignature: ";
const char* const PKE_PROJ_FILE_ENTITY_TYPE_STARTING_INSTANCE_COUNT = "StartingInstanceCount: ";
const char* const PKE_PROJ_FILE_ENTITY_TYPE_IMPORTER_GLTF_ACCESSOR_INDEX_VERTEX = "Importer_GLTF::AccessorIndexVertex: ";
const char* const PKE_PROJ_FILE_ENTITY_TYPE_IMPORTER_GLTF_ACCESSOR_INDEX_NORMAL = "Importer_GLTF::AccessorIndexNormal: ";
@@ -61,6 +62,7 @@ void Proj_SerializeEntityType(std::ofstream &stream, const EntityType &et) {
char handleStr[19] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
snprintf(handleStr, 19, "0x%016lX", et.entityHandle.hash);
EntityType e{};
+ CompGrBinds *grBinds = ECS_GetGrBinds(et.entityHandle);
if (et.modelsDir != e.modelsDir)
stream << PKE_PROJ_FILE_ENTITY_TYPE_MODELS_DIR << et.modelsDir << std::endl;
if (et.modelFile != e.modelFile)
@@ -69,6 +71,11 @@ void Proj_SerializeEntityType(std::ofstream &stream, const EntityType &et) {
stream << PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_TYPE_CODE << et.entityTypeCode << std::endl;
if (et.entityHandle != e.entityHandle)
stream << PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE << handleStr << std::endl;
+ if (grBinds) {
+ if (grBinds->collisionCallback.name[0] != '\0') {
+ stream << PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE << grBinds->collisionCallback.name << std::endl;
+ }
+ }
if (et.startingInstanceCount != e.startingInstanceCount)
stream << PKE_PROJ_FILE_ENTITY_TYPE_STARTING_INSTANCE_COUNT << et.startingInstanceCount << std::endl;
if (et.Importer_GLTF.AccessorIndexVertex != e.Importer_GLTF.AccessorIndexVertex)
@@ -126,6 +133,8 @@ void Proj_ParseProjectSettings(std::ifstream &stream) {
*/
void Proj_ParseEntityType(std::ifstream &stream) {
+ CallbackSignature collisionSig;
+ collisionSig[0] = '\0';
EntityType et{};
while (stream.getline(projReadLine, projReadLineLength)) {
if (strcmp(PKE_PROJ_FILE_OBJ_END, projReadLine) == 0) {
@@ -136,6 +145,11 @@ void Proj_ParseEntityType(std::ifstream &stream) {
et.entityHandle = ECS_CreateEntity();
EntityType_Load(et);
GlobalEntityTypes.Push(et);
+ CompGrBinds *grBinds = ECS_GetGrBinds(et.entityHandle);
+ if (grBinds) {
+ strncpy(grBinds->collisionCallback.name, collisionSig, 16);
+ PkePlugin_SetSignatureFunc(&grBinds->collisionCallback);
+ }
return;
}
if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_MODELS_DIR)) {
@@ -171,6 +185,11 @@ void Proj_ParseEntityType(std::ifstream &stream) {
assert(result == STR2NUM_ERROR::SUCCESS);
continue;
}
+ if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE)) {
+ uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE);
+ memcpy(collisionSig, projReadLine + prefixLen, 16);
+ continue;
+ }
if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_STARTING_INSTANCE_COUNT)) {
uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_STARTING_INSTANCE_COUNT);
STR2NUM_ERROR result = str2num(et.startingInstanceCount, projReadLine + prefixLen);
diff --git a/src/window.cpp b/src/window.cpp
index f9b6ff2..e7d4506 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -2428,13 +2428,23 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
// ImGui
- if (pkePlugin.OnImGuiRender) {
+ const auto count = LoadedPkePlugins.Count();
+ bool any = false;
+ for (long i = 0; i < count; ++i) {
+ if (LoadedPkePlugins[i].OnImGuiRender != nullptr) {
+ any = true;
+ break;
+ }
+ }
+ if (any) {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
-
- pkePlugin.OnImGuiRender();
-
+ for (long i = 0; i < count; ++i) {
+ if (LoadedPkePlugins[i].OnImGuiRender != nullptr) {
+ LoadedPkePlugins[i].OnImGuiRender();
+ }
+ }
ImGui::Render();
auto drawData = ImGui::GetDrawData();
const bool isMinimized = drawData->DisplaySize.x <= 0.0f || drawData->DisplaySize.y <= 0.0f;