diff --git a/libs/video/renderer/vulkan/render_ui.c b/libs/video/renderer/vulkan/render_ui.c index 347e6b5fc..2c9a16de8 100644 --- a/libs/video/renderer/vulkan/render_ui.c +++ b/libs/video/renderer/vulkan/render_ui.c @@ -29,9 +29,14 @@ #endif #include "QF/fbsearch.h" +#include "QF/heapsort.h" #include "QF/va.h" + +#include "QF/scene/scene.h" + #include "QF/ui/imui.h" +#include "QF/Vulkan/qf_scene.h" #include "QF/Vulkan/mouse_pick.h" #include "QF/Vulkan/render.h" #include "vid_vulkan.h" @@ -43,8 +48,12 @@ typedef struct qfv_renderdebug_s { imui_window_t job_timings_window; imui_window_t job_control_window; - imui_window_t entity_window; + imui_window_t entid_window; uint32_t picked_enties[picked_entity_count]; + uint32_t locked_entities[picked_entity_count]; + struct DARRAY_TYPE (imui_window_t) ent_windows; + struct DARRAY_TYPE (uint32_t) ent_window_ids; + uint32_t num_locked_entities; } qfv_renderdebug_t; static void @@ -182,8 +191,98 @@ mousepick_callback (const uint32_t *entid, void *data) memcpy (debug->picked_enties, entid, sizeof (debug->picked_enties)); } +typedef struct { + uint32_t entid; + uint32_t count; +} entid_counts_t; + static int -entid_counts_cmp (const void *_a, const void *_b) +entid_counts_id_cmp (const void *_a, const void *_b) +{ + const uint32_t *a = _a; + const entid_counts_t *b = _b; + return *a - b->entid; +} + +static int +entid_counts_count_cmp (const void *_a, const void *_b) +{ + const entid_counts_t *a = _a; + const entid_counts_t *b = _b; + // reverse sort + return b->count - a->count; +} + +static void +collect_entids (vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx) +{ + auto rctx = ctx->render_context; + auto debug = rctx->debug; + + entid_counts_t entid_counts[picked_entity_count]; + uint32_t num_entids = 0; + for (uint32_t i = 0; i < picked_entity_count; i++) { + if (debug->picked_enties[i] == nullent) { + continue; + } + if (!num_entids) { + entid_counts[num_entids++] = (entid_counts_t) { + .entid = debug->picked_enties[i], + .count = 1, + }; + continue; + } + entid_counts_t *ec = 0; + ec = fbsearch (&debug->picked_enties[i], + entid_counts, num_entids, sizeof (entid_counts_t), + entid_counts_id_cmp); + uint32_t ind = 0; + if (ec) { + if (ec->entid == debug->picked_enties[i]) { + ec->count++; + continue; + } + ind = ec - entid_counts + 1; + } + memmove (entid_counts + ind + 1, entid_counts + ind, + sizeof (entid_counts_t[num_entids - ind])); + entid_counts[ind] = (entid_counts_t) { + .entid = debug->picked_enties[i], + .count = 1, + }; + num_entids++; + } + + auto io = IMUI_GetIO (imui_ctx); + if (io.hot == nullent && io.active == nullent) { + QFV_MousePick_Read (ctx, io.mouse.x, io.mouse.y, + mousepick_callback, rctx); + if (io.buttons & 1) { + debug->num_locked_entities = 0; + for (uint32_t i = num_entids; i-- > 0; ) { + UI_Horizontal { + UI_Label ("Entity"); + hs (imui_ctx, 1); + UI_FlexibleSpace (); + UI_Labelf ("%08x %2d##%p.entity_count", + entid_counts[i].entid, + entid_counts[i].count, rctx); + } + } + } + if (io.released & 1) { + heapsort (entid_counts, num_entids, sizeof (entid_counts_t), + entid_counts_count_cmp); + debug->num_locked_entities = num_entids; + for (uint32_t i = 0; i < num_entids; i++) { + debug->locked_entities[i] = entid_counts[i].entid; + } + } + } +} + +static int +ent_window_id_cmp (const void *_a, const void *_b) { const uint32_t *a = _a; const uint32_t *b = _b; @@ -191,63 +290,91 @@ entid_counts_cmp (const void *_a, const void *_b) } static void -entity_window (vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx) +entid_button (uint32_t entid, vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx) { auto rctx = ctx->render_context; auto debug = rctx->debug; - UI_Window (&debug->entity_window) { - if (debug->entity_window.is_collapsed) { + + auto e_w_ids = &debug->ent_window_ids; + uint32_t *weid = bsearch (&entid, e_w_ids->a, e_w_ids->size, + sizeof (uint32_t), ent_window_id_cmp); + bool open = weid ? debug->ent_windows.a[weid - e_w_ids->a].is_open : false; + + UI_Horizontal { + hs (imui_ctx, 1); + UI_Checkbox (&open, va (ctx->va_ctx, "%08x##%p.entity", entid, rctx)); + } + if (weid) { + debug->ent_windows.a[weid - e_w_ids->a].is_open = open; + return; + } + if (!open) { + return; + } + + Sys_Printf ("opening window for %x\n", entid); + auto io = IMUI_GetIO (imui_ctx); + + // need to maintain entid sort order of the windows + weid = fbsearch (&entid, e_w_ids->a, e_w_ids->size, sizeof (uint32_t), + ent_window_id_cmp); + uint32_t ind = weid ? weid - e_w_ids->a + 1 : 0; + DARRAY_INSERT_AT (e_w_ids, entid, ind); + DARRAY_INSERT_AT (&debug->ent_windows, + ((imui_window_t) { + .name = nva ("Entity %08x##%p.window", entid, rctx), + .xpos = io.mouse.x + 50, + .ypos = io.mouse.y, + .is_open = true, + }), ind); +} + +static void +entid_window (vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx) +{ + auto rctx = ctx->render_context; + auto debug = rctx->debug; + UI_Window (&debug->entid_window) { + if (debug->entid_window.is_collapsed) { continue; } - typedef struct { - uint32_t entid; - uint32_t count; - } entid_counts_t; - entid_counts_t entid_counts[picked_entity_count]; - uint32_t num_entids = 0; - for (uint32_t i = 0; i < picked_entity_count; i++) { - if (debug->picked_enties[i] == nullent) { - continue; - } - if (!num_entids) { - entid_counts[num_entids++] = (entid_counts_t) { - .entid = debug->picked_enties[i], - .count = 1, - }; - continue; - } - entid_counts_t *ec = 0; - ec = fbsearch (&debug->picked_enties[i], - entid_counts, num_entids, sizeof (entid_counts_t), - entid_counts_cmp); - uint32_t ind = 0; - if (ec) { - if (ec->entid == debug->picked_enties[i]) { - ec->count++; - continue; - } - ind = ec - entid_counts + 1; - } - memmove (entid_counts + ind + 1, entid_counts + ind, - sizeof (entid_counts_t[num_entids - ind])); - entid_counts[ind] = (entid_counts_t) { - .entid = debug->picked_enties[i], - .count = 1, - }; - num_entids++; - } - auto io = IMUI_GetIO (imui_ctx); - if (io.hot == nullent && io.active == nullent) { - QFV_MousePick_Read (ctx, io.mouse.x, io.mouse.y, - mousepick_callback, rctx); - for (uint32_t i = num_entids; i-- > 0; ) { + collect_entids (ctx, imui_ctx); + if (debug->num_locked_entities) { + UI_Horizontal { + UI_Label ("Entity"); + UI_FlexibleSpace (); + } + for (uint32_t i = 0; i < debug->num_locked_entities; i++) { + entid_button (debug->locked_entities[i], ctx, imui_ctx); + } + } + } +} + +static void +entity_window (uint32_t id, vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx) +{ + auto scene = ctx->scene_context->scene; + auto reg = scene->reg; + if (!ECS_EntValid (id, reg)) { + UI_Label ("Invalid Entity"); + return; + } + for (size_t i = 0; i < reg->components.size; i++) { + if (Ent_HasComponent (id, i, reg)) { + UI_Horizontal { + UI_Label (reg->components.a[i].name); + UI_FlexibleSpace (); + } + if (reg->components.a[i].ui) { + void *comp = Ent_GetComponent (id, i, reg); UI_Horizontal { - UI_Label ("Entity"); hs (imui_ctx, 1); - UI_FlexibleSpace (); - UI_Labelf ("%08x %2d##%p.entity", entid_counts[i].entid, - entid_counts[i].count, rctx); + UI_Vertical { + IMUI_Layout_SetXSize (imui_ctx, imui_size_expand, 100); + reg->components.a[i].ui (comp, imui_ctx, reg, id, ctx); + } } } } @@ -271,18 +398,39 @@ QFV_Render_UI (vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx) .xpos = 100, .ypos = 50, }, - .entity_window = { + .entid_window = { .name = nva ("Entities##%p.window", rctx), .xpos = 100, .ypos = 50, }, + .ent_windows = DARRAY_STATIC_INIT (4), + .ent_window_ids = DARRAY_STATIC_INIT (4), }; memset (rctx->debug->picked_enties, 0xff, sizeof (rctx->debug->picked_enties)); } job_timings_window (ctx, imui_ctx); job_control_window (ctx, imui_ctx); - entity_window (ctx, imui_ctx); + entid_window (ctx, imui_ctx); + for (size_t i = 0; i < rctx->debug->ent_windows.size; i++) { + while (i < rctx->debug->ent_windows.size + && !rctx->debug->ent_windows.a[i].is_open) { + auto w = &rctx->debug->ent_windows.a[i]; + free ((char *) w->name); + DARRAY_CLOSE_AT (&rctx->debug->ent_windows, i, 1); + DARRAY_CLOSE_AT (&rctx->debug->ent_window_ids, i, 1); + } + if (i < rctx->debug->ent_windows.size) { + auto window = &rctx->debug->ent_windows.a[i]; + auto id = rctx->debug->ent_window_ids.a[i]; + UI_Window (window) { + if (window->is_collapsed) { + continue; + } + entity_window (id, ctx, imui_ctx); + } + } + } } void @@ -296,7 +444,7 @@ QFV_Render_Menu (vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx) rctx->debug->job_control_window.is_open = true; } if (UI_MenuItem (va (ctx->va_ctx, "Entities##%p", rctx))) { - rctx->debug->entity_window.is_open = true; + rctx->debug->entid_window.is_open = true; } } @@ -305,9 +453,14 @@ QFV_Render_UI_Shutdown (vulkan_ctx_t *ctx) { auto rctx = ctx->render_context; if (rctx->debug) { - free ((char *) rctx->debug->job_timings_window.name); - free ((char *) rctx->debug->job_control_window.name); - free ((char *) rctx->debug->entity_window.name); - free (rctx->debug); + auto d = rctx->debug; + for (size_t i = 0; i < d->ent_windows.size; i++) { + free ((char *) d->ent_windows.a[i].name); + } + DARRAY_CLEAR (&d->ent_windows); + free ((char *) d->job_timings_window.name); + free ((char *) d->job_control_window.name); + free ((char *) d->entid_window.name); + free (d); } }