summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2023-08-30 11:00:04 -0400
committerJonathan Bradley <jcb@pikum.xyz>2023-09-06 17:19:09 -0400
commitea218cad0ee862964e12bb7f15d442acb7de6c43 (patch)
treef9c15c073e2a60e957d6d6b74f5f991a28b222a9
parent2bdb644e2f4f821a367713ad951369013be8b611 (diff)
first pass add ecs
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/ecs.cpp71
-rw-r--r--src/ecs.hpp25
-rw-r--r--src/game.cpp7
-rw-r--r--src/game.hpp4
-rw-r--r--src/main.cpp4
6 files changed, 112 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 011126f..e90552d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,6 +14,8 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3 -s DNDEBUG")
set(PKE_SOURCE_FILES
src/main.cpp
src/macros.hpp
+ src/ecs.hpp
+ src/ecs.cpp
src/game.hpp
src/game.cpp
src/memory.hpp
diff --git a/src/ecs.cpp b/src/ecs.cpp
new file mode 100644
index 0000000..2c0a26f
--- /dev/null
+++ b/src/ecs.cpp
@@ -0,0 +1,71 @@
+
+#include "ecs.hpp"
+
+TypeSafeInt_B(EntityHandle);
+const uint64_t bucketItemCount = 256;
+
+struct EntityBucket{
+ Entity entities[bucketItemCount];
+};
+
+uint64_t entityBucketIncrementer = 2;
+EntityHandle_T entityBucketCounter{0};
+EntityHandle_T entityCounter{0};
+EntityBucket *entityBuckets = nullptr;
+DynArray<EntityHandle> entitiesMarkedForRemoval{16};
+DynArray<EntityHandle> EntitiesToBeRemoved{16};
+
+void ECS_Init() {
+ entityBuckets = pke::PkeNew<EntityBucket>(entityBucketIncrementer);
+}
+
+EntityHandle ECS_CreateEntity_Inner(EntityHandle parentEntityHandle) {
+ EntityHandle_T entityHandle_T{Buckets_NewHandle<EntityBucket>(bucketItemCount, entityBucketIncrementer, entityBucketCounter, entityCounter, entityBuckets)};
+ EntityHandle entityHandle{entityHandle_T};
+
+ Entity *entity = &entityBuckets[Buckets_GetBucketIndex(entityHandle_T)].entities[Buckets_GetItemIndex(entityHandle_T)];
+
+ entity->handle = entityHandle;
+ entity->parentHandle = parentEntityHandle;
+
+ return entityHandle;
+}
+
+EntityHandle ECS_CreateEntity(EntityHandle parentEntityHandle) {
+ return ECS_CreateEntity_Inner(parentEntityHandle);
+}
+
+void ECS_MarkForRemoval(EntityHandle entityHandle) {
+ auto b = Buckets_GetBucketIndex(static_cast<EntityHandle_T>(entityHandle));
+ auto e = Buckets_GetItemIndex(static_cast<EntityHandle_T>(entityHandle));
+ const Entity *ent = &entityBuckets[b].entities[e];
+ assert(ent->isMarkedForRemoval == false && "Entity already marked for removal");
+ entitiesMarkedForRemoval.Push(entityHandle);
+}
+
+void ECS_Tick(double delta) {
+ EntitiesToBeRemoved.Resize(0);
+ for (long b = 0; b <= entityBucketCounter; ++b) {
+ uint64_t entCount = b == entityBucketCounter ? entityCounter >> 32 : bucketItemCount;
+ for (long e = 0; e < entCount; ++e) {
+ Entity *ent = &entityBuckets[b].entities[e];
+ if (ent->handle == EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}}) continue;
+ if (ent->isMarkedForRemoval) {
+ ent->handle = EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}};
+ ent->parentHandle = EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}};
+ ent->isMarkedForRemoval = false;
+ } else {
+ if (entitiesMarkedForRemoval.Has(ent->handle)) {
+ ent->isMarkedForRemoval = true;
+ EntitiesToBeRemoved.Push(ent->handle);
+ continue;
+ }
+ if (EntitiesToBeRemoved.Has(ent->parentHandle)) {
+ ent->isMarkedForRemoval = true;
+ EntitiesToBeRemoved.Push(ent->handle);
+ }
+ }
+ }
+ }
+ entitiesMarkedForRemoval.Resize(0);
+}
diff --git a/src/ecs.hpp b/src/ecs.hpp
new file mode 100644
index 0000000..d37ff57
--- /dev/null
+++ b/src/ecs.hpp
@@ -0,0 +1,25 @@
+#ifndef PKE_ECS_HPP
+#define PKE_ECS_HPP
+
+#include "dynamic-array.hpp"
+#include "macros.hpp"
+#include "memory.hpp"
+
+#include "glm/vec3.hpp"
+
+TypeSafeInt_H(EntityHandle, uint64_t, UINT64_MAX);
+
+extern DynArray<EntityHandle> EntitiesToBeRemoved;
+
+struct Entity {
+ EntityHandle handle = EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}};
+ EntityHandle parentHandle = EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}};
+ bool isMarkedForRemoval = false;
+};
+
+void ECS_Init();
+void ECS_Tick(double delta);
+EntityHandle ECS_CreateEntity(EntityHandle parentEntityHandle = EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}});
+void ECS_MarkForRemoval(EntityHandle entityHandle);
+
+#endif /* PKE_ECS_HPP */
diff --git a/src/game.cpp b/src/game.cpp
index 3cf2109..cfb6d7c 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -3,3 +3,10 @@
GameSettings pkeSettings{};
+void GameTick(double delta) {
+ /*
+ * ECS_Tick() gets called first because it updates the public
+ * `EntitiesToBeRemoved` for all other ticks to use.
+ */
+ ECS_Tick(delta);
+}
diff --git a/src/game.hpp b/src/game.hpp
index 4ab021b..fad551b 100644
--- a/src/game.hpp
+++ b/src/game.hpp
@@ -4,6 +4,8 @@
#include <chrono>
#include <cstdint>
+#include "ecs.hpp"
+
using GameTimeDuration = std::chrono::duration<int64_t, std::nano>;
using GameTimePoint = std::chrono::steady_clock::time_point;
#define NANO_DENOM std::chrono::nanoseconds::period::den
@@ -21,4 +23,6 @@ struct GameSettings {
extern GameSettings pkeSettings;
+void GameTick(double delta);
+
#endif /* PKE_GAME_HPP */
diff --git a/src/main.cpp b/src/main.cpp
index 026ddb8..b5a0697 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,6 +7,7 @@
#include <csignal>
#include "asset-manager.hpp"
+#include "ecs.hpp"
#include "game.hpp"
#include "window.hpp"
@@ -18,7 +19,7 @@ void signal_handler(int signal_num) {
PKEWindowProperties windowProps{};
void Tick(double delta) {
- /* no-op */
+ GameTick(delta);
}
int main() {
@@ -27,6 +28,7 @@ int main() {
printf("PKE ENTERING\n");
try {
AssetManagerInit();
+ ECS_Init();
CreateWindow(&windowProps);
auto steadyClock = std::chrono::steady_clock();