100#define ECS_NULL ((ecs_id_t)-1)
111#define ECS_DT_TYPE double
386#ifdef PICO_ECS_IMPLEMENTATION
392#ifndef PICO_ECS_MAX_COMPONENTS
393#define PICO_ECS_MAX_COMPONENTS 32
396#ifndef PICO_ECS_MAX_SYSTEMS
397#define PICO_ECS_MAX_SYSTEMS 16
401 #define PICO_ECS_ASSERT(expr) ((void)0)
403 #ifndef PICO_ECS_ASSERT
405 #define PICO_ECS_ASSERT(expr) (assert(expr))
409#if !defined(PICO_ECS_MALLOC) || !defined(PICO_ECS_REALLOC) || !defined(PICO_ECS_FREE)
411#define PICO_ECS_MALLOC(size, ctx) (malloc(size))
412#define PICO_ECS_REALLOC(ptr, size, ctx) (realloc(ptr, size))
413#define PICO_ECS_FREE(ptr, ctx) (free(ptr))
420#define ECS_ASSERT PICO_ECS_ASSERT
421#define ECS_MAX_COMPONENTS PICO_ECS_MAX_COMPONENTS
422#define ECS_MAX_SYSTEMS PICO_ECS_MAX_SYSTEMS
423#define ECS_MALLOC PICO_ECS_MALLOC
424#define ECS_REALLOC PICO_ECS_REALLOC
425#define ECS_FREE PICO_ECS_FREE
431#if ECS_MAX_COMPONENTS <= 32
432typedef uint32_t ecs_bitset_t;
433#elif ECS_MAX_COMPONENTS <= 64
434typedef uint64_t ecs_bitset_t;
436#define ECS_BITSET_WIDTH 64
437#define ECS_BITSET_SIZE (((ECS_MAX_COMPONENTS - 1) / ECS_BITSET_WIDTH) + 1)
441 uint64_t array[ECS_BITSET_SIZE];
473 ecs_bitset_t comp_bits;
486 ecs_sparse_set_t entity_ids;
490 ecs_bitset_t require_bits;
491 ecs_bitset_t exclude_bits;
497 ecs_stack_t entity_pool;
498 ecs_stack_t destroy_queue;
499 ecs_stack_t remove_queue;
500 ecs_entity_t* entities;
502 ecs_comp_t comps[ECS_MAX_COMPONENTS];
503 ecs_array_t comp_arrays[ECS_MAX_COMPONENTS];
505 ecs_sys_t systems[ECS_MAX_SYSTEMS];
513static void* ecs_realloc_zero(
ecs_t* ecs,
void* ptr,
size_t old_size,
size_t new_size);
523static void ecs_flush_destroyed(
ecs_t* ecs);
524static void ecs_flush_removed(
ecs_t* ecs);
529static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on);
530static inline bool ecs_bitset_is_zero(ecs_bitset_t* set);
531static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit);
532static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1, ecs_bitset_t* set2);
533static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1, ecs_bitset_t* set2);
534static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set);
535static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2);
536static inline bool ecs_bitset_true(ecs_bitset_t* set);
541static void ecs_sparse_set_init(
ecs_t* ecs, ecs_sparse_set_t* set,
size_t capacity);
542static void ecs_sparse_set_free(
ecs_t* ecs, ecs_sparse_set_t* set);
543static bool ecs_sparse_set_add(
ecs_t* ecs, ecs_sparse_set_t* set,
ecs_id_t id);
544static size_t ecs_sparse_set_find(ecs_sparse_set_t* set,
ecs_id_t id);
545static bool ecs_sparse_set_remove(ecs_sparse_set_t* set,
ecs_id_t id);
550static bool ecs_entity_system_test(ecs_bitset_t* require_bits,
551 ecs_bitset_t* exclude_bits,
552 ecs_bitset_t* entity_bits);
557static void ecs_stack_init(
ecs_t* ecs, ecs_stack_t* pool,
int capacity);
558static void ecs_stack_free(
ecs_t* ecs, ecs_stack_t* pool);
559static void ecs_stack_push(
ecs_t* ecs, ecs_stack_t* pool,
ecs_id_t id);
560static ecs_id_t ecs_stack_pop(ecs_stack_t* pool);
561static int ecs_stack_size(ecs_stack_t* pool);
566static void ecs_array_init(
ecs_t* ecs, ecs_array_t* array,
size_t size,
size_t capacity);
567static void ecs_array_free(
ecs_t* ecs, ecs_array_t* array);
568static void ecs_array_resize(
ecs_t* ecs, ecs_array_t* array,
size_t capacity);
574static bool ecs_is_not_null(
void* ptr);
575static bool ecs_is_valid_component_id(
ecs_id_t id);
576static bool ecs_is_valid_system_id(
ecs_id_t id);
577static bool ecs_is_entity_ready(
ecs_t* ecs,
ecs_id_t entity_id);
578static bool ecs_is_component_ready(
ecs_t* ecs,
ecs_id_t comp_id);
587 ECS_ASSERT(entity_count > 0);
595 memset(ecs, 0,
sizeof(
ecs_t));
597 ecs->entity_count = entity_count;
598 ecs->mem_ctx = mem_ctx;
601 ecs_stack_init(ecs, &ecs->entity_pool, entity_count);
602 ecs_stack_init(ecs, &ecs->destroy_queue, entity_count);
603 ecs_stack_init(ecs, &ecs->remove_queue, entity_count * 2);
606 ecs->entities = (ecs_entity_t*)ECS_MALLOC(ecs->entity_count *
sizeof(ecs_entity_t),
610 memset(ecs->entities, 0, ecs->entity_count *
sizeof(ecs_entity_t));
613 for (
ecs_id_t id = 0;
id < entity_count;
id++)
615 ecs_stack_push(ecs, &ecs->entity_pool,
id);
623 ECS_ASSERT(ecs_is_not_null(ecs));
625 for (
ecs_id_t entity_id = 0; entity_id < ecs->entity_count; entity_id++)
627 if (ecs->entities[entity_id].ready)
628 ecs_destruct(ecs, entity_id);
631 ecs_stack_free(ecs, &ecs->entity_pool);
632 ecs_stack_free(ecs, &ecs->destroy_queue);
633 ecs_stack_free(ecs, &ecs->remove_queue);
635 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
637 ecs_array_t* comp_array = &ecs->comp_arrays[comp_id];
638 ecs_array_free(ecs, comp_array);
641 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
643 ecs_sys_t* sys = &ecs->systems[sys_id];
644 ecs_sparse_set_free(ecs, &sys->entity_ids);
647 ECS_FREE(ecs->entities, ecs->mem_ctx);
648 ECS_FREE(ecs, ecs->mem_ctx);
653 ECS_ASSERT(ecs_is_not_null(ecs));
655 for (
ecs_id_t entity_id = 0; entity_id < ecs->entity_count; entity_id++)
657 if (ecs->entities[entity_id].ready)
658 ecs_destruct(ecs, entity_id);
661 ecs->entity_pool.size = 0;
662 ecs->destroy_queue.size = 0;
663 ecs->remove_queue.size = 0;
665 memset(ecs->entities, 0, ecs->entity_count *
sizeof(ecs_entity_t));
667 for (
ecs_id_t entity_id = 0; entity_id < ecs->entity_count; entity_id++)
669 ecs_stack_push(ecs, &ecs->entity_pool, entity_id);
672 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
674 ecs->systems[sys_id].entity_ids.size = 0;
683 ECS_ASSERT(ecs_is_not_null(ecs));
684 ECS_ASSERT(ecs->comp_count < ECS_MAX_COMPONENTS);
685 ECS_ASSERT(size > 0);
689 ecs_array_t* comp_array = &ecs->comp_arrays[comp_id];
690 ecs_array_init(ecs, comp_array, size, ecs->entity_count);
692 ecs->comps[comp_id].constructor = constructor;
693 ecs->comps[comp_id].destructor = destructor;
706 ECS_ASSERT(ecs_is_not_null(ecs));
707 ECS_ASSERT(ecs->system_count < ECS_MAX_SYSTEMS);
708 ECS_ASSERT(NULL != system_cb);
710 ecs_id_t sys_id = ecs->system_count;
711 ecs_sys_t* sys = &ecs->systems[sys_id];
713 ecs_sparse_set_init(ecs, &sys->entity_ids, ecs->entity_count);
716 sys->system_cb = system_cb;
717 sys->add_cb = add_cb;
718 sys->remove_cb = remove_cb;
728 ECS_ASSERT(ecs_is_not_null(ecs));
729 ECS_ASSERT(ecs_is_valid_system_id(sys_id));
730 ECS_ASSERT(ecs_is_valid_component_id(comp_id));
731 ECS_ASSERT(ecs_is_system_ready(ecs, sys_id));
732 ECS_ASSERT(ecs_is_component_ready(ecs, comp_id));
735 ecs_sys_t* sys = &ecs->systems[sys_id];
736 ecs_bitset_flip(&sys->require_bits, comp_id,
true);
741 ECS_ASSERT(ecs_is_not_null(ecs));
742 ECS_ASSERT(ecs_is_valid_system_id(sys_id));
743 ECS_ASSERT(ecs_is_valid_component_id(comp_id));
744 ECS_ASSERT(ecs_is_system_ready(ecs, sys_id));
745 ECS_ASSERT(ecs_is_component_ready(ecs, comp_id));
748 ecs_sys_t* sys = &ecs->systems[sys_id];
749 ecs_bitset_flip(&sys->exclude_bits, comp_id,
true);
754 ECS_ASSERT(ecs_is_not_null(ecs));
755 ECS_ASSERT(ecs_is_valid_system_id(sys_id));
756 ECS_ASSERT(ecs_is_system_ready(ecs, sys_id));
758 ecs_sys_t* sys = &ecs->systems[sys_id];
764 ECS_ASSERT(ecs_is_not_null(ecs));
765 ECS_ASSERT(ecs_is_valid_system_id(sys_id));
766 ECS_ASSERT(ecs_is_system_ready(ecs, sys_id));
768 ecs_sys_t* sys = &ecs->systems[sys_id];
774 ECS_ASSERT(ecs_is_not_null(ecs));
776 ecs_stack_t* pool = &ecs->entity_pool;
779 if (0 == ecs_stack_size(pool))
781 size_t old_count = ecs->entity_count;
782 size_t new_count = old_count + (old_count / 2) + 2;
785 ecs->entities = (ecs_entity_t*)ecs_realloc_zero(ecs, ecs->entities,
786 old_count *
sizeof(ecs_entity_t),
787 new_count *
sizeof(ecs_entity_t));
790 for (
ecs_id_t id = old_count;
id < new_count;
id++)
792 ecs_stack_push(ecs, pool,
id);
796 ecs->entity_count = new_count;
799 ecs_id_t entity_id = ecs_stack_pop(pool);
800 ecs->entities[entity_id].ready =
true;
807 ECS_ASSERT(ecs_is_not_null(ecs));
809 return ecs->entities[entity_id].ready;
814 ECS_ASSERT(ecs_is_not_null(ecs));
815 ECS_ASSERT(ecs_is_entity_ready(ecs, entity_id));
818 ecs_entity_t* entity = &ecs->entities[entity_id];
821 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
823 ecs_sys_t* sys = &ecs->systems[sys_id];
825 if (ecs_entity_system_test(&sys->require_bits, &sys->exclude_bits, &entity->comp_bits) &&
826 ecs_sparse_set_remove(&sys->entity_ids, entity_id))
829 sys->remove_cb(ecs, entity_id, sys->udata);
834 ecs_destruct(ecs, entity_id);
837 ecs_stack_t* pool = &ecs->entity_pool;
838 ecs_stack_push(ecs, pool, entity_id);
841 memset(entity, 0,
sizeof(ecs_entity_t));
846 ECS_ASSERT(ecs_is_not_null(ecs));
847 ECS_ASSERT(ecs_is_valid_component_id(comp_id));
848 ECS_ASSERT(ecs_is_entity_ready(ecs, entity_id));
851 ecs_entity_t* entity = &ecs->entities[entity_id];
854 return ecs_bitset_test(&entity->comp_bits, comp_id);
859 ECS_ASSERT(ecs_is_not_null(ecs));
860 ECS_ASSERT(ecs_is_valid_component_id(comp_id));
861 ECS_ASSERT(ecs_is_component_ready(ecs, comp_id));
862 ECS_ASSERT(ecs_is_entity_ready(ecs, entity_id));
867 ecs_array_t* comp_array = &ecs->comp_arrays[comp_id];
868 return (
char*)comp_array->data + (comp_array->size * entity_id);
873 ECS_ASSERT(ecs_is_not_null(ecs));
874 ECS_ASSERT(ecs_is_valid_component_id(comp_id));
875 ECS_ASSERT(ecs_is_entity_ready(ecs, entity_id));
876 ECS_ASSERT(ecs_is_component_ready(ecs, comp_id));
879 ecs_entity_t* entity = &ecs->entities[entity_id];
882 ecs_array_t* comp_array = &ecs->comp_arrays[comp_id];
883 ecs_comp_t* comp = &ecs->comps[comp_id];
886 ecs_array_resize(ecs, comp_array, entity_id);
889 void* ptr =
ecs_get(ecs, entity_id, comp_id);
892 memset(ptr, 0, comp_array->size);
895 if (comp->constructor)
896 comp->constructor(ecs, entity_id, ptr, args);
900 ecs_bitset_flip(&entity->comp_bits, comp_id,
true);
903 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
905 ecs_sys_t* sys = &ecs->systems[sys_id];
907 if (ecs_entity_system_test(&sys->require_bits, &sys->exclude_bits, &entity->comp_bits))
909 if (ecs_sparse_set_add(ecs, &sys->entity_ids, entity_id))
912 sys->add_cb(ecs, entity_id, sys->udata);
917 if (!ecs_bitset_is_zero(&sys->exclude_bits) &&
918 ecs_sparse_set_remove(&sys->entity_ids, entity_id))
921 sys->remove_cb(ecs, entity_id, sys->udata);
932 ECS_ASSERT(ecs_is_not_null(ecs));
933 ECS_ASSERT(ecs_is_valid_component_id(comp_id));
934 ECS_ASSERT(ecs_is_component_ready(ecs, comp_id));
935 ECS_ASSERT(ecs_is_entity_ready(ecs, entity_id));
938 ecs_entity_t* entity = &ecs->entities[entity_id];
941 ecs_bitset_t comp_bit;
943 memset(&comp_bit, 0,
sizeof(ecs_bitset_t));
944 ecs_bitset_flip(&comp_bit, comp_id,
true);
946 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
948 ecs_sys_t* sys = &ecs->systems[sys_id];
950 if (ecs_entity_system_test(&sys->require_bits, &sys->exclude_bits, &comp_bit))
952 if (ecs_sparse_set_remove(&sys->entity_ids, entity_id))
955 sys->remove_cb(ecs, entity_id, sys->udata);
960 if (!ecs_bitset_is_zero(&sys->exclude_bits) &&
961 ecs_sparse_set_add(ecs, &sys->entity_ids, entity_id))
964 sys->add_cb(ecs, entity_id, sys->udata);
969 ecs_comp_t* comp = &ecs->comps[comp_id];
971 if (comp->destructor)
973 void* ptr =
ecs_get(ecs, entity_id, comp_id);
974 comp->destructor(ecs, entity_id, ptr);
978 ecs_bitset_flip(&entity->comp_bits, comp_id,
false);
983 ECS_ASSERT(ecs_is_not_null(ecs));
984 ECS_ASSERT(ecs_is_entity_ready(ecs, entity_id));
986 ecs_stack_push(ecs, &ecs->destroy_queue, entity_id);
991 ECS_ASSERT(ecs_is_not_null(ecs));
992 ECS_ASSERT(ecs_is_entity_ready(ecs, entity_id));
993 ECS_ASSERT(
ecs_has(ecs, entity_id, comp_id));
995 ecs_stack_push(ecs, &ecs->remove_queue, entity_id);
996 ecs_stack_push(ecs, &ecs->remove_queue, comp_id);
1001 ECS_ASSERT(ecs_is_not_null(ecs));
1002 ECS_ASSERT(ecs_is_valid_system_id(sys_id));
1003 ECS_ASSERT(ecs_is_system_ready(ecs, sys_id));
1004 ECS_ASSERT(dt >= 0.0f);
1006 ecs_sys_t* sys = &ecs->systems[sys_id];
1012 sys->entity_ids.dense,
1013 sys->entity_ids.size,
1017 ecs_flush_destroyed(ecs);
1018 ecs_flush_removed(ecs);
1025 ECS_ASSERT(ecs_is_not_null(ecs));
1026 ECS_ASSERT(dt >= 0.0f);
1028 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1042static void* ecs_realloc_zero(
ecs_t* ecs,
void* ptr,
size_t old_size,
size_t new_size)
1046 ptr = ECS_REALLOC(ptr, new_size, ecs->mem_ctx);
1048 if (new_size > old_size && ptr) {
1049 size_t diff = new_size - old_size;
1050 void* start = ((
char*)ptr)+ old_size;
1051 memset(start, 0, diff);
1063 ecs_entity_t* entity = &ecs->entities[entity_id];
1066 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
1068 if (ecs_bitset_test(&entity->comp_bits, comp_id))
1070 ecs_comp_t* comp = &ecs->comps[comp_id];
1072 if (comp->destructor)
1074 void* ptr =
ecs_get(ecs, entity_id, comp_id);
1075 comp->destructor(ecs, entity_id, ptr);
1085static void ecs_flush_destroyed(
ecs_t* ecs)
1087 ecs_stack_t* destroy_queue = &ecs->destroy_queue;
1089 for (
size_t i = 0; i < destroy_queue->size; i++)
1091 ecs_id_t entity_id = destroy_queue->array[i];
1097 destroy_queue->size = 0;
1100static void ecs_flush_removed(
ecs_t* ecs)
1102 ecs_stack_t* remove_queue = &ecs->remove_queue;
1104 for (
size_t i = 0; i < remove_queue->size; i += 2)
1106 ecs_id_t entity_id = remove_queue->array[i];
1110 ecs_id_t comp_id = remove_queue->array[i + 1];
1115 remove_queue->size = 0;
1123#if ECS_MAX_COMPONENTS <= 64
1125static inline bool ecs_bitset_is_zero(ecs_bitset_t* set)
1130static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on)
1133 *set |= ((uint64_t)1 << bit);
1135 *set &= ~((uint64_t)1 << bit);
1138static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit)
1140 return *set & ((uint64_t)1 << bit);
1143static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1, ecs_bitset_t* set2)
1145 return *set1 & *set2;
1148static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1, ecs_bitset_t* set2)
1150 return *set1 | *set2;
1153static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set)
1158static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2)
1160 return *set1 == *set2;
1163static inline bool ecs_bitset_true(ecs_bitset_t* set)
1170static inline bool ecs_bitset_is_zero(ecs_bitset_t* set)
1172 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1174 if (set->array[i] != 0)
1181static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on)
1183 int index = bit / ECS_BITSET_WIDTH;
1186 set->array[index] |= ((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1188 set->array[index] &= ~((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1191static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit)
1193 int index = bit / ECS_BITSET_WIDTH;
1194 return set->array[index] & ((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1197static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1,
1202 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1204 set.array[i] = set1->array[i] & set2->array[i];
1210static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1,
1215 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1217 set.array[i] = set1->array[i] | set2->array[i];
1224static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set)
1228 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1230 out.array[i] = ~set->array[i];
1236static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2)
1238 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1240 if (set1->array[i] != set2->array[i])
1249static inline bool ecs_bitset_true(ecs_bitset_t* set)
1251 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1266static void ecs_sparse_set_init(
ecs_t* ecs, ecs_sparse_set_t* set,
size_t capacity)
1268 ECS_ASSERT(ecs_is_not_null(ecs));
1269 ECS_ASSERT(ecs_is_not_null(set));
1270 ECS_ASSERT(capacity > 0);
1274 set->capacity = capacity;
1277 set->dense = (
ecs_id_t*)ECS_MALLOC(capacity *
sizeof(
ecs_id_t), ecs->mem_ctx);
1278 set->sparse = (
size_t*) ECS_MALLOC(capacity *
sizeof(
size_t), ecs->mem_ctx);
1280 memset(set->sparse, 0, capacity *
sizeof(
size_t));
1283static void ecs_sparse_set_free(
ecs_t* ecs, ecs_sparse_set_t* set)
1285 ECS_ASSERT(ecs_is_not_null(ecs));
1286 ECS_ASSERT(ecs_is_not_null(set));
1290 ECS_FREE(set->dense, ecs->mem_ctx);
1291 ECS_FREE(set->sparse, ecs->mem_ctx);
1294static bool ecs_sparse_set_add(
ecs_t* ecs, ecs_sparse_set_t* set,
ecs_id_t id)
1296 ECS_ASSERT(ecs_is_not_null(ecs));
1297 ECS_ASSERT(ecs_is_not_null(set));
1302 if (
id >= set->capacity)
1304 size_t old_capacity = set->capacity;
1305 size_t new_capacity = old_capacity;
1308 while (new_capacity <=
id)
1310 new_capacity += (new_capacity / 2) + 2;
1314 set->dense = (
ecs_id_t*)ECS_REALLOC(set->dense,
1319 set->sparse = (
size_t*)ecs_realloc_zero(ecs,
1321 old_capacity *
sizeof(
size_t),
1322 new_capacity *
sizeof(size_t));
1325 set->capacity = new_capacity;
1329 if (
ECS_NULL != ecs_sparse_set_find(set,
id))
1333 set->dense[set->size] = id;
1334 set->sparse[id] = set->size;
1341static size_t ecs_sparse_set_find(ecs_sparse_set_t* set,
ecs_id_t id)
1343 ECS_ASSERT(ecs_is_not_null(set));
1345 if (set->sparse[
id] < set->size && set->dense[set->sparse[
id]] ==
id)
1346 return set->sparse[id];
1351static bool ecs_sparse_set_remove(ecs_sparse_set_t* set,
ecs_id_t id)
1353 ECS_ASSERT(ecs_is_not_null(set));
1355 if (
ECS_NULL == ecs_sparse_set_find(set,
id))
1359 ecs_id_t tmp = set->dense[set->size - 1];
1360 set->dense[set->sparse[id]] = tmp;
1361 set->sparse[tmp] = set->sparse[id];
1372inline static bool ecs_entity_system_test(ecs_bitset_t* require_bits,
1373 ecs_bitset_t* exclude_bits,
1374 ecs_bitset_t* entity_bits)
1376 if (!ecs_bitset_is_zero(exclude_bits))
1378 ecs_bitset_t overlap = ecs_bitset_and(entity_bits, exclude_bits);
1380 if (ecs_bitset_true(&overlap))
1386 ecs_bitset_t entity_and_require = ecs_bitset_and(entity_bits, require_bits);
1387 return ecs_bitset_equal(&entity_and_require, require_bits);
1394inline static void ecs_stack_init(
ecs_t* ecs, ecs_stack_t* stack,
int capacity)
1396 ECS_ASSERT(ecs_is_not_null(ecs));
1397 ECS_ASSERT(ecs_is_not_null(stack));
1398 ECS_ASSERT(capacity > 0);
1403 stack->capacity = capacity;
1404 stack->array = (
ecs_id_t*)ECS_MALLOC(capacity *
sizeof(
ecs_id_t), ecs->mem_ctx);
1407inline static void ecs_stack_free(
ecs_t* ecs, ecs_stack_t* stack)
1409 ECS_ASSERT(ecs_is_not_null(ecs));
1410 ECS_ASSERT(ecs_is_not_null(stack));
1414 ECS_FREE(stack->array, ecs->mem_ctx);
1417inline static void ecs_stack_push(
ecs_t* ecs, ecs_stack_t* stack,
ecs_id_t id)
1419 ECS_ASSERT(ecs_is_not_null(ecs));
1420 ECS_ASSERT(ecs_is_not_null(stack));
1421 ECS_ASSERT(stack->capacity > 0);
1425 if (stack->size == stack->capacity)
1427 stack->capacity += (stack->capacity / 2) + 2;
1429 stack->array = (
ecs_id_t*)ECS_REALLOC(stack->array,
1430 stack->capacity *
sizeof(
ecs_id_t),
1434 stack->array[stack->size++] = id;
1437inline static ecs_id_t ecs_stack_pop(ecs_stack_t* stack)
1439 ECS_ASSERT(ecs_is_not_null(stack));
1440 return stack->array[--stack->size];
1443inline static int ecs_stack_size(ecs_stack_t* stack)
1448static void ecs_array_init(
ecs_t* ecs, ecs_array_t* array,
size_t size,
size_t capacity)
1450 ECS_ASSERT(ecs_is_not_null(ecs));
1451 ECS_ASSERT(ecs_is_not_null(array));
1455 memset(array, 0,
sizeof(ecs_array_t));
1457 array->capacity = capacity;
1460 array->data = ECS_MALLOC(size * capacity, ecs->mem_ctx);
1463static void ecs_array_free(
ecs_t* ecs, ecs_array_t* array)
1465 ECS_ASSERT(ecs_is_not_null(ecs));
1466 ECS_ASSERT(ecs_is_not_null(array));
1470 ECS_FREE(array->data, ecs->mem_ctx);
1473static void ecs_array_resize(
ecs_t* ecs, ecs_array_t* array,
size_t capacity)
1475 ECS_ASSERT(ecs_is_not_null(ecs));
1476 ECS_ASSERT(ecs_is_not_null(array));
1480 if (capacity >= array->capacity)
1482 while (array->capacity <= capacity)
1484 array->capacity += (array->capacity / 2) + 2;
1487 array->data = ECS_REALLOC(array->data,
1488 array->capacity * array->size,
1497static bool ecs_is_not_null(
void* ptr)
1502static bool ecs_is_valid_component_id(
ecs_id_t id)
1504 return id < ECS_MAX_COMPONENTS;
1507static bool ecs_is_valid_system_id(
ecs_id_t id)
1509 return id < ECS_MAX_SYSTEMS;
1512static bool ecs_is_entity_ready(
ecs_t* ecs,
ecs_id_t entity_id)
1514 return ecs->entities[entity_id].ready;
1517static bool ecs_is_component_ready(
ecs_t* ecs,
ecs_id_t comp_id)
1519 return comp_id < ecs->comp_count;
1524 return sys_id < ecs->system_count;
void ecs_disable_system(ecs_t *ecs, ecs_id_t sys_id)
Disables a system.
void ecs_queue_remove(ecs_t *ecs, ecs_id_t entity_id, ecs_id_t comp_id)
Queues a component for removable.
void(* ecs_removed_fn)(ecs_t *ecs, ecs_id_t entity_id, void *udata)
Called when an entity is removed from a system.
Definition pico_ecs.h:213
void(* ecs_destructor_fn)(ecs_t *ecs, ecs_id_t entity_id, void *ptr)
Called when a component is destroyed (via ecs_remove or ecs_destroy)
Definition pico_ecs.h:157
ECS_DT_TYPE ecs_dt_t
Definition pico_ecs.h:114
ecs_id_t ecs_register_system(ecs_t *ecs, ecs_system_fn system_cb, ecs_added_fn add_cb, ecs_removed_fn remove_cb, void *udata)
Registers a system.
int8_t ecs_ret_t
Return code for update callback and calling functions.
Definition pico_ecs.h:105
ecs_id_t ecs_register_component(ecs_t *ecs, size_t size, ecs_constructor_fn constructor, ecs_destructor_fn destructor)
Registers a component.
void ecs_free(ecs_t *ecs)
Destroys an ECS instance.
#define ECS_DT_TYPE
Determine delta-time type.
Definition pico_ecs.h:111
void ecs_exclude_component(ecs_t *ecs, ecs_id_t sys_id, ecs_id_t comp_id)
Excludes entities having the specified component from being added to the target system.
void(* ecs_added_fn)(ecs_t *ecs, ecs_id_t entity_id, void *udata)
Called when an entity is added to a system.
Definition pico_ecs.h:204
#define ECS_NULL
NULL/invalid/undefined value.
Definition pico_ecs.h:100
ecs_id_t ecs_create(ecs_t *ecs)
Creates an entity.
void(* ecs_constructor_fn)(ecs_t *ecs, ecs_id_t entity_id, void *ptr, void *args)
Called when a component is created (via ecs_add)
Definition pico_ecs.h:145
struct ecs_s ecs_t
ECS context.
Definition pico_ecs.h:90
void * ecs_add(ecs_t *ecs, ecs_id_t entity_id, ecs_id_t comp_id, void *args)
Adds a component instance to an entity.
void ecs_reset(ecs_t *ecs)
Removes all entities from the ECS, preserving systems and components.
void ecs_destroy(ecs_t *ecs, ecs_id_t entity_id)
Destroys an entity.
ecs_ret_t ecs_update_systems(ecs_t *ecs, ecs_dt_t dt)
Updates all systems.
void ecs_queue_destroy(ecs_t *ecs, ecs_id_t entity_id)
Queues an entity for destruction at the end of system execution.
void ecs_remove(ecs_t *ecs, ecs_id_t entity_id, ecs_id_t comp_id)
Removes a component instance from an entity.
ecs_ret_t(* ecs_system_fn)(ecs_t *ecs, ecs_id_t *entities, int entity_count, ecs_dt_t dt, void *udata)
System update callback.
Definition pico_ecs.h:191
uint32_t ecs_id_t
ID used for entity and components.
Definition pico_ecs.h:95
bool ecs_is_ready(ecs_t *ecs, ecs_id_t entity_id)
Returns true if the entity is currently active.
void ecs_enable_system(ecs_t *ecs, ecs_id_t sys_id)
Enables a system.
void ecs_require_component(ecs_t *ecs, ecs_id_t sys_id, ecs_id_t comp_id)
Determines which components are available to the specified system.
ecs_ret_t ecs_update_system(ecs_t *ecs, ecs_id_t sys_id, ecs_dt_t dt)
Update an individual system.
ecs_t * ecs_new(size_t entity_count, void *mem_ctx)
Creates an ECS instance.
bool ecs_has(ecs_t *ecs, ecs_id_t entity_id, ecs_id_t comp_id)
Test if entity has the specified component.
void * ecs_get(ecs_t *ecs, ecs_id_t entity_id, ecs_id_t comp_id)
Gets a component instance associated with an entity.