[ecs] Split component registration from pool creation

While this does require an extra call after registering components, it
allows for multiple component sets (ie, sub-systems) to be registered
before the component pools are created. The base id for the registered
component set is returned so it can be passed to the subsystem as
needed.
This commit is contained in:
Bill Currie 2022-12-13 22:58:44 +09:00
parent 3c4dccf801
commit b230fe18ce
17 changed files with 54 additions and 26 deletions

View file

@ -34,6 +34,7 @@
#include <string.h>
#include <stdlib.h>
#include "QF/darray.h"
#include "QF/qtypes.h"
#include "QF/progs.h"//FIXME for PR_RESMAP
@ -58,22 +59,26 @@ typedef struct ecs_pool_s {
uint32_t max_count; // current capacity for components/entity ids
} ecs_pool_t;
typedef struct DARRAY_TYPE(component_t) componentset_t;
typedef struct ecs_registry_s {
uint32_t *entities;
uint32_t next;
uint32_t available;
uint32_t num_entities;
uint32_t max_entities;
const component_t *components;
componentset_t components;
ecs_pool_t *comp_pools;
uint32_t num_components;
PR_RESMAP (hierarchy_t) hierarchies;//FIXME find a better way
} ecs_registry_t;
ecs_registry_t *ECS_NewRegistry (void);
void ECS_DelRegistry (ecs_registry_t *registry);
void ECS_RegisterComponents (ecs_registry_t *registry,
const component_t *components, uint32_t count);
uint32_t ECS_RegisterComponents (ecs_registry_t *registry,
const component_t *components,
uint32_t count);
void ECS_CreateComponentPools (ecs_registry_t *registry);
#ifndef __compar_d_fn_t_defined
#define __compar_d_fn_t_defined

View file

