Update: Merge all versions into becs.h
This commit is contained in:
parent
af9cc43bfa
commit
8d26a42db1
433
becs.h
433
becs.h
|
|
@ -1,137 +1,390 @@
|
||||||
|
/*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* Define BECS_MAX_ENTITIES and BECS_MAX_COMPONENTS. Otherwise they will have
|
||||||
|
* the following defaults:
|
||||||
|
*
|
||||||
|
* #define BECS_MAX_ENTITIES 4096
|
||||||
|
* #define BECS_MAX_COMPONENTS 64
|
||||||
|
*
|
||||||
|
* Then define BECS_IMPLEMENTATION in exactly _one_ file before including this
|
||||||
|
* file as follows:
|
||||||
|
*
|
||||||
|
* #define BECS_IMPLEMENTATION
|
||||||
|
* #include "becs.h"
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef BECS_H
|
#ifndef BECS_H
|
||||||
#define BECS_H
|
#define BECS_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef struct BECS_ComponentArray BECS_ComponentArray;
|
#ifdef BECS_SLOW
|
||||||
typedef struct BECS_Properties BECS_Properties;
|
#include <assert.h>
|
||||||
|
#else
|
||||||
|
#define assert(expression)
|
||||||
|
#endif /* BECS_SLOW */
|
||||||
|
|
||||||
|
typedef struct BECS_Arena BECS_Arena;
|
||||||
|
typedef struct BECS_ComponentPool BECS_ComponentPool;
|
||||||
typedef struct BECS_ECS BECS_ECS;
|
typedef struct BECS_ECS BECS_ECS;
|
||||||
|
|
||||||
size_t BECS_GetMinMemorySize(BECS_Properties props);
|
typedef uint32_t BECS_Entity;
|
||||||
BECS_ECS *BECS_Init(void *memory, size_t size, BECS_Properties *props);
|
typedef uint32_t BECS_ComponentID;
|
||||||
int32_t BECS_AddComponent(BECS_ECS *ecs, uint32_t entityID, uint64_t componentBitMask, void *component);
|
|
||||||
|
|
||||||
#define MAX_ENTITY_COUNT 100
|
size_t BECS_GetMinMemoryArenaSize(size_t *componentSizes, size_t arrayLength);
|
||||||
|
BECS_ECS BECS_InitECS(void *memory, size_t size);
|
||||||
|
void BECS_ResetECS(BECS_ECS *ecs);
|
||||||
|
|
||||||
|
BECS_Entity BECS_EntityCreate(BECS_ECS *ecs);
|
||||||
|
void BECS_EntityDestroy(BECS_ECS *ecs, BECS_Entity entity);
|
||||||
|
bool BECS_IsEntityAlive(BECS_ECS *ecs, BECS_Entity entity);
|
||||||
|
|
||||||
|
BECS_ComponentID BECS_ComponentRegister(BECS_ECS *ecs, size_t componentSize, size_t maximumComponentCount);
|
||||||
|
void *BECS_ComponentAdd(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId);
|
||||||
|
void BECS_ComponentRemove(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId);
|
||||||
|
void *BECS_ComponentGet(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId);
|
||||||
|
bool BECS_ComponentHas(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId);
|
||||||
|
|
||||||
#ifdef BECS_IMPLEMENTATION
|
#ifdef BECS_IMPLEMENTATION
|
||||||
#ifdef MAX_ENTITY_COUNT
|
|
||||||
|
|
||||||
struct BECS_ComponentArray {
|
#ifndef BECS_MAX_ENTITIES
|
||||||
uint32_t lastEntityAdded;
|
#define BECS_MAX_ENTITIES 4096
|
||||||
size_t unitSize;
|
#endif /* BECS_MAX_ENTITIES */
|
||||||
uint32_t length;
|
|
||||||
uint32_t capacity;
|
#ifndef BECS_MAX_COMPONENTS
|
||||||
void *array;
|
#define BECS_MAX_COMPONENTS 64
|
||||||
|
#endif /* BECS_MAX_COMPONENTS */
|
||||||
|
|
||||||
|
#define BECS_NULL_ENTITY BECS_MAX_COMPONENTS + 1
|
||||||
|
#define BECS_INVALID_COMPONENT_ID UINT32_MAX
|
||||||
|
|
||||||
|
typedef uint64_t BECS_Signature;
|
||||||
|
|
||||||
|
struct BECS_Arena {
|
||||||
|
uintptr_t nextAllocation;
|
||||||
|
size_t capacity;
|
||||||
|
void *memory;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BECS_Properties {
|
struct BECS_ComponentPool {
|
||||||
uint32_t maxEntities;
|
size_t unitSize;
|
||||||
uint32_t numComponents;
|
size_t capacity;
|
||||||
size_t *componentSizes;
|
size_t count;
|
||||||
|
uint32_t sparseArray[BECS_MAX_ENTITIES];
|
||||||
|
void *denseArray;
|
||||||
|
BECS_Entity *denseEntityMapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BECS_ECS {
|
struct BECS_ECS {
|
||||||
uint64_t *bitMasks;
|
BECS_Arena arena;
|
||||||
BECS_Properties props;
|
|
||||||
BECS_ComponentArray *componentSets;
|
/* Entity Management */
|
||||||
|
BECS_Entity nextEntity;
|
||||||
|
uint32_t entityCount;
|
||||||
|
BECS_Signature entitySignatures[BECS_MAX_ENTITIES];
|
||||||
|
bool aliveEntites[BECS_MAX_ENTITIES];
|
||||||
|
|
||||||
|
BECS_Entity freeEntities[BECS_MAX_ENTITIES];
|
||||||
|
uint32_t freeEntityCount;
|
||||||
|
|
||||||
|
/* Component Management */
|
||||||
|
uint32_t componentTypeCount;
|
||||||
|
BECS_ComponentPool componentPools[BECS_MAX_COMPONENTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t BECS_GetMinMemorySize
|
/* Signature Helpers */
|
||||||
(BECS_Properties props)
|
static BECS_Signature BECS_SignatureSet(BECS_Signature sig, BECS_ComponentID componentId)
|
||||||
{
|
{
|
||||||
|
return sig | (1ULL << componentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool BECS_SignatureHas(BECS_Signature sig, BECS_ComponentID component_id)
|
||||||
|
{
|
||||||
|
return (sig & (1ULL << component_id)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool BECS_SignatureMatches(BECS_Signature entitySig, BECS_Signature querySig)
|
||||||
|
{
|
||||||
|
return (entitySig & querySig) == querySig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Memory Arena */
|
||||||
|
|
||||||
|
BECS_Arena BECS_CreateArena(void *memory, size_t capacity)
|
||||||
|
{
|
||||||
|
uintptr_t baseOffset = 64 - ((uintptr_t)memory % 64);
|
||||||
|
BECS_Arena arena = {
|
||||||
|
baseOffset,
|
||||||
|
capacity,
|
||||||
|
memory
|
||||||
|
};
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *BECS_AllocateMemory(BECS_Arena *arena, size_t size)
|
||||||
|
{
|
||||||
|
size_t totalSizeBytes = size;
|
||||||
|
uintptr_t nextAllocOffset = arena->nextAllocation + ((64 - (arena->nextAllocation % 64)) & 63);
|
||||||
|
if (nextAllocOffset + totalSizeBytes <= arena->capacity)
|
||||||
|
{
|
||||||
|
arena->nextAllocation = nextAllocOffset + totalSizeBytes;
|
||||||
|
return (void *)((uintptr_t)arena->memory + (uintptr_t)nextAllocOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Component Pool Backend */
|
||||||
|
|
||||||
|
static void BECS_ComponentPoolInit
|
||||||
|
(BECS_Arena *arena, BECS_ComponentPool *pool ,size_t componentSize, size_t capacity)
|
||||||
|
{
|
||||||
|
pool->unitSize = componentSize;
|
||||||
|
pool->capacity = capacity;
|
||||||
|
pool->count = 0;
|
||||||
|
|
||||||
|
pool->denseArray = BECS_AllocateMemory(arena, componentSize * capacity);
|
||||||
|
pool->denseEntityMapping = (BECS_Entity *)BECS_AllocateMemory(arena, sizeof(BECS_Entity) * capacity);
|
||||||
|
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < BECS_MAX_ENTITIES; i++)
|
||||||
|
{
|
||||||
|
pool->sparseArray[i] = UINT32_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *BECS_ComponentPoolAdd(BECS_ComponentPool *pool, BECS_Entity entity)
|
||||||
|
{
|
||||||
|
uint32_t index = pool->count;
|
||||||
|
pool->count++;
|
||||||
|
pool->denseEntityMapping[index] = entity;
|
||||||
|
pool->sparseArray[entity] = index;
|
||||||
|
|
||||||
|
return (uint8_t *)pool->denseArray + (index * pool->unitSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void BECS_ComponentPoolRemove(BECS_ComponentPool *pool, BECS_Entity entity)
|
||||||
|
{
|
||||||
|
uint32_t index = pool->sparseArray[entity];
|
||||||
|
if (index == UINT32_MAX)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t last_index = pool->count - 1;
|
||||||
|
BECS_Entity last_entity = pool->denseEntityMapping[last_index];
|
||||||
|
|
||||||
|
if (index != last_index)
|
||||||
|
{
|
||||||
|
void *dst = (uint8_t *)pool->denseArray + (index * pool->unitSize);
|
||||||
|
void *src = (uint8_t *)pool->denseArray + (last_index * pool->unitSize);
|
||||||
|
memcpy(dst, src, pool->unitSize);
|
||||||
|
|
||||||
|
pool->denseEntityMapping[index] = last_entity;
|
||||||
|
pool->sparseArray[last_entity] = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->sparseArray[entity] = UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *BECS_ComponentPoolGet(BECS_ComponentPool *pool, BECS_Entity entity)
|
||||||
|
{
|
||||||
|
uint32_t index = pool->sparseArray[entity];
|
||||||
|
if (index == UINT32_MAX)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (uint8_t *)pool->denseArray + (index * pool->unitSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool BECS_ComponentPoolHas(BECS_ComponentPool *pool, BECS_Entity entity)
|
||||||
|
{
|
||||||
|
return pool->sparseArray[entity] != UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper API Functions */
|
||||||
|
|
||||||
|
size_t BECS_GetMinMemoryArenaSize(size_t *componentSizes, size_t arrayLength)
|
||||||
|
{
|
||||||
|
assert(arrayLength < BECS_MAX_COMPONENTS);
|
||||||
size_t totalSize = 0;
|
size_t totalSize = 0;
|
||||||
totalSize += sizeof(BECS_ECS);
|
totalSize += sizeof(BECS_ECS);
|
||||||
totalSize += sizeof(BECS_ComponentArray) * props.numComponents;
|
totalSize += sizeof(BECS_ComponentPool) * BECS_MAX_COMPONENTS;
|
||||||
for (uint32_t i = 0; i < props.numComponents; i++)
|
totalSize += sizeof(BECS_Entity) * BECS_MAX_ENTITIES * BECS_MAX_COMPONENTS;
|
||||||
|
|
||||||
|
size_t sumCompSizes = 0;
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < arrayLength; i++)
|
||||||
{
|
{
|
||||||
totalSize += props.componentSizes[i] * props.maxEntities;
|
sumCompSizes += componentSizes[i];
|
||||||
totalSize += sizeof(uint64_t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sumCompSizes *= BECS_MAX_ENTITIES;
|
||||||
|
totalSize += sumCompSizes;
|
||||||
|
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
BECS_ECS *BECS_Init
|
/* World API Functions */
|
||||||
(void *memory, size_t size, BECS_Properties *props)
|
|
||||||
{
|
|
||||||
BECS_ECS *ecs = (BECS_ECS *)memory;
|
|
||||||
uint64_t *bitMasks = (uint64_t *)(ecs + 1);
|
|
||||||
BECS_ComponentArray *componentSets = (BECS_ComponentArray *)((uint8_t *)(ecs + 1) + props->maxEntities);
|
|
||||||
ecs->bitMasks = bitMasks;
|
|
||||||
ecs->componentSets = componentSets;
|
|
||||||
ecs->props = *props;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < props->maxEntities; i++)
|
BECS_ECS BECS_InitECS(void *memory, size_t size)
|
||||||
{
|
{
|
||||||
ecs->bitMasks[i] = 0;
|
BECS_ECS ecs;
|
||||||
|
ecs.arena = BECS_CreateArena(memory, size);
|
||||||
|
ecs.entityCount = 0;
|
||||||
|
memset(ecs.entitySignatures, 0, sizeof(BECS_Signature) * BECS_MAX_ENTITIES);
|
||||||
|
memset(ecs.aliveEntites, false, sizeof(bool) * BECS_MAX_ENTITIES);
|
||||||
|
memset(ecs.freeEntities, BECS_NULL_ENTITY, sizeof(BECS_Entity) * BECS_MAX_ENTITIES);
|
||||||
|
ecs.freeEntityCount = 0;
|
||||||
|
ecs.nextEntity = 0;
|
||||||
|
|
||||||
|
ecs.componentTypeCount = 0;
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < BECS_MAX_COMPONENTS; i++)
|
||||||
|
{
|
||||||
|
ecs.componentPools[i].denseArray = NULL;
|
||||||
|
ecs.componentPools[i].denseEntityMapping = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < props->numComponents; i++)
|
|
||||||
{
|
|
||||||
ecs->componentSets[i].unitSize = props->componentSizes[i];
|
|
||||||
ecs->componentSets[i].capacity = ecs->componentSets[i].unitSize * props->maxEntities;
|
|
||||||
ecs->componentSets[i].lastEntityAdded = props->maxEntities + 1;
|
|
||||||
ecs->componentSets[i].length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t index = 0;
|
|
||||||
|
|
||||||
// FIX: This is completely fucked. I feel like I am overcomplicating this... Might be easier to use a defined constant :/
|
|
||||||
for (uint32_t i = 0; i < props->numComponents; i++)
|
|
||||||
{
|
|
||||||
uint32_t index = i;
|
|
||||||
if (index - 1 > props->numComponents)
|
|
||||||
{
|
|
||||||
index = 1;
|
|
||||||
}
|
|
||||||
ecs->componentSets[index - 1].array = componentSets + 4;
|
|
||||||
}
|
|
||||||
return ecs;
|
return ecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
void BECS_ResetECS(BECS_ECS *ecs)
|
||||||
BECS_AddComponent(BECS_ECS *ecs, uint32_t entityID, uint64_t componentBitMask, void *component)
|
|
||||||
{
|
{
|
||||||
int32_t result = 0;
|
ecs->arena = BECS_CreateArena(ecs->arena.memory, ecs->arena.capacity);
|
||||||
if (componentBitMask == 0)
|
ecs->entityCount = 0;
|
||||||
|
memset(ecs->entitySignatures, 0, sizeof(BECS_Signature) * BECS_MAX_ENTITIES);
|
||||||
|
memset(ecs->aliveEntites, false, sizeof(bool) * BECS_MAX_ENTITIES);
|
||||||
|
memset(ecs->freeEntities, BECS_NULL_ENTITY, sizeof(BECS_Entity) * BECS_MAX_ENTITIES);
|
||||||
|
ecs->freeEntityCount = 0;
|
||||||
|
ecs->nextEntity = 0;
|
||||||
|
|
||||||
|
ecs->componentTypeCount = 0;
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < BECS_MAX_COMPONENTS; i++)
|
||||||
{
|
{
|
||||||
return result;
|
ecs->componentPools[i].denseArray = NULL;
|
||||||
|
ecs->componentPools[i].denseEntityMapping = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t componentType = 0;
|
/* Entity API Functions */
|
||||||
while (!(componentBitMask & 1))
|
|
||||||
|
BECS_Entity BECS_EntityCreate(BECS_ECS *ecs)
|
||||||
{
|
{
|
||||||
componentBitMask >>= 1;
|
BECS_Entity entity = BECS_NULL_ENTITY;
|
||||||
componentType++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ecs->bitMasks[entityID] = ecs->bitMasks[entityID] | componentBitMask;
|
if (ecs->nextEntity + 1 > BECS_NULL_ENTITY)
|
||||||
uint32_t insertIndex = ecs->componentSets[componentType].length;
|
|
||||||
if (insertIndex > ecs->props.maxEntities)
|
|
||||||
{
|
{
|
||||||
return result;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t componentSize = ecs->props.componentSizes[componentType];
|
if (ecs->freeEntityCount)
|
||||||
uint8_t *componentArray = (uint8_t *)ecs->componentSets[componentType].array;
|
|
||||||
uint8_t *source = (uint8_t *)component;
|
|
||||||
componentArray += componentSize;
|
|
||||||
while (componentSize > 0)
|
|
||||||
{
|
{
|
||||||
*componentArray = *source;
|
/* Pop entity off the back of the free list */
|
||||||
componentSize--;
|
entity = ecs->freeEntities[--ecs->freeEntityCount];
|
||||||
}
|
ecs->entitySignatures[entity] = 0;
|
||||||
ecs->componentSets[componentType].length++;
|
ecs->aliveEntites[entity] = true;
|
||||||
result = 1;
|
return entity;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int32_t
|
entity = ecs->nextEntity;
|
||||||
// BECS_RemoveComponent()
|
ecs->aliveEntites[entity] = true;
|
||||||
// {
|
ecs->entitySignatures[entity] = 0;
|
||||||
// }
|
ecs->nextEntity++;
|
||||||
#endif
|
ecs->entityCount++;
|
||||||
#endif
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
void BECS_EntityDestroy(BECS_ECS *ecs, BECS_Entity entity)
|
||||||
|
{
|
||||||
|
if (!ecs->aliveEntites[entity])
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < BECS_MAX_COMPONENTS; i++)
|
||||||
|
{
|
||||||
|
BECS_Signature sig = ecs->entitySignatures[entity];
|
||||||
|
if (BECS_SignatureHas(sig, i))
|
||||||
|
{
|
||||||
|
BECS_ComponentRemove(ecs, entity, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ecs->aliveEntites[entity] = false;
|
||||||
|
ecs->entitySignatures[entity] = 0;
|
||||||
|
ecs->freeEntities[ecs->freeEntityCount] = entity;
|
||||||
|
ecs->entityCount--;
|
||||||
|
ecs->freeEntityCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BECS_IsEntityAlive(BECS_ECS *ecs, BECS_Entity entity)
|
||||||
|
{
|
||||||
|
return ecs->aliveEntites[entity];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Component API Functions */
|
||||||
|
|
||||||
|
BECS_ComponentID BECS_ComponentRegister(BECS_ECS *ecs, size_t componentSize, size_t maximumComponentCount)
|
||||||
|
{
|
||||||
|
if (maximumComponentCount == 0)
|
||||||
|
{
|
||||||
|
maximumComponentCount = BECS_MAX_ENTITIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
BECS_ComponentID id = ecs->componentTypeCount;
|
||||||
|
BECS_ComponentPoolInit(&ecs->arena, &ecs->componentPools[id],
|
||||||
|
componentSize, maximumComponentCount);
|
||||||
|
ecs->componentTypeCount++;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *BECS_ComponentAdd(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId)
|
||||||
|
{
|
||||||
|
void *component = BECS_ComponentPoolAdd(&ecs->componentPools[componentId], entity);
|
||||||
|
ecs->entitySignatures[entity] = BECS_SignatureSet(ecs->entitySignatures[entity], componentId);
|
||||||
|
memset(component, 0, ecs->componentPools[componentId].unitSize);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BECS_ComponentRemove(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId)
|
||||||
|
{
|
||||||
|
if (!ecs->aliveEntites[entity])
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BECS_ComponentPoolRemove(&ecs->componentPools[componentId], entity);
|
||||||
|
ecs->entitySignatures[entity] &= ~(1ULL << componentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *BECS_ComponentGet(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ecs->aliveEntites[entity])
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return BECS_ComponentPoolGet(&ecs->componentPools[componentId], entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BECS_ComponentHas(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId)
|
||||||
|
{
|
||||||
|
if (!ecs->aliveEntites[entity])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return BECS_SignatureHas(ecs->entitySignatures[entity], componentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BECS_IMPLEMENTATION */
|
||||||
|
#endif /* BECS_H */
|
||||||
|
|
|
||||||
185
becs2.h
185
becs2.h
|
|
@ -1,185 +0,0 @@
|
||||||
#ifndef BECS_H
|
|
||||||
#define BECS_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
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
|
|
||||||
390
becs3.h
390
becs3.h
|
|
@ -1,390 +0,0 @@
|
||||||
/*
|
|
||||||
* Usage:
|
|
||||||
*
|
|
||||||
* Define BECS_MAX_ENTITIES and BECS_MAX_COMPONENTS. Otherwise they will have
|
|
||||||
* the following defaults:
|
|
||||||
*
|
|
||||||
* #define BECS_MAX_ENTITIES 4096
|
|
||||||
* #define BECS_MAX_COMPONENTS 64
|
|
||||||
*
|
|
||||||
* Then define BECS_IMPLEMENTATION in exactly _one_ file before including this
|
|
||||||
* file as follows:
|
|
||||||
*
|
|
||||||
* #define BECS_IMPLEMENTATION
|
|
||||||
* #include "becs.h"
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BECS_H
|
|
||||||
#define BECS_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#ifdef BECS_SLOW
|
|
||||||
#include <assert.h>
|
|
||||||
#else
|
|
||||||
#define assert(expression)
|
|
||||||
#endif /* BECS_SLOW */
|
|
||||||
|
|
||||||
typedef struct BECS_Arena BECS_Arena;
|
|
||||||
typedef struct BECS_ComponentPool BECS_ComponentPool;
|
|
||||||
typedef struct BECS_ECS BECS_ECS;
|
|
||||||
|
|
||||||
typedef uint32_t BECS_Entity;
|
|
||||||
typedef uint32_t BECS_ComponentID;
|
|
||||||
|
|
||||||
size_t BECS_GetMinMemoryArenaSize(size_t *componentSizes, size_t arrayLength);
|
|
||||||
BECS_ECS BECS_InitECS(void *memory, size_t size);
|
|
||||||
void BECS_ResetECS(BECS_ECS *ecs);
|
|
||||||
|
|
||||||
BECS_Entity BECS_EntityCreate(BECS_ECS *ecs);
|
|
||||||
void BECS_EntityDestroy(BECS_ECS *ecs, BECS_Entity entity);
|
|
||||||
bool BECS_IsEntityAlive(BECS_ECS *ecs, BECS_Entity entity);
|
|
||||||
|
|
||||||
BECS_ComponentID BECS_ComponentRegister(BECS_ECS *ecs, size_t componentSize, size_t maximumComponentCount);
|
|
||||||
void *BECS_ComponentAdd(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId);
|
|
||||||
void BECS_ComponentRemove(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId);
|
|
||||||
void *BECS_ComponentGet(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId);
|
|
||||||
bool BECS_ComponentHas(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId);
|
|
||||||
|
|
||||||
#ifdef BECS_IMPLEMENTATION
|
|
||||||
|
|
||||||
#ifndef BECS_MAX_ENTITIES
|
|
||||||
#define BECS_MAX_ENTITIES 4096
|
|
||||||
#endif /* BECS_MAX_ENTITIES */
|
|
||||||
|
|
||||||
#ifndef BECS_MAX_COMPONENTS
|
|
||||||
#define BECS_MAX_COMPONENTS 64
|
|
||||||
#endif /* BECS_MAX_COMPONENTS */
|
|
||||||
|
|
||||||
#define BECS_NULL_ENTITY BECS_MAX_COMPONENTS + 1
|
|
||||||
#define BECS_INVALID_COMPONENT_ID UINT32_MAX
|
|
||||||
|
|
||||||
typedef uint64_t BECS_Signature;
|
|
||||||
|
|
||||||
struct BECS_Arena {
|
|
||||||
uintptr_t nextAllocation;
|
|
||||||
size_t capacity;
|
|
||||||
void *memory;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BECS_ComponentPool {
|
|
||||||
size_t unitSize;
|
|
||||||
size_t capacity;
|
|
||||||
size_t count;
|
|
||||||
uint32_t sparseArray[BECS_MAX_ENTITIES];
|
|
||||||
void *denseArray;
|
|
||||||
BECS_Entity *denseEntityMapping;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BECS_ECS {
|
|
||||||
BECS_Arena arena;
|
|
||||||
|
|
||||||
/* Entity Management */
|
|
||||||
BECS_Entity nextEntity;
|
|
||||||
uint32_t entityCount;
|
|
||||||
BECS_Signature entitySignatures[BECS_MAX_ENTITIES];
|
|
||||||
bool aliveEntites[BECS_MAX_ENTITIES];
|
|
||||||
|
|
||||||
BECS_Entity freeEntities[BECS_MAX_ENTITIES];
|
|
||||||
uint32_t freeEntityCount;
|
|
||||||
|
|
||||||
/* Component Management */
|
|
||||||
uint32_t componentTypeCount;
|
|
||||||
BECS_ComponentPool componentPools[BECS_MAX_COMPONENTS];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Signature Helpers */
|
|
||||||
static BECS_Signature BECS_SignatureSet(BECS_Signature sig, BECS_ComponentID componentId)
|
|
||||||
{
|
|
||||||
return sig | (1ULL << componentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BECS_SignatureHas(BECS_Signature sig, BECS_ComponentID component_id)
|
|
||||||
{
|
|
||||||
return (sig & (1ULL << component_id)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BECS_SignatureMatches(BECS_Signature entitySig, BECS_Signature querySig)
|
|
||||||
{
|
|
||||||
return (entitySig & querySig) == querySig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Memory Arena */
|
|
||||||
|
|
||||||
BECS_Arena BECS_CreateArena(void *memory, size_t capacity)
|
|
||||||
{
|
|
||||||
uintptr_t baseOffset = 64 - ((uintptr_t)memory % 64);
|
|
||||||
BECS_Arena arena = {
|
|
||||||
baseOffset,
|
|
||||||
capacity,
|
|
||||||
memory
|
|
||||||
};
|
|
||||||
return arena;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *BECS_AllocateMemory(BECS_Arena *arena, size_t size)
|
|
||||||
{
|
|
||||||
size_t totalSizeBytes = size;
|
|
||||||
uintptr_t nextAllocOffset = arena->nextAllocation + ((64 - (arena->nextAllocation % 64)) & 63);
|
|
||||||
if (nextAllocOffset + totalSizeBytes <= arena->capacity)
|
|
||||||
{
|
|
||||||
arena->nextAllocation = nextAllocOffset + totalSizeBytes;
|
|
||||||
return (void *)((uintptr_t)arena->memory + (uintptr_t)nextAllocOffset);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Component Pool Backend */
|
|
||||||
|
|
||||||
static void BECS_ComponentPoolInit
|
|
||||||
(BECS_Arena *arena, BECS_ComponentPool *pool ,size_t componentSize, size_t capacity)
|
|
||||||
{
|
|
||||||
pool->unitSize = componentSize;
|
|
||||||
pool->capacity = capacity;
|
|
||||||
pool->count = 0;
|
|
||||||
|
|
||||||
pool->denseArray = BECS_AllocateMemory(arena, componentSize * capacity);
|
|
||||||
pool->denseEntityMapping = (BECS_Entity *)BECS_AllocateMemory(arena, sizeof(BECS_Entity) * capacity);
|
|
||||||
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < BECS_MAX_ENTITIES; i++)
|
|
||||||
{
|
|
||||||
pool->sparseArray[i] = UINT32_MAX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *BECS_ComponentPoolAdd(BECS_ComponentPool *pool, BECS_Entity entity)
|
|
||||||
{
|
|
||||||
uint32_t index = pool->count;
|
|
||||||
pool->count++;
|
|
||||||
pool->denseEntityMapping[index] = entity;
|
|
||||||
pool->sparseArray[entity] = index;
|
|
||||||
|
|
||||||
return (uint8_t *)pool->denseArray + (index * pool->unitSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void BECS_ComponentPoolRemove(BECS_ComponentPool *pool, BECS_Entity entity)
|
|
||||||
{
|
|
||||||
uint32_t index = pool->sparseArray[entity];
|
|
||||||
if (index == UINT32_MAX)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t last_index = pool->count - 1;
|
|
||||||
BECS_Entity last_entity = pool->denseEntityMapping[last_index];
|
|
||||||
|
|
||||||
if (index != last_index)
|
|
||||||
{
|
|
||||||
void *dst = (uint8_t *)pool->denseArray + (index * pool->unitSize);
|
|
||||||
void *src = (uint8_t *)pool->denseArray + (last_index * pool->unitSize);
|
|
||||||
memcpy(dst, src, pool->unitSize);
|
|
||||||
|
|
||||||
pool->denseEntityMapping[index] = last_entity;
|
|
||||||
pool->sparseArray[last_entity] = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
pool->sparseArray[entity] = UINT32_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *BECS_ComponentPoolGet(BECS_ComponentPool *pool, BECS_Entity entity)
|
|
||||||
{
|
|
||||||
uint32_t index = pool->sparseArray[entity];
|
|
||||||
if (index == UINT32_MAX)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (uint8_t *)pool->denseArray + (index * pool->unitSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BECS_ComponentPoolHas(BECS_ComponentPool *pool, BECS_Entity entity)
|
|
||||||
{
|
|
||||||
return pool->sparseArray[entity] != UINT32_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helper API Functions */
|
|
||||||
|
|
||||||
size_t BECS_GetMinMemoryArenaSize(size_t *componentSizes, size_t arrayLength)
|
|
||||||
{
|
|
||||||
assert(arrayLength < BECS_MAX_COMPONENTS);
|
|
||||||
size_t totalSize = 0;
|
|
||||||
totalSize += sizeof(BECS_ECS);
|
|
||||||
totalSize += sizeof(BECS_ComponentPool) * BECS_MAX_COMPONENTS;
|
|
||||||
totalSize += sizeof(BECS_Entity) * BECS_MAX_ENTITIES * BECS_MAX_COMPONENTS;
|
|
||||||
|
|
||||||
size_t sumCompSizes = 0;
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < arrayLength; i++)
|
|
||||||
{
|
|
||||||
sumCompSizes += componentSizes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
sumCompSizes *= BECS_MAX_ENTITIES;
|
|
||||||
totalSize += sumCompSizes;
|
|
||||||
|
|
||||||
return totalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* World API Functions */
|
|
||||||
|
|
||||||
BECS_ECS BECS_InitECS(void *memory, size_t size)
|
|
||||||
{
|
|
||||||
BECS_ECS ecs;
|
|
||||||
ecs.arena = BECS_CreateArena(memory, size);
|
|
||||||
ecs.entityCount = 0;
|
|
||||||
memset(ecs.entitySignatures, 0, sizeof(BECS_Signature) * BECS_MAX_ENTITIES);
|
|
||||||
memset(ecs.aliveEntites, false, sizeof(bool) * BECS_MAX_ENTITIES);
|
|
||||||
memset(ecs.freeEntities, BECS_NULL_ENTITY, sizeof(BECS_Entity) * BECS_MAX_ENTITIES);
|
|
||||||
ecs.freeEntityCount = 0;
|
|
||||||
ecs.nextEntity = 0;
|
|
||||||
|
|
||||||
ecs.componentTypeCount = 0;
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < BECS_MAX_COMPONENTS; i++)
|
|
||||||
{
|
|
||||||
ecs.componentPools[i].denseArray = NULL;
|
|
||||||
ecs.componentPools[i].denseEntityMapping = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ecs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BECS_ResetECS(BECS_ECS *ecs)
|
|
||||||
{
|
|
||||||
ecs->arena = BECS_CreateArena(ecs->arena.memory, ecs->arena.capacity);
|
|
||||||
ecs->entityCount = 0;
|
|
||||||
memset(ecs->entitySignatures, 0, sizeof(BECS_Signature) * BECS_MAX_ENTITIES);
|
|
||||||
memset(ecs->aliveEntites, false, sizeof(bool) * BECS_MAX_ENTITIES);
|
|
||||||
memset(ecs->freeEntities, BECS_NULL_ENTITY, sizeof(BECS_Entity) * BECS_MAX_ENTITIES);
|
|
||||||
ecs->freeEntityCount = 0;
|
|
||||||
ecs->nextEntity = 0;
|
|
||||||
|
|
||||||
ecs->componentTypeCount = 0;
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < BECS_MAX_COMPONENTS; i++)
|
|
||||||
{
|
|
||||||
ecs->componentPools[i].denseArray = NULL;
|
|
||||||
ecs->componentPools[i].denseEntityMapping = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Entity API Functions */
|
|
||||||
|
|
||||||
BECS_Entity BECS_EntityCreate(BECS_ECS *ecs)
|
|
||||||
{
|
|
||||||
BECS_Entity entity = BECS_NULL_ENTITY;
|
|
||||||
|
|
||||||
if (ecs->nextEntity + 1 > BECS_NULL_ENTITY)
|
|
||||||
{
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ecs->freeEntityCount)
|
|
||||||
{
|
|
||||||
/* Pop entity off the back of the free list */
|
|
||||||
entity = ecs->freeEntities[--ecs->freeEntityCount];
|
|
||||||
ecs->entitySignatures[entity] = 0;
|
|
||||||
ecs->aliveEntites[entity] = true;
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
entity = ecs->nextEntity;
|
|
||||||
ecs->aliveEntites[entity] = true;
|
|
||||||
ecs->entitySignatures[entity] = 0;
|
|
||||||
ecs->nextEntity++;
|
|
||||||
ecs->entityCount++;
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BECS_EntityDestroy(BECS_ECS *ecs, BECS_Entity entity)
|
|
||||||
{
|
|
||||||
if (!ecs->aliveEntites[entity])
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < BECS_MAX_COMPONENTS; i++)
|
|
||||||
{
|
|
||||||
BECS_Signature sig = ecs->entitySignatures[entity];
|
|
||||||
if (BECS_SignatureHas(sig, i))
|
|
||||||
{
|
|
||||||
BECS_ComponentRemove(ecs, entity, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ecs->aliveEntites[entity] = false;
|
|
||||||
ecs->entitySignatures[entity] = 0;
|
|
||||||
ecs->freeEntities[ecs->freeEntityCount] = entity;
|
|
||||||
ecs->entityCount--;
|
|
||||||
ecs->freeEntityCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BECS_IsEntityAlive(BECS_ECS *ecs, BECS_Entity entity)
|
|
||||||
{
|
|
||||||
return ecs->aliveEntites[entity];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Component API Functions */
|
|
||||||
|
|
||||||
BECS_ComponentID BECS_ComponentRegister(BECS_ECS *ecs, size_t componentSize, size_t maximumComponentCount)
|
|
||||||
{
|
|
||||||
if (maximumComponentCount == 0)
|
|
||||||
{
|
|
||||||
maximumComponentCount = BECS_MAX_ENTITIES;
|
|
||||||
}
|
|
||||||
|
|
||||||
BECS_ComponentID id = ecs->componentTypeCount;
|
|
||||||
BECS_ComponentPoolInit(&ecs->arena, &ecs->componentPools[id],
|
|
||||||
componentSize, maximumComponentCount);
|
|
||||||
ecs->componentTypeCount++;
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *BECS_ComponentAdd(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId)
|
|
||||||
{
|
|
||||||
void *component = BECS_ComponentPoolAdd(&ecs->componentPools[componentId], entity);
|
|
||||||
ecs->entitySignatures[entity] = BECS_SignatureSet(ecs->entitySignatures[entity], componentId);
|
|
||||||
memset(component, 0, ecs->componentPools[componentId].unitSize);
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BECS_ComponentRemove(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId)
|
|
||||||
{
|
|
||||||
if (!ecs->aliveEntites[entity])
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BECS_ComponentPoolRemove(&ecs->componentPools[componentId], entity);
|
|
||||||
ecs->entitySignatures[entity] &= ~(1ULL << componentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *BECS_ComponentGet(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!ecs->aliveEntites[entity])
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return BECS_ComponentPoolGet(&ecs->componentPools[componentId], entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BECS_ComponentHas(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId)
|
|
||||||
{
|
|
||||||
if (!ecs->aliveEntites[entity])
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return BECS_SignatureHas(ecs->entitySignatures[entity], componentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* BECS_IMPLEMENTATION */
|
|
||||||
#endif /* BECS_H */
|
|
||||||
Loading…
Reference in a new issue