diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2023-12-21 17:44:03 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2023-12-23 11:42:23 -0500 |
| commit | fa7fc343a0e444da72938fad58d219cf52228976 (patch) | |
| tree | 24630be0c54f9768a13f32c5970558768e343543 /src | |
| parent | 6fa3b137c74536d2bab77f3309ca5b4c60953fe0 (diff) | |
plugin checkpoint - multiple plugins and collision callbacks
Diffstat (limited to 'src')
| -rw-r--r-- | src/components.hpp | 3 | ||||
| -rw-r--r-- | src/ecs.cpp | 51 | ||||
| -rw-r--r-- | src/ecs.hpp | 2 | ||||
| -rw-r--r-- | src/game.cpp | 39 | ||||
| -rw-r--r-- | src/physics.cpp | 32 | ||||
| -rw-r--r-- | src/plugins.cpp | 74 | ||||
| -rw-r--r-- | src/plugins.hpp | 22 | ||||
| -rw-r--r-- | src/project.cpp | 19 | ||||
| -rw-r--r-- | src/window.cpp | 18 |
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; |