@ -97,7 +97,7 @@ Ent_HasComponent (uint32_t ent, uint32_t comp, ecs_registry_t *reg)
ENTINLINE void *
Ent_GetComponent (uint32_t ent, uint32_t comp, ecs_registry_t *reg)
{
const component_t *component = &reg->components[comp];
const component_t *component = &reg->components.a[comp];
uint32_t ind = reg->comp_pools[comp].sparse[Ent_Index (ent)];
byte *data = reg->comp_pools[comp].data;
return data + ind * component->size;
@ -113,10 +113,10 @@ Ent_SetComponent (uint32_t ent, uint32_t comp, ecs_registry_t *registry,
{
void *dst = Ent_AddComponent (ent, comp, registry);
if (data) {
return Component_CopyElements (&registry->components[comp],
return Component_CopyElements (&registry->components.a[comp],
dst, 0, data, 0, 1);
} else {
return Component_CreateElements (&registry->components[comp],
return Component_CreateElements (&registry->components.a[comp],
dst, 0, 1);
}
}

View file

@ -49,6 +49,9 @@ enum scene_components {
scene_old_origin, //XXX FIXME XXX should not be here
scene_colormap,
scene_canvas,
scene_vref, //view hierarchy reference
//FIXME these should probably be private to the sw renderer (and in a
//group, which needs to be implemented), but need to sort out a good
//scheme for semi-dynamic components

View file

@ -21,7 +21,7 @@ extern vid_render_funcs_t *vid_render_funcs;
#define vr_funcs vid_render_funcs
extern refdef_t r_refdef;
#define SW_COMP(comp, id) ((void *)((byte *)r_refdef.registry->comp_pools[comp].data + (id) * r_refdef.registry->components[comp].size))
#define SW_COMP(comp, id) ((void *)((byte *)r_refdef.registry->comp_pools[comp].data + (id) * r_refdef.registry->components.a[comp].size))
extern int r_viewsize;
void R_LineGraph (int x, int y, int *h_vals, int count, int height);

View file

@ -266,6 +266,7 @@ HUD_Init (void)
{
hud_registry = ECS_NewRegistry ();
ECS_RegisterComponents (hud_registry, hud_components, hud_comp_count);
ECS_CreateComponentPools (hud_registry);
}
void

View file

@ -1023,6 +1023,7 @@ C_Init (void)
{
client_reg = ECS_NewRegistry ();
ECS_RegisterComponents (client_reg, client_components, client_comp_count);
ECS_CreateComponentPools (client_reg);
#ifdef __QNXNTO__
setlocale (LC_ALL, "C-TRADITIONAL");

View file

@ -679,6 +679,7 @@ init (void)
server_reg = ECS_NewRegistry ();
ECS_RegisterComponents (server_reg, server_components, server_comp_count);
ECS_CreateComponentPools (server_reg);
get_size (&screen_x, &screen_y);

View file

@ -38,6 +38,7 @@ VISIBLE ecs_registry_t *
ECS_NewRegistry (void)
{
ecs_registry_t *reg = calloc (1, sizeof (ecs_registry_t));
reg->components = (componentset_t) DARRAY_STATIC_INIT (32);
reg->next = Ent_Index (nullent);
return reg;
}
@ -46,7 +47,7 @@ VISIBLE void
ECS_DelRegistry (ecs_registry_t *registry)
{
free (registry->entities);
for (uint32_t i = 0; i < registry->num_components; i++) {
for (uint32_t i = 0; i < registry->components.size; i++) {
free (registry->comp_pools[i].sparse);
free (registry->comp_pools[i].dense);
free (registry->comp_pools[i].data);
@ -55,15 +56,24 @@ ECS_DelRegistry (ecs_registry_t *registry)
free (registry);
}
VISIBLE void
VISIBLE uint32_t
ECS_RegisterComponents (ecs_registry_t *registry,
const component_t *components, uint32_t count)
{
registry->num_components = count;
registry->components = components;
uint32_t base = registry->components.size;
DARRAY_RESIZE (&registry->components, base + count);
memcpy (registry->components.a + base, components,
count * sizeof (component_t));
return base;
}
VISIBLE void
ECS_CreateComponentPools (ecs_registry_t *registry)
{
uint32_t count = registry->components.size;
registry->comp_pools = calloc (count, sizeof (ecs_pool_t));
size_t size = registry->max_entities * sizeof (uint32_t);
for (uint32_t i = 0; i < registry->num_components; i++) {
for (uint32_t i = 0; i < count; i++) {
registry->comp_pools[i].sparse = malloc (size);
memset (registry->comp_pools[i].sparse, nullent, size);
}
@ -114,14 +124,14 @@ VISIBLE void
ECS_SortComponentPool (ecs_registry_t *registry, uint32_t component,
__compar_d_fn_t cmp, void *arg)
{
if (component >= registry->num_components) {
if (component >= registry->components.size) {
Sys_Error ("ECS_SortComponentPool: invalid component: %u", component);
}
ecs_pool_t *pool = &registry->comp_pools[component];
if (!pool->count) {
return;
}
__auto_type comp = &registry->components[component];
__auto_type comp = &registry->components.a[component];
ecs_sort_t sortctx = { .cmp = cmp, .arg = arg, .pool = pool, .comp = comp };
heapsort_s (pool->dense, pool->count, sizeof (uint32_t),
ecs_compare, ecs_swap, &sortctx);
@ -145,7 +155,7 @@ ECS_NewEntity (ecs_registry_t *registry)
registry->max_entities += ENT_GROW;
size_t size = registry->max_entities * sizeof (uint32_t);
registry->entities = realloc (registry->entities, size);
for (uint32_t i = 0; i < registry->num_components; i++) {
for (uint32_t i = 0; i < registry->components.size; i++) {
uint32_t *sparse = registry->comp_pools[i].sparse;
sparse = realloc (sparse, size);
memset (sparse + registry->max_entities - ENT_GROW, nullent,
@ -169,7 +179,7 @@ ECS_DelEntity (ecs_registry_t *registry, uint32_t ent)
registry->next = id;
registry->available++;
for (uint32_t i = 0; i < registry->num_components; i++) {
for (uint32_t i = 0; i < registry->components.size; i++) {
Ent_RemoveComponent (ent, i, registry);
}
}
@ -178,7 +188,7 @@ VISIBLE void
ECS_RemoveEntities (ecs_registry_t *registry, uint32_t component)
{
ecs_pool_t *pool = &registry->comp_pools[component];
const component_t *comp = &registry->components[component];
const component_t *comp = &registry->components.a[component];
__auto_type destroy = comp->destroy;
if (destroy) {
byte *data = registry->comp_pools[component].data;

View file

@ -45,7 +45,7 @@ Ent_AddComponent (uint32_t ent, uint32_t comp, ecs_registry_t *registry)
pool->max_count += COMP_GROW;
pool->dense = realloc (pool->dense,
pool->max_count * sizeof (uint32_t));
Component_ResizeArray (&registry->components[comp], &pool->data,
Component_ResizeArray (&registry->components.a[comp], &pool->data,
pool->max_count);
}
uint32_t ind = pool->count++;
@ -63,12 +63,12 @@ Ent_RemoveComponent (uint32_t ent, uint32_t comp, ecs_registry_t *registry)
uint32_t ind = pool->sparse[id];
if (ind < pool->count && pool->dense[ind] == ent) {
uint32_t last = pool->count - 1;
Component_DestroyElements (&registry->components[comp], pool->data,
Component_DestroyElements (&registry->components.a[comp], pool->data,
ind, 1);
if (last > ind) {
pool->sparse[Ent_Index (pool->dense[last])] = ind;
pool->dense[ind] = pool->dense[last];
Component_MoveElements (&registry->components[comp], pool->data,
Component_MoveElements (&registry->components.a[comp], pool->data,
ind, last, 1);
}
pool->count--;

View file

@ -8,7 +8,7 @@
#include "QF/simd/types.h"
#include "QF/mathlib.h"
#include "QF/ecs/component.h"
#include "QF/ecs.h"
enum test_components {
test_position,
@ -62,7 +62,7 @@ check_ent_components (const uint32_t *ents, uint32_t count, uint32_t comp,
ecs_registry_t *reg)
{
ecs_pool_t *pool = &reg->comp_pools[comp];
const component_t *component = &reg->components[comp];
const component_t *component = &reg->components.a[comp];
if (pool->count != count) {
printf ("%s pool has wrong object count: %d %d\n", component->name,
pool->count, count);
@ -106,6 +106,8 @@ main (void)
{
ecs_registry_t *reg = ECS_NewRegistry ();
ECS_RegisterComponents (reg, test_components, test_num_components);
ECS_CreateComponentPools (reg);
uint32_t enta = ECS_NewEntity (reg);
uint32_t entb = ECS_NewEntity (reg);
uint32_t entc = ECS_NewEntity (reg);

View file

@ -6,8 +6,7 @@
#include <string.h>
#include <unistd.h>
#include "QF/ecs/component.h"
#include "QF/ecs/hierarchy.h"
#include "QF/ecs.h"
enum {
test_href,
@ -886,6 +885,7 @@ main (void)
{
test_reg = ECS_NewRegistry ();
ECS_RegisterComponents (test_reg, test_components, test_num_components);
ECS_CreateComponentPools (test_reg);
if (test_single_transform ()) { return 1; }
if (test_parent_child_init ()) { return 1; }

View file

@ -6,7 +6,7 @@
#include <string.h>
#include <unistd.h>
#include "QF/ecs/component.h"
#include "QF/ecs.h"
static int
test_new_del (void)

View file

@ -213,6 +213,7 @@ Scene_NewScene (void)
scene->reg = ECS_NewRegistry ();
ECS_RegisterComponents (scene->reg, scene_components, scene_comp_count);
ECS_CreateComponentPools (scene->reg);
scene_resources_t *res = calloc (1, sizeof (scene_resources_t));
*(scene_resources_t **)&scene->resources = res;

View file

@ -280,6 +280,7 @@ main (void)
test_reg = ECS_NewRegistry ();
ECS_RegisterComponents (test_reg, test_components, 1);
ECS_CreateComponentPools (test_reg);
if (test_flow (right_down_views, right_down_count, view_flow_right_down)) {
printf ("right-down failed\n");

View file

@ -280,6 +280,7 @@ main (void)
test_reg = ECS_NewRegistry ();
ECS_RegisterComponents (test_reg, test_components, 1);
ECS_CreateComponentPools (test_reg);
if (test_flow (right_down_views, right_down_count, view_flow_right_down)) {
printf ("right-down failed\n");

View file

@ -64,6 +64,7 @@ main (void)
int ret = 0;
ecs_registry_t *registry = ECS_NewRegistry ();
ECS_RegisterComponents (registry, test_components, 1);
ECS_CreateComponentPools (registry);
passage_t *passage = Passage_New (registry, test_href);
Passage_ParseText (passage, test_text);

View file

@ -92,6 +92,7 @@ Text_Init (void)
{
text_reg = ECS_NewRegistry ();
ECS_RegisterComponents (text_reg, text_components, text_comp_count);
ECS_CreateComponentPools (text_reg);
}
typedef struct glyphnode_s {