181#define ECS_ID_TYPE uint64_t
193#define ECS_MASK_TYPE uint64_t
224#define ECS_INVALID_ID ((ecs_id_t)-1)
229#define ECS_IS_INVALID(obj) ((obj.id) == ECS_INVALID_ID)
540#ifdef PICO_ECS_IMPLEMENTATION
542#ifndef PICO_ECS_MAX_COMPONENTS
543#define PICO_ECS_MAX_COMPONENTS 32
546#ifndef PICO_ECS_MAX_SYSTEMS
547#define PICO_ECS_MAX_SYSTEMS 16
551 #define PICO_ECS_ASSERT(expr) ((void)0)
553 #ifndef PICO_ECS_ASSERT
555 #define PICO_ECS_ASSERT(expr) (assert(expr))
559#if !defined(PICO_ECS_MALLOC) || !defined(PICO_ECS_REALLOC) || !defined(PICO_ECS_FREE)
561#define PICO_ECS_MALLOC(size, ctx) (malloc(size))
562#define PICO_ECS_REALLOC(ptr, size, ctx) (realloc(ptr, size))
563#define PICO_ECS_FREE(ptr, ctx) (free(ptr))
566#ifndef PICO_ECS_MEMSET
568 #define PICO_ECS_MEMSET memset
575#define ECS_ASSERT PICO_ECS_ASSERT
576#define ECS_MAX_COMPONENTS PICO_ECS_MAX_COMPONENTS
577#define ECS_MAX_SYSTEMS PICO_ECS_MAX_SYSTEMS
578#define ECS_MALLOC PICO_ECS_MALLOC
579#define ECS_REALLOC PICO_ECS_REALLOC
580#define ECS_FREE PICO_ECS_FREE
581#define ECS_MEMSET PICO_ECS_MEMSET
587#if ECS_MAX_COMPONENTS <= 32
588typedef uint32_t ecs_bitset_t;
589#elif ECS_MAX_COMPONENTS <= 64
590typedef uint64_t ecs_bitset_t;
592#define ECS_BITSET_WIDTH 64
593#define ECS_BITSET_SIZE (((ECS_MAX_COMPONENTS - 1) / ECS_BITSET_WIDTH) + 1)
597 uint64_t array[ECS_BITSET_SIZE];
629 ecs_bitset_t comp_bits;
643 ecs_sparse_set_t entity_ids;
648 ecs_bitset_t require_bits;
649 ecs_bitset_t exclude_bits;
655 ecs_id_array_t entity_pool;
656 ecs_id_array_t add_queue;
657 ecs_id_array_t remove_queue;
658 ecs_id_array_t destroy_queue;
659 ecs_entity_data_t* entities;
661 size_t next_entity_id;
662 ecs_comp_data_t comps[ECS_MAX_COMPONENTS];
663 ecs_comp_array_t comp_arrays[ECS_MAX_COMPONENTS];
665 ecs_sys_data_t systems[ECS_MAX_SYSTEMS];
681static void* ecs_realloc_zero(
ecs_t* ecs,
void* ptr,
size_t old_size,
size_t new_size);
691static inline bool ecs_is_active(
ecs_t* ecs,
ecs_id_t entity_id);
703static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on);
704static inline bool ecs_bitset_is_zero(ecs_bitset_t* set);
705static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit);
706static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1, ecs_bitset_t* set2);
707static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1, ecs_bitset_t* set2);
708static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set);
709static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2);
710static inline bool ecs_bitset_true(ecs_bitset_t* set);
715static void ecs_sparse_set_init(
ecs_t* ecs, ecs_sparse_set_t* set,
size_t capacity);
716static void ecs_sparse_set_free(
ecs_t* ecs, ecs_sparse_set_t* set);
717static bool ecs_sparse_set_add(
ecs_t* ecs, ecs_sparse_set_t* set,
ecs_id_t id);
718static inline bool ecs_sparse_set_find(ecs_sparse_set_t* set,
ecs_id_t id,
size_t* found);
719static inline bool ecs_sparse_set_remove(ecs_sparse_set_t* set,
ecs_id_t id);
724static bool ecs_entity_system_test(ecs_bitset_t* require_bits,
725 ecs_bitset_t* exclude_bits,
726 ecs_bitset_t* entity_bits);
728static bool ecs_entity_system_remove_test(ecs_bitset_t* require_bits,
729 ecs_bitset_t* exclude_bits,
730 ecs_bitset_t* entity_bits);
735static void ecs_id_array_init(
ecs_t* ecs, ecs_id_array_t* pool,
size_t capacity);
736static void ecs_id_array_free(
ecs_t* ecs, ecs_id_array_t* pool);
737static inline void ecs_id_array_push(
ecs_t* ecs, ecs_id_array_t* pool,
ecs_id_t id);
738static inline ecs_id_t ecs_id_array_pop(ecs_id_array_t* pool);
739static int ecs_id_array_size(ecs_id_array_t* pool);
744static void ecs_comp_array_init(
ecs_t* ecs, ecs_comp_array_t* array,
size_t size,
size_t capacity);
745static void ecs_comp_array_free(
ecs_t* ecs, ecs_comp_array_t* array);
746static void ecs_comp_array_resize(
ecs_t* ecs, ecs_comp_array_t* array,
ecs_id_t id);
752static bool ecs_is_not_null(
void* ptr);
753static bool ecs_is_valid_component_id(
ecs_id_t id);
754static bool ecs_is_valid_system_id(
ecs_id_t id);
755static bool ecs_is_valid_id(
ecs_id_t id);
756static bool ecs_is_valid_capacity(
size_t capacity,
size_t elem_size);
757static bool ecs_is_entity_ready(
ecs_t* ecs,
ecs_id_t entity_id);
758static bool ecs_is_component_ready(
ecs_t* ecs,
ecs_id_t comp_id);
768 ECS_ASSERT(entity_count > 0);
769 ECS_ASSERT(!ecs_is_valid_id(
ECS_INVALID_ID) &&
"ecs_id_t is signed");
777 ECS_MEMSET(ecs, 0,
sizeof(
ecs_t));
779 ecs->entity_count = (entity_count > 0) ? entity_count : 1;
780 ecs->next_entity_id = 0;
781 ecs->active_system = -1;
782 ecs->mem_ctx = mem_ctx;
785 ecs_id_array_init(ecs, &ecs->entity_pool, entity_count);
786 ecs_id_array_init(ecs, &ecs->add_queue, entity_count);
787 ecs_id_array_init(ecs, &ecs->remove_queue, entity_count);
788 ecs_id_array_init(ecs, &ecs->destroy_queue, entity_count);
791 ECS_ASSERT(ecs_is_valid_capacity(ecs->entity_count,
sizeof(ecs_entity_data_t)));
792 ecs->entities = (ecs_entity_data_t*)ECS_MALLOC(ecs->entity_count *
sizeof(ecs_entity_data_t),
796 ECS_MEMSET(ecs->entities, 0, ecs->entity_count *
sizeof(ecs_entity_data_t));
803 ECS_ASSERT(ecs_is_not_null(ecs));
805 for (
ecs_id_t entity_id = 0; entity_id < ecs->entity_count; entity_id++)
807 if (ecs->entities[entity_id].active)
808 ecs_destruct(ecs, entity_id);
811 ecs_id_array_free(ecs, &ecs->entity_pool);
812 ecs_id_array_free(ecs, &ecs->add_queue);
813 ecs_id_array_free(ecs, &ecs->remove_queue);
814 ecs_id_array_free(ecs, &ecs->destroy_queue);
816 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
818 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp_id];
819 ecs_comp_array_free(ecs, comp_array);
822 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
824 ecs_sys_data_t* sys = &ecs->systems[sys_id];
825 ecs_sparse_set_free(ecs, &sys->entity_ids);
828 ECS_FREE(ecs->entities, ecs->mem_ctx);
829 ECS_FREE(ecs, ecs->mem_ctx);
834 ECS_ASSERT(ecs_is_not_null(ecs));
836 for (
ecs_id_t entity_id = 0; entity_id < ecs->entity_count; entity_id++)
838 if (ecs->entities[entity_id].active)
839 ecs_destruct(ecs, entity_id);
842 ecs->entity_pool.size = 0;
843 ecs->add_queue.size = 0;
844 ecs->destroy_queue.size = 0;
845 ecs->remove_queue.size = 0;
847 ECS_MEMSET(ecs->entities, 0, ecs->entity_count *
sizeof(ecs_entity_data_t));
849 ecs->next_entity_id = 0;
851 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
853 ecs->systems[sys_id].entity_ids.size = 0;
862 ECS_ASSERT(ecs_is_not_null(ecs));
863 ECS_ASSERT(ecs->comp_count < ECS_MAX_COMPONENTS);
864 ECS_ASSERT(size > 0);
866 ecs_comp_t comp = ecs_make_comp(ecs->comp_count);
868 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp.
id];
869 ecs_comp_array_init(ecs, comp_array, size, ecs->entity_count);
871 ecs->comps[comp.
id].constructor = constructor;
872 ecs->comps[comp.
id].destructor = destructor;
886 ECS_ASSERT(ecs_is_not_null(ecs));
887 ECS_ASSERT(ecs->system_count < ECS_MAX_SYSTEMS);
888 ECS_ASSERT(NULL != system_cb);
891 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
893 ecs_sparse_set_init(ecs, &sys_data->entity_ids, ecs->entity_count);
895 sys_data->active =
true;
896 sys_data->mask = mask;
897 sys_data->system_cb = system_cb;
898 sys_data->add_cb = add_cb;
899 sys_data->remove_cb = remove_cb;
900 sys_data->udata = udata;
909 ECS_ASSERT(ecs_is_not_null(ecs));
910 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
911 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
912 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
913 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
916 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
917 ecs_bitset_flip(&sys_data->require_bits, comp.
id,
true);
922 ECS_ASSERT(ecs_is_not_null(ecs));
923 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
924 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
925 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
926 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
929 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
930 ecs_bitset_flip(&sys_data->exclude_bits, comp.
id,
true);
935 ECS_ASSERT(ecs_is_not_null(ecs));
936 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
937 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
939 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
940 sys_data->active =
true;
945 ECS_ASSERT(ecs_is_not_null(ecs));
946 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
947 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
949 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
950 sys_data->active =
false;
959 ECS_ASSERT(ecs_is_not_null(ecs));
960 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
961 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
962 ECS_ASSERT(NULL != system_cb);
964 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
965 sys_data->system_cb = system_cb;
966 sys_data->add_cb = add_cb;
967 sys_data->remove_cb = remove_cb;
972 ECS_ASSERT(ecs_is_not_null(ecs));
973 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
974 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
976 ecs->systems[sys.
id].udata = udata;
981 ECS_ASSERT(ecs_is_not_null(ecs));
982 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
983 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
985 return ecs->systems[sys.
id].udata;
990 ECS_ASSERT(ecs_is_not_null(ecs));
991 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
992 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
994 ecs->systems[sys.
id].mask = mask;
999 ECS_ASSERT(ecs_is_not_null(ecs));
1000 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1001 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1003 return ecs->systems[sys.
id].mask;
1008 return ecs->systems[sys.
id].entity_ids.size;
1013 ECS_ASSERT(ecs_is_not_null(ecs));
1018 ecs_id_array_t* pool = &ecs->entity_pool;
1020 if (0 != ecs_id_array_size(pool))
1022 entity_id = ecs_id_array_pop(pool);
1027 entity_id = ecs->next_entity_id++;
1030 if (entity_id >= ecs->entity_count)
1032 size_t old_count = ecs->entity_count;
1033 size_t new_count = 2 * old_count;
1035 ECS_ASSERT(ecs_is_valid_capacity(new_count,
sizeof(ecs_entity_data_t)));
1036 ecs->entities = (ecs_entity_data_t*)ecs_realloc_zero(ecs, ecs->entities,
1037 old_count *
sizeof(ecs_entity_data_t),
1038 new_count *
sizeof(ecs_entity_data_t));
1040 ecs->entity_count = new_count;
1045 ecs->entities[entity_id].active =
true;
1046 ecs->entities[entity_id].ready =
true;
1048 return ecs_make_entity(entity_id);
1053 ECS_ASSERT(ecs_is_not_null(ecs));
1055 return ecs->entities[entity.
id].ready;
1060 ECS_ASSERT(ecs_is_not_null(ecs));
1061 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1062 ECS_ASSERT(ecs_is_active(ecs, entity.
id));
1065 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1068 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1072 if (ecs->active_system == (
int)sys_id)
1075 ecs_sys_data_t* sys_data = &ecs->systems[sys_id];
1078 if (ecs_entity_system_test(&sys_data->require_bits,
1079 &sys_data->exclude_bits,
1080 &entity_data->comp_bits))
1084 if (ecs_sparse_set_remove(&sys_data->entity_ids, entity.
id))
1086 if (sys_data->remove_cb)
1087 sys_data->remove_cb(ecs, entity, sys_data->udata);
1093 if (ecs->active_system >= 0)
1095 ecs_sys_data_t* sys_data = &ecs->systems[ecs->active_system];
1098 if (ecs_entity_system_test(&sys_data->require_bits,
1099 &sys_data->exclude_bits,
1100 &entity_data->comp_bits))
1104 if (ecs_sparse_set_find(&sys_data->entity_ids, entity.
id, NULL))
1106 if (sys_data->remove_cb)
1107 sys_data->remove_cb(ecs, entity, sys_data->udata);
1109 ecs_id_array_push(ecs, &ecs->destroy_queue, entity.
id);
1111 entity_data->ready =
false;
1112 entity_data->active =
true;
1118 ecs_destruct(ecs, entity.
id);
1121 if (ecs->active_system < 0)
1124 ecs_id_array_t* pool = &ecs->entity_pool;
1125 ecs_id_array_push(ecs, pool, entity.
id);
1128 ECS_MEMSET(entity_data, 0,
sizeof(ecs_entity_data_t));
1134 ECS_ASSERT(ecs_is_not_null(ecs));
1135 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1136 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1137 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1140 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1143 return ecs_bitset_test(&entity_data->comp_bits, comp.
id);
1148 ECS_ASSERT(ecs_is_not_null(ecs));
1149 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1150 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1151 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1152 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1157 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp.
id];
1158 return (
char*)comp_array->data + (comp_array->size * entity.
id);
1163 ECS_ASSERT(ecs_is_not_null(ecs));
1164 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1165 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1166 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1167 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1170 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1173 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp.
id];
1174 ecs_comp_data_t* comp_data = &ecs->comps[comp.
id];
1177 ecs_comp_array_resize(ecs, comp_array, entity.
id);
1180 void* comp_ptr =
ecs_get(ecs, entity, comp);
1183 ECS_MEMSET(comp_ptr, 0, comp_array->size);
1186 if (comp_data->constructor)
1187 comp_data->constructor(ecs, entity, comp_ptr, args);
1191 ecs_bitset_flip(&entity_data->comp_bits, comp.
id,
true);
1194 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1198 if (ecs->active_system == (
int)sys_id)
1201 ecs_sys_data_t* sys_data = &ecs->systems[sys_id];
1204 if (ecs_entity_system_test(&sys_data->require_bits,
1205 &sys_data->exclude_bits,
1206 &entity_data->comp_bits))
1209 if (ecs_sparse_set_add(ecs, &sys_data->entity_ids, entity.
id))
1211 if (sys_data->add_cb)
1212 sys_data->add_cb(ecs, entity, sys_data->udata);
1218 if (!ecs_bitset_is_zero(&sys_data->exclude_bits))
1222 if (ecs_sparse_set_remove(&sys_data->entity_ids, entity.
id))
1224 if (sys_data->remove_cb)
1225 sys_data->remove_cb(ecs, entity, sys_data->udata);
1232 if (ecs->active_system >= 0)
1235 ecs_sys_data_t* sys_data = &ecs->systems[ecs->active_system];
1238 if (ecs_entity_system_test(&sys_data->require_bits,
1239 &sys_data->exclude_bits,
1240 &entity_data->comp_bits))
1242 ecs_sparse_set_t* set = &sys_data->entity_ids;
1246 if (set->size < set->capacity)
1249 if (ecs_sparse_set_add(ecs, set, entity.
id))
1251 if (sys_data->add_cb)
1252 sys_data->add_cb(ecs, entity, sys_data->udata);
1258 if (!ecs_sparse_set_find(set, entity.
id, NULL))
1260 if (sys_data->add_cb)
1261 sys_data->add_cb(ecs, entity, sys_data->udata);
1263 ecs_id_array_push(ecs, &ecs->add_queue, entity.
id);
1270 if (!ecs_bitset_is_zero(&sys_data->exclude_bits))
1275 if (ecs_sparse_set_find(&sys_data->entity_ids, entity.
id, NULL))
1277 if (sys_data->remove_cb)
1278 sys_data->remove_cb(ecs, entity, sys_data->udata);
1280 ecs_id_array_push(ecs, &ecs->remove_queue, entity.
id);
1292 ECS_ASSERT(ecs_is_not_null(ecs));
1293 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1294 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1295 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1296 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1299 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1302 ecs_bitset_t comp_bit;
1304 ECS_MEMSET(&comp_bit, 0,
sizeof(ecs_bitset_t));
1305 ecs_bitset_flip(&comp_bit, comp.
id,
true);
1308 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1312 if (ecs->active_system == (
int)sys_id)
1315 ecs_sys_data_t* sys_data = &ecs->systems[sys_id];
1318 if (ecs_entity_system_remove_test(&sys_data->require_bits,
1319 &sys_data->exclude_bits,
1323 if (ecs_sparse_set_remove(&sys_data->entity_ids, entity.
id))
1325 if (sys_data->remove_cb)
1326 sys_data->remove_cb(ecs, entity, sys_data->udata);
1332 if (!ecs_bitset_is_zero(&sys_data->exclude_bits))
1335 if (ecs_sparse_set_add(ecs, &sys_data->entity_ids, entity.
id))
1337 if (sys_data->add_cb)
1338 sys_data->add_cb(ecs, entity, sys_data->udata);
1345 if (ecs->active_system >= 0)
1348 ecs_sys_data_t* sys_data = &ecs->systems[ecs->active_system];
1351 if (ecs_entity_system_remove_test(&sys_data->require_bits,
1352 &sys_data->exclude_bits,
1359 if (ecs_sparse_set_find(&sys_data->entity_ids, entity.
id, NULL))
1361 if (sys_data->remove_cb)
1362 sys_data->remove_cb(ecs, entity, sys_data->udata);
1364 ecs_id_array_push(ecs, &ecs->remove_queue, entity.
id);
1370 if (!ecs_bitset_is_zero(&sys_data->exclude_bits))
1372 ecs_sparse_set_t* set = &sys_data->entity_ids;
1376 if (set->size < set->capacity)
1378 if (ecs_sparse_set_add(ecs, set, entity.
id))
1380 if (sys_data->add_cb)
1381 sys_data->add_cb(ecs, entity, sys_data->udata);
1387 if (!ecs_sparse_set_find(set, entity.
id, NULL))
1389 if (sys_data->add_cb)
1390 sys_data->add_cb(ecs, entity, sys_data->udata);
1392 ecs_id_array_push(ecs, &ecs->add_queue, entity.
id);
1400 ecs_comp_data_t* comp_data = &ecs->comps[comp.
id];
1402 if (comp_data->destructor)
1404 void* comp_ptr =
ecs_get(ecs, entity, comp);
1405 comp_data->destructor(ecs, entity, comp_ptr);
1409 ecs_bitset_flip(&entity_data->comp_bits, comp.
id,
false);
1414 ECS_ASSERT(ecs_is_not_null(ecs));
1415 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1416 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1418 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1420 if (!sys_data->active)
1423 if (0 != sys_data->mask && !(sys_data->mask & mask))
1426 ecs->active_system = (int)sys.
id;
1428 ecs_ret_t code = sys_data->system_cb(ecs,
1429 sys_data->entity_ids.dense,
1430 sys_data->entity_ids.size,
1433 ecs_flush_added(ecs, sys.
id);
1434 ecs_flush_removed(ecs, sys.
id);
1435 ecs_flush_destroyed(ecs, sys.
id);
1437 ecs->active_system = -1;
1444 ECS_ASSERT(ecs_is_not_null(ecs));
1446 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1482static void* ecs_realloc_zero(
ecs_t* ecs,
void* ptr,
size_t old_size,
size_t new_size)
1486 ptr = ECS_REALLOC(ptr, new_size, ecs->mem_ctx);
1488 if (new_size > old_size && ptr) {
1489 size_t diff = new_size - old_size;
1490 void* start = ((
char*)ptr)+ old_size;
1491 ECS_MEMSET(start, 0, diff);
1500static inline bool ecs_is_active(
ecs_t* ecs,
ecs_id_t entity_id)
1502 ECS_ASSERT(ecs_is_not_null(ecs));
1503 return ecs->entities[entity_id].active;
1512 ecs_entity_data_t* entity = &ecs->entities[entity_id];
1515 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
1517 if (ecs_bitset_test(&entity->comp_bits, comp_id))
1519 ecs_comp_data_t* comp = &ecs->comps[comp_id];
1521 if (comp->destructor)
1525 ecs_comp_array_t* comp_array = &ecs->comp_arrays[comp_id];
1526 void* comp_ptr = (
char*)comp_array->data + (comp_array->size * entity_id);
1529 comp->destructor(ecs, entity, comp_ptr);
1540 ecs_id_array_t* queue = &ecs->add_queue;
1542 for (
size_t i = 0; i < queue->size; i++)
1544 ecs_id_t entity_id = queue->data[i];
1546 ECS_ASSERT(ecs_is_active(ecs, entity_id));
1547 ecs_sparse_set_add(ecs, &ecs->systems[sys_id].entity_ids, entity_id);
1555 ecs_id_array_t* remove_queue = &ecs->remove_queue;
1557 for (
size_t i = 0; i < remove_queue->size; i++)
1559 ecs_id_t entity_id = remove_queue->data[i];
1561 ECS_ASSERT(ecs_is_active(ecs, entity_id));
1562 ecs_sparse_set_remove(&ecs->systems[sys_id].entity_ids, entity_id);
1565 remove_queue->size = 0;
1570 ecs_id_array_t* destroy_queue = &ecs->destroy_queue;
1572 for (
size_t i = 0; i < destroy_queue->size; i++)
1574 ecs_id_t entity_id = destroy_queue->data[i];
1576 ECS_ASSERT(ecs_is_active(ecs, entity_id));
1577 ecs_sparse_set_remove(&ecs->systems[sys_id].entity_ids, entity_id);
1580 ecs_id_array_t* pool = &ecs->entity_pool;
1581 ecs_id_array_push(ecs, pool, entity_id);
1584 ECS_MEMSET(&ecs->entities[entity_id], 0,
sizeof(ecs_entity_data_t));
1587 destroy_queue->size = 0;
1595#if ECS_MAX_COMPONENTS <= 64
1597static inline bool ecs_bitset_is_zero(ecs_bitset_t* set)
1602static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on)
1605 *set |= ((uint64_t)1 << bit);
1607 *set &= ~((uint64_t)1 << bit);
1610static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit)
1612 return *set & ((uint64_t)1 << bit);
1615static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1, ecs_bitset_t* set2)
1617 return *set1 & *set2;
1620static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1, ecs_bitset_t* set2)
1622 return *set1 | *set2;
1625static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set)
1630static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2)
1632 return *set1 == *set2;
1635static inline bool ecs_bitset_true(ecs_bitset_t* set)
1642static inline bool ecs_bitset_is_zero(ecs_bitset_t* set)
1644 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1646 if (set->array[i] != 0)
1653static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on)
1655 int index = bit / ECS_BITSET_WIDTH;
1658 set->array[index] |= ((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1660 set->array[index] &= ~((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1663static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit)
1665 int index = bit / ECS_BITSET_WIDTH;
1666 return set->array[index] & ((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1669static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1,
1674 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1676 set.array[i] = set1->array[i] & set2->array[i];
1682static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1,
1687 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1689 set.array[i] = set1->array[i] | set2->array[i];
1695static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set)
1699 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1701 out.array[i] = ~set->array[i];
1707static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2)
1709 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1711 if (set1->array[i] != set2->array[i])
1720static inline bool ecs_bitset_true(ecs_bitset_t* set)
1722 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1737static void ecs_sparse_set_init(
ecs_t* ecs, ecs_sparse_set_t* set,
size_t capacity)
1739 ECS_ASSERT(ecs_is_not_null(ecs));
1740 ECS_ASSERT(ecs_is_not_null(set));
1744 set->capacity = capacity;
1747 ECS_ASSERT(ecs_is_valid_capacity(capacity,
sizeof(
ecs_entity_t)));
1750 ECS_ASSERT(ecs_is_valid_capacity(capacity,
sizeof(
size_t)));
1751 set->sparse = (
size_t*) ECS_MALLOC(capacity *
sizeof(
size_t), ecs->mem_ctx);
1753 ECS_MEMSET(set->sparse, 0, capacity *
sizeof(
size_t));
1756static void ecs_sparse_set_free(
ecs_t* ecs, ecs_sparse_set_t* set)
1758 ECS_ASSERT(ecs_is_not_null(ecs));
1759 ECS_ASSERT(ecs_is_not_null(set));
1763 ECS_FREE(set->dense, ecs->mem_ctx);
1764 ECS_FREE(set->sparse, ecs->mem_ctx);
1767static bool ecs_sparse_set_add(
ecs_t* ecs, ecs_sparse_set_t* set,
ecs_id_t id)
1769 ECS_ASSERT(ecs_is_not_null(ecs));
1770 ECS_ASSERT(ecs_is_not_null(set));
1771 ECS_ASSERT(ecs_is_valid_id(
id));
1776 if (ecs_sparse_set_find(set,
id, NULL))
1780 if (
id >= set->capacity)
1782 size_t old_capacity = set->capacity;
1783 size_t new_capacity = old_capacity;
1789 }
while (
id >= new_capacity);
1793 ECS_ASSERT(ecs_is_valid_capacity(set->capacity,
sizeof(
ecs_entity_t)));
1801 ECS_ASSERT(ecs_is_valid_capacity(set->capacity,
sizeof(
size_t)));
1802 set->sparse = (
size_t*)ecs_realloc_zero(ecs,
1804 old_capacity *
sizeof(
size_t),
1805 new_capacity *
sizeof(size_t));
1808 set->capacity = new_capacity;
1812 set->dense[set->size].id = id;
1813 set->sparse[id] = set->size;
1819static inline bool ecs_sparse_set_find(ecs_sparse_set_t* set,
ecs_id_t id,
size_t* found)
1821 ECS_ASSERT(ecs_is_not_null(set));
1822 ECS_ASSERT(ecs_is_valid_id(
id));
1824 if (id < set->capacity && set->sparse[
id] < set->size && set->dense[set->sparse[
id]].id ==
id)
1826 if (found) *found = set->sparse[id];
1831 if (found) *found = 0;
1836static inline bool ecs_sparse_set_remove(ecs_sparse_set_t* set,
ecs_id_t id)
1838 ECS_ASSERT(ecs_is_not_null(set));
1839 ECS_ASSERT(ecs_is_valid_id(
id));
1841 if (!ecs_sparse_set_find(set,
id, NULL))
1845 ecs_id_t tmp = set->dense[set->size - 1].id;
1846 set->dense[set->sparse[id]].id = tmp;
1847 set->sparse[tmp] = set->sparse[id];
1858static inline bool ecs_entity_system_test(ecs_bitset_t* require_bits,
1859 ecs_bitset_t* exclude_bits,
1860 ecs_bitset_t* entity_bits)
1862 if (!ecs_bitset_is_zero(exclude_bits))
1864 ecs_bitset_t overlap = ecs_bitset_and(entity_bits, exclude_bits);
1866 if (ecs_bitset_true(&overlap))
1872 ecs_bitset_t entity_and_require = ecs_bitset_and(entity_bits, require_bits);
1873 return ecs_bitset_equal(&entity_and_require, require_bits);
1876static inline bool ecs_entity_system_remove_test(ecs_bitset_t* require_bits,
1877 ecs_bitset_t* exclude_bits,
1878 ecs_bitset_t* entity_bits)
1880 if (!ecs_bitset_is_zero(exclude_bits))
1882 ecs_bitset_t overlap = ecs_bitset_and(entity_bits, exclude_bits);
1884 if (ecs_bitset_true(&overlap))
1890 ecs_bitset_t entity_and_require = ecs_bitset_and(entity_bits, require_bits);
1891 return ecs_bitset_true(&entity_and_require);
1898static void ecs_id_array_init(
ecs_t* ecs, ecs_id_array_t* array,
size_t capacity)
1900 ECS_ASSERT(ecs_is_not_null(ecs));
1901 ECS_ASSERT(ecs_is_not_null(array));
1906 array->capacity = capacity;
1908 ECS_ASSERT(ecs_is_valid_capacity(capacity,
sizeof(
ecs_id_t)));
1909 array->data = (
ecs_id_t*)ECS_MALLOC(capacity *
sizeof(
ecs_id_t), ecs->mem_ctx);
1912static void ecs_id_array_free(
ecs_t* ecs, ecs_id_array_t* array)
1914 ECS_ASSERT(ecs_is_not_null(ecs));
1915 ECS_ASSERT(ecs_is_not_null(array));
1919 ECS_FREE(array->data, ecs->mem_ctx);
1922static inline void ecs_id_array_push(
ecs_t* ecs, ecs_id_array_t* array,
ecs_id_t id)
1924 ECS_ASSERT(ecs_is_not_null(ecs));
1925 ECS_ASSERT(ecs_is_not_null(array));
1926 ECS_ASSERT(ecs_is_valid_id(
id));
1930 if (array->size == array->capacity)
1935 array->capacity *= 2;
1937 ECS_ASSERT(ecs_is_valid_capacity(array->capacity,
sizeof(
ecs_id_t)));
1938 array->data = (
ecs_id_t*)ECS_REALLOC(array->data,
1939 array->capacity *
sizeof(
ecs_id_t),
1943 array->data[array->size++] = id;
1946static inline ecs_id_t ecs_id_array_pop(ecs_id_array_t* array)
1948 ECS_ASSERT(ecs_is_not_null(array));
1949 return array->data[--array->size];
1952static inline int ecs_id_array_size(ecs_id_array_t* array)
1957static void ecs_comp_array_init(
ecs_t* ecs, ecs_comp_array_t* array,
size_t size,
size_t capacity)
1959 ECS_ASSERT(ecs_is_not_null(ecs));
1960 ECS_ASSERT(ecs_is_not_null(array));
1964 ECS_MEMSET(array, 0,
sizeof(ecs_comp_array_t));
1966 array->capacity = capacity;
1969 ECS_ASSERT(ecs_is_valid_capacity(capacity, size));
1970 array->data = ECS_MALLOC(capacity * size, ecs->mem_ctx);
1973static void ecs_comp_array_free(
ecs_t* ecs, ecs_comp_array_t* array)
1975 ECS_ASSERT(ecs_is_not_null(ecs));
1976 ECS_ASSERT(ecs_is_not_null(array));
1980 ECS_FREE(array->data, ecs->mem_ctx);
1983static void ecs_comp_array_resize(
ecs_t* ecs, ecs_comp_array_t* array,
ecs_id_t id)
1985 ECS_ASSERT(ecs_is_not_null(ecs));
1986 ECS_ASSERT(ecs_is_not_null(array));
1987 ECS_ASSERT(ecs_is_valid_id(
id));
1991 if (
id >= array->capacity)
1996 array->capacity *= 2;
1997 }
while (
id >= array->capacity);
1999 ECS_ASSERT(ecs_is_valid_capacity(array->capacity, array->size));
2000 array->data = ECS_REALLOC(array->data,
2001 array->capacity * array->size,
2010static bool ecs_is_not_null(
void* ptr)
2015static bool ecs_is_valid_component_id(
ecs_id_t id)
2017 return id < ECS_MAX_COMPONENTS;
2020static bool ecs_is_valid_system_id(
ecs_id_t id)
2022 return id < ECS_MAX_SYSTEMS;
2025static bool ecs_is_valid_id(
ecs_id_t id)
2028 return id == ((id << 1) >> 1);
2031static bool ecs_is_valid_capacity(
size_t capacity,
size_t elem_size)
2036 if (capacity == 0 || elem_size == 0)
2041 size_t max_cap = (SIZE_MAX >> 1) / elem_size;
2042 return capacity <= max_cap;
2045static bool ecs_is_entity_ready(
ecs_t* ecs,
ecs_id_t entity_id)
2047 return ecs->entities[entity_id].ready;
2050static bool ecs_is_component_ready(
ecs_t* ecs,
ecs_id_t comp_id)
2052 return comp_id < ecs->comp_count;
2057 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:272
void ecs_enable_system(ecs_t *ecs, ecs_system_t sys)
Enables a system.
#define ECS_INVALID_ID
An invalid ID.
Definition pico_ecs.h:224
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:193
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.
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:199
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:187
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:305
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:326
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:175
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:317
int32_t ecs_ret_t
Return code for system callback and calling functions.
Definition pico_ecs.h:204
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:260
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.
#define ECS_ID_TYPE
Determine ID type. It should be unsigned.
Definition pico_ecs.h:181
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:214
ecs_id_t id
Definition pico_ecs.h:214
An entity handle.
Definition pico_ecs.h:209
ecs_id_t id
Definition pico_ecs.h:209
A system handle.
Definition pico_ecs.h:219
ecs_id_t id
Definition pico_ecs.h:219