3dtoys/old/ecs.h
2024-08-18 19:13:25 -04:00

104 lines
4.0 KiB
C

// A very simple library for constructing the basis of EXTREMELY simple ecs
// systems. Made mostly for fun
#ifndef __HALOO3D_ECS_H
#define __HALOO3D_ECS_H
#include <math.h>
#include <stdint.h>
#include <string.h>
#ifndef HECS_MAXENTITIES
#define HECS_MAXENTITIES 1024
#endif
typedef uint64_t hecs_cidt;
typedef int hecs_eidt;
#define HECS_MAXCTYPES 63 // One minus the thing
typedef struct {
hecs_cidt e_components[HECS_MAXENTITIES];
void *components[HECS_MAXCTYPES];
int numcomponents;
hecs_eidt entitytop;
} haloo_ecs;
static void haloo_ecs_init(haloo_ecs *ecs) {
memset(ecs, 0, sizeof(haloo_ecs));
}
// Add an entity with given components to ecs system.
static hecs_eidt haloo_ecs_newentity(haloo_ecs *ecs, hecs_cidt basecomponents) {
for (int i = 0; i < HECS_MAXENTITIES; i++) {
hecs_eidt id = ecs->entitytop++;
if (ecs->e_components[id] == 0) {
// Utilize the very last bit to indicate that the entity is active
ecs->e_components[id] = (1ULL << HECS_MAXCTYPES) | basecomponents;
return id;
}
}
return -1;
}
static int haloo_ecs_match(haloo_ecs *ecs, hecs_eidt eid, hecs_cidt comps) {
hecs_cidt realcomps = (1ULL << HECS_MAXCTYPES) | comps;
return (ecs->e_components[eid] & realcomps) == realcomps;
}
static void haloo_ecs_removeentity(haloo_ecs *ecs, int eid) {
if (eid >= 0 && eid < HECS_MAXENTITIES)
ecs->e_components[eid] = 0;
}
// Add a new component to ecs. Create the type or storage with
// HECS_NEWCOMPONENT(type, name)
static int haloo_ecs_newcomponent(haloo_ecs *ecs, void *component) {
int id = ecs->numcomponents++;
ecs->components[id] = component;
return id;
}
// Convert component id into flag for use with system identification
#define HECS_CIDF(id) (1ULL << id)
// Shortcut to both create the storage and add it to the given ecs.
// Automatically stores the name as __type. Stores the id for the component in
// type_id. For convenience, another variable of type_f is created for the flag
// version of the component id
#define HECS_ADDNEWCOMPONENT(type, ecs) \
type __##type[HECS_MAXENTITIES]; \
hecs_cidt type##_id = haloo_ecs_newcomponent(ecs, __##type); \
hecs_cidt type##_f = HECS_CIDF(type##_id);
// Set component values on a given entity, also sets the flag indicating this
// component is now registered with the given entity. You should follow this
// statement immediately with the values for your component.
// Example: HECS_SETCOMPONENT(mytype, &ecs, playerid) { .x = 1, .y = 2 }
#define HECS_SETCOMPONENT(type, ecs, eid) \
(ecs)->e_components[eid] |= type##_f; \
__##type[eid] = (type)
// Retrieve a component for a single entity from the entity system,
// casting it to the given type
#define HECS_ENTITYCOMPONENT(type, eid, cid, ecs) \
(((type)ecs->components[cid]) + eid)
// Run a function against ecs using the given limiting components. Note that
// components MUST be passed in the EXACT order the function expects them!
#define HECS_RUNSYS(ecs, eid, func, ...) \
{ \
const hecs_cidt _hecstemp[] = {__VA_ARGS__}; \
const int _hecsnumargs = sizeof(_hecstemp) / sizeof(hecs_cidt); \
hecs_cidt _hecsflags = 0; \
/*eprintf("MADE ARGS: %d\n", _hecsnumargs);*/ \
for (int _hecsi = 0; _hecsi < _hecsnumargs; _hecsi++) { \
_hecsflags |= HECS_CIDF(_hecstemp[_hecsi]); \
} \
if (haloo_ecs_match(ecs, eid, _hecsflags)) { \
func(ecs, eid, __VA_ARGS__); \
} \
}
#endif