summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2023-10-31 12:46:09 -0400
committerJonathan Bradley <jcb@pikum.xyz>2023-11-15 13:13:25 -0500
commitf2c808b1235b9d76e4d4753c025f404e7736ca3c (patch)
tree34100f4a05d6feb40474c50f1d3539611b0016ba /src
parent18e65823663af6e2a1472b66486526a23d5e9c30 (diff)
use model for collision + refactor physics init and rigidbody creation
Diffstat (limited to 'src')
-rw-r--r--src/components.hpp15
-rw-r--r--src/ecs.cpp74
-rw-r--r--src/ecs.hpp2
-rw-r--r--src/entities.cpp14
-rw-r--r--src/entities.hpp4
-rw-r--r--src/game.cpp47
-rw-r--r--src/main.cpp3
-rw-r--r--src/physics.cpp90
-rw-r--r--src/physics.hpp15
9 files changed, 187 insertions, 77 deletions
diff --git a/src/components.hpp b/src/components.hpp
index 0903492..a8b4e88 100644
--- a/src/components.hpp
+++ b/src/components.hpp
@@ -4,9 +4,8 @@
#include "macros.hpp"
#include "dynamic-array.hpp"
-#include <BulletCollision/CollisionShapes/btCollisionShape.h>
-#include <LinearMath/btDefaultMotionState.h>
#include <BulletDynamics/Dynamics/btRigidBody.h>
+#include <LinearMath/btDefaultMotionState.h>
#include <vulkan/vulkan_core.h>
const uint64_t ECS_UNSET_VAL = 0xFFFFFFFFFFFFFFFF;
@@ -57,18 +56,16 @@ struct InstPos {
btTransform posRot;
btVector3 scale;
};
-
+struct InstBt {
+ btDefaultMotionState *motionState;
+ btRigidBody *rigidBody;
+};
struct CompInstance {
EntityHandle entHandle = EntityHandle_MAX;
GrBindsHandle grBindsHandle = GrBindsHandle_MAX;
InstanceHandle instanceHandle = InstanceHandle_MAX;
uint64_t index = ECS_UNSET_VAL;
- struct {
- btVector3 localInertia;
- btCollisionShape *collisionShape;
- btDefaultMotionState defaultMotionState;
- btRigidBody *rigidBody;
- } bt;
+ InstBt bt;
bool isNeedingUpdated = false;
};
diff --git a/src/ecs.cpp b/src/ecs.cpp
index b5b0ce4..654bc71 100644
--- a/src/ecs.cpp
+++ b/src/ecs.cpp
@@ -4,10 +4,12 @@
#include "game-settings.hpp"
#include "math-helpers.hpp"
#include "memory.hpp"
+#include "physics.hpp"
#include "vendor/glm_include.hpp"
#include "window.hpp"
#include <btBulletDynamicsCommon.h>
+#include <BulletCollision/CollisionShapes/btConvexHullShape.h>
#include <glm/gtc/type_ptr.hpp>
TypeSafeInt_B(EntityHandle);
@@ -34,13 +36,6 @@ BucketContainer<EntityBucket, EntityHandle_T> Entities_BucketContainer{};
BucketContainer<GrBindsBucket, GrBindsHandle_T> Comp_GrBinds_BucketContainer{};
BucketContainer<InstanceBucket, InstanceHandle_T> Comp_Instance_BucketContainer{};
-MemBucket *bulletBucket = nullptr;
-btDefaultCollisionConfiguration *btConfiguration = nullptr;
-btCollisionDispatcher *btDispatcher = nullptr;
-btBroadphaseInterface *btBroadphase = nullptr;
-btConstraintSolver *btSolver = nullptr;
-btDiscreteDynamicsWorld *btDynamicsWorld = nullptr;
-
void ECS_GetEntity_Inner(EntityHandle entHandle, Entity*& ent) {
EntityHandle_T entHandle_t{static_cast<EntityHandle_T>(entHandle)};
assert(entHandle_t != EntityHandle_T_MAX && "Unknown entity handle");
@@ -53,19 +48,6 @@ void ECS_Init() {
Buckets_Init(Entities_BucketContainer);
Buckets_Init(Comp_GrBinds_BucketContainer);
Buckets_Init(Comp_Instance_BucketContainer);
- // bullet
- {
- bulletBucket = Pke_BeginTransientBucket();
- btConfiguration = Pke_New<btDefaultCollisionConfiguration>(bulletBucket);
- btDispatcher = Pke_New<btCollisionDispatcher>(bulletBucket);
- new (btDispatcher) btCollisionDispatcher(btConfiguration);
- btBroadphase = Pke_New<btDbvtBroadphase>(bulletBucket);
- btSolver = Pke_New<btSequentialImpulseConstraintSolver>(bulletBucket);
- btDynamicsWorld = Pke_New<btDiscreteDynamicsWorld>(bulletBucket);
- new (btDynamicsWorld) btDiscreteDynamicsWorld(btDispatcher, btBroadphase, btSolver, btConfiguration);
- auto grav = btDynamicsWorld->getGravity();
- btDynamicsWorld->setGravity(btVector3(grav.getX(), grav.getZ(), grav.getY()));
- }
}
uint64_t ECS_GetEntities_BucketCount() {
@@ -182,20 +164,18 @@ void ECS_Tick_Early(double delta) {
}
void ECS_Tick(double delta) {
- if (btDynamicsWorld && pkeSettings.isSimulationPaused == false) {
- auto physicsTickCount = btDynamicsWorld->stepSimulation(delta, 0);
- if (physicsTickCount != 0) {
- for (long b = 0; b <= Comp_Instance_BucketContainer.bucketCounter; ++b) {
- auto &bkt = Comp_Instance_BucketContainer.buckets[b];
- long count = Comp_Instance_BucketContainer.bucketCounter == b ? Comp_Instance_BucketContainer.itemCounter >> 32 : maxBucketItemCount;
- for (uint32_t i = 0; i < count; ++i) {
- auto &inst = bkt.instances[i];
- auto activationState = inst.bt.rigidBody->getActivationState();
- if (activationState == ISLAND_SLEEPING || activationState == DISABLE_SIMULATION || activationState == WANTS_DEACTIVATION) {
- continue;
- }
- inst.isNeedingUpdated = true;
+ int32_t physicsTickCount = Physics_Tick(delta);
+ if (physicsTickCount != 0) {
+ for (long b = 0; b <= Comp_Instance_BucketContainer.bucketCounter; ++b) {
+ auto &bkt = Comp_Instance_BucketContainer.buckets[b];
+ long count = Comp_Instance_BucketContainer.bucketCounter == b ? Comp_Instance_BucketContainer.itemCounter >> 32 : maxBucketItemCount;
+ for (uint32_t i = 0; i < count; ++i) {
+ auto &inst = bkt.instances[i];
+ auto activationState = inst.bt.rigidBody->getActivationState();
+ if (activationState == ISLAND_SLEEPING || activationState == DISABLE_SIMULATION || activationState == WANTS_DEACTIVATION) {
+ continue;
}
+ inst.isNeedingUpdated = true;
}
}
}
@@ -258,13 +238,13 @@ void ECS_Tick_Late(double delta) {
}
btTransform btMatrix_posRot;
- inst.bt.defaultMotionState.getWorldTransform(btMatrix_posRot);
+ inst.bt.motionState->getWorldTransform(btMatrix_posRot);
float openglMatrix[16];
btMatrix_posRot.getOpenGLMatrix(openglMatrix);
glm::mat4 glmMat_posRot = glm::make_mat4(openglMatrix);
glm::vec3 scale;
- BulletToGlm(inst.bt.collisionShape->getLocalScaling(), scale);
+ BulletToGlm(inst.bt.rigidBody->getCollisionShape()->getLocalScaling(), scale);
chunk->mats.Push(glm::scale(glmMat_posRot, scale));
bfrUpdate->runningSize += sizeof(glm::mat4);
@@ -365,7 +345,7 @@ CompGrBinds *ECS_GetGrBinds(uint64_t bucketIndex, uint64_t &itemCount) {
return Comp_GrBinds_BucketContainer.buckets[bucketIndex].compGrBinds;
}
-CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityTypeEntityHandle, const InstPos &instPos) {
+CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityTypeEntityHandle) {
assert(entHandle != EntityHandle_MAX);
assert(entityTypeEntityHandle != EntityHandle_MAX);
@@ -401,20 +381,6 @@ CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityType
EntitiesWithExcessInstances.Push(grBinds->entHandle);
}
- if (btDynamicsWorld) {
- comp->bt.localInertia = btVector3(0, 0, 0);
- comp->bt.collisionShape = Pke_New<btBoxShape>(bulletBucket);
- new (comp->bt.collisionShape) btBoxShape(instPos.scale);
- comp->bt.collisionShape->calculateLocalInertia(btScalar(1.f), comp->bt.localInertia);
- comp->bt.defaultMotionState = btDefaultMotionState(instPos.posRot);
- comp->bt.rigidBody = Pke_New<btRigidBody>(bulletBucket);
- new (comp->bt.rigidBody) btRigidBody(btScalar(1.f), &comp->bt.defaultMotionState, comp->bt.collisionShape, comp->bt.localInertia);
- comp->bt.rigidBody->setLinearVelocity(btVector3(0,0,0));
- comp->bt.rigidBody->setAngularVelocity(btVector3(0,0,0));
- btDynamicsWorld->addRigidBody(comp->bt.rigidBody);
- comp->bt.rigidBody->setUserPointer(reinterpret_cast<void *>(comp->entHandle));
- }
-
return *comp;
}
@@ -445,14 +411,13 @@ void ECS_UpdateInstance(EntityHandle entHandle, const InstPos &instPos, bool ove
auto i = Buckets_GetItemIndex(instanceHandle_t);
auto *inst = &Comp_Instance_BucketContainer.buckets[b].instances[i];
- if (btDynamicsWorld && overridePhysics) {
+ if (BtDynamicsWorld && overridePhysics) {
inst->bt.rigidBody->setWorldTransform(instPos.posRot);
- inst->bt.collisionShape->setLocalScaling(instPos.scale);
+ inst->bt.rigidBody->getCollisionShape()->setLocalScaling(instPos.scale);
inst->bt.rigidBody->setLinearVelocity(btVector3(0,0,0));
inst->bt.rigidBody->setAngularVelocity(btVector3(0,0,0));
- btDynamicsWorld->getPairCache()->cleanProxyFromPairs(inst->bt.rigidBody->getBroadphaseProxy(), btDynamicsWorld->getDispatcher());
+ BtDynamicsWorld->getPairCache()->cleanProxyFromPairs(inst->bt.rigidBody->getBroadphaseProxy(), BtDynamicsWorld->getDispatcher());
inst->bt.rigidBody->activate();
-
inst->isNeedingUpdated = true;
}
}
@@ -471,7 +436,6 @@ CompInstance *ECS_GetInstances(uint64_t bucketIndex, uint64_t &itemCount) {
}
void ECS_Teardown() {
- Pke_EndTransientBucket(bulletBucket);
EntitiesWithExcessInstances.~DynArray();
entitiesYetToBeRemoved.~DynArray();
EntitiesToBeRemoved.~DynArray();
diff --git a/src/ecs.hpp b/src/ecs.hpp
index 4a10b3a..480ba0c 100644
--- a/src/ecs.hpp
+++ b/src/ecs.hpp
@@ -32,7 +32,7 @@ CompGrBinds *ECS_GetGrBinds(EntityHandle entHandle);
uint64_t ECS_GetGrBinds_BucketCount();
CompGrBinds *ECS_GetGrBinds(uint64_t bucketIndex, uint64_t &itemCount);
-CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityTypeEntityHandle, const InstPos &instPos);
+CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityTypeEntityHandle);
CompInstance *ECS_GetInstance(EntityHandle entHandle);
void ECS_UpdateInstance(EntityHandle entHandle, const InstPos &instPos, bool overridePhysics = false);
uint64_t ECS_GetInstances_BucketCount();
diff --git a/src/entities.cpp b/src/entities.cpp
index a9108a0..c06aa3c 100644
--- a/src/entities.cpp
+++ b/src/entities.cpp
@@ -1,7 +1,10 @@
#include "entities.hpp"
-#include <vulkan/vulkan_core.h>
+#include "physics.hpp"
+
+#include <BulletCollision/CollisionShapes/btConvexHullShape.h>
+
DynArray<EntityType> GlobalEntityTypes{16};
void EntityType_Init() {
@@ -546,7 +549,6 @@ void EntityType_Load(EntityType &et) {
srcPtr = static_cast<char *>(gltfData->buffers[0].data) + accIndex.buffer_view->offset;
memcpy(dstPtr, srcPtr, accIndex.buffer_view->size);
-
VkCommandBufferBeginInfo vkCommandBufferBeginInfo;
vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vkCommandBufferBeginInfo.pNext = nullptr;
@@ -610,6 +612,14 @@ void EntityType_Load(EntityType &et) {
vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &et.deviceMemoryInst);
vkBindBufferMemory(vkDevice, grBinds.instanceBuffer, et.deviceMemoryInst, 0);
+ // bullet
+ {
+ et.bt.shape = Pke_New<btConvexHullShape>(MemBkt_Bullet);
+ btScalar *vertDataPointer = reinterpret_cast<btScalar *>(accVert.buffer_view->buffer->data);
+ vertDataPointer += accVert.buffer_view->offset;
+ new (et.bt.shape) btConvexHullShape(vertDataPointer, accVert.count, accVert.stride);
+ }
+
// cleanup
cgltf_free(gltfData);
AM_Destroy(assetHandle);
diff --git a/src/entities.hpp b/src/entities.hpp
index 4c5b498..f45f7d3 100644
--- a/src/entities.hpp
+++ b/src/entities.hpp
@@ -9,6 +9,7 @@
#include "memory.hpp"
#include "window.hpp"
+#include <BulletCollision/CollisionShapes/btCollisionShape.h>
#include <vulkan/vulkan_core.h>
struct EntityType {
@@ -30,6 +31,9 @@ struct EntityType {
int16_t AccessorIndexUV = -1;
int16_t AccessorIndexIndex = -1;
} Importer_GLTF;
+ struct {
+ btCollisionShape *shape = nullptr;
+ } bt;
};
extern DynArray<EntityType> GlobalEntityTypes;
diff --git a/src/game.cpp b/src/game.cpp
index f0fac6c..6cde580 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1,6 +1,7 @@
#include "game.hpp"
+#include "BulletCollision/CollisionShapes/btConvexHullShape.h"
#include "camera.hpp"
#include "components.hpp"
#include "dynamic-array.hpp"
@@ -9,6 +10,7 @@
#include "helpers.hpp"
#include "imgui.h"
#include "math-helpers.hpp"
+#include "physics.hpp"
#include "player-input.hpp"
#include "vendor/glm_include.hpp"
#include "window.hpp"
@@ -138,8 +140,8 @@ void SerializeInstance(std::ofstream &stream, const CompInstance &comp) {
stream << PKE_FILE_INSTANCE_ENTITY_TYPE_CODE << et->entityTypeCode << std::endl;
btTransform trans;
- comp.bt.defaultMotionState.getWorldTransform(trans);
- btVector3 scale = comp.bt.collisionShape->getLocalScaling();
+ comp.bt.motionState->getWorldTransform(trans);
+ btVector3 scale = comp.bt.rigidBody->getCollisionShape()->getLocalScaling();
if (trans != baseInst.posRot) {
btVector3 pos = trans.getOrigin();
btQuaternion rot = trans.getRotation();
@@ -262,7 +264,19 @@ void ParseInstance(std::ifstream &stream) {
}
const auto &et = GlobalEntityTypes[existingEntityTypeIndex];
auto entityHandle = ECS_CreateEntity();
- ECS_CreateInstance(entityHandle, et.entityHandle, instPos);
+ auto &compInst = ECS_CreateInstance(entityHandle, et.entityHandle);
+
+ btVector3 localInertia(0, 0, 0);
+ et.bt.shape->calculateLocalInertia(btScalar(1.f), localInertia);
+ compInst.bt.motionState = Pke_New<btDefaultMotionState>(MemBkt_Bullet);
+ new (compInst.bt.motionState) btDefaultMotionState(instPos.posRot);
+ compInst.bt.rigidBody = Pke_New<btRigidBody>(MemBkt_Bullet);
+ new (compInst.bt.rigidBody) btRigidBody(btScalar(1.f), compInst.bt.motionState, et.bt.shape, localInertia);
+ compInst.bt.rigidBody->setLinearVelocity(btVector3(0,0,0));
+ compInst.bt.rigidBody->setAngularVelocity(btVector3(0,0,0));
+ compInst.bt.rigidBody->getCollisionShape()->setLocalScaling(instPos.scale);
+ BtDynamicsWorld->addRigidBody(compInst.bt.rigidBody);
+ compInst.bt.rigidBody->setUserPointer(reinterpret_cast<void *>(compInst.entHandle));
break;
}
if (strstr(readLine, PKE_FILE_INSTANCE_ENTITY_HANDLE)) {
@@ -438,12 +452,25 @@ void Game_Tick(double delta) {
}
while (entityInstancesToCreate.Count() > 0) {
auto createInfo = entityInstancesToCreate.Pop();
+ // TODO needs to be more elegant
+ int64_t etIndex = EntityType_FindByEntityHandle(createInfo.entityTypeEntityHandle);
+ auto &et = GlobalEntityTypes[etIndex];
EntityHandle newEntity = ECS_CreateEntity();
- InstPos instPos;
- instPos.posRot = btTransform{};
- instPos.posRot.setIdentity();
- instPos.scale = btVector3(1, 1, 1);
- ECS_CreateInstance(newEntity, createInfo.entityTypeEntityHandle, instPos);
+ auto &compInst = ECS_CreateInstance(newEntity, createInfo.entityTypeEntityHandle);
+
+ btVector3 localInertia(0, 0, 0);
+ et.bt.shape->calculateLocalInertia(btScalar(1.f), localInertia);
+ btTransform posRot{};
+ posRot.setIdentity();
+ compInst.bt.motionState = Pke_New<btDefaultMotionState>(MemBkt_Bullet);
+ new (compInst.bt.motionState) btDefaultMotionState(posRot);
+ compInst.bt.rigidBody = Pke_New<btRigidBody>(MemBkt_Bullet);
+ new (compInst.bt.rigidBody) btRigidBody(btScalar(1.f), compInst.bt.motionState, et.bt.shape, localInertia);
+ compInst.bt.rigidBody->setLinearVelocity(btVector3(0,0,0));
+ compInst.bt.rigidBody->setAngularVelocity(btVector3(0,0,0));
+ compInst.bt.rigidBody->getCollisionShape()->setLocalScaling(btVector3(1, 1, 1));
+ BtDynamicsWorld->addRigidBody(compInst.bt.rigidBody);
+ compInst.bt.rigidBody->setUserPointer(reinterpret_cast<void *>(compInst.entHandle));
}
PkeInput_Tick(delta);
@@ -834,8 +861,8 @@ void RecordImGui_CompInstPos(bool readonly, CompInstance *component) {
bool changed = false;
InstPos instPos;
- component->bt.defaultMotionState.getWorldTransform(instPos.posRot);
- instPos.scale = component->bt.collisionShape->getLocalScaling();
+ component->bt.motionState->getWorldTransform(instPos.posRot);
+ instPos.scale = component->bt.rigidBody->getCollisionShape()->getLocalScaling();
btVector3 pos = instPos.posRot.getOrigin();
btQuaternion rot = instPos.posRot.getRotation();
diff --git a/src/main.cpp b/src/main.cpp
index c8c8a0d..045fdfe 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,6 +6,7 @@
#include <thread>
#include <csignal>
+#include "physics.hpp"
#include "player-input.hpp"
#include "asset-manager.hpp"
#include "ecs.hpp"
@@ -32,6 +33,7 @@ int main() {
fprintf(stdout, "PKE ENTERING\n");
try {
AM_Init();
+ Physics_Init();
Game_Init();
ECS_Init();
CreateWindow(&windowProps);
@@ -126,6 +128,7 @@ int main() {
Event_Teardown();
EntityType_Teardown();
PkeInput_Teardown();
+ Physics_Teardown();
ECS_Teardown();
AM_DebugPrint();
AM_Teardown();
diff --git a/src/physics.cpp b/src/physics.cpp
new file mode 100644
index 0000000..b8d093d
--- /dev/null
+++ b/src/physics.cpp
@@ -0,0 +1,90 @@
+
+#include "physics.hpp"
+
+#include "dynamic-array.hpp"
+#include "game-settings.hpp"
+
+#include <btBulletDynamicsCommon.h>
+#include <LinearMath/btAlignedAllocator.h>
+
+MemBucket *MemBkt_Bullet = nullptr;
+btDiscreteDynamicsWorld *BtDynamicsWorld = nullptr;
+
+struct AllocedData {
+ void *data;
+ std::size_t size;
+};
+DynArray<AllocedData> *bulletAllocs;
+
+btDefaultCollisionConfiguration *btConfiguration = nullptr;
+btCollisionDispatcher *btDispatcher = nullptr;
+btBroadphaseInterface *btBroadphase = nullptr;
+btConstraintSolver *btSolver = nullptr;
+
+void *pke_btAlignedAllocFunc(size_t size, int alignment) {
+ void *ptr = Pke_New(size, alignment, MemBkt_Bullet);
+ bulletAllocs->Push({ptr, size});
+ return ptr;
+}
+void pke_btAlignedFreeFunc(void *memBlock) {
+ auto &arr = *bulletAllocs;
+ auto count = arr.Count();
+ long index = -1;
+ for (long i = 0; i < count; ++i) {
+ if (arr[i].data == memBlock) {
+ index = i;
+ break;
+ }
+ }
+ assert(index != -1);
+ Pke_Delete(const_cast<void *>(memBlock), arr[index].size, MemBkt_Bullet);
+ bulletAllocs->Remove(index);
+}
+void *pke_btAllocFunc(size_t size) {
+ void *ptr = Pke_New(size, MINIMUM_ALIGNMENT, MemBkt_Bullet);
+ bulletAllocs->Push({ptr, size});
+ return ptr;
+}
+void pke_btFreeFunc(void *memBlock) {
+ auto &arr = *bulletAllocs;
+ auto count = arr.Count();
+ long index = -1;
+ for (long i = 0; i < count; ++i) {
+ if (arr[i].data == memBlock) {
+ index = i;
+ break;
+ }
+ }
+ assert(index != -1);
+ Pke_Delete(const_cast<void *>(memBlock), arr[index].size, MemBkt_Bullet);
+ bulletAllocs->Remove(index);
+}
+
+void Physics_Init() {
+ MemBkt_Bullet = Pke_BeginTransientBucket();
+ bulletAllocs = Pke_New<DynArray<AllocedData>>(MemBkt_Bullet);
+ new (bulletAllocs) DynArray<AllocedData>(MemBkt_Bullet);
+ bulletAllocs->Reserve(1024);
+ btAlignedAllocSetCustom(pke_btAllocFunc, pke_btFreeFunc);
+ btAlignedAllocSetCustomAligned(pke_btAlignedAllocFunc, pke_btAlignedFreeFunc);
+
+ btConfiguration = Pke_New<btDefaultCollisionConfiguration>(MemBkt_Bullet);
+ btDispatcher = Pke_New<btCollisionDispatcher>(MemBkt_Bullet);
+ new (btDispatcher) btCollisionDispatcher(btConfiguration);
+ btBroadphase = Pke_New<btDbvtBroadphase>(MemBkt_Bullet);
+ btSolver = Pke_New<btSequentialImpulseConstraintSolver>(MemBkt_Bullet);
+ BtDynamicsWorld = Pke_New<btDiscreteDynamicsWorld>(MemBkt_Bullet);
+ new (BtDynamicsWorld) btDiscreteDynamicsWorld(btDispatcher, btBroadphase, btSolver, btConfiguration);
+ auto grav = BtDynamicsWorld->getGravity();
+ BtDynamicsWorld->setGravity(btVector3(grav.getX(), grav.getZ(), grav.getY()));
+}
+
+int32_t Physics_Tick(double delta) {
+ if (pkeSettings.isSimulationPaused == true)
+ return 0;
+ return BtDynamicsWorld->stepSimulation(delta, 0);
+}
+
+void Physics_Teardown() {
+ Pke_EndTransientBucket(MemBkt_Bullet);
+}
diff --git a/src/physics.hpp b/src/physics.hpp
new file mode 100644
index 0000000..3d41ab7
--- /dev/null
+++ b/src/physics.hpp
@@ -0,0 +1,15 @@
+#ifndef PKE_PHYSICS_HPP
+#define PKE_PHYSICS_HPP
+
+#include "memory.hpp"
+
+#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
+
+extern MemBucket *MemBkt_Bullet;
+extern btDiscreteDynamicsWorld *BtDynamicsWorld;
+
+void Physics_Init();
+int32_t Physics_Tick(double delta);
+void Physics_Teardown();
+
+#endif /* PKE_PHYSICS_HPP */