// A purely global, all macro-driven ecs implementation. // You are expected to have only a need for a global // ecs when using this. #ifndef __HALOO3D_ECS2_H #define __HALOO3D_ECS2_H #include #ifndef ECS_MAXENTITIES #define ECS_MAXENTITIES 1024 #endif #define ECS_MAXCTYPES 63 // uint64 bits minus one typedef uint64_t ecs_cid; typedef int ecs_eid; #define ECS_START(name) \ typedef struct { \ ecs_cid entities[ECS_MAXENTITIES]; \ ecs_eid entitytop; #define ECS_END(name) \ } \ name; \ static void name##_init(name *_ecs) { memset(_ecs, 0, sizeof(name)); } \ static ecs_eid name##_newentity(name *_ecs, ecs_cid basecomponents) { \ for (int i = 0; i < ECS_MAXENTITIES; i++) { \ ecs_eid id = _ecs->entitytop++; \ if (_ecs->entities[id] == 0) { \ _ecs->entities[id] = (1ULL << ECS_MAXCTYPES) | basecomponents; \ return id; \ } \ } \ return -1; \ } \ static void name##_deleteentity(name *_ecs, ecs_eid eid) { \ if (eid >= 0 && eid < ECS_MAXENTITIES) \ _ecs->entities[eid] = 0; \ } \ static int name##_match(name *_ecs, ecs_eid _eid, ecs_cid _comps) { \ ecs_cid _realcomps = (1ULL << ECS_MAXCTYPES) | _comps; \ return (_ecs->entities[_eid] & _realcomps) == _realcomps; \ } #define ECS_COMPONENT(type) type c_##type[ECS_MAXENTITIES]; #define ECS_CID(type, id) \ const int type##_id = id; \ const ecs_cid type##_fl = (1ULL << id); // Set the given entity to have the given component (by type). Follow this // macro immediately with the struct initializer #define ECS_SETCOMPONENT(_ecs, eid, type) \ (_ecs)->entities[eid] |= type##_fl; \ (_ecs)->c_##type[eid] = (type) // Add a system function which automatically calls your given function with // pre-pulled items from the entity component arrays. The new function is // named the same as the old one, just with _run appeneded #define ECS_SYSTEM1(ecsname, fname, type1) \ void fname##_run(ecsname *_ecs, ecs_eid eid) { \ ecs_cid _ecsflags = type1##_fl; \ if (ecsname##_match(_ecs, eid, _ecsflags)) { \ fname(_ecs->c_##type1 + eid); \ } \ } #define ECS_SYSTEM2(ecsname, fname, type1, type2) \ void fname##_run(ecsname *_ecs, ecs_eid eid) { \ ecs_cid _ecsflags = type1##_fl | type2##_fl; \ if (ecsname##_match(_ecs, eid, _ecsflags)) { \ fname(_ecs->c_##type1 + eid, _ecs->c_##type2 + eid); \ } \ } #define ECS_SYSTEM3(ecsname, fname, type1, type2, type3) \ void fname##_run(ecsname *_ecs, ecs_eid eid) { \ ecs_cid _ecsflags = type1##_fl | type2##_fl | type3##_fl; \ if (ecsname##_match(_ecs, eid, _ecsflags)) { \ fname(_ecs->c_##type1 + eid, _ecs->c_##type2 + eid, \ _ecs->c_##type3 + eid); \ } \ } #define ECS_SYSTEM4(ecsname, fname, type1, type2, type3, type4) \ void fname##_run(ecsname *_ecs, ecs_eid eid) { \ ecs_cid _ecsflags = type1##_fl | type2##_fl | type3##_fl | type4##_fl; \ if (ecsname##_match(_ecs, eid, _ecsflags)) { \ fname(_ecs->c_##type1 + eid, _ecs->c_##type2 + eid, \ _ecs->c_##type3 + eid, _ecs->c_##type4 + eid); \ } \ } #endif