#ifndef _ENGINE_UTILITY_H_
#define _ENGINE_UTILITY_H_
#include <alias/ecs.h>
#include <alias/cpp.h>
#include <assert.h>
#include <stdio.h>
#include <math.h>
#define Entity alias_ecs_EntityHandle
extern alias_ecs_Instance * Engine_ecs(void);
#define LAZY_GLOBAL(TYPE, IDENT, ...) \
TYPE IDENT (void) { \
static TYPE inner; \
static int init = 0; \
if(init == 0) { \
printf("making "#IDENT" ...\n");\
__VA_ARGS__ \
init = 1; \
} \
return inner; \
}
#define LAZY_GLOBAL_PTR(TYPE, IDENT, ...) \
TYPE * IDENT (void) { \
static TYPE inner; \
static TYPE * __ptr = NULL; \
if(__ptr == NULL) { \
printf("making "#IDENT" ...\n"); \
__VA_ARGS__ \
__ptr = &inner; \
} \
return __ptr; \
}
#define ECS(F, ...) assert(ALIAS_ECS_SUCCESS == alias_ecs_##F(__VA_ARGS__))
#define DEFINE_FONT(IDENT, PATH) LAZY_GLOBAL_PTR(Font, IDENT, inner = LoadFont(PATH);)
#define DECLARE_COMPONENT(IDENT, ...) \
struct IDENT __VA_ARGS__; \
alias_ecs_ComponentHandle IDENT##_component(void); \
const struct IDENT * IDENT##_read(Entity entity); \
struct IDENT * IDENT##_write(Entity entity);
#define DEFINE_COMPONENT(IDENT, ...) \
LAZY_GLOBAL( \
alias_ecs_ComponentHandle, \
IDENT##_component, \
ECS(register_component, Engine_ecs() \
, &(alias_ecs_ComponentCreateInfo) { .size = sizeof(struct IDENT), ## __VA_ARGS__ }, &inner); \
) \
const struct IDENT * IDENT##_read(Entity entity) { \
const struct IDENT * ptr; \
alias_ecs_read_entity_component(Engine_ecs(), entity, IDENT##_component(), (const void **)&ptr); \
return ptr; \
} \
struct IDENT * IDENT##_write(Entity entity) { \
struct IDENT * ptr; \
alias_ecs_write_entity_component(Engine_ecs(), entity, IDENT##_component(), (void **)&ptr); \
return ptr; \
}
#define DECLARE_TAG_COMPONENT(IDENT) \
alias_ecs_ComponentHandle IDENT##_component(void);
#define DEFINE_TAG_COMPONENT(IDENT) \
LAZY_GLOBAL( \
alias_ecs_ComponentHandle, \
IDENT##_component, \
ECS(register_component, Engine_ecs(), &(alias_ecs_ComponentCreateInfo) { .size = 0 }, &inner); \
)
#define COMPONENT_impl(IDENT, ITYPE, DREF, ...) \
LAZY_GLOBAL( \
alias_ecs_ComponentHandle, \
IDENT##_component, \
ECS(register_component, Engine_ecs() \
, &(alias_ecs_ComponentCreateInfo) { .size = sizeof(ITYPE), ## __VA_ARGS__ }, &inner); \
) \
const struct IDENT * IDENT##_read(Entity entity) { \
const ITYPE * ptr; \
alias_ecs_read_entity_component(Engine_ecs(), entity, IDENT##_component(), (const void **)&ptr); \
return DREF ptr; \
} \
struct IDENT * IDENT##_write(Entity entity) { \
ITYPE * ptr; \
alias_ecs_write_entity_component(Engine_ecs(), entity, IDENT##_component(), (void **)&ptr); \
return DREF ptr; \
}
#define COMPONENT(IDENT, ...) COMPONENT_impl(IDENT, struct IDENT, , ## __VA_ARGS__)
#define SPAWN_COMPONENT(...) SPAWN_COMPONENT_ __VA_ARGS__
#define SPAWN_COMPONENT_(TYPE, ...) { .component = TYPE##_component(), .stride = sizeof(struct TYPE), .data = (void *)&(struct TYPE) { __VA_ARGS__ } },
#define SPAWN_LAYER(LAYER, ...) ({ \
alias_ecs_EntityHandle _entity; \
alias_ecs_EntitySpawnComponent _components[] = { \
ALIAS_CPP_EVAL(ALIAS_CPP_MAP(SPAWN_COMPONENT, __VA_ARGS__)) \
}; \
ECS(spawn, Engine_ecs(), &(alias_ecs_EntitySpawnInfo) { \
.layer = LAYER, \
.count = 1, \
.num_components = sizeof(_components) / sizeof(_components[0]), \
.components = _components \
}, &_entity); \
_entity; \
})
#define SPAWN(...) SPAWN_LAYER(ALIAS_ECS_INVALID_LAYER, ## __VA_ARGS__)
#define ENGINE_COMPONENT(BUNDLE, IDENT) \
static inline alias_ecs_ComponentHandle alias_##IDENT##_component(void) { \
return BUNDLE()->IDENT##_component; \
} \
static inline const struct alias_##IDENT * alias_##IDENT##_read(Entity entity) { \
const struct alias_##IDENT * ptr; \
alias_ecs_read_entity_component(Engine_ecs(), entity, BUNDLE()->IDENT##_component, (const void **)&ptr); \
return ptr; \
} \
static inline struct alias_##IDENT * alias_##IDENT##_write(Entity entity) { \
struct alias_##IDENT * ptr; \
alias_ecs_write_entity_component(Engine_ecs(), entity, BUNDLE()->IDENT##_component, (void **)&ptr); \
return ptr; \
}
#if 0#endif
#define ALIAS_CPP_EQ__QUERYstate_state(...) ALIAS_CPP_PROBE
#define ALIAS_CPP_EQ__QUERYpre_pre(...) ALIAS_CPP_PROBE
#define ALIAS_CPP_EQ__QUERYread_read(...) ALIAS_CPP_PROBE
#define ALIAS_CPP_EQ__QUERYwrite_write(...) ALIAS_CPP_PROBE
#define ALIAS_CPP_EQ__QUERYoptional_optional(...) ALIAS_CPP_PROBE
#define ALIAS_CPP_EQ__QUERYexclude_exclude(...) ALIAS_CPP_PROBE
#define ALIAS_CPP_EQ__QUERYmodified_modified(...) ALIAS_CPP_PROBE
#define ALIAS_CPP_EQ__QUERYaction_action(...) ALIAS_CPP_PROBE
#define ALIAS_CPP_EQ__QUERYpost_post(...) ALIAS_CPP_PROBE
#define QUERY_is_state(X) ALIAS_CPP_EQ(QUERY, state, X)
#define QUERY_is_pre(X) ALIAS_CPP_EQ(QUERY, pre, X)
#define QUERY_is_read(X) ALIAS_CPP_EQ(QUERY, read, X)
#define QUERY_is_write(X) ALIAS_CPP_EQ(QUERY, write, X)
#define QUERY_is_filter(X) ALIAS_CPP_OR(ALIAS_CPP_OR(ALIAS_CPP_EQ(QUERY, optional, X), ALIAS_CPP_EQ(QUERY, exclude, X)), ALIAS_CPP_EQ(QUERY, modified, X))
#define QUERY_is_action(X) ALIAS_CPP_EQ(QUERY, action, X)
#define QUERY_is_post(X) ALIAS_CPP_EQ(QUERY, post, X)
#define QUERY_emit(X) ALIAS_CPP_CAT(QUERY_emit_, X)
#define QUERY_emit_state(TYPE, NAME, ...) TYPE NAME;
#define QUERY_emit_write(TYPE, NAME) struct TYPE * NAME = (struct TYPE *)data[__i++];
#define QUERY_emit_read(TYPE, NAME) const struct TYPE * NAME = (const struct TYPE *)data[__i++];
#define QUERY_emit_pre(...) __VA_ARGS__
#define QUERY_emit_action(...) __VA_ARGS__
#define QUERY_emit_post(...) __VA_ARGS__
#define QUERY_emit_create(X) ALIAS_CPP_CAT(QUERY_emit_create_, X)
#define QUERY_emit_create_read(TYPE, NAME) TYPE##_component(),
#define QUERY_emit_create_write(TYPE, NAME) TYPE##_component(),
#define QUERY_emit_create_optional(TYPE) { .component = TYPE##_component(), .filter = ALIAS_ECS_FILTER_OPTIONAL },
#define QUERY_emit_create_exclude(TYPE) { .component = TYPE##_component(), .filter = ALIAS_ECS_FILTER_EXCLUDE },
#define QUERY_emit_create_modified(TYPE) { .component = TYPE##_component(), .filter = ALIAS_ECS_FILTER_MODIFIED },
#define QUERY(NAME, ...) ALIAS_CPP_EVAL(QUERY_impl(NAME, __VA_ARGS__))
#define QUERY_impl(NAME, ...) \
struct ALIAS_CPP_CAT(NAME, _state) { \
alias_ecs_Query * query; \
ALIAS_CPP_FILTER_MAP(QUERY_is_state, QUERY_emit, __VA_ARGS__) \
}; \
static void ALIAS_CPP_CAT(NAME, _do)(void * ud, alias_ecs_Instance * instance, alias_ecs_EntityHandle entity, void ** data) { \
uint32_t __i = 0; \
struct ALIAS_CPP_CAT(NAME, _state) * state = (struct ALIAS_CPP_CAT(NAME, _state) *)ud; \
ALIAS_CPP_FILTER_MAP(QUERY_is_write, QUERY_emit, __VA_ARGS__) \
ALIAS_CPP_FILTER_MAP(QUERY_is_read, QUERY_emit, __VA_ARGS__) \
ALIAS_CPP_FILTER_MAP(QUERY_is_action, QUERY_emit, __VA_ARGS__) \
} \
void NAME(void) { \
static struct ALIAS_CPP_CAT(NAME, _state) _state = { 0 }; \
static struct ALIAS_CPP_CAT(NAME, _state) * state = &_state; \
if(state->query == NULL) { \
alias_ecs_ComponentHandle _rlist[] = { ALIAS_CPP_FILTER_MAP(QUERY_is_read, QUERY_emit_create, __VA_ARGS__) }; \
alias_ecs_ComponentHandle _wlist[] = { ALIAS_CPP_FILTER_MAP(QUERY_is_write, QUERY_emit_create, __VA_ARGS__) }; \
alias_ecs_QueryFilterCreateInfo _flist[] = { ALIAS_CPP_FILTER_MAP(QUERY_is_filter, QUERY_emit_create, __VA_ARGS__) }; \
alias_ecs_create_query(Engine_ecs(), &(alias_ecs_QueryCreateInfo) { \
.num_write_components = sizeof(_wlist) / sizeof(_wlist[0]), \
.write_components = _wlist, \
.num_read_components = sizeof(_rlist) / sizeof(_rlist[0]), \
.read_components = _rlist, \
.num_filters = sizeof(_flist) / sizeof(_flist[0]), \
.filters = _flist \
}, &state->query); \
} \
ALIAS_CPP_FILTER_MAP(QUERY_is_pre, QUERY_emit, __VA_ARGS__) \
alias_ecs_execute_query(Engine_ecs(), state->query, (alias_ecs_QueryCB) { ALIAS_CPP_CAT(NAME, _do), state }); \
ALIAS_CPP_FILTER_MAP(QUERY_is_post, QUERY_emit, __VA_ARGS__) \
}
struct Cmd {
uint32_t size;
enum {
cmd_add_component,
cmd_remove_component,
cmd_despawn
} tag;
alias_ecs_EntityHandle entity;
alias_ecs_ComponentHandle component;
};
struct CmdBuf {
void * start;
void * pointer;
void * end;
};
void CmdBuf_add_component(struct CmdBuf * cbuf, alias_ecs_EntityHandle entity, alias_ecs_ComponentHandle component, void * data, size_t data_size);
void CmdBuf_remove_component(struct CmdBuf * cbuf, alias_ecs_EntityHandle entity, alias_ecs_ComponentHandle component);
void CmdBuf_despawn(struct CmdBuf * cbuf, alias_ecs_EntityHandle entity);
void CmdBuf_begin_recording(struct CmdBuf * cbuf);
void CmdBuf_end_recording(struct CmdBuf * cbuf);
void CmdBuf_execute(struct CmdBuf * cbuf, alias_ecs_Instance * instance);
#endif