#include "ecs.hpp" #include TypeSafeInt_B(EntityHandle); const uint64_t maxBucketItemCount = 256; struct EntityBucket { Entity entities[maxBucketItemCount]; }; struct GrBindsBucket { CompGrBinds compGrBinds[maxBucketItemCount]; }; struct InstanceBucket { CompInstance instances[maxBucketItemCount]; }; DynArray EntitiesToBeRemoved{16}; // public DynArray entitiesMarkedForRemoval{16}; BucketContainer Entities_BucketContainer{}; BucketContainer Comp_GrBinds_BucketContainer{}; BucketContainer Comp_Instance_BucketContainer{}; void ECS_GetEntity_Inner(EntityHandle entHandle, Entity*& ent) { EntityHandle_T entHandle_t{static_cast(entHandle)}; assert(entHandle_t != EntityHandle_T_MAX && "Unknown entity handle"); auto b = Buckets_GetBucketIndex(static_cast(entHandle)); auto e = Buckets_GetItemIndex(static_cast(entHandle)); ent = &Entities_BucketContainer.buckets[b].entities[e]; } void ECS_Init() { Buckets_Init(Entities_BucketContainer); Buckets_Init(Comp_GrBinds_BucketContainer); Buckets_Init(Comp_Instance_BucketContainer); } uint64_t ECS_GetEntities_BucketCount() { return Entities_BucketContainer.bucketCounter; } Entity *ECS_GetEntities(uint64_t bucketIndex, uint64_t &itemCount) { assert(bucketIndex <= Entities_BucketContainer.bucketCounter); itemCount = bucketIndex == Entities_BucketContainer.bucketCounter ? Entities_BucketContainer.itemCounter >> 32 : maxBucketItemCount; return Entities_BucketContainer.buckets[bucketIndex].entities; } EntityHandle ECS_CreateEntity_Inner(EntityHandle parentEntHandle) { EntityHandle_T entityHandle_T{Buckets_NewHandle(maxBucketItemCount, Entities_BucketContainer)}; EntityHandle entityHandle{entityHandle_T}; auto b = Buckets_GetBucketIndex(static_cast(entityHandle)); auto e = Buckets_GetItemIndex(static_cast(entityHandle)); Entity *entity = &Entities_BucketContainer.buckets[b].entities[e]; entity = new (entity) Entity{}; entity->handle = entityHandle; entity->parentHandle = parentEntHandle; return entityHandle; } EntityHandle ECS_CreateEntity(EntityHandle parentEntHandle) { return ECS_CreateEntity_Inner(parentEntHandle); } void ECS_MarkForRemoval(EntityHandle entityHandle) { auto b = Buckets_GetBucketIndex(static_cast(entityHandle)); auto e = Buckets_GetItemIndex(static_cast(entityHandle)); const Entity *ent = &Entities_BucketContainer.buckets[b].entities[e]; assert(ent->isMarkedForRemoval == false && "Entity already marked for removal"); entitiesMarkedForRemoval.Push(entityHandle); } void ECS_Tick(double delta) { static DynArray entitiesYetToBeRemoved{0}; entitiesYetToBeRemoved.Resize(EntitiesToBeRemoved.Count()); EntitiesToBeRemoved.Resize(0); for (long b = 0; b <= Entities_BucketContainer.bucketCounter; ++b) { uint64_t entCount = b == Entities_BucketContainer.bucketCounter ? Entities_BucketContainer.itemCounter >> 32 : maxBucketItemCount; for (long e = 0; e < entCount; ++e) { Entity *ent = &Entities_BucketContainer.buckets[b].entities[e]; if (ent->handle == EntityHandle_MAX) continue; if (ent->isMarkedForRemoval) { ent->handle = EntityHandle_MAX; ent->parentHandle = EntityHandle_MAX; ent->isMarkedForRemoval = false; entitiesYetToBeRemoved[0] = *ent; } else { if (entitiesMarkedForRemoval.Has(ent->handle) || EntitiesToBeRemoved.Has(ent->parentHandle)) { ent->isMarkedForRemoval = true; EntitiesToBeRemoved.Push(ent->handle); } } } } for (long e = 0; e < entitiesYetToBeRemoved.Count(); ++e) { Entity &clonedEnt = entitiesYetToBeRemoved[e]; CompGrBinds *grBinds = nullptr; InstanceBucket *instBucket = nullptr; CompInstance *inst = nullptr; uint64_t instBucketIndex = 0; if (clonedEnt.grBindsHandle != GrBindsHandle_MAX) { GrBindsHandle_T bindsHandle_t{static_cast(clonedEnt.grBindsHandle)}; auto b = Buckets_GetBucketIndex(bindsHandle_t); auto i = Buckets_GetItemIndex(bindsHandle_t); grBinds = &Comp_GrBinds_BucketContainer.buckets[b].compGrBinds[i]; } if (grBinds != nullptr && clonedEnt.instanceHandle != InstanceHandle_MAX) { InstanceHandle_T instanceHandle_t{static_cast(clonedEnt.instanceHandle)}; auto b = Buckets_GetBucketIndex(instanceHandle_t); auto i = Buckets_GetItemIndex(instanceHandle_t); instBucket = &Comp_Instance_BucketContainer.buckets[b]; inst = &instBucket->instances[i]; instBucketIndex = b; } if (inst != nullptr) { grBinds->instances.Remove(inst->index); for (long bi = instBucketIndex; bi <= Comp_Instance_BucketContainer.bucketCounter; ++bi) { uint64_t instCounter = 0; if (bi == Comp_Instance_BucketContainer.bucketCounter) { instCounter = Comp_Instance_BucketContainer.itemCounter; } else { instCounter = maxBucketItemCount; } auto &bucket = Comp_Instance_BucketContainer.buckets[bi]; for (long ii = 0; ii < instCounter; ++ii) { if (bucket.instances[ii].grBindsHandle != clonedEnt.grBindsHandle) { continue; } if (bucket.instances[ii].instanceHandle < clonedEnt.instanceHandle) { continue; } bucket.instances[ii].index -= 1; } } inst->entHandle = EntityHandle_MAX; inst->grBindsHandle = GrBindsHandle_MAX; inst->index = ECS_UNSET_VAL; inst->instanceHandle = InstanceHandle_MAX; inst->ptr = CAFE_BABE(InstPos); } else if (grBinds != nullptr) { /* * 2023-09-05 JB note - the Vulkan assets (device memory, buffers, * pipeline layout, and descriptor set) are unloaded elsewhere, just, * as they were created elsewhere. */ DynArrayDestroy(&grBinds->instances); } } entitiesMarkedForRemoval.Resize(0); } CompGrBinds &ECS_CreateGrBinds(EntityHandle entHandle) { assert(entHandle != EntityHandle_MAX); Entity *ent = nullptr; ECS_GetEntity_Inner(entHandle, ent); assert(ent->grBindsHandle == GrBindsHandle_MAX); GrBindsHandle_T newHandle{Buckets_NewHandle(maxBucketItemCount, Comp_GrBinds_BucketContainer)}; ent->grBindsHandle = GrBindsHandle{newHandle}; auto b = Buckets_GetBucketIndex(newHandle); auto i = Buckets_GetItemIndex(newHandle); auto *comp = &Comp_GrBinds_BucketContainer.buckets[b].compGrBinds[i]; comp = new (comp) CompGrBinds{}; comp->entHandle = entHandle; comp->grBindsHandle = ent->grBindsHandle; return *comp; } CompGrBinds *ECS_GetGrBinds(EntityHandle entHandle) { Entity *ent = nullptr; ECS_GetEntity_Inner(entHandle, ent); if (ent->grBindsHandle == GrBindsHandle_MAX) return nullptr; GrBindsHandle_T grBindsHandle_t{static_cast(ent->grBindsHandle)}; auto b = Buckets_GetBucketIndex(grBindsHandle_t); auto i = Buckets_GetItemIndex(grBindsHandle_t); return &Comp_GrBinds_BucketContainer.buckets[b].compGrBinds[i]; } uint64_t ECS_GetGrBinds_BucketCount() { return Comp_GrBinds_BucketContainer.bucketCounter; } CompGrBinds *ECS_GetGrBinds(uint64_t bucketIndex, uint64_t &itemCount) { if (bucketIndex == Comp_GrBinds_BucketContainer.bucketCounter) { itemCount = Comp_GrBinds_BucketContainer.itemCounter >> 32; } else { itemCount = maxBucketItemCount; } return Comp_GrBinds_BucketContainer.buckets[bucketIndex].compGrBinds; } CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityTypeEntityHandle) { assert(entHandle != EntityHandle_MAX); assert(entityTypeEntityHandle != EntityHandle_MAX); Entity *ent = nullptr; Entity *entTypeEnt = nullptr; ECS_GetEntity_Inner(entHandle, ent); ECS_GetEntity_Inner(entityTypeEntityHandle, entTypeEnt); assert(ent->grBindsHandle == GrBindsHandle_MAX); assert(entTypeEnt->grBindsHandle != GrBindsHandle_MAX); InstanceHandle_T newHandle{Buckets_NewHandle(maxBucketItemCount, Comp_Instance_BucketContainer)}; ent->instanceHandle = InstanceHandle{newHandle}; GrBindsHandle_T grBindsHandle_t{static_cast(entTypeEnt->grBindsHandle)}; auto b2 = Buckets_GetBucketIndex(grBindsHandle_t); auto i2 = Buckets_GetItemIndex(grBindsHandle_t); auto &grBinds = Comp_GrBinds_BucketContainer.buckets[b2].compGrBinds[i2]; auto b = Buckets_GetBucketIndex(newHandle); auto i = Buckets_GetItemIndex(newHandle); auto *comp = &Comp_Instance_BucketContainer.buckets[b].instances[i]; comp = new (comp) CompInstance{}; comp->entHandle = entHandle; comp->grBindsHandle = ent->grBindsHandle; comp->instanceHandle = ent->instanceHandle; comp->index = grBinds.instances.Count(); grBinds.instances.Push({ .pos = glm::vec3(0), .rot = glm::vec3(1), .scale = glm::vec3(1), }); comp->ptr = &grBinds.instances[comp->index]; return *comp; } CompInstance *ECS_GetInstance(EntityHandle entHandle) { Entity *ent = nullptr; ECS_GetEntity_Inner(entHandle, ent); if (ent->grBindsHandle == GrBindsHandle_MAX) return nullptr; if (ent->instanceHandle == InstanceHandle_MAX) return nullptr; GrBindsHandle_T grBindsHandle_t{static_cast(ent->grBindsHandle)}; InstanceHandle_T instanceHandle_t{static_cast(ent->instanceHandle)}; auto b2 = Buckets_GetBucketIndex(grBindsHandle_t); auto i2 = Buckets_GetItemIndex(grBindsHandle_t); auto &grBinds = Comp_GrBinds_BucketContainer.buckets[b2].compGrBinds[i2]; auto b = Buckets_GetBucketIndex(instanceHandle_t); auto i = Buckets_GetItemIndex(instanceHandle_t); auto &comp = Comp_Instance_BucketContainer.buckets[b].instances[i]; if (comp.index == ECS_UNSET_VAL) return nullptr; comp.ptr = &grBinds.instances[comp.index]; return ∁ }