3dtoys/ecs2.h
2024-08-19 02:24:19 -04:00

120 lines
6.7 KiB
C

// haloopdy - 2024
// A super simple, all macro-driven ecs implementation.
// Macros create a struct and associated functions to build
// a simple, lightweight ecs implementation
#ifndef __HALOO3D_ECS2_H
#define __HALOO3D_ECS2_H
#include <stdint.h>
#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); \
} \
}
// 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_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); \
} \
}
// 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_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); \
} \
}
// 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_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); \
} \
}
// 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_SYSTEM5(ecsname, fname, type1, type2, type3, type4, type5) \
void fname##_run(ecsname *_ecs, ecs_eid eid) { \
ecs_cid _ecsflags = \
type1##_fl | type2##_fl | type3##_fl | type4##_fl | type5##_fl; \
if (ecsname##_match(_ecs, eid, _ecsflags)) { \
fname(_ecs->c_##type1 + eid, _ecs->c_##type2 + eid, \
_ecs->c_##type3 + eid, _ecs->c_##type4 + eid, \
_ecs->c_##type5 + eid); \
} \
}
#endif