ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | LICENSE

Commit: 752f76c0ff806292854b956a21ac5ab9260b2a8f
Parent: 204111785a680e2b466b1d1b76ef37b35044e420
Author: Randy Palamar
Date:   Sun, 13 Apr 2025 07:35:20 -0600

ui: add default menu for all ui views

Diffstat:
Mui.c | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 109 insertions(+), 48 deletions(-)

diff --git a/ui.c b/ui.c @@ -3,7 +3,6 @@ * [ ]: ui should be in its own thread and that thread should only be concerned with the ui * [ ]: scroll bar for views that don't have enough space * [ ]: compute times through same path as parameter list ? - * [ ]: global menu * [ ]: allow views to collapse to just their title bar * - title bar struct with expanded. Check when pushing onto draw stack; if expanded * do normal behaviour else make size title bar size and ignore the splits fraction. @@ -181,9 +180,14 @@ typedef struct { X(FV_COPY_HORIZONTAL, "Copy Horizontal") \ X(FV_COPY_VERTICAL, "Copy Vertical") +#define GLOBAL_MENU_BUTTONS \ + X(GM_OPEN_LIVE_VIEW_RIGHT, "Open Live View Right") \ + X(GM_OPEN_LIVE_VIEW_BELOW, "Open Live View Below") + #define X(id, text) UI_BID_ ##id, typedef enum { UI_BID_CLOSE_VIEW, + GLOBAL_MENU_BUTTONS FRAME_VIEW_BUTTONS } UIButtonID; #undef X @@ -332,6 +336,7 @@ struct BeamformerUI { BeamformerUIParameters params; b32 flush_params; + FragmentShaderCtx *fsctx; OS *os; }; @@ -479,13 +484,13 @@ ui_variable_free(BeamformerUI *ui, Variable *var) if (bv->type == FVT_COPY) { glDeleteTextures(1, &bv->frame->texture); bv->frame->texture = 0; + SLLPush(bv->frame, ui->frame_freelist); } DLLRemove(bv); /* TODO(rnp): hack; use a sentinal */ if (bv == ui->views) ui->views = bv->next; - SLLPush(bv->frame, ui->frame_freelist); - SLLPush(bv, ui->view_freelist); + SLLPush(bv, ui->view_freelist); } Variable *next = SLLPush(var, ui->variable_freelist); @@ -588,6 +593,19 @@ add_ui_split(BeamformerUI *ui, Variable *parent, Arena *arena, s8 name, f32 frac return result; } +function Variable * +add_global_menu(BeamformerUI *ui, Arena *arena, Variable *parent) +{ + Variable *result = add_variable_group(ui, 0, &ui->arena, s8(""), VG_LIST, ui->small_font); + result->parent = parent; + result->flags = V_MENU; + #define X(id, text) add_button(ui, result, &ui->arena, s8(text), UI_BID_ ##id, \ + V_CLOSES_MENU, ui->small_font); + GLOBAL_MENU_BUTTONS + #undef X + return result; +} + static Variable * add_ui_view(BeamformerUI *ui, Variable *parent, Arena *arena, s8 name, u32 view_flags, b32 closable) { @@ -595,6 +613,7 @@ add_ui_view(BeamformerUI *ui, Variable *parent, Arena *arena, s8 name, u32 view_ UIView *view = &result->u.view; view->group.type = VG_LIST; view->flags = view_flags; + view->menu = add_global_menu(ui, arena, result); if (closable) { view->close = add_button(ui, 0, arena, s8(""), UI_BID_CLOSE_VIEW, 0, ui->small_font); /* NOTE(rnp): we do this explicitly so that close doesn't end up in the view group */ @@ -700,14 +719,6 @@ add_beamformer_frame_view(BeamformerUI *ui, Variable *parent, Arena *arena, { /* TODO(rnp): this can be always closable once we have a way of opening new views */ Variable *result = add_ui_view(ui, parent, arena, s8(""), UI_VIEW_CUSTOM_TEXT, closable); - Variable *menu = result->u.view.menu = add_variable_group(ui, 0, arena, s8(""), - VG_LIST, ui->small_font); - menu->flags = V_MENU; - menu->parent = result; - #define X(id, text) add_button(ui, menu, arena, s8(text), UI_BID_ ##id, V_CLOSES_MENU, ui->small_font); - FRAME_VIEW_BUTTONS - #undef X - Variable *var = add_variable(ui, result, arena, s8(""), 0, VT_BEAMFORMER_FRAME_VIEW, ui->small_font); @@ -727,6 +738,23 @@ add_beamformer_frame_view(BeamformerUI *ui, Variable *parent, Arena *arena, bv->dynamic_range.u.f32 = -50.0f; bv->threshold.u.f32 = 40.0f; + bv->lateral_scale_bar.limits = (v2){.x = -1, .y = 1}; + bv->axial_scale_bar.limits = (v2){.x = 0, .y = 1}; + bv->lateral_scale_bar.scroll_scale = (v2){.x = -0.5e-3, .y = 0.5e-3}; + bv->axial_scale_bar.scroll_scale = (v2){.x = 0, .y = 1e-3}; + bv->lateral_scale_bar.zoom_starting_point = (v2){.x = F32_INFINITY, .y = F32_INFINITY}; + bv->axial_scale_bar.zoom_starting_point = (v2){.x = F32_INFINITY, .y = F32_INFINITY}; + + Variable *menu = result->u.view.menu; + /* TODO(rnp): push to head of list? */ + Variable *old_menu_first = menu->u.group.first; + Variable *old_menu_last = menu->u.group.last; + menu->u.group.first = menu->u.group.last = 0; + + #define X(id, text) add_button(ui, menu, arena, s8(text), UI_BID_ ##id, V_CLOSES_MENU, ui->small_font); + FRAME_VIEW_BUTTONS + #undef X + switch (type) { case FVT_LATEST: { #define X(_type, _id, pretty) s8(pretty), @@ -748,12 +776,8 @@ add_beamformer_frame_view(BeamformerUI *ui, Variable *parent, Arena *arena, bv->lateral_scale_bar_active = add_variable(ui, menu, arena, s8("Lateral Scale Bar"), V_INPUT|V_RADIO_BUTTON, VT_B32, ui->small_font); - bv->lateral_scale_bar.limits = (v2){.x = -1, .y = 1}; - bv->axial_scale_bar.limits = (v2){.x = 0, .y = 1}; - bv->lateral_scale_bar.scroll_scale = (v2){.x = -0.5e-3, .y = 0.5e-3}; - bv->axial_scale_bar.scroll_scale = (v2){.x = 0, .y = 1e-3}; - bv->lateral_scale_bar.zoom_starting_point = (v2){.x = F32_INFINITY, .y = F32_INFINITY}; - bv->axial_scale_bar.zoom_starting_point = (v2){.x = F32_INFINITY, .y = F32_INFINITY}; + menu->u.group.last->next = old_menu_first; + menu->u.group.last = old_menu_last; return result; } @@ -781,11 +805,50 @@ add_compute_stats_view(BeamformerUI *ui, Variable *parent, Arena *arena, Variabl return result; } -static void -ui_copy_frame(BeamformerUI *ui, Variable *button, RegionSplitDirection direction) +function Variable * +ui_split_region(BeamformerUI *ui, Variable *region, Variable *split_side, RegionSplitDirection direction) +{ + Variable *result = add_ui_split(ui, region, &ui->arena, s8(""), 0.5, direction, ui->small_font); + if (split_side == region->u.region_split.left) { + region->u.region_split.left = result; + } else { + region->u.region_split.right = result; + } + split_side->parent = result; + result->u.region_split.left = split_side; + return result; +} + +function void +ui_fill_live_frame_view(BeamformerUI *ui, BeamformerFrameView *bv) +{ + bv->lateral_scale_bar.min_value = &ui->params.output_min_coordinate.x; + bv->lateral_scale_bar.max_value = &ui->params.output_max_coordinate.x; + bv->axial_scale_bar.min_value = &ui->params.output_min_coordinate.z; + bv->axial_scale_bar.max_value = &ui->params.output_max_coordinate.z; + bv->axial_scale_bar.causes_compute = 1; + bv->lateral_scale_bar.causes_compute = 1; + bv->axial_scale_bar_active->u.b32 = 1; + bv->lateral_scale_bar_active->u.b32 = 1; + bv->ctx = ui->fsctx; +} + +function void +ui_add_live_frame_view(BeamformerUI *ui, Variable *view, RegionSplitDirection direction) +{ + Variable *region = view->parent; + ASSERT(region->type == VT_UI_REGION_SPLIT); + ASSERT(view->type == VT_UI_VIEW); + + Variable *new_region = ui_split_region(ui, region, view, direction); + new_region->u.region_split.right = add_beamformer_frame_view(ui, new_region, &ui->arena, FVT_LATEST, 1); + + ui_fill_live_frame_view(ui, new_region->u.region_split.right->u.group.first->u.generic); +} + +function void +ui_copy_frame(BeamformerUI *ui, Variable *view, RegionSplitDirection direction) { - Variable *menu = button->parent; - Variable *view = menu->parent; Variable *region = view->parent; ASSERT(region->type == VT_UI_REGION_SPLIT); ASSERT(view->type == VT_UI_VIEW); @@ -795,15 +858,7 @@ ui_copy_frame(BeamformerUI *ui, Variable *button, RegionSplitDirection direction if (!old->frame) return; - Variable *new_region = add_ui_split(ui, region, &ui->arena, s8(""), 0.5, direction, ui->small_font); - - if (view == region->u.region_split.left) { - region->u.region_split.left = new_region; - } else { - region->u.region_split.right = new_region; - } - view->parent = new_region; - new_region->u.region_split.left = view; + Variable *new_region = ui_split_region(ui, region, view, direction); new_region->u.region_split.right = add_beamformer_frame_view(ui, new_region, &ui->arena, FVT_COPY, 1); BeamformerFrameView *bv = new_region->u.region_split.right->u.group.first->u.generic; @@ -1162,7 +1217,6 @@ draw_title_bar(BeamformerUI *ui, Arena arena, Variable *ui_view, Rect r, v2 mous add_v2(menu.pos, (v2){.x = menu.size.w, .y = menu.size.h / 2}).rl, 4, colour); } - /* TODO(rnp): hover the title text rect and use it to access the global menu */ v2 title_pos = title_rect.pos; title_pos.y += 0.5 * TITLE_BAR_PAD; TextSpec text_spec = {.font = &ui->small_font, .flags = TF_LIMITED, @@ -2186,8 +2240,18 @@ ui_button_interaction(BeamformerUI *ui, Variable *button) { ASSERT(button->type == VT_UI_BUTTON); switch (button->u.button) { - case UI_BID_FV_COPY_HORIZONTAL: ui_copy_frame(ui, button, RSD_HORIZONTAL); break; - case UI_BID_FV_COPY_VERTICAL: ui_copy_frame(ui, button, RSD_VERTICAL); break; + case UI_BID_FV_COPY_HORIZONTAL: { + ui_copy_frame(ui, button->parent->parent, RSD_HORIZONTAL); + } break; + case UI_BID_FV_COPY_VERTICAL: { + ui_copy_frame(ui, button->parent->parent, RSD_VERTICAL); + } break; + case UI_BID_GM_OPEN_LIVE_VIEW_RIGHT: { + ui_add_live_frame_view(ui, button->parent->parent, RSD_HORIZONTAL); + } break; + case UI_BID_GM_OPEN_LIVE_VIEW_BELOW: { + ui_add_live_frame_view(ui, button->parent->parent, RSD_VERTICAL); + } break; case UI_BID_CLOSE_VIEW: { Variable *view = button->parent; Variable *region = view->parent; @@ -2404,8 +2468,11 @@ ui_init(BeamformerCtx *ctx, Arena store) UnloadRenderTexture(view->rendered_view); } + DEBUG_DECL(u8 *arena_start = store.beg); + ui = ctx->ui = push_struct(&store, typeof(*ui)); ui->os = &ctx->os; + ui->fsctx = &ctx->fsctx; ui->arena = store; /* TODO: build these into the binary */ @@ -2414,22 +2481,13 @@ ui_init(BeamformerCtx *ctx, Arena store) ui->small_font = LoadFontEx("assets/IBMPlexSans-Bold.ttf", 20, 0, 0); ui->scratch_variable = ui->scratch_variables + 0; - Variable *split = ui->regions = add_ui_split(ui, 0, &ui->arena, s8("UI Root"), 0.4, - RSD_HORIZONTAL, ui->font); - split->u.region_split.left = add_ui_split(ui, split, &ui->arena, s8(""), 0.475, - RSD_VERTICAL, ui->font); - split->u.region_split.right = add_beamformer_frame_view(ui, split, &ui->arena, FVT_LATEST, 0); + Variable *split = ui->regions = add_ui_split(ui, 0, &ui->arena, s8("UI Root"), 0.4, + RSD_HORIZONTAL, ui->font); + split->u.region_split.left = add_ui_split(ui, split, &ui->arena, s8(""), 0.475, + RSD_VERTICAL, ui->font); + split->u.region_split.right = add_beamformer_frame_view(ui, split, &ui->arena, FVT_LATEST, 0); - BeamformerFrameView *bv = split->u.region_split.right->u.group.first->u.generic; - bv->lateral_scale_bar.min_value = &ui->params.output_min_coordinate.x; - bv->lateral_scale_bar.max_value = &ui->params.output_max_coordinate.x; - bv->axial_scale_bar.min_value = &ui->params.output_min_coordinate.z; - bv->axial_scale_bar.max_value = &ui->params.output_max_coordinate.z; - bv->axial_scale_bar.causes_compute = 1; - bv->lateral_scale_bar.causes_compute = 1; - bv->axial_scale_bar_active->u.b32 = 1; - bv->lateral_scale_bar_active->u.b32 = 1; - bv->ctx = &ctx->fsctx; + ui_fill_live_frame_view(ui, split->u.region_split.right->u.group.first->u.generic); split = split->u.region_split.left; split->u.region_split.left = add_beamformer_parameters_view(split, ctx); @@ -2446,6 +2504,9 @@ ui_init(BeamformerCtx *ctx, Arena store) compute_stats->stats = &ui->latest_compute_stats; ctx->ui_read_params = 1; + + /* NOTE(rnp): shrink variable size once this fires */ + ASSERT(ui->arena.beg - arena_start < KB(64)); } static void