[ecs] Support sorting subpools

Sorting the whole pool when subpools are in use could break the
subpools (very high probability, depending on the sort criteria and
subpool criteria).
This commit is contained in:
Bill Currie 2023-01-16 11:32:12 +09:00
parent 2383c12a4a
commit 8833518826
4 changed files with 61 additions and 11 deletions

View file

@ -117,6 +117,9 @@ typedef int (*__compar_d_fn_t)(const void *, const void *, void *);
#endif
void ECS_SortComponentPool (ecs_registry_t *registry, uint32_t component,
__compar_d_fn_t cmp, void *arg);
void ECS_SortComponentPoolRange (ecs_registry_t *registry, uint32_t component,
ecs_range_t range,
__compar_d_fn_t cmp, void *arg);
uint32_t ECS_NewEntity (ecs_registry_t *registry);
void ECS_DelEntity (ecs_registry_t *registry, uint32_t ent);

View file

@ -78,5 +78,8 @@ typedef struct canvas_subpic_s {
void Canvas_AddToEntity (canvas_system_t canvas_sys, uint32_t ent);
void Canvas_Draw (canvas_system_t canvas_sys);
void Canvas_SortComponentPool (canvas_system_t canvas_sys, uint32_t ent,
uint32_t component);
#endif//__QF_scene_canvas_h

View file

@ -125,6 +125,26 @@ ecs_swap (void *_a, void *_b, void *arg)
swap_uint32 (&pool->sparse[a_ent_ind], &pool->sparse[b_ent_ind]);
}
VISIBLE void
ECS_SortComponentPoolRange (ecs_registry_t *registry, uint32_t component,
ecs_range_t range, __compar_d_fn_t cmp, void *arg)
{
if (component >= registry->components.size) {
Sys_Error ("ECS_SortComponentPoolRange: invalid component: %u",
component);
}
ecs_pool_t *pool = &registry->comp_pools[component];
if (!pool->count || range.end <= range.start) {
return;
}
uint32_t count = range.end - range.start;
uint32_t *start = pool->dense + range.start;
__auto_type comp = &registry->components.a[component];
ecs_sort_t sortctx = { .cmp = cmp, .arg = arg, .pool = pool, .comp = comp };
heapsort_s (start, count, sizeof (uint32_t),
ecs_compare, ecs_swap, &sortctx);
}
VISIBLE void
ECS_SortComponentPool (ecs_registry_t *registry, uint32_t component,
__compar_d_fn_t cmp, void *arg)
@ -133,13 +153,8 @@ ECS_SortComponentPool (ecs_registry_t *registry, uint32_t component,
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.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);
ecs_range_t range = { .start = 0, .end = pool->count };
ECS_SortComponentPoolRange (registry, component, range, cmp, arg);
}
VISIBLE uint32_t

View file

@ -312,10 +312,10 @@ Canvas_Draw (canvas_system_t canvas_sys)
};
uint32_t comp = canvas_sys.base + canvas_canvas;
ecs_pool_t *pool = &canvas_sys.reg->comp_pools[comp];
uint32_t count = pool->count;
//uint32_t *entities = pool->dense;
__auto_type canvases = (canvas_t *) pool->data;
ecs_pool_t *canvas_pool = &canvas_sys.reg->comp_pools[comp];
uint32_t count = canvas_pool->count;
//uint32_t *entities = canvas_pool->dense;
__auto_type canvases = (canvas_t *) canvas_pool->data;
while (count-- > 0) {
canvas_t *canvas = canvases++;
@ -347,3 +347,32 @@ Canvas_AddToEntity (canvas_system_t canvas_sys, uint32_t ent)
(ecs_system_t) { canvas_sys.reg, canvas_sys.view_base },
nullview);
}
static int
canvas_href_cmp (const void *_a, const void *_b, void *arg)
{
uint32_t enta = *(const uint32_t *)_a;
uint32_t entb = *(const uint32_t *)_b;
canvas_system_t *canvas_sys = arg;
ecs_registry_t *reg = canvas_sys->reg;
uint32_t href = canvas_sys->view_base + view_href;
hierref_t *ref_a = Ent_GetComponent (enta, href, reg);
hierref_t *ref_b = Ent_GetComponent (entb, href, reg);
if (ref_a->hierarchy == ref_b->hierarchy) {
return ref_a->index - ref_b->index;
}
ptrdiff_t diff = ref_a->hierarchy - ref_b->hierarchy;
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
}
void
Canvas_SortComponentPool (canvas_system_t canvas_sys, uint32_t ent,
uint32_t component)
{
canvas_t *canvas = Ent_GetComponent (ent, canvas_sys.base + canvas_canvas,
canvas_sys.reg);
uint32_t rid = canvas->range[component - canvas_sys.base];
ecs_range_t range = ECS_GetSubpoolRange (canvas_sys.reg, component, rid);
ECS_SortComponentPoolRange (canvas_sys.reg, component, range,
canvas_href_cmp, &canvas_sys);
}