165#define ECS_ID_TYPE uint64_t
177#define ECS_MASK_TYPE uint64_t
556#ifdef PICO_ECS_IMPLEMENTATION
563#ifndef PICO_ECS_MAX_COMPONENTS
564#define PICO_ECS_MAX_COMPONENTS 32
567#ifndef PICO_ECS_MAX_SYSTEMS
568#define PICO_ECS_MAX_SYSTEMS 16
572 #define PICO_ECS_ASSERT(expr) ((void)0)
574 #ifndef PICO_ECS_ASSERT
576 #define PICO_ECS_ASSERT(expr) (assert(expr))
580#if !defined(PICO_ECS_MALLOC) || !defined(PICO_ECS_REALLOC) || !defined(PICO_ECS_FREE)
582#define PICO_ECS_MALLOC(size, ctx) (malloc(size))
583#define PICO_ECS_REALLOC(ptr, size, ctx) (realloc(ptr, size))
584#define PICO_ECS_FREE(ptr, ctx) (free(ptr))
591#define ECS_ASSERT PICO_ECS_ASSERT
592#define ECS_MAX_COMPONENTS PICO_ECS_MAX_COMPONENTS
593#define ECS_MAX_SYSTEMS PICO_ECS_MAX_SYSTEMS
594#define ECS_MALLOC PICO_ECS_MALLOC
595#define ECS_REALLOC PICO_ECS_REALLOC
596#define ECS_FREE PICO_ECS_FREE
602#if ECS_MAX_COMPONENTS <= 32
603typedef uint32_t ecs_bitset_t;
604#elif ECS_MAX_COMPONENTS <= 64
605typedef uint64_t ecs_bitset_t;
607#define ECS_BITSET_WIDTH 64
608#define ECS_BITSET_SIZE (((ECS_MAX_COMPONENTS - 1) / ECS_BITSET_WIDTH) + 1)
612 uint64_t array[ECS_BITSET_SIZE];
644 ecs_bitset_t comp_bits;
658 ecs_sparse_set_t entity_ids;
663 ecs_bitset_t require_bits;
664 ecs_bitset_t exclude_bits;
670 ecs_id_array_t entity_pool;
671 ecs_id_array_t destroy_queue;
672 ecs_id_array_t remove_queue;
673 ecs_entity_data_t* entities;
675 size_t next_entity_id;
676 ecs_comp_data_t comps[ECS_MAX_COMPONENTS];
677 ecs_comp_array_t comp_arrays[ECS_MAX_COMPONENTS];
679 ecs_sys_data_t systems[ECS_MAX_SYSTEMS];
694static void* ecs_realloc_zero(
ecs_t* ecs,
void* ptr,
size_t old_size,
size_t new_size);
709static inline bool ecs_is_active(
ecs_t* ecs,
ecs_id_t entity_id);
714static void ecs_flush_destroyed(
ecs_t* ecs);
715static void ecs_flush_removed(
ecs_t* ecs);
720static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on);
721static inline bool ecs_bitset_is_zero(ecs_bitset_t* set);
722static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit);
723static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1, ecs_bitset_t* set2);
724static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1, ecs_bitset_t* set2);
725static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set);
726static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2);
727static inline bool ecs_bitset_true(ecs_bitset_t* set);
732static void ecs_sparse_set_init(
ecs_t* ecs, ecs_sparse_set_t* set,
size_t capacity);
733static void ecs_sparse_set_free(
ecs_t* ecs, ecs_sparse_set_t* set);
734static bool ecs_sparse_set_add(
ecs_t* ecs, ecs_sparse_set_t* set,
ecs_id_t id);
735static bool ecs_sparse_set_find(ecs_sparse_set_t* set,
ecs_id_t id,
size_t* found);
736static bool ecs_sparse_set_remove(ecs_sparse_set_t* set,
ecs_id_t id);
741static bool ecs_entity_system_test(ecs_bitset_t* require_bits,
742 ecs_bitset_t* exclude_bits,
743 ecs_bitset_t* entity_bits);
748static void ecs_id_array_init(
ecs_t* ecs, ecs_id_array_t* pool,
int capacity);
749static void ecs_id_array_free(
ecs_t* ecs, ecs_id_array_t* pool);
750static void ecs_id_array_push(
ecs_t* ecs, ecs_id_array_t* pool,
ecs_id_t id);
751static ecs_id_t ecs_id_array_pop(ecs_id_array_t* pool);
752static int ecs_id_array_size(ecs_id_array_t* pool);
757static void ecs_comp_array_init(
ecs_t* ecs, ecs_comp_array_t* array,
size_t size,
size_t capacity);
758static void ecs_comp_array_free(
ecs_t* ecs, ecs_comp_array_t* array);
759static void ecs_comp_array_resize(
ecs_t* ecs, ecs_comp_array_t* array,
size_t capacity);
765static bool ecs_is_not_null(
void* ptr);
766static bool ecs_is_valid_component_id(
ecs_id_t id);
767static bool ecs_is_valid_system_id(
ecs_id_t id);
768static bool ecs_is_entity_ready(
ecs_t* ecs,
ecs_id_t entity_id);
769static bool ecs_is_component_ready(
ecs_t* ecs,
ecs_id_t comp_id);
779 return 0 == entity.
id;
790 ECS_ASSERT(entity_count > 0);
798 memset(ecs, 0,
sizeof(
ecs_t));
800 ecs->entity_count = (entity_count > 0) ? entity_count : 1;
801 ecs->next_entity_id = 1;
802 ecs->mem_ctx = mem_ctx;
805 ecs_id_array_init(ecs, &ecs->entity_pool, entity_count);
806 ecs_id_array_init(ecs, &ecs->destroy_queue, entity_count);
807 ecs_id_array_init(ecs, &ecs->remove_queue, entity_count * 2);
810 ecs->entities = (ecs_entity_data_t*)ECS_MALLOC(ecs->entity_count *
sizeof(ecs_entity_data_t),
814 memset(ecs->entities, 0, ecs->entity_count *
sizeof(ecs_entity_data_t));
821 ECS_ASSERT(ecs_is_not_null(ecs));
823 for (
ecs_id_t entity_id = 0; entity_id < ecs->entity_count; entity_id++)
825 if (ecs->entities[entity_id].active)
826 ecs_destruct(ecs, entity_id);
829 ecs_id_array_free(ecs, &ecs->entity_pool);
830 ecs_id_array_free(ecs, &ecs->destroy_queue);
831 ecs_id_array_free(ecs, &ecs->remove_queue);
833 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
835 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp_id];
836 ecs_comp_array_free(ecs, comp_array);
839 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
841 ecs_sys_data_t* sys = &ecs->systems[sys_id];
842 ecs_sparse_set_free(ecs, &sys->entity_ids);
845 ECS_FREE(ecs->entities, ecs->mem_ctx);
846 ECS_FREE(ecs, ecs->mem_ctx);
851 ECS_ASSERT(ecs_is_not_null(ecs));
853 for (
ecs_id_t entity_id = 0; entity_id < ecs->entity_count; entity_id++)
855 if (ecs->entities[entity_id].active)
856 ecs_destruct(ecs, entity_id);
859 ecs->entity_pool.size = 0;
860 ecs->destroy_queue.size = 0;
861 ecs->remove_queue.size = 0;
863 memset(ecs->entities, 0, ecs->entity_count *
sizeof(ecs_entity_data_t));
865 ecs->next_entity_id = 1;
867 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
869 ecs->systems[sys_id].entity_ids.size = 0;
878 ECS_ASSERT(ecs_is_not_null(ecs));
879 ECS_ASSERT(ecs->comp_count < ECS_MAX_COMPONENTS);
880 ECS_ASSERT(size > 0);
882 ecs_comp_t comp = ecs_make_comp(ecs->comp_count);
884 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp.
id];
885 ecs_comp_array_init(ecs, comp_array, size, ecs->entity_count);
887 ecs->comps[comp.
id].constructor = constructor;
888 ecs->comps[comp.
id].destructor = destructor;
902 ECS_ASSERT(ecs_is_not_null(ecs));
903 ECS_ASSERT(ecs->system_count < ECS_MAX_SYSTEMS);
904 ECS_ASSERT(NULL != system_cb);
907 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
909 ecs_sparse_set_init(ecs, &sys_data->entity_ids, ecs->entity_count);
911 sys_data->active =
true;
912 sys_data->mask = mask;
913 sys_data->system_cb = system_cb;
914 sys_data->add_cb = add_cb;
915 sys_data->remove_cb = remove_cb;
916 sys_data->udata = udata;
925 ECS_ASSERT(ecs_is_not_null(ecs));
926 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
927 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
928 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
929 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
932 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
933 ecs_bitset_flip(&sys_data->require_bits, comp.
id,
true);
938 ECS_ASSERT(ecs_is_not_null(ecs));
939 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
940 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
941 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
942 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
945 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
946 ecs_bitset_flip(&sys_data->exclude_bits, comp.
id,
true);
951 ECS_ASSERT(ecs_is_not_null(ecs));
952 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
953 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
955 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
956 sys_data->active =
true;
961 ECS_ASSERT(ecs_is_not_null(ecs));
962 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
963 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
965 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
966 sys_data->active =
false;
975 ECS_ASSERT(ecs_is_not_null(ecs));
976 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
977 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
978 ECS_ASSERT(NULL != system_cb);
980 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
981 sys_data->system_cb = system_cb;
982 sys_data->add_cb = add_cb;
983 sys_data->remove_cb = remove_cb;
988 ECS_ASSERT(ecs_is_not_null(ecs));
989 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
990 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
992 ecs->systems[sys.
id].udata = udata;
997 ECS_ASSERT(ecs_is_not_null(ecs));
998 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
999 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1001 return ecs->systems[sys.
id].udata;
1006 ECS_ASSERT(ecs_is_not_null(ecs));
1007 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1008 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1010 ecs->systems[sys.
id].mask = mask;
1015 ECS_ASSERT(ecs_is_not_null(ecs));
1016 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1017 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1019 return ecs->systems[sys.
id].mask;
1024 return ecs->systems[sys.
id].entity_ids.size;
1029 ECS_ASSERT(ecs_is_not_null(ecs));
1034 ecs_id_array_t* pool = &ecs->entity_pool;
1036 if (0 != ecs_id_array_size(pool))
1038 entity_id = ecs_id_array_pop(pool);
1043 entity_id = ecs->next_entity_id++;
1046 if (entity_id >= ecs->entity_count)
1048 size_t old_count = ecs->entity_count;
1049 size_t new_count = 2 * old_count;
1051 ecs->entities = (ecs_entity_data_t*)ecs_realloc_zero(ecs, ecs->entities,
1052 old_count *
sizeof(ecs_entity_data_t),
1053 new_count *
sizeof(ecs_entity_data_t));
1055 ecs->entity_count = new_count;
1060 ecs->entities[entity_id].active =
true;
1061 ecs->entities[entity_id].ready =
true;
1063 return ecs_make_entity(entity_id);
1068 ECS_ASSERT(ecs_is_not_null(ecs));
1070 return ecs->entities[entity.
id].ready;
1075 ECS_ASSERT(ecs_is_not_null(ecs));
1076 ECS_ASSERT(ecs_is_active(ecs, entity.
id));
1079 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1084 ecs_remove_from_systems(ecs, entity);
1088 ecs_destruct(ecs, entity.
id);
1091 ecs_id_array_t* pool = &ecs->entity_pool;
1092 ecs_id_array_push(ecs, pool, entity.
id);
1095 memset(entity_data, 0,
sizeof(ecs_entity_data_t));
1100 ECS_ASSERT(ecs_is_not_null(ecs));
1101 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1102 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1105 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1108 return ecs_bitset_test(&entity_data->comp_bits, comp.
id);
1113 ECS_ASSERT(ecs_is_not_null(ecs));
1114 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1115 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1116 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1121 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp.
id];
1122 return (
char*)comp_array->data + (comp_array->size * entity.
id);
1127 ECS_ASSERT(ecs_is_not_null(ecs));
1128 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1129 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1130 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1133 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1136 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp.
id];
1137 ecs_comp_data_t* comp_data = &ecs->comps[comp.
id];
1140 ecs_comp_array_resize(ecs, comp_array, entity.
id);
1143 void* comp_ptr =
ecs_get(ecs, entity, comp);
1146 memset(comp_ptr, 0, comp_array->size);
1149 if (comp_data->constructor)
1150 comp_data->constructor(ecs, entity, comp_ptr, args);
1154 ecs_bitset_flip(&entity_data->comp_bits, comp.
id,
true);
1157 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1159 ecs_sys_data_t* sys_data = &ecs->systems[sys_id];
1161 if (ecs_entity_system_test(&sys_data->require_bits, &sys_data->exclude_bits, &entity_data->comp_bits))
1163 if (ecs_sparse_set_add(ecs, &sys_data->entity_ids, entity.
id))
1165 if (sys_data->add_cb)
1166 sys_data->add_cb(ecs, entity, sys_data->udata);
1171 if (!ecs_bitset_is_zero(&sys_data->exclude_bits) &&
1172 ecs_sparse_set_remove(&sys_data->entity_ids, entity.
id))
1174 if (sys_data->remove_cb)
1175 sys_data->remove_cb(ecs, entity, sys_data->udata);
1186 ECS_ASSERT(ecs_is_not_null(ecs));
1187 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1188 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1189 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1192 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1195 ecs_bitset_t comp_bit;
1197 memset(&comp_bit, 0,
sizeof(ecs_bitset_t));
1198 ecs_bitset_flip(&comp_bit, comp.
id,
true);
1200 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1202 ecs_sys_data_t* sys_data = &ecs->systems[sys_id];
1204 if (ecs_entity_system_test(&sys_data->require_bits, &sys_data->exclude_bits, &comp_bit))
1206 if (ecs_sparse_set_remove(&sys_data->entity_ids, entity.
id))
1208 if (sys_data->remove_cb)
1209 sys_data->remove_cb(ecs, entity, sys_data->udata);
1214 if (!ecs_bitset_is_zero(&sys_data->exclude_bits) &&
1215 ecs_sparse_set_add(ecs, &sys_data->entity_ids, entity.
id))
1217 if (sys_data->add_cb)
1218 sys_data->add_cb(ecs, entity, sys_data->udata);
1223 ecs_comp_data_t* comp_data = &ecs->comps[comp.
id];
1225 if (comp_data->destructor)
1227 void* comp_ptr =
ecs_get(ecs, entity, comp);
1228 comp_data->destructor(ecs, entity, comp_ptr);
1232 ecs_bitset_flip(&entity_data->comp_bits, comp.
id,
false);
1237 ECS_ASSERT(ecs_is_not_null(ecs));
1238 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1240 ecs_remove_from_systems(ecs, entity);
1242 ecs->entities[entity.
id].ready =
false;
1244 ecs_id_array_push(ecs, &ecs->destroy_queue, entity.
id);
1249 ECS_ASSERT(ecs_is_not_null(ecs));
1250 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1251 ECS_ASSERT(
ecs_has(ecs, entity, comp));
1253 ecs_id_array_push(ecs, &ecs->remove_queue, entity.
id);
1254 ecs_id_array_push(ecs, &ecs->remove_queue, comp.
id);
1259 ECS_ASSERT(ecs_is_not_null(ecs));
1260 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1261 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1263 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1265 if (!sys_data->active)
1268 if (0 != sys_data->mask && !(sys_data->mask & mask))
1271 ecs_ret_t code = sys_data->system_cb(ecs,
1272 sys_data->entity_ids.dense,
1273 sys_data->entity_ids.size,
1276 ecs_flush_destroyed(ecs);
1277 ecs_flush_removed(ecs);
1284 ECS_ASSERT(ecs_is_not_null(ecs));
1286 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1322static void* ecs_realloc_zero(
ecs_t* ecs,
void* ptr,
size_t old_size,
size_t new_size)
1326 ptr = ECS_REALLOC(ptr, new_size, ecs->mem_ctx);
1328 if (new_size > old_size && ptr) {
1329 size_t diff = new_size - old_size;
1330 void* start = ((
char*)ptr)+ old_size;
1331 memset(start, 0, diff);
1340static inline bool ecs_is_active(
ecs_t* ecs,
ecs_id_t entity_id)
1342 ECS_ASSERT(ecs_is_not_null(ecs));
1343 return ecs->entities[entity_id].active;
1352 ecs_entity_data_t* entity = &ecs->entities[entity_id];
1355 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
1357 if (ecs_bitset_test(&entity->comp_bits, comp_id))
1359 ecs_comp_data_t* comp = &ecs->comps[comp_id];
1361 if (comp->destructor)
1365 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp_id];
1366 void* comp_ptr = (
char*)comp_array->data + (comp_array->size * entity_id);
1369 comp->destructor(ecs, entity, comp_ptr);
1381 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1383 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1385 ecs_sys_data_t* sys_data = &ecs->systems[sys_id];
1387 if (ecs_entity_system_test(&sys_data->require_bits,
1388 &sys_data->exclude_bits,
1389 &entity_data->comp_bits) &&
1390 ecs_sparse_set_remove(&sys_data->entity_ids, entity.
id))
1392 if (sys_data->remove_cb)
1393 sys_data->remove_cb(ecs, entity, sys_data->udata);
1402static void ecs_flush_destroyed(
ecs_t* ecs)
1404 ecs_id_array_t* destroy_queue = &ecs->destroy_queue;
1406 for (
size_t i = 0; i < destroy_queue->size; i++)
1408 ecs_id_t entity_id = destroy_queue->data[i];
1410 if (ecs_is_active(ecs, entity_id))
1414 destroy_queue->size = 0;
1417static void ecs_flush_removed(
ecs_t* ecs)
1419 ecs_id_array_t* remove_queue = &ecs->remove_queue;
1421 for (
size_t i = 0; i < remove_queue->size; i += 2)
1423 ecs_id_t entity_id = remove_queue->data[i];
1425 if (ecs_is_active(ecs, entity_id))
1427 ecs_id_t comp_id = remove_queue->data[i + 1];
1428 ecs_remove(ecs, ecs_make_entity(entity_id), ecs_make_comp(comp_id));
1432 remove_queue->size = 0;
1440#if ECS_MAX_COMPONENTS <= 64
1442static inline bool ecs_bitset_is_zero(ecs_bitset_t* set)
1447static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on)
1450 *set |= ((uint64_t)1 << bit);
1452 *set &= ~((uint64_t)1 << bit);
1455static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit)
1457 return *set & ((uint64_t)1 << bit);
1460static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1, ecs_bitset_t* set2)
1462 return *set1 & *set2;
1465static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1, ecs_bitset_t* set2)
1467 return *set1 | *set2;
1470static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set)
1475static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2)
1477 return *set1 == *set2;
1480static inline bool ecs_bitset_true(ecs_bitset_t* set)
1487static inline bool ecs_bitset_is_zero(ecs_bitset_t* set)
1489 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1491 if (set->array[i] != 0)
1498static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on)
1500 int index = bit / ECS_BITSET_WIDTH;
1503 set->array[index] |= ((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1505 set->array[index] &= ~((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1508static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit)
1510 int index = bit / ECS_BITSET_WIDTH;
1511 return set->array[index] & ((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1514static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1,
1519 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1521 set.array[i] = set1->array[i] & set2->array[i];
1527static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1,
1532 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1534 set.array[i] = set1->array[i] | set2->array[i];
1540static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set)
1544 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1546 out.array[i] = ~set->array[i];
1552static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2)
1554 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1556 if (set1->array[i] != set2->array[i])
1565static inline bool ecs_bitset_true(ecs_bitset_t* set)
1567 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1582static void ecs_sparse_set_init(
ecs_t* ecs, ecs_sparse_set_t* set,
size_t capacity)
1584 ECS_ASSERT(ecs_is_not_null(ecs));
1585 ECS_ASSERT(ecs_is_not_null(set));
1586 ECS_ASSERT(capacity > 0);
1590 set->capacity = capacity;
1594 set->sparse = (
size_t*) ECS_MALLOC(capacity *
sizeof(
size_t), ecs->mem_ctx);
1596 memset(set->sparse, 0, capacity *
sizeof(
size_t));
1599static void ecs_sparse_set_free(
ecs_t* ecs, ecs_sparse_set_t* set)
1601 ECS_ASSERT(ecs_is_not_null(ecs));
1602 ECS_ASSERT(ecs_is_not_null(set));
1606 ECS_FREE(set->dense, ecs->mem_ctx);
1607 ECS_FREE(set->sparse, ecs->mem_ctx);
1610static bool ecs_sparse_set_add(
ecs_t* ecs, ecs_sparse_set_t* set,
ecs_id_t id)
1612 ECS_ASSERT(ecs_is_not_null(ecs));
1613 ECS_ASSERT(ecs_is_not_null(set));
1618 if (
id >= set->capacity)
1620 size_t old_capacity = set->capacity;
1621 size_t new_capacity = old_capacity;
1632 set->sparse = (
size_t*)ecs_realloc_zero(ecs,
1634 old_capacity *
sizeof(
size_t),
1635 new_capacity *
sizeof(size_t));
1638 set->capacity = new_capacity;
1642 if (ecs_sparse_set_find(set,
id, NULL))
1646 set->dense[set->size].id = id;
1647 set->sparse[id] = set->size;
1654static bool ecs_sparse_set_find(ecs_sparse_set_t* set,
ecs_id_t id,
size_t* found)
1656 ECS_ASSERT(ecs_is_not_null(set));
1658 if (set->sparse[
id] < set->size && set->dense[set->sparse[
id]].id ==
id)
1660 if (found) *found = set->sparse[id];
1665 if (found) *found = 0;
1670static bool ecs_sparse_set_remove(ecs_sparse_set_t* set,
ecs_id_t id)
1672 ECS_ASSERT(ecs_is_not_null(set));
1674 if (!ecs_sparse_set_find(set,
id, NULL))
1678 ecs_id_t tmp = set->dense[set->size - 1].id;
1679 set->dense[set->sparse[id]].id = tmp;
1680 set->sparse[tmp] = set->sparse[id];
1691inline static bool ecs_entity_system_test(ecs_bitset_t* require_bits,
1692 ecs_bitset_t* exclude_bits,
1693 ecs_bitset_t* entity_bits)
1695 if (!ecs_bitset_is_zero(exclude_bits))
1697 ecs_bitset_t overlap = ecs_bitset_and(entity_bits, exclude_bits);
1699 if (ecs_bitset_true(&overlap))
1705 ecs_bitset_t entity_and_require = ecs_bitset_and(entity_bits, require_bits);
1706 return ecs_bitset_equal(&entity_and_require, require_bits);
1713inline static void ecs_id_array_init(
ecs_t* ecs, ecs_id_array_t* array,
int capacity)
1715 ECS_ASSERT(ecs_is_not_null(ecs));
1716 ECS_ASSERT(ecs_is_not_null(array));
1717 ECS_ASSERT(capacity > 0);
1722 array->capacity = capacity;
1723 array->data = (
ecs_id_t*)ECS_MALLOC(capacity *
sizeof(
ecs_id_t), ecs->mem_ctx);
1726inline static void ecs_id_array_free(
ecs_t* ecs, ecs_id_array_t* array)
1728 ECS_ASSERT(ecs_is_not_null(ecs));
1729 ECS_ASSERT(ecs_is_not_null(array));
1733 ECS_FREE(array->data, ecs->mem_ctx);
1736inline static void ecs_id_array_push(
ecs_t* ecs, ecs_id_array_t* array,
ecs_id_t id)
1738 ECS_ASSERT(ecs_is_not_null(ecs));
1739 ECS_ASSERT(ecs_is_not_null(array));
1740 ECS_ASSERT(array->capacity > 0);
1744 if (array->size == array->capacity)
1746 array->capacity *= 2;
1747 array->data = (
ecs_id_t*)ECS_REALLOC(array->data,
1748 array->capacity *
sizeof(
ecs_id_t),
1752 array->data[array->size++] = id;
1755inline static ecs_id_t ecs_id_array_pop(ecs_id_array_t* array)
1757 ECS_ASSERT(ecs_is_not_null(array));
1758 return array->data[--array->size];
1761inline static int ecs_id_array_size(ecs_id_array_t* array)
1766static void ecs_comp_array_init(
ecs_t* ecs, ecs_comp_array_t* array,
size_t size,
size_t capacity)
1768 ECS_ASSERT(ecs_is_not_null(ecs));
1769 ECS_ASSERT(ecs_is_not_null(array));
1773 memset(array, 0,
sizeof(ecs_comp_array_t));
1775 array->capacity = capacity;
1777 array->data = ECS_MALLOC(size * capacity, ecs->mem_ctx);
1780static void ecs_comp_array_free(
ecs_t* ecs, ecs_comp_array_t* array)
1782 ECS_ASSERT(ecs_is_not_null(ecs));
1783 ECS_ASSERT(ecs_is_not_null(array));
1787 ECS_FREE(array->data, ecs->mem_ctx);
1790static void ecs_comp_array_resize(
ecs_t* ecs, ecs_comp_array_t* array,
size_t capacity)
1792 ECS_ASSERT(ecs_is_not_null(ecs));
1793 ECS_ASSERT(ecs_is_not_null(array));
1797 if (capacity >= array->capacity)
1799 array->capacity *= 2;
1800 array->data = ECS_REALLOC(array->data,
1801 array->capacity * array->size,
1810static bool ecs_is_not_null(
void* ptr)
1815static bool ecs_is_valid_component_id(
ecs_id_t id)
1817 return id < ECS_MAX_COMPONENTS;
1820static bool ecs_is_valid_system_id(
ecs_id_t id)
1822 return id < ECS_MAX_SYSTEMS;
1825static bool ecs_is_entity_ready(
ecs_t* ecs,
ecs_id_t entity_id)
1827 return ecs->entities[entity_id].ready;
1830static bool ecs_is_component_ready(
ecs_t* ecs,
ecs_id_t comp_id)
1832 return comp_id < ecs->comp_count;
1837 return sys_id < ecs->system_count;
void(* ecs_destructor_fn)(ecs_t *ecs, ecs_entity_t entity, void *comp_ptr)
Called when a component is destroyed (via ecs_remove or ecs_destroy)
Definition pico_ecs.h:256
void ecs_enable_system(ecs_t *ecs, ecs_system_t sys)
Enables a system.
void ecs_queue_remove(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp)
Queues a component for removal from the specified entity.
void * ecs_add(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp, void *args)
Adds a component instance to an entity.
#define ECS_MASK_TYPE
Determine mask type.
Definition pico_ecs.h:177
ecs_system_t ecs_define_system(ecs_t *ecs, ecs_mask_t mask, ecs_system_fn system_cb, ecs_added_fn add_cb, ecs_removed_fn remove_cb, void *udata)
Defines a system.
ecs_entity_t ecs_invalid_entity()
Returns an invalid entity.
void * ecs_get(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp)
Gets a component instance associated with an entity.
void ecs_remove(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp)
Removes a component instance from an entity.
ECS_MASK_TYPE ecs_mask_t
Type for value used in system matching.
Definition pico_ecs.h:183
void ecs_queue_destroy(ecs_t *ecs, ecs_entity_t entity)
Queues an entity for destruction after the current system returns.
void ecs_exclude_component(ecs_t *ecs, ecs_system_t sys, ecs_comp_t comp)
Excludes entities having the specified component from being added to the target system.
void ecs_set_system_callbacks(ecs_t *ecs, ecs_system_t sys, ecs_system_fn system_cb, ecs_added_fn add_cb, ecs_removed_fn remove_cb)
Updates the callbacks for an existing system.
ecs_ret_t ecs_run_systems(ecs_t *ecs, ecs_mask_t mask)
Updates all systems.
ECS_ID_TYPE ecs_id_t
ID used for entity and components.
Definition pico_ecs.h:171
ecs_ret_t(* ecs_system_fn)(ecs_t *ecs, ecs_entity_t *entities, size_t entity_count, void *udata)
System callback.
Definition pico_ecs.h:289
void ecs_destroy(ecs_t *ecs, ecs_entity_t entity)
Destroys an entity.
ecs_comp_t ecs_define_component(ecs_t *ecs, size_t size, ecs_constructor_fn constructor, ecs_destructor_fn destructor)
Defines a component.
void ecs_free(ecs_t *ecs)
Destroys an ECS context.
void(* ecs_removed_fn)(ecs_t *ecs, ecs_entity_t entity, void *udata)
Called when an entity is removed from a system.
Definition pico_ecs.h:310
void * ecs_get_system_udata(ecs_t *ecs, ecs_system_t sys)
Gets the user data from a system.
void ecs_set_system_udata(ecs_t *ecs, ecs_system_t sys, void *udata)
Sets the user data for a system.
struct ecs_s ecs_t
ECS context.
Definition pico_ecs.h:159
void ecs_reset(ecs_t *ecs)
Removes all entities from the ECS, preserving systems and components.
bool ecs_is_ready(ecs_t *ecs, ecs_entity_t entity)
Returns true if the entity is currently active and has not been queued for destruction.
size_t ecs_get_system_entity_count(ecs_t *ecs, ecs_system_t sys)
Returns the number of entities assigned to the specified system.
void ecs_require_component(ecs_t *ecs, ecs_system_t sys, ecs_comp_t comp)
Entities are processed by the target system if they have all of the the components required by the sy...
ecs_ret_t ecs_run_system(ecs_t *ecs, ecs_system_t sys, ecs_mask_t mask)
Update an individual system.
void(* ecs_added_fn)(ecs_t *ecs, ecs_entity_t entity, void *udata)
Called when an entity is added to a system.
Definition pico_ecs.h:301
int32_t ecs_ret_t
Return code for system callback and calling functions.
Definition pico_ecs.h:188
void ecs_set_system_mask(ecs_t *ecs, ecs_system_t sys, ecs_mask_t mask)
Sets the system's mask.
void ecs_disable_system(ecs_t *ecs, ecs_system_t sys)
Disables a system.
bool ecs_has(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp)
Test if entity has the specified component.
void(* ecs_constructor_fn)(ecs_t *ecs, ecs_entity_t entity, void *comp_ptr, void *args)
Called when a component is created (via ecs_add)
Definition pico_ecs.h:244
ecs_entity_t ecs_create(ecs_t *ecs)
Creates an entity.
ecs_t * ecs_new(size_t entity_count, void *mem_ctx)
Creates an ECS context.
bool ecs_is_invalid_entity(ecs_entity_t entity)
Returns true if the entity is invalid and false otherwise.
#define ECS_ID_TYPE
Determine ID type.
Definition pico_ecs.h:165
ecs_mask_t ecs_get_system_mask(ecs_t *ecs, ecs_system_t sys)
Returns the system mask.
A component handle.
Definition pico_ecs.h:198
ecs_id_t id
Definition pico_ecs.h:198
An entity handle.
Definition pico_ecs.h:193
ecs_id_t id
Definition pico_ecs.h:193
A system handle.
Definition pico_ecs.h:203
ecs_id_t id
Definition pico_ecs.h:203