#ifndef BECS_H #define BECS_H #include #include #include #include typedef struct Entity Entity; typedef struct BECS_Properties BECS_Properties; typedef struct BECS_ComponentArray BECS_ComponentArray; typedef struct BECS_ECS BECS_ECS; size_t BECS_GetMinMemorySize(BECS_Properties props); BECS_ECS *BECS_Init(void *memory, size_t size, BECS_Properties props); void *BECS_AddComponent(BECS_ECS *ecs, uint32_t entityID, uint32_t componentIndex); void *BECS_GetComponent(BECS_ECS *ecs, uint32_t entityID, uint32_t componentIndex); #ifdef MAX_ENTITIES #ifdef NUM_COMPONENTS #ifdef BECS_IMPLEMENTATION #define BECS_NULL_INDEX MAX_ENTITIES + 1 struct Entity { uint64_t componentBitMask; }; struct BECS_Properties { size_t componentSizes[NUM_COMPONENTS]; }; struct BECS_ComponentArray { uint32_t lastEntityAdded; size_t unitSize; uint32_t sparseArray[MAX_ENTITIES]; void *denseArray; uint32_t denseArraylength; }; struct BECS_ECS { Entity entities[MAX_ENTITIES]; BECS_Properties props; BECS_ComponentArray componentArrays[NUM_COMPONENTS]; }; size_t BECS_GetMinMemorySize(BECS_Properties props) { size_t totalSize = 0; totalSize += sizeof(BECS_ECS); totalSize += sizeof(BECS_ComponentArray) * NUM_COMPONENTS; for (uint32_t i = 0; i < NUM_COMPONENTS; i++) { totalSize += props.componentSizes[i] * MAX_ENTITIES; } return totalSize; } BECS_ECS *BECS_Init(void *memory, size_t size, BECS_Properties props) { assert(memory); BECS_ECS *ecs = (BECS_ECS *)memory; ecs->props = props; for (uint32_t i = 0; i < NUM_COMPONENTS; i++) { ecs->componentArrays[i].lastEntityAdded = BECS_NULL_INDEX; ecs->componentArrays[i].unitSize = props.componentSizes[i]; ecs->componentArrays[i].denseArraylength = 0; for (uint32_t j = 0; j < MAX_ENTITIES; j++) { ecs->componentArrays[i].sparseArray[j] = BECS_NULL_INDEX; } } uintptr_t startOfComponentArrays = (uintptr_t)(ecs + 1); for (uint32_t i = 0; i < NUM_COMPONENTS; i++) { startOfComponentArrays += props.componentSizes[i] * MAX_ENTITIES; ecs->componentArrays[i].denseArray = (void *)startOfComponentArrays; } return ecs; } void *BECS_AddComponent(BECS_ECS *ecs, uint32_t entityID, uint32_t componentIndex) { if (entityID > MAX_ENTITIES) { return NULL; } uint64_t componentBitMask = 0 | (1 << (componentIndex + 1)); if (ecs->entities[entityID].componentBitMask & componentBitMask) { return NULL; } ecs->entities[entityID].componentBitMask |= componentBitMask; BECS_ComponentArray *componentArray = &ecs->componentArrays[componentIndex]; componentArray->sparseArray[entityID] = componentArray->denseArraylength; size_t componentSize = ecs->props.componentSizes[componentIndex]; uint32_t componentOffset = componentSize * componentArray->sparseArray[entityID]; void *component = (void *)((uintptr_t)componentArray->denseArray + componentOffset); componentArray->denseArraylength++; componentArray->lastEntityAdded = entityID; return component; } int32_t BECS_RemoveComponent(BECS_ECS *ecs, uint32_t entityID, uint32_t componentIndex) { assert(entityID < MAX_ENTITIES); uint64_t componentBitMask = 0 | (1 << (componentIndex + 1)); if (!(ecs->entities[entityID].componentBitMask & componentBitMask)) { return 2; } BECS_ComponentArray * componentArray = &ecs->componentArrays[componentIndex]; if (entityID == componentArray->lastEntityAdded) { componentArray->sparseArray[entityID] = BECS_NULL_INDEX; componentArray->denseArraylength--; for (uint32_t i = 0; i < MAX_ENTITIES; i++) { if (componentArray->sparseArray[i] == componentArray->denseArraylength - 1) { componentArray->lastEntityAdded = componentArray->sparseArray[i]; break; } } ecs->entities[entityID].componentBitMask &= ~(1 << (componentIndex + 1)); return 0; } uint32_t lastEntityAddedIndex = componentArray->sparseArray[componentArray->lastEntityAdded]; uint32_t deletedCompIndex = componentArray->sparseArray[entityID]; uintptr_t denseArray = (uintptr_t)componentArray->denseArray; uintptr_t lastEntityAdded = denseArray + (lastEntityAddedIndex * componentArray->unitSize); uintptr_t deletedComp = denseArray + (lastEntityAddedIndex * componentArray->unitSize); memcpy((void *)deletedComp, (void*)lastEntityAdded, componentArray->unitSize); componentArray->sparseArray[entityID] = lastEntityAddedIndex; componentArray->denseArraylength--; ecs->entities[entityID].componentBitMask &= ~(1 << (componentIndex + 1)); return 0; } void *BECS_GetComponent(BECS_ECS *ecs, uint32_t entityID, uint32_t componentIndex) { assert(entityID < MAX_ENTITIES); assert(componentIndex < NUM_COMPONENTS); void *component = NULL; BECS_ComponentArray *componentArray = &ecs->componentArrays[componentIndex]; uint32_t componentDenseIndex = componentArray->sparseArray[entityID]; if (componentDenseIndex == BECS_NULL_INDEX) { return component; } else { size_t componentSize = componentArray->unitSize; component = (void *)((uintptr_t)componentArray->denseArray + (componentSize * componentDenseIndex)); } return component; } #endif #endif #endif #endif