[ui] Add the concept of draw order to canvases

Canvas draw order is sorted by group then order within the group. As a
fallback, the canvas entity id is used to keep the sort stable, but
that's only as stable as the ids themselves (if the canvases are
destroyed and recreated, the ids may switch around).
This commit is contained in:
Bill Currie 2023-07-09 22:18:04 +09:00
parent c2d68f5495
commit 79e4a5f6a8
3 changed files with 66 additions and 0 deletions

View file

@ -60,6 +60,8 @@ enum {
typedef struct canvas_s {
ecs_registry_t *reg;
uint32_t base;
int16_t draw_order;
int16_t draw_group;
bool visible;
uint32_t range[canvas_canvas];
} canvas_t;
@ -98,6 +100,11 @@ void Canvas_SetLen (canvas_system_t canvas_sys, uint32_t ent, view_pos_t len);
CANVASINLINE view_t Canvas_GetRootView (canvas_system_t canvas_sys,
uint32_t ent);
CANVASINLINE bool *Canvas_Visible (canvas_system_t canvas_sys, uint32_t ent);
CANVASINLINE int16_t *Canvas_DrawGroup (canvas_system_t canvas_sys,
uint32_t ent);
CANVASINLINE int16_t *Canvas_DrawOrder (canvas_system_t canvas_sys,
uint32_t ent);
void Canvas_DrawSort (canvas_system_t canvas_sys);
#undef CANVASINLINE
#ifndef IMPLEMENT_CANVAS_Funcs
@ -123,6 +130,24 @@ Canvas_Visible (canvas_system_t canvas_sys, uint32_t ent)
return &canvas->visible;
}
CANVASINLINE
int16_t *
Canvas_DrawGroup (canvas_system_t canvas_sys, uint32_t ent)
{
uint32_t comp = canvas_sys.base + canvas_canvas;
auto canvas = (canvas_t *) Ent_GetComponent (ent, comp, canvas_sys.reg);
return &canvas->draw_group;
}
CANVASINLINE
int16_t *
Canvas_DrawOrder (canvas_system_t canvas_sys, uint32_t ent)
{
uint32_t comp = canvas_sys.base + canvas_canvas;
auto canvas = (canvas_t *) Ent_GetComponent (ent, comp, canvas_sys.reg);
return &canvas->draw_order;
}
#undef CANVASINLINE
#endif//__QF_scene_canvas_h

View file

@ -573,3 +573,33 @@ Canvas_SetLen (canvas_system_t canvas_sys, uint32_t ent, view_pos_t len)
View_SetLen (view, len.x, len.y);
View_UpdateHierarchy (view);
}
static int
canvas_draw_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;
auto reg = canvas_sys->reg;
uint32_t c_canvas = canvas_sys->base + canvas_canvas;
auto canvasa = (canvas_t *) Ent_GetComponent (enta, c_canvas, reg);
auto canvasb = (canvas_t *) Ent_GetComponent (entb, c_canvas, reg);
int diff = canvasa->draw_group - canvasb->draw_group;
if (!diff) {
diff = canvasa->draw_order - canvasb->draw_order;
}
if (!diff) {
// order possibly undefined, but at least stable so long as the entity
// ids are stable
diff = enta - entb;
}
return diff;
}
void
Canvas_DrawSort (canvas_system_t canvas_sys)
{
auto reg = canvas_sys.reg;
uint32_t c_canvas = canvas_sys.base + canvas_canvas;
ECS_SortComponentPool (reg, c_canvas, canvas_draw_cmp, &canvas_sys);
}

View file

@ -57,6 +57,8 @@
#define c_color (ctx->tsys.text_base + text_color)
#define c_fill (ctx->csys.base + canvas_fill)
#define imui_draw_group ((1 << 15) - 1)
const component_t imui_components[imui_comp_count] = {
[imui_percent_x] = {
.size = sizeof (int),
@ -218,6 +220,7 @@ IMUI_NewContext (canvas_system_t canvas_sys, const char *font, float fontsize)
},
},
};
*Canvas_DrawGroup (ctx->csys, ctx->canvas) = imui_draw_group;
ctx->tab = Hash_NewTable (511, imui_state_getkey, 0, ctx, &ctx->hashctx);
ctx->current_parent = ctx->root_view;
@ -639,6 +642,11 @@ IMUI_Draw (imui_ctx_t *ctx)
auto ref = View_GetRef (ctx->windows.a[i]);
Hierarchy_SetTreeMode (ref->hierarchy, false);
}
for (uint32_t i = 0; i < ctx->window_canvases.size; i++) {
// root is 0
*Canvas_DrawOrder (ctx->csys, ctx->window_canvases.a[i]) = i + 1;
}
Canvas_DrawSort (ctx->csys);
prune_objects (ctx);
layout_objects (ctx, ctx->root_view);
@ -995,9 +1003,12 @@ IMUI_StartWindow (imui_ctx_t *ctx, imui_window_t *window)
DARRAY_APPEND (&ctx->parent_stack, ctx->current_parent);
auto canvas = Canvas_New (ctx->csys);
*Canvas_DrawGroup (ctx->csys, canvas) = imui_draw_group;
auto window_view = Canvas_GetRootView (ctx->csys, canvas);
state->entity = window_view.id;
int mode = update_hot_active (ctx, old_entity, state->entity);
auto ref = View_GetRef (window_view);
Hierarchy_SetTreeMode (ref->hierarchy, true);
DARRAY_APPEND (&ctx->windows, window_view);
DARRAY_APPEND (&ctx->window_canvases, canvas);