summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--editor/editor.cpp53
-rw-r--r--editor/main.cpp10
-rw-r--r--example/CMakeLists.txt14
-rw-r--r--example/example.cpp27
-rw-r--r--example/example.hpp14
-rw-r--r--example/example_export.h42
-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
16 files changed, 375 insertions, 46 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4ede1a9..0900da7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -198,3 +198,4 @@ add_dependencies(pke shaders)
add_subdirectory(editor)
add_subdirectory(runtime)
add_subdirectory(test)
+add_subdirectory(example)
diff --git a/editor/editor.cpp b/editor/editor.cpp
index 5016070..db97802 100644
--- a/editor/editor.cpp
+++ b/editor/editor.cpp
@@ -696,6 +696,23 @@ void RecordImGuiUBO() {
ImGui::End();
}
+bool RecordImGui_CallbackSelectModal(long &selectedIndex) {
+ bool returnValue = false;
+ if (ImGui::BeginPopupModal("CallbackSelect", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
+ long count = 0;
+ auto *signatures = PkePlugin_GetSortedSignatures(count);
+ for (long i = 0; i < count; ++i) {
+ const CallbackSignature &sig = signatures[i];
+ if (ImGui::Selectable(sig, selectedIndex == i)) {
+ returnValue = true;
+ selectedIndex = i;
+ }
+ }
+ ImGui::EndPopup();
+ }
+ return returnValue;
+}
+
void RecordImGuiModalCreateEntityType() {
if (ImGui::BeginPopupModal("CreateEntityType", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
static char modelsDir[64];
@@ -835,6 +852,24 @@ void RecordImGui_CompGrBinds(bool readonly, CompGrBinds *component) {
ImGui::InputScalar("InstanceBufferMaxCount", ImGuiDataType_U32, &component->instanceBufferMaxCount, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly);
ImGui::InputScalar("Instance Count", ImGuiDataType_U32, &component->instanceCounter, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly);
+ static long index = -1;
+ if (ImGui::Button("Clear")) {
+ index = -1;
+ component->collisionCallback.name[0] = '\0';
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("Change")) {
+ index = -1;
+ ImGui::OpenPopup("CallbackSelect");
+ }
+ ImGui::SameLine();
+ ImGui::Text("Collision Callback: '%s'", component->collisionCallback.name);
+ if (RecordImGui_CallbackSelectModal(index)) {
+ long x = 0;
+ memcpy(component->collisionCallback.name, PkePlugin_GetSortedSignatures(x)[index], 16);
+ PkePlugin_SetSignatureFunc(&component->collisionCallback);
+ }
+
ImGui::Spacing();
}
@@ -868,6 +903,24 @@ void RecordImGui_CompInstPos(bool readonly, CompInstance *component) {
changed = ImGui::InputScalar("Phys - Collision Layer", ImGuiDataType_U16, &component->physicsLayer, nullptr, nullptr, nullptr, inputTextFlags) || changed;
changed = ImGui::InputScalar("Phys - Collision Mask", ImGuiDataType_U16, &component->physicsMask, nullptr, nullptr, nullptr, inputTextFlags) || changed;
+ static long index = -1;
+ if (ImGui::Button("Clear")) {
+ index = -1;
+ component->collisionCallback.name[0] = '\0';
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("Change")) {
+ index = -1;
+ ImGui::OpenPopup("CallbackSelect");
+ }
+ ImGui::SameLine();
+ ImGui::Text("Collision Callback: '%s'", component->collisionCallback.name);
+ if (RecordImGui_CallbackSelectModal(index)) {
+ long x = 0;
+ memcpy(component->collisionCallback.name, PkePlugin_GetSortedSignatures(x)[index], 16);
+ PkePlugin_SetSignatureFunc(&component->collisionCallback);
+ }
+
ImGui::InputScalar("Phys - Rigid Body", ImGuiDataType_U64, &component->bt.rigidBody, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly);
ImGui::InputScalar("Phys - Motion State", ImGuiDataType_U64, &component->bt.motionState, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly);
diff --git a/editor/main.cpp b/editor/main.cpp
index af0e66a..2dee016 100644
--- a/editor/main.cpp
+++ b/editor/main.cpp
@@ -23,10 +23,12 @@ int main(int argc, char *argv[]) {
{
pkeSettings.isSimulationPaused = true;
pkeSettings.isShowingEditor = true;
- pkePlugin.OnInit = PkeEditor_Init;
- pkePlugin.OnTick = PkeEditor_Tick;
- pkePlugin.OnTeardown = PkeEditor_Teardown;
- pkePlugin.OnImGuiRender = PkeEditor_RecordImGui;
+ LoadedPkePlugins.Push({
+ .OnInit = PkeEditor_Init,
+ .OnTick = PkeEditor_Tick,
+ .OnTeardown = PkeEditor_Teardown,
+ .OnImGuiRender = PkeEditor_RecordImGui,
+ });
}
// run
PkeArgs_Parse(argc, argv);
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
new file mode 100644
index 0000000..a895b5d
--- /dev/null
+++ b/example/CMakeLists.txt
@@ -0,0 +1,14 @@
+project(pke_example VERSION 0.0)
+
+set(PKE_EDITOR_SOURCE_FILES
+ # example_export.h
+ example.hpp
+ example.cpp
+)
+
+add_library(pke_example
+ ${PKE_EDITOR_SOURCE_FILES}
+)
+
+target_link_libraries(pke_example PUBLIC pke)
+target_include_directories(pke_example PUBLIC pke)
diff --git a/example/example.cpp b/example/example.cpp
new file mode 100644
index 0000000..b870806
--- /dev/null
+++ b/example/example.cpp
@@ -0,0 +1,27 @@
+
+#include "example.hpp"
+
+#include "components.hpp"
+
+void OnEntityTypeCollision(const EntityHandle &lhs, const EntityHandle &rhs) {
+ fprintf(stdout, "[Example::OnEntityTypeCollision] Called\n");
+}
+
+void OnEntityCollision(const EntityHandle &lhs, const EntityHandle &rhs) {
+ fprintf(stdout, "[Example::OnEntityCollision] Called\n");
+}
+
+void OnInit() {
+ PkeArray_Add(&pkePluginCallbacks, PkeCallback {
+ .name = "OnEntTypeColl",
+ .func = reinterpret_cast<void *>(OnEntityTypeCollision),
+ });
+ PkeArray_Add(&pkePluginCallbacks, PkeCallback {
+ .name = "OnEntColl",
+ .func = reinterpret_cast<void *>(OnEntityCollision),
+ });
+}
+
+PKEPluginInterface pkePluginInterface {
+ .OnInit = OnInit,
+};
diff --git a/example/example.hpp b/example/example.hpp
new file mode 100644
index 0000000..c64b3e9
--- /dev/null
+++ b/example/example.hpp
@@ -0,0 +1,14 @@
+#ifndef PKE_EXAMPLE_HPP
+#define PKE_EXAMPLE_HPP
+
+#include "plugins.hpp"
+
+// EXAMPLE_EXPORT void OnEntityTypeCollision(const EntityHandle &lhs, const EntityHandle &rhs);
+// void OnEntityTypeCollision(const EntityHandle &lhs, const EntityHandle &rhs);
+
+// EXAMPLE_EXPORT void OnEntityCollision(const EntityHandle &lhs, const EntityHandle &rhs);
+// void OnEntityCollision(const EntityHandle &lhs, const EntityHandle &rhs);
+
+extern PKEPluginInterface pkePluginInterface;
+
+#endif /* PKE_EXAMPLE_HPP */
diff --git a/example/example_export.h b/example/example_export.h
new file mode 100644
index 0000000..53bf208
--- /dev/null
+++ b/example/example_export.h
@@ -0,0 +1,42 @@
+
+#ifndef EXAMPLE_EXPORT_H
+#define EXAMPLE_EXPORT_H
+
+#ifdef EXAMPLE_STATIC_DEFINE
+# define EXAMPLE_EXPORT
+# define EXAMPLE_NO_EXPORT
+#else
+# ifndef EXAMPLE_EXPORT
+# ifdef extension_EXPORTS
+ /* We are building this library */
+# define EXAMPLE_EXPORT extern "C" __attribute__((visibility("default")))
+# else
+ /* We are using this library */
+# define EXAMPLE_EXPORT __attribute__((visibility("default")))
+# endif
+# endif
+
+# ifndef EXAMPLE_NO_EXPORT
+# define EXAMPLE_NO_EXPORT __attribute__((visibility("hidden")))
+# endif
+#endif
+
+#ifndef EXAMPLE_DEPRECATED
+# define EXAMPLE_DEPRECATED __attribute__ ((__deprecated__))
+#endif
+
+#ifndef EXAMPLE_DEPRECATED_EXPORT
+# define EXAMPLE_DEPRECATED_EXPORT EXAMPLE_EXPORT EXAMPLE_DEPRECATED
+#endif
+
+#ifndef EXAMPLE_DEPRECATED_NO_EXPORT
+# define EXAMPLE_DEPRECATED_NO_EXPORT EXAMPLE_NO_EXPORT EXAMPLE_DEPRECATED
+#endif
+
+#if 0 /* DEFINE_NO_DEPRECATED */
+# ifndef EXAMPLE_NO_DEPRECATED
+# define EXAMPLE_NO_DEPRECATED
+# endif
+#endif
+
+#endif /* EXAMPLE_EXPORT_H */
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;