183#define ECS_ID_TYPE uint64_t
195#define ECS_MASK_TYPE uint64_t
226#define ECS_INVALID_ID ((ecs_id_t)-1)
231#define ECS_IS_INVALID(obj) ((obj.id) == ECS_INVALID_ID)
616#ifdef PICO_ECS_IMPLEMENTATION
618#ifndef PICO_ECS_MAX_COMPONENTS
619#define PICO_ECS_MAX_COMPONENTS 32
622#ifndef PICO_ECS_MAX_SYSTEMS
623#define PICO_ECS_MAX_SYSTEMS 16
626#ifndef PICO_ECS_COMP_BLOCK_SIZE
627#define PICO_ECS_COMP_BLOCK_SIZE 64
631 #define PICO_ECS_ASSERT(expr) ((void)0)
633 #ifndef PICO_ECS_ASSERT
635 #define PICO_ECS_ASSERT(expr) (assert(expr))
639#if !defined(PICO_ECS_MALLOC) || !defined(PICO_ECS_REALLOC) || !defined(PICO_ECS_FREE)
641#define PICO_ECS_MALLOC(size, ctx) (malloc(size))
642#define PICO_ECS_REALLOC(ptr, size, ctx) (realloc(ptr, size))
643#define PICO_ECS_FREE(ptr, ctx) (free(ptr))
646#ifndef PICO_ECS_MEMSET
648 #define PICO_ECS_MEMSET memset
651#ifndef PICO_ECS_MEMCPY
653 #define PICO_ECS_MEMCPY memcpy
662#define ECS_ASSERT PICO_ECS_ASSERT
663#define ECS_MAX_COMPONENTS PICO_ECS_MAX_COMPONENTS
664#define ECS_MAX_SYSTEMS PICO_ECS_MAX_SYSTEMS
665#define ECS_COMP_BLOCK_SIZE PICO_ECS_COMP_BLOCK_SIZE
666#define ECS_MALLOC PICO_ECS_MALLOC
667#define ECS_REALLOC PICO_ECS_REALLOC
668#define ECS_FREE PICO_ECS_FREE
669#define ECS_MEMSET PICO_ECS_MEMSET
670#define ECS_MEMCPY PICO_ECS_MEMCPY
676#if ECS_MAX_COMPONENTS <= 32
677typedef uint32_t ecs_bitset_t;
678#elif ECS_MAX_COMPONENTS <= 64
679typedef uint64_t ecs_bitset_t;
681#define ECS_BITSET_WIDTH 64
682#define ECS_BITSET_SIZE (((ECS_MAX_COMPONENTS - 1) / ECS_BITSET_WIDTH) + 1)
686 uint64_t array[ECS_BITSET_SIZE];
691typedef struct ecs_arena_block_s
696 struct ecs_arena_block_s* next;
699typedef struct ecs_arena_s
702 ecs_arena_block_t* first;
703 ecs_arena_block_t* current;
728 size_t block_capacity;
735 ecs_bitset_t comp_bits;
754 ecs_sparse_set_t entity_ids;
759 ecs_bitset_t require_bits;
760 ecs_bitset_t exclude_bits;
790 ecs_id_array_t entity_pool;
791 ecs_entity_data_t* entities;
792 size_t entity_capacity;
793 size_t next_entity_id;
794 ecs_comp_data_t comps[ECS_MAX_COMPONENTS];
795 ecs_comp_blocks_t comp_blocks[ECS_MAX_COMPONENTS];
797 ecs_sys_data_t systems[ECS_MAX_SYSTEMS];
800 ecs_cmd_array_t cmd_queue;
815static void* ecs_realloc_zero(
ecs_t* ecs,
void* ptr,
size_t old_size,
size_t new_size);
820static inline bool ecs_is_active(
ecs_t* ecs,
ecs_id_t entity_id);
825static void ecs_cmd_array_init(
ecs_t* ecs, ecs_cmd_array_t* queue,
size_t capacity);
826static void ecs_cmd_array_free(
ecs_t* ecs, ecs_cmd_array_t* queue);
827static ecs_cmd_t* ecs_cmd_array_push(
ecs_t* ecs, ecs_cmd_array_t* queue);
828static void ecs_cmd_flush_queue(
ecs_t* ecs);
833static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on);
834static inline bool ecs_bitset_is_zero(ecs_bitset_t* set);
835static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit);
836static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1, ecs_bitset_t* set2);
837static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1, ecs_bitset_t* set2);
838static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set);
839static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2);
840static inline bool ecs_bitset_true(ecs_bitset_t* set);
845static ecs_arena_block_t* ecs_arena_block_create(
ecs_t* ecs,
size_t size);
846static bool ecs_arena_init(
ecs_t* ecs, ecs_arena_t* arena,
size_t initial_block_size);
847static bool ecs_arena_grow(
ecs_t* ecs, ecs_arena_t* arena,
size_t min_size);
848static uintptr_t ecs_arena_align_forward(uintptr_t ptr,
size_t align);
849static void* ecs_arena_alloc_align(
ecs_t* ecs, ecs_arena_t* arena,
size_t size,
size_t align);
850static void* ecs_arena_alloc(
ecs_t* ecs, ecs_arena_t* arena,
size_t size);
851static void ecs_arena_reset(
ecs_t* ecs, ecs_arena_t* arena);
852static void ecs_arena_destroy(
ecs_t* ecs, ecs_arena_t* arena);
857static void ecs_sparse_set_init(
ecs_t* ecs, ecs_sparse_set_t* set,
size_t capacity);
858static void ecs_sparse_set_free(
ecs_t* ecs, ecs_sparse_set_t* set);
859static bool ecs_sparse_set_add(
ecs_t* ecs, ecs_sparse_set_t* set,
ecs_id_t id);
860static inline bool ecs_sparse_set_find(ecs_sparse_set_t* set,
ecs_id_t id,
size_t* found);
861static inline bool ecs_sparse_set_remove(ecs_sparse_set_t* set,
ecs_id_t id);
867static bool ecs_entity_system_test(ecs_bitset_t require_bits,
868 ecs_bitset_t exclude_bits,
869 ecs_bitset_t entity_bits);
877static void ecs_id_array_init(
ecs_t* ecs, ecs_id_array_t* pool,
size_t capacity);
878static void ecs_id_array_free(
ecs_t* ecs, ecs_id_array_t* pool);
879static inline void ecs_id_array_push(
ecs_t* ecs, ecs_id_array_t* pool,
ecs_id_t id);
880static inline ecs_id_t ecs_id_array_pop(ecs_id_array_t* pool);
881static inline size_t ecs_id_array_size(ecs_id_array_t* pool);
886static void ecs_comp_blocks_init(
ecs_t* ecs, ecs_comp_blocks_t* array,
size_t size,
size_t capacity);
887static void ecs_comp_blocks_free(
ecs_t* ecs, ecs_comp_blocks_t* array);
888static void ecs_comp_blocks_resize(
ecs_t* ecs, ecs_comp_blocks_t* array,
ecs_id_t id);
894static bool ecs_is_not_null(
void* ptr);
895static bool ecs_is_valid_component_id(
ecs_id_t id);
896static bool ecs_is_valid_system_id(
ecs_id_t id);
897static bool ecs_is_valid_id(
ecs_id_t id);
898static bool ecs_is_valid_capacity(
size_t capacity,
size_t elem_size);
899static bool ecs_is_entity_ready(
ecs_t* ecs,
ecs_id_t entity_id);
900static bool ecs_is_component_ready(
ecs_t* ecs,
ecs_id_t comp_id);
910 ECS_ASSERT(entity_capacity > 0);
911 ECS_ASSERT(!ecs_is_valid_id(
ECS_INVALID_ID) &&
"ecs_id_t is signed");
919 ECS_MEMSET(ecs, 0,
sizeof(
ecs_t));
921 ecs->entity_capacity = (entity_capacity > 0) ? entity_capacity : 32;
922 ecs->next_entity_id = 0;
923 ecs->system_active =
false;
924 ecs->mem_ctx = mem_ctx;
927 ecs_id_array_init(ecs, &ecs->entity_pool, entity_capacity);
930 ecs_cmd_array_init(ecs, &ecs->cmd_queue, entity_capacity);
933 ECS_ASSERT(ecs_is_valid_capacity(ecs->entity_capacity,
sizeof(ecs_entity_data_t)));
934 ecs->entities = (ecs_entity_data_t*)ECS_MALLOC(ecs->entity_capacity *
sizeof(ecs_entity_data_t),
938 ECS_MEMSET(ecs->entities, 0, ecs->entity_capacity *
sizeof(ecs_entity_data_t));
940 ecs_arena_init(ecs, &ecs->arena, 512);
947 ECS_ASSERT(ecs_is_not_null(ecs));
949 ecs_id_array_free(ecs, &ecs->entity_pool);
950 ecs_cmd_array_free(ecs, &ecs->cmd_queue);
951 ecs_arena_destroy(ecs, &ecs->arena);
953 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
955 ecs_comp_blocks_t* comp_blocks = &ecs->comp_blocks[comp_id];
956 ecs_comp_blocks_free(ecs, comp_blocks);
959 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
961 ecs_sys_data_t* sys = &ecs->systems[sys_id];
962 ecs_sparse_set_free(ecs, &sys->entity_ids);
965 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
967 ecs_comp_data_t* comp_data = &ecs->comps[comp_id];
969 if (comp_data->default_value)
971 ECS_FREE(comp_data->default_value, ecs->mem_ctx);
975 ECS_FREE(ecs->entities, ecs->mem_ctx);
976 ECS_FREE(ecs, ecs->mem_ctx);
981 ECS_ASSERT(ecs_is_not_null(ecs));
983 ecs->entity_pool.size = 0;
985 ECS_MEMSET(ecs->entities, 0, ecs->entity_capacity *
sizeof(ecs_entity_data_t));
987 ecs->next_entity_id = 0;
989 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
991 ecs->systems[sys_id].entity_ids.size = 0;
999 ECS_ASSERT(ecs_is_not_null(ecs));
1000 ECS_ASSERT(ecs->comp_count < ECS_MAX_COMPONENTS);
1001 ECS_ASSERT(size > 0);
1003 ecs_comp_t comp = ecs_make_comp(ecs->comp_count);
1005 ecs_comp_blocks_t* comp_blocks = &ecs->comp_blocks[comp.
id];
1006 ecs_comp_blocks_init(ecs, comp_blocks, size, ecs->entity_capacity);
1008 ecs_comp_data_t* comp_data = &ecs->comps[comp.
id];
1010 ECS_MEMSET(comp_data, 0,
sizeof(ecs_comp_data_t));
1011 comp_data->size = size;
1019 comp_data->udata = desc->
udata;
1023 comp_data->default_value = ECS_MALLOC(size, ctx->mem_ctx);
1024 ECS_MEMCPY(comp_data->default_value, desc->
default_value, size);
1037 ECS_ASSERT(ecs_is_not_null(ecs));
1038 ECS_ASSERT(ecs->system_count < ECS_MAX_SYSTEMS);
1039 ECS_ASSERT(NULL != system_cb);
1042 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1044 ECS_MEMSET(sys_data, 0,
sizeof(ecs_sys_data_t));
1046 ecs_sparse_set_init(ecs, &sys_data->entity_ids, ecs->entity_capacity);
1048 sys_data->system_cb = system_cb;
1049 sys_data->active =
true;
1053 sys_data->mask = desc->
mask;
1056 sys_data->udata = desc->
udata;
1059 ecs->system_count++;
1066 ECS_ASSERT(ecs_is_not_null(ecs));
1067 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1068 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1069 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1070 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1073 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1074 ecs_bitset_flip(&sys_data->require_bits, comp.
id,
true);
1079 ECS_ASSERT(ecs_is_not_null(ecs));
1080 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1081 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1082 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1083 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1086 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1087 ecs_bitset_flip(&sys_data->exclude_bits, comp.
id,
true);
1092 ECS_ASSERT(ecs_is_not_null(ecs));
1093 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1094 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1096 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1097 sys_data->active =
true;
1102 ECS_ASSERT(ecs_is_not_null(ecs));
1103 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1104 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1106 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1107 sys_data->active =
false;
1116 ECS_ASSERT(ecs_is_not_null(ecs));
1117 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1118 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1119 ECS_ASSERT(NULL != system_cb);
1121 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1122 sys_data->system_cb = system_cb;
1123 sys_data->on_join = on_join;
1124 sys_data->on_leave = on_leave;
1129 ECS_ASSERT(ecs_is_not_null(ecs));
1130 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1131 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1133 ecs->systems[sys.
id].udata = udata;
1138 ECS_ASSERT(ecs_is_not_null(ecs));
1139 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1140 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1142 return ecs->systems[sys.
id].udata;
1147 ECS_ASSERT(ecs_is_not_null(ecs));
1148 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1149 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1151 ecs->systems[sys.
id].mask = mask;
1156 ECS_ASSERT(ecs_is_not_null(ecs));
1157 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1158 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1160 return ecs->systems[sys.
id].mask;
1165 ECS_ASSERT(ecs_is_not_null(ecs));
1166 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1167 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1169 return ecs->systems[sys.
id].entity_ids.dense;
1174 ECS_ASSERT(ecs_is_not_null(ecs));
1175 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1176 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1178 return ecs->systems[sys.
id].entity_ids.size;
1183 ECS_ASSERT(ecs_is_not_null(ecs));
1188 ecs_id_array_t* pool = &ecs->entity_pool;
1190 if (0 != ecs_id_array_size(pool))
1192 entity_id = ecs_id_array_pop(pool);
1197 entity_id = ecs->next_entity_id++;
1200 if (entity_id >= ecs->entity_capacity)
1202 size_t old_capacity = ecs->entity_capacity;
1203 size_t new_capacity = 2 * old_capacity;
1205 ECS_ASSERT(ecs_is_valid_capacity(new_capacity,
sizeof(ecs_entity_data_t)));
1206 ecs->entities = (ecs_entity_data_t*)ecs_realloc_zero(ecs, ecs->entities,
1207 old_capacity *
sizeof(ecs_entity_data_t),
1208 new_capacity *
sizeof(ecs_entity_data_t));
1210 ecs->entity_capacity = new_capacity;
1215 ecs->entities[entity_id].active =
true;
1216 ecs->entities[entity_id].ready =
true;
1218 return ecs_make_entity(entity_id);
1223 ECS_ASSERT(ecs_is_not_null(ecs));
1225 return ecs->entities[entity.
id].ready;
1230 ECS_ASSERT(ecs_is_not_null(ecs));
1231 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1232 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1233 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1234 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1236 if (!
ecs_has(ecs, entity, comp))
1238 ecs_add(ecs, entity, comp, NULL);
1241 ecs_comp_data_t* comp_data = &ecs->comps[comp.
id];
1243 if (ecs->system_active)
1245 ecs_cmd_t* cmd = ecs_cmd_array_push(ecs, &ecs->cmd_queue);
1246 cmd->type = ECS_CMD_SET;
1247 cmd->entity = entity;
1249 cmd->data = ecs_arena_alloc(ecs, &ecs->arena, comp_data->size);
1250 ECS_MEMCPY(cmd->data, data, comp_data->size);
1254 void* comp_ptr =
ecs_get(ecs, entity, comp);
1255 ECS_MEMCPY(comp_ptr, data, comp_data->size);
1258 if (comp_data->on_set)
1259 comp_data->on_set(ecs, entity, comp, comp_data->udata);
1264 ECS_ASSERT(ecs_is_not_null(ecs));
1265 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1266 ECS_ASSERT(ecs_is_active(ecs, entity.
id));
1268 if (!ecs_is_active(ecs, entity.
id))
1271 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1272 ecs_bitset_t comp_bits = entity_data->comp_bits;
1274 if (ecs->system_active)
1276 ecs_cmd_t* cmd = ecs_cmd_array_push(ecs, &ecs->cmd_queue);
1277 cmd->type = ECS_CMD_DESTROY;
1278 cmd->entity = entity;
1279 ecs->entities[entity.
id].ready =
false;
1283 for (
ecs_id_t comp_id = 0; comp_id < ecs->comp_count; comp_id++)
1285 if (ecs_bitset_test(&comp_bits, comp_id))
1287 ecs_comp_data_t* comp_data = &ecs->comps[comp_id];
1289 if (comp_data->on_remove)
1292 comp_data->on_remove(ecs, entity, comp, comp_data->udata);
1297 ecs_sync_destroy(ecs, entity.
id);
1299 ecs_id_array_t* pool = &ecs->entity_pool;
1300 ecs_id_array_push(ecs, pool, entity.
id);
1302 ECS_MEMSET(&entity_data->comp_bits, 0,
sizeof(ecs_bitset_t));
1303 entity_data->active =
false;
1304 entity_data->ready =
false;
1309 ECS_ASSERT(ecs_is_not_null(ecs));
1310 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1311 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1314 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1316 if (!entity_data->ready)
1320 return ecs_bitset_test(&entity_data->comp_bits, comp.
id);
1325 ECS_ASSERT(ecs_is_not_null(ecs));
1326 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1327 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1328 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1329 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1333 ecs_comp_blocks_t* comp_blocks = &ecs->comp_blocks[comp.
id];
1335 size_t block = entity.
id / ECS_COMP_BLOCK_SIZE;
1336 size_t slot = entity.
id % ECS_COMP_BLOCK_SIZE;
1338 return (
char*)comp_blocks->blocks[block] + (comp_blocks->comp_size * slot);
1343 ECS_ASSERT(ecs_is_not_null(ecs));
1344 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1345 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1346 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1347 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1349 if (
ecs_has(ecs, entity, comp))
1353 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1357 ecs_bitset_flip(&entity_data->comp_bits, comp.
id,
true);
1360 ecs_comp_blocks_t* comp_blocks = &ecs->comp_blocks[comp.
id];
1365 ecs_comp_blocks_resize(ecs, comp_blocks, entity.
id);
1367 ecs_comp_data_t* comp_data = &ecs->comps[comp.
id];
1369 if (ecs->system_active)
1371 ecs_cmd_t* cmd = ecs_cmd_array_push(ecs, &ecs->cmd_queue);
1372 cmd->type = ECS_CMD_ADD;
1373 cmd->entity = entity;
1380 if (args && comp_data->args_size > 0)
1382 cmd->args = ecs_arena_alloc(ecs, &ecs->arena, comp_data->args_size);
1383 ECS_MEMCPY(cmd->args, args, comp_data->args_size);
1390 void* comp_ptr =
ecs_get(ecs, entity, comp);
1393 if (comp_data->default_value)
1394 ECS_MEMCPY(comp_ptr, comp_data->default_value, comp_data->size);
1396 ECS_MEMSET(comp_ptr, 0, comp_blocks->comp_size);
1399 if (comp_data->on_add)
1400 comp_data->on_add(ecs, entity, comp, args, comp_data->udata);
1403 ecs_sync_add_remove(ecs, entity.
id, comp.
id);
1408 ECS_ASSERT(ecs_is_not_null(ecs));
1409 ECS_ASSERT(ecs_is_valid_id(entity.
id));
1410 ECS_ASSERT(ecs_is_valid_component_id(comp.
id));
1411 ECS_ASSERT(ecs_is_component_ready(ecs, comp.
id));
1412 ECS_ASSERT(ecs_is_entity_ready(ecs, entity.
id));
1414 if (!
ecs_has(ecs, entity, comp))
1418 ecs_entity_data_t* entity_data = &ecs->entities[entity.
id];
1422 ecs_bitset_flip(&entity_data->comp_bits, comp.
id,
false);
1424 if (ecs->system_active)
1426 ecs_cmd_t* cmd = ecs_cmd_array_push(ecs, &ecs->cmd_queue);
1427 cmd->type = ECS_CMD_REMOVE;
1428 cmd->entity = entity;
1434 ecs_comp_data_t* comp_data = &ecs->comps[comp.
id];
1436 if (comp_data->on_remove)
1437 comp_data->on_remove(ecs, entity, comp, comp_data->udata);
1440 ecs_sync_add_remove(ecs, entity.
id, comp.
id);
1445 ECS_ASSERT(ecs_is_not_null(ecs));
1446 ECS_ASSERT(ecs_is_valid_system_id(sys.
id));
1447 ECS_ASSERT(ecs_is_system_ready(ecs, sys.
id));
1449 ecs_sys_data_t* sys_data = &ecs->systems[sys.
id];
1451 if (!sys_data->active)
1454 if (0 != sys_data->mask && !(sys_data->mask & mask))
1457 ecs->system_active =
true;
1459 ecs_ret_t code = sys_data->system_cb(ecs,
1460 sys_data->entity_ids.dense,
1461 sys_data->entity_ids.size,
1464 ecs->system_active =
false;
1466 ecs_cmd_flush_queue(ecs);
1467 ecs_arena_reset(ecs, &ecs->arena);
1474 ECS_ASSERT(ecs_is_not_null(ecs));
1476 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
1509static void* ecs_realloc_zero(
ecs_t* ecs,
void* ptr,
size_t old_size,
size_t new_size)
1513 ptr = ECS_REALLOC(ptr, new_size, ecs->mem_ctx);
1515 if (new_size > old_size && ptr) {
1516 size_t diff = new_size - old_size;
1517 void* start = ((
char*)ptr)+ old_size;
1518 ECS_MEMSET(start, 0, diff);
1527static inline bool ecs_is_active(
ecs_t* ecs,
ecs_id_t entity_id)
1529 ECS_ASSERT(ecs_is_not_null(ecs));
1530 return ecs->entities[entity_id].active;
1536static void ecs_cmd_array_init(
ecs_t* ecs, ecs_cmd_array_t* queue,
size_t capacity)
1538 ECS_ASSERT(ecs_is_not_null(ecs));
1539 ECS_ASSERT(ecs_is_not_null(queue));
1540 ECS_ASSERT(capacity > 0);
1545 queue->capacity = capacity;
1546 queue->data = (ecs_cmd_t*)ECS_MALLOC(capacity *
sizeof(ecs_cmd_t), ecs->mem_ctx);
1548 ECS_ASSERT(ecs_is_not_null(queue->data));
1551static void ecs_cmd_array_free(
ecs_t* ecs, ecs_cmd_array_t* queue)
1553 ECS_ASSERT(ecs_is_not_null(ecs));
1554 ECS_ASSERT(ecs_is_not_null(queue));
1555 ECS_FREE(queue->data, ecs->mem_ctx);
1560static ecs_cmd_t* ecs_cmd_array_push(
ecs_t* ecs, ecs_cmd_array_t* queue)
1562 ECS_ASSERT(ecs_is_not_null(ecs));
1563 ECS_ASSERT(ecs_is_not_null(queue));
1567 if (queue->size == queue->capacity)
1569 size_t new_capacity = queue->capacity * 2;
1571 ECS_ASSERT(ecs_is_valid_capacity(new_capacity,
sizeof(ecs_cmd_t)));
1572 queue->data = (ecs_cmd_t*)ECS_REALLOC(queue->data,
1573 new_capacity *
sizeof(ecs_cmd_t),
1575 queue->capacity = new_capacity;
1578 ecs_cmd_t* cmd = &queue->data[queue->size++];
1579 ECS_MEMSET(cmd, 0,
sizeof(ecs_cmd_t));
1583static void ecs_cmd_flush_queue(
ecs_t* ecs)
1585 ECS_ASSERT(ecs_is_not_null(ecs));
1587 ecs_cmd_array_t* queue = &ecs->cmd_queue;
1589 for (
size_t i = 0; i < queue->size; ++i)
1591 ecs_cmd_t* cmd = &queue->data[i];
1598 ecs_set(ecs, cmd->entity, cmd->comp, cmd->data);
1605 ecs_bitset_flip(&ecs->entities[cmd->entity.id].comp_bits, cmd->comp.id,
false);
1606 ecs_add(ecs, cmd->entity, cmd->comp, cmd->args);
1610 case ECS_CMD_REMOVE:
1613 ecs_bitset_flip(&ecs->entities[cmd->entity.id].comp_bits, cmd->comp.id,
true);
1618 case ECS_CMD_DESTROY:
1619 if (ecs_is_active(ecs, cmd->entity.id))
1621 ecs->entities[cmd->entity.id].ready =
true;
1635#if ECS_MAX_COMPONENTS <= 64
1637static inline bool ecs_bitset_is_zero(ecs_bitset_t* set)
1642static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on)
1645 *set |= ((uint64_t)1 << bit);
1647 *set &= ~((uint64_t)1 << bit);
1650static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit)
1652 return *set & ((uint64_t)1 << bit);
1655static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1, ecs_bitset_t* set2)
1657 return *set1 & *set2;
1660static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1, ecs_bitset_t* set2)
1662 return *set1 | *set2;
1665static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set)
1670static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2)
1672 return *set1 == *set2;
1675static inline bool ecs_bitset_true(ecs_bitset_t* set)
1682static inline bool ecs_bitset_is_zero(ecs_bitset_t* set)
1684 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1686 if (set->array[i] != 0)
1693static inline void ecs_bitset_flip(ecs_bitset_t* set,
int bit,
bool on)
1695 int index = bit / ECS_BITSET_WIDTH;
1698 set->array[index] |= ((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1700 set->array[index] &= ~((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1703static inline bool ecs_bitset_test(ecs_bitset_t* set,
int bit)
1705 int index = bit / ECS_BITSET_WIDTH;
1706 return set->array[index] & ((uint64_t)1 << bit % ECS_BITSET_WIDTH);
1709static inline ecs_bitset_t ecs_bitset_and(ecs_bitset_t* set1,
1714 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1716 set.array[i] = set1->array[i] & set2->array[i];
1722static inline ecs_bitset_t ecs_bitset_or(ecs_bitset_t* set1,
1727 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1729 set.array[i] = set1->array[i] | set2->array[i];
1735static inline ecs_bitset_t ecs_bitset_not(ecs_bitset_t* set)
1739 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1741 out.array[i] = ~set->array[i];
1747static inline bool ecs_bitset_equal(ecs_bitset_t* set1, ecs_bitset_t* set2)
1749 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1751 if (set1->array[i] != set2->array[i])
1760static inline bool ecs_bitset_true(ecs_bitset_t* set)
1762 for (
int i = 0; i < ECS_BITSET_SIZE; i++)
1773static ecs_arena_block_t* ecs_arena_block_create(
ecs_t* ecs,
size_t size)
1777 ecs_arena_block_t* block = (ecs_arena_block_t*)ECS_MALLOC(
sizeof(ecs_arena_block_t), ecs->mem_ctx);
1782 block->memory = (uint8_t*)ECS_MALLOC(size, ecs->mem_ctx);
1786 ECS_FREE(block, ecs->mem_ctx);
1797static bool ecs_arena_init(
ecs_t* ecs, ecs_arena_t* arena,
size_t initial_block_size)
1799 ecs_arena_block_t* block = ecs_arena_block_create(ecs, initial_block_size);
1804 arena->first = block;
1805 arena->current = block;
1806 arena->block_size = initial_block_size;
1811static bool ecs_arena_grow(
ecs_t* ecs, ecs_arena_t* arena,
size_t min_size)
1813 size_t new_size = arena->block_size;
1815 while (new_size < min_size)
1820 ecs_arena_block_t* block = ecs_arena_block_create(ecs, new_size);
1825 arena->current->next = block;
1826 arena->current = block;
1831static uintptr_t ecs_arena_align_forward(uintptr_t ptr,
size_t align)
1833 uintptr_t mask = (uintptr_t)align - 1;
1834 return (ptr + mask) & ~mask;
1837static void* ecs_arena_alloc_align(
ecs_t* ecs, ecs_arena_t* arena,
size_t size,
size_t align)
1839 if ((align & (align - 1)) != 0)
1842 ecs_arena_block_t* block = arena->current;
1844 uintptr_t base = (uintptr_t)block->memory;
1845 uintptr_t ptr = base + block->offset;
1846 uintptr_t aligned = ecs_arena_align_forward(ptr, align);
1847 size_t new_offset = (aligned - base) + size;
1849 if (new_offset > block->size)
1851 size_t required = size + align;
1853 if (!ecs_arena_grow(ecs, arena, required))
1856 block = arena->current;
1857 base = (uintptr_t)block->memory;
1858 aligned = ecs_arena_align_forward(base, align);
1859 new_offset = (aligned - base) + size;
1862 block->offset = new_offset;
1864 return (
void*)aligned;
1867static void* ecs_arena_alloc(
ecs_t* ecs, ecs_arena_t* arena,
size_t size)
1869 return ecs_arena_alloc_align(ecs, arena, size,
alignof(max_align_t));
1872static void ecs_arena_reset(
ecs_t* ecs, ecs_arena_t* arena)
1876 ecs_arena_block_t* block = arena->first->next;
1880 ecs_arena_block_t* next = block->next;
1881 ECS_FREE(block->memory, ecs->mem_ctx);
1882 ECS_FREE(block, ecs->mem_ctx);
1886 arena->first->next = NULL;
1887 arena->first->offset = 0;
1888 arena->current = arena->first;
1891static void ecs_arena_destroy(
ecs_t* ecs, ecs_arena_t* arena)
1895 ecs_arena_block_t* block = arena->first;
1899 ecs_arena_block_t* next = block->next;
1900 ECS_FREE(block->memory, ecs->mem_ctx);
1901 ECS_FREE(block, ecs->mem_ctx);
1905 arena->first = NULL;
1906 arena->current = NULL;
1913static void ecs_sparse_set_init(
ecs_t* ecs, ecs_sparse_set_t* set,
size_t capacity)
1915 ECS_ASSERT(ecs_is_not_null(ecs));
1916 ECS_ASSERT(ecs_is_not_null(set));
1920 set->capacity = capacity;
1923 ECS_ASSERT(ecs_is_valid_capacity(capacity,
sizeof(
ecs_entity_t)));
1926 ECS_ASSERT(ecs_is_valid_capacity(capacity,
sizeof(
size_t)));
1927 set->sparse = (
size_t*) ECS_MALLOC(capacity *
sizeof(
size_t), ecs->mem_ctx);
1929 ECS_MEMSET(set->sparse, 0, capacity *
sizeof(
size_t));
1932static void ecs_sparse_set_free(
ecs_t* ecs, ecs_sparse_set_t* set)
1934 ECS_ASSERT(ecs_is_not_null(ecs));
1935 ECS_ASSERT(ecs_is_not_null(set));
1939 ECS_FREE(set->dense, ecs->mem_ctx);
1940 ECS_FREE(set->sparse, ecs->mem_ctx);
1943static bool ecs_sparse_set_add(
ecs_t* ecs, ecs_sparse_set_t* set,
ecs_id_t id)
1945 ECS_ASSERT(ecs_is_not_null(ecs));
1946 ECS_ASSERT(ecs_is_not_null(set));
1947 ECS_ASSERT(ecs_is_valid_id(
id));
1952 if (ecs_sparse_set_find(set,
id, NULL))
1956 if (
id >= set->capacity)
1958 size_t old_capacity = set->capacity;
1959 size_t new_capacity = old_capacity;
1965 }
while (
id >= new_capacity);
1969 ECS_ASSERT(ecs_is_valid_capacity(set->capacity,
sizeof(
ecs_entity_t)));
1977 ECS_ASSERT(ecs_is_valid_capacity(set->capacity,
sizeof(
size_t)));
1978 set->sparse = (
size_t*)ecs_realloc_zero(ecs,
1980 old_capacity *
sizeof(
size_t),
1981 new_capacity *
sizeof(size_t));
1984 set->capacity = new_capacity;
1988 set->dense[set->size].id = id;
1989 set->sparse[id] = set->size;
1995static inline bool ecs_sparse_set_find(ecs_sparse_set_t* set,
ecs_id_t id,
size_t* found)
1997 ECS_ASSERT(ecs_is_not_null(set));
1998 ECS_ASSERT(ecs_is_valid_id(
id));
2000 if (id < set->capacity && set->sparse[
id] < set->size && set->dense[set->sparse[
id]].id ==
id)
2002 if (found) *found = set->sparse[id];
2007 if (found) *found = 0;
2012static inline bool ecs_sparse_set_remove(ecs_sparse_set_t* set,
ecs_id_t id)
2014 ECS_ASSERT(ecs_is_not_null(set));
2015 ECS_ASSERT(ecs_is_valid_id(
id));
2017 if (!ecs_sparse_set_find(set,
id, NULL))
2021 ecs_id_t tmp = set->dense[set->size - 1].id;
2022 set->dense[set->sparse[id]].id = tmp;
2023 set->sparse[tmp] = set->sparse[id];
2033#if ECS_MAX_COMPONENTS <= 64
2035static inline bool ecs_entity_system_test(ecs_bitset_t require_bits,
2036 ecs_bitset_t exclude_bits,
2037 ecs_bitset_t entity_bits)
2039 if (entity_bits & exclude_bits)
2042 if ((entity_bits & require_bits) != require_bits)
2050static inline bool ecs_entity_system_test(ecs_bitset_t require_bits,
2051 ecs_bitset_t exclude_bits,
2052 ecs_bitset_t entity_bits)
2054 if (!ecs_bitset_is_zero(&exclude_bits))
2056 ecs_bitset_t overlap = ecs_bitset_and(&entity_bits, &exclude_bits);
2058 if (ecs_bitset_true(&overlap))
2064 ecs_bitset_t entity_and_require = ecs_bitset_and(&entity_bits, &require_bits);
2065 return ecs_bitset_equal(&entity_and_require, &require_bits);
2072 ecs_entity_data_t* entity_data = &ecs->entities[entity_id];
2075 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
2077 ecs_sys_data_t* sys_data = &ecs->systems[sys_id];
2081 if (!ecs_bitset_test(&sys_data->require_bits, comp_id) &&
2082 !ecs_bitset_test(&sys_data->exclude_bits, comp_id))
2086 if (ecs_entity_system_test(sys_data->require_bits,
2087 sys_data->exclude_bits,
2088 entity_data->comp_bits))
2091 if (ecs_sparse_set_add(ecs, &sys_data->entity_ids, entity_id))
2093 if (sys_data->on_join)
2094 sys_data->on_join(ecs, ecs_make_entity(entity_id), sys_data->udata);
2101 if (ecs_sparse_set_remove(&sys_data->entity_ids, entity_id))
2103 if (sys_data->on_leave)
2104 sys_data->on_leave(ecs, ecs_make_entity(entity_id), sys_data->udata);
2113 for (
ecs_id_t sys_id = 0; sys_id < ecs->system_count; sys_id++)
2115 ecs_sys_data_t* sys_data = &ecs->systems[sys_id];
2117 if (ecs_sparse_set_remove(&sys_data->entity_ids, entity_id))
2119 if (sys_data->on_leave)
2120 sys_data->on_leave(ecs, ecs_make_entity(entity_id), sys_data->udata);
2129static void ecs_id_array_init(
ecs_t* ecs, ecs_id_array_t* array,
size_t capacity)
2131 ECS_ASSERT(ecs_is_not_null(ecs));
2132 ECS_ASSERT(ecs_is_not_null(array));
2137 array->capacity = capacity;
2139 ECS_ASSERT(ecs_is_valid_capacity(capacity,
sizeof(
ecs_id_t)));
2140 array->data = (
ecs_id_t*)ECS_MALLOC(capacity *
sizeof(
ecs_id_t), ecs->mem_ctx);
2143static void ecs_id_array_free(
ecs_t* ecs, ecs_id_array_t* array)
2145 ECS_ASSERT(ecs_is_not_null(ecs));
2146 ECS_ASSERT(ecs_is_not_null(array));
2150 ECS_FREE(array->data, ecs->mem_ctx);
2153static inline void ecs_id_array_push(
ecs_t* ecs, ecs_id_array_t* array,
ecs_id_t id)
2155 ECS_ASSERT(ecs_is_not_null(ecs));
2156 ECS_ASSERT(ecs_is_not_null(array));
2157 ECS_ASSERT(ecs_is_valid_id(
id));
2161 if (array->size == array->capacity)
2166 array->capacity *= 2;
2168 ECS_ASSERT(ecs_is_valid_capacity(array->capacity,
sizeof(
ecs_id_t)));
2169 array->data = (
ecs_id_t*)ECS_REALLOC(array->data,
2170 array->capacity *
sizeof(
ecs_id_t),
2174 array->data[array->size++] = id;
2177static inline ecs_id_t ecs_id_array_pop(ecs_id_array_t* array)
2179 ECS_ASSERT(ecs_is_not_null(array));
2180 ECS_ASSERT(array->size > 0);
2182 return array->data[--array->size];
2185static inline size_t ecs_id_array_size(ecs_id_array_t* array)
2190static void ecs_comp_blocks_init(
ecs_t* ecs, ecs_comp_blocks_t* array,
size_t size,
size_t capacity)
2192 ECS_ASSERT(ecs_is_not_null(ecs));
2193 ECS_ASSERT(ecs_is_not_null(array));
2197 ECS_MEMSET(array, 0,
sizeof(ecs_comp_blocks_t));
2199 array->comp_size = size;
2201 size_t initial_blocks = (capacity + ECS_COMP_BLOCK_SIZE - 1) / ECS_COMP_BLOCK_SIZE;
2202 if (initial_blocks == 0) initial_blocks = 1;
2204 array->block_capacity = initial_blocks;
2205 array->block_count = initial_blocks;
2207 ECS_ASSERT(ecs_is_valid_capacity(initial_blocks,
sizeof(
void*)));
2208 array->blocks = (
void**)ECS_MALLOC(initial_blocks *
sizeof(
void*), ecs->mem_ctx);
2210 for (
size_t i = 0; i < initial_blocks; i++)
2212 ECS_ASSERT(ecs_is_valid_capacity(ECS_COMP_BLOCK_SIZE, size));
2213 array->blocks[i] = ECS_MALLOC(ECS_COMP_BLOCK_SIZE * size, ecs->mem_ctx);
2214 ECS_MEMSET(array->blocks[i], 0, ECS_COMP_BLOCK_SIZE * size);
2218static void ecs_comp_blocks_free(
ecs_t* ecs, ecs_comp_blocks_t* array)
2220 ECS_ASSERT(ecs_is_not_null(ecs));
2221 ECS_ASSERT(ecs_is_not_null(array));
2225 for (
size_t i = 0; i < array->block_count; i++)
2227 ECS_FREE(array->blocks[i], ecs->mem_ctx);
2230 ECS_FREE(array->blocks, ecs->mem_ctx);
2233static void ecs_comp_blocks_resize(
ecs_t* ecs, ecs_comp_blocks_t* array,
ecs_id_t id)
2235 ECS_ASSERT(ecs_is_not_null(ecs));
2236 ECS_ASSERT(ecs_is_not_null(array));
2237 ECS_ASSERT(ecs_is_valid_id(
id));
2239 size_t required_block =
id / ECS_COMP_BLOCK_SIZE;
2241 while (required_block >= array->block_count)
2245 if (array->block_count == array->block_capacity)
2247 size_t old_capacity = array->block_capacity;
2248 size_t new_capacity = old_capacity * 2;
2250 ECS_ASSERT(ecs_is_valid_capacity(array->block_capacity,
sizeof(
void*)));
2251 array->blocks = (
void**)ecs_realloc_zero(ecs,
2253 old_capacity *
sizeof(
void*),
2254 new_capacity *
sizeof(
void*));
2257 array->block_capacity = new_capacity;
2261 ECS_ASSERT(ecs_is_valid_capacity(ECS_COMP_BLOCK_SIZE, array->comp_size));
2262 void* block = ECS_MALLOC(ECS_COMP_BLOCK_SIZE * array->comp_size, ecs->mem_ctx);
2263 ECS_MEMSET(block, 0, ECS_COMP_BLOCK_SIZE * array->comp_size);
2264 array->blocks[array->block_count++] = block;
2272static bool ecs_is_not_null(
void* ptr)
2277static bool ecs_is_valid_component_id(
ecs_id_t id)
2279 return id < ECS_MAX_COMPONENTS;
2282static bool ecs_is_valid_system_id(
ecs_id_t id)
2284 return id < ECS_MAX_SYSTEMS;
2287static bool ecs_is_valid_id(
ecs_id_t id)
2290 return id == ((id << 1) >> 1);
2293static bool ecs_is_valid_capacity(
size_t capacity,
size_t elem_size)
2298 if (capacity == 0 || elem_size == 0)
2303 size_t max_cap = (SIZE_MAX >> 1) / elem_size;
2304 return capacity <= max_cap;
2307static bool ecs_is_entity_ready(
ecs_t* ecs,
ecs_id_t entity_id)
2309 return ecs->entities[entity_id].ready;
2312static bool ecs_is_component_ready(
ecs_t* ecs,
ecs_id_t comp_id)
2314 return comp_id < ecs->comp_count;
2319 return sys_id < ecs->system_count;
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:226
#define ECS_MASK_TYPE
Determine mask type.
Definition pico_ecs.h:195
void * ecs_get(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp)
Gets a component instance associated with an entity.
void(* ecs_on_leave_fn)(ecs_t *ecs, ecs_entity_t entity, void *udata)
Called when an entity is removed from a system.
Definition pico_ecs.h:365
void(* ecs_on_join_fn)(ecs_t *ecs, ecs_entity_t entity, void *udata)
Called when an entity is added to a system.
Definition pico_ecs.h:356
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:201
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:189
void ecs_set(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp, void *data)
Copies data into a component instance associated with an entity.
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:344
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, const ecs_comp_desc_t *desc)
Defines a component.
void(* ecs_on_remove_fn)(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp, void *udata)
Called when a component is destroyed (via ecs_remove or ecs_destroy)
Definition pico_ecs.h:275
void ecs_free(ecs_t *ecs)
Destroys an ECS context.
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:177
void ecs_reset(ecs_t *ecs)
Removes all entities from the ECS, preserving systems and components.
void ecs_set_system_callbacks(ecs_t *ecs, ecs_system_t sys, ecs_system_fn system_cb, ecs_on_join_fn on_join, ecs_on_leave_fn on_leave)
Updates the callbacks for an existing system.
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.
void(* ecs_on_add_fn)(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp, const void *args, void *udata)
Called when a component is created (via ecs_add)
Definition pico_ecs.h:262
void(* ecs_on_set_fn)(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp, void *udata)
Called when a component's data is set (via ecs_set)
Definition pico_ecs.h:289
ecs_ret_t ecs_run_system(ecs_t *ecs, ecs_system_t sys, ecs_mask_t mask)
Update an individual system.
ecs_entity_t * ecs_get_entity_array(ecs_t *ecs, ecs_system_t sys)
Returns the entities associated with the specified system.
ecs_t * ecs_new(size_t entity_capacity, void *mem_ctx)
Creates an ECS context.
int32_t ecs_ret_t
Return code for system callback and calling functions.
Definition pico_ecs.h:206
void ecs_set_system_mask(ecs_t *ecs, ecs_system_t sys, ecs_mask_t mask)
Sets the system's mask.
size_t ecs_get_entity_count(ecs_t *ecs, ecs_system_t sys)
Returns the number of entities assigned to the specified system.
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.
ecs_entity_t ecs_create(ecs_t *ecs)
Creates an entity.
#define ECS_ID_TYPE
Determine ID type. It should be unsigned.
Definition pico_ecs.h:183
void ecs_add(ecs_t *ecs, ecs_entity_t entity, ecs_comp_t comp, void *args)
Adds a component instance to an entity.
void ecs_exclude(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_require(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_system_t ecs_define_system(ecs_t *ecs, ecs_system_fn system_cb, const ecs_sys_desc_t *desc)
Defines a system.
ecs_mask_t ecs_get_system_mask(ecs_t *ecs, ecs_system_t sys)
Returns the system mask.
Optional parameters for component definition.
Definition pico_ecs.h:309
ecs_on_remove_fn on_remove_cb
Definition pico_ecs.h:311
size_t args_size
Definition pico_ecs.h:314
ecs_on_add_fn on_add_cb
Definition pico_ecs.h:310
ecs_on_set_fn on_set_cb
Definition pico_ecs.h:312
void * udata
Definition pico_ecs.h:315
void * default_value
Definition pico_ecs.h:313
A component handle.
Definition pico_ecs.h:216
ecs_id_t id
Definition pico_ecs.h:216
An entity handle.
Definition pico_ecs.h:211
ecs_id_t id
Definition pico_ecs.h:211
Optional parameters for system definition.
Definition pico_ecs.h:377
void * udata
Definition pico_ecs.h:381
ecs_on_join_fn on_join_cb
Definition pico_ecs.h:379
ecs_on_leave_fn on_leave_cb
Definition pico_ecs.h:380
ecs_mask_t mask
Definition pico_ecs.h:378
A system handle.
Definition pico_ecs.h:221
ecs_id_t id
Definition pico_ecs.h:221