ogl_beamforming

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

Commit: bda26e35280d9c059a5f55cecc5600a37faf0862
Parent: 3bbcadfffdeaf85a29ca7244cdba4a154c8997f1
Author: Randy Palamar
Date:   Tue, 15 Apr 2025 20:12:16 -0600

ui: convert scale bars into variables, remove hot_type and scratch_variables

Diffstat:
Mui.c | 188++++++++++++++++++++++++++++++++++---------------------------------------------
1 file changed, 80 insertions(+), 108 deletions(-)

diff --git a/ui.c b/ui.c @@ -13,7 +13,8 @@ * hot = next_hot .... * * hot->hover_t += hover_speed * dt_for_frame - * [ ]: is IT_SCALE_BAR even necessary? + * [ ]: refactor: a number of variables (scroll bar, text, menu, display) need to know + * their region for interaction, store it, and remove from all of these * [ ]: scroll bar for views that don't have enough space * [ ]: compute times through same path as parameter list ? * [ ]: allow views to collapse to just their title bar @@ -70,6 +71,11 @@ #define LISTING_LINE_PAD 6.0f #define TITLE_BAR_PAD 6.0f +typedef struct v2_sll { + struct v2_sll *next; + v2 v; +} v2_sll; + typedef struct { u8 buf[64]; i32 buf_len; @@ -90,7 +96,6 @@ typedef enum { IT_NOP, IT_DRAG, IT_MENU, - IT_SCALE_BAR, IT_SCROLL, IT_SET, IT_TEXT, @@ -108,10 +113,19 @@ typedef struct { RulerState state; } Ruler; -typedef struct v2_sll { - struct v2_sll *next; - v2 v; -} v2_sll; +typedef enum { + SB_LATERAL, + SB_AXIAL, +} ScaleBarDirection; + +typedef struct { + f32 *min_value, *max_value; + v2_sll *savepoint_stack; + v2 zoom_starting_point; + v2 screen_offset; + v2 screen_space_to_value; + v2 scroll_scale; +} ScaleBar; typedef struct { f32 val, scale; } scaled_f32; @@ -249,6 +263,7 @@ struct Variable { ComputeProgressBar compute_progress_bar; ComputeStatsView compute_stats_view; RegionSplit region_split; + ScaleBar scale_bar; UIButtonID button; UIView view; VariableCycler cycler; @@ -269,31 +284,14 @@ struct Variable { }; typedef enum { - SB_LATERAL, - SB_AXIAL, -} ScaleBarDirection; - -typedef struct { - f32 *min_value, *max_value; - v2_sll *savepoint_stack; - v2 zoom_starting_point; - v2 screen_offset; - v2 screen_space_to_value; - v2 limits; - v2 scroll_scale; - f32 hover_t; - b32 causes_compute; -} ScaleBar; - -typedef enum { FVT_LATEST, FVT_INDEXED, FVT_COPY, } BeamformerFrameViewType; typedef struct BeamformerFrameView { - ScaleBar lateral_scale_bar; - ScaleBar axial_scale_bar; + Variable lateral_scale_bar; + Variable axial_scale_bar; /* NOTE(rnp): these are pointers because they are added to the menu and will * be put onto the freelist if the view is closed */ @@ -328,7 +326,6 @@ typedef struct BeamformerFrameView { typedef struct { Variable *hot; Variable *active; - InteractionType hot_type; InteractionType type; } InteractionState; @@ -340,8 +337,6 @@ struct BeamformerUI { Variable *regions; Variable *variable_freelist; - Variable *scratch_variable; - Variable scratch_variables[2]; BeamformerFrameView *views; BeamformerFrameView *view_freelist; @@ -772,12 +767,14 @@ add_beamformer_frame_view(BeamformerUI *ui, Variable *parent, Arena *arena, bv->gamma.u.scaled_f32.val = 1.0f; bv->gamma.u.scaled_f32.scale = 0.05f; - 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}; + fill_variable(&bv->lateral_scale_bar, var, s8(""), V_INPUT, VT_SCALE_BAR, ui->small_font); + fill_variable(&bv->axial_scale_bar, var, s8(""), V_INPUT, VT_SCALE_BAR, ui->small_font); + ScaleBar *lateral = &bv->lateral_scale_bar.u.scale_bar; + ScaleBar *axial = &bv->axial_scale_bar.u.scale_bar; + lateral->scroll_scale = (v2){.x = -0.5e-3, .y = 0.5e-3}; + axial->scroll_scale = (v2){.x = 0, .y = 1e-3}; + lateral->zoom_starting_point = (v2){.x = F32_INFINITY, .y = F32_INFINITY}; + axial->zoom_starting_point = (v2){.x = F32_INFINITY, .y = F32_INFINITY}; Variable *menu = result->u.view.menu; /* TODO(rnp): push to head of list? */ @@ -859,15 +856,17 @@ ui_split_region(BeamformerUI *ui, Variable *region, Variable *split_side, Region 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; + ScaleBar *lateral = &bv->lateral_scale_bar.u.scale_bar; + ScaleBar *axial = &bv->axial_scale_bar.u.scale_bar; + lateral->min_value = &ui->params.output_min_coordinate.x; + lateral->max_value = &ui->params.output_max_coordinate.x; + axial->min_value = &ui->params.output_min_coordinate.z; + axial->max_value = &ui->params.output_max_coordinate.z; + bv->axial_scale_bar_active->u.b32 = 1; + bv->lateral_scale_bar_active->u.b32 = 1; bv->ctx = ui->frame_view_render_context; + bv->axial_scale_bar.flags |= V_CAUSES_COMPUTE; + bv->lateral_scale_bar.flags |= V_CAUSES_COMPUTE; } function void @@ -899,10 +898,12 @@ ui_copy_frame(BeamformerUI *ui, Variable *view, RegionSplitDirection 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; - bv->lateral_scale_bar.min_value = &bv->min_coordinate.x; - bv->lateral_scale_bar.max_value = &bv->max_coordinate.x; - bv->axial_scale_bar.min_value = &bv->min_coordinate.z; - bv->axial_scale_bar.max_value = &bv->max_coordinate.z; + ScaleBar *lateral = &bv->lateral_scale_bar.u.scale_bar; + ScaleBar *axial = &bv->axial_scale_bar.u.scale_bar; + lateral->min_value = &bv->min_coordinate.x; + lateral->max_value = &bv->max_coordinate.x; + axial->min_value = &bv->min_coordinate.z; + axial->max_value = &bv->max_coordinate.z; bv->ctx = old->ctx; bv->needs_update = 1; @@ -1220,10 +1221,7 @@ hover_var(BeamformerUI *ui, v2 mouse, Rect rect, Variable *var) b32 result = 0; if (ui->interaction.type != IT_DRAG || ui->interaction.active == var) { result = hover_rect(mouse, rect, &var->hover_t); - if (result) { - ui->interaction.hot_type = IT_NONE; - ui->interaction.hot = var; - } + if (result) ui->interaction.hot = var; } return result; } @@ -1335,11 +1333,12 @@ draw_ruler(BeamformerUI *ui, Stream *buf, v2 start_point, v2 end_point, rlPopMatrix(); } -static void -do_scale_bar(BeamformerUI *ui, Stream *buf, ScaleBar *sb, ScaleBarDirection direction, +function void +do_scale_bar(BeamformerUI *ui, Stream *buf, Variable *scale_bar, ScaleBarDirection direction, v2 mouse, Rect draw_rect, f32 start_value, f32 end_value, s8 suffix) { - InteractionState *is = &ui->interaction; + ASSERT(scale_bar->type == VT_SCALE_BAR); + ScaleBar *sb = &scale_bar->u.scale_bar; v2 txt_s = measure_text(ui->small_font, s8("-288.8 mm")); @@ -1371,19 +1370,12 @@ do_scale_bar(BeamformerUI *ui, Stream *buf, ScaleBar *sb, ScaleBarDirection dire sb->screen_space_to_value = (v2){.x = (*sb->max_value - *sb->min_value) / tick_rect.size.x}; } - if (hover_rect(mouse, tick_rect, &sb->hover_t)) { - Variable *var = zero_struct(ui->scratch_variable); - var->u.generic = sb; - var->type = VT_SCALE_BAR; - is->hot_type = IT_SCALE_BAR; - is->hot = var; - - marker_count = 2; - } + if (hover_var(ui, mouse, tick_rect, scale_bar)) + marker_count = 2; draw_ruler(ui, buf, start_pos, end_pos, start_value, end_value, markers, marker_count, tick_count, suffix, colour_from_normalized(FG_COLOUR), - colour_from_normalized(lerp_v4(FG_COLOUR, HOVERED_COLOUR, sb->hover_t))); + colour_from_normalized(lerp_v4(FG_COLOUR, HOVERED_COLOUR, scale_bar->hover_t))); } static v2 @@ -1515,8 +1507,8 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa Stream buf = arena_stream(&tmp); do_scale_bar(ui, &buf, &view->lateral_scale_bar, SB_LATERAL, mouse, (Rect){.pos = start_pos, .size = vr.size}, - *view->lateral_scale_bar.min_value * 1e3, - *view->lateral_scale_bar.max_value * 1e3, s8(" mm")); + *view->lateral_scale_bar.u.scale_bar.min_value * 1e3, + *view->lateral_scale_bar.u.scale_bar.max_value * 1e3, s8(" mm")); } start_pos = vr.pos; @@ -1527,8 +1519,8 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa Stream buf = arena_stream(&tmp); do_scale_bar(ui, &buf, &view->axial_scale_bar, SB_AXIAL, mouse, (Rect){.pos = start_pos, .size = vr.size}, - *view->axial_scale_bar.max_value * 1e3, - *view->axial_scale_bar.min_value * 1e3, s8(" mm")); + *view->axial_scale_bar.u.scale_bar.max_value * 1e3, + *view->axial_scale_bar.u.scale_bar.min_value * 1e3, s8(" mm")); } v2 pixels_to_mm; @@ -2215,11 +2207,8 @@ update_text_input(InputState *is, Variable *var) } function void -scale_bar_interaction(BeamformerCtx *ctx, v2 mouse) +scale_bar_interaction(BeamformerUI *ui, ScaleBar *sb, v2 mouse) { - BeamformerUI *ui = ctx->ui; - InteractionState *is = &ui->interaction; - ScaleBar *sb = is->active->u.generic; b32 mouse_left_pressed = IsMouseButtonPressed(MOUSE_BUTTON_LEFT); b32 mouse_right_pressed = IsMouseButtonPressed(MOUSE_BUTTON_RIGHT); f32 mouse_wheel = GetMouseWheelMoveV().y; @@ -2243,20 +2232,16 @@ scale_bar_interaction(BeamformerCtx *ctx, v2 mouse) savepoint->v.y = *sb->max_value; SLLPush(savepoint, sb->savepoint_stack); - *sb->min_value = MAX(min, sb->limits.x); - *sb->max_value = MIN(max, sb->limits.y); + *sb->min_value = min; + *sb->max_value = max; sb->zoom_starting_point = (v2){.x = F32_INFINITY, .y = F32_INFINITY}; - if (sb->causes_compute) - ui->flush_params = 1; } } if (mouse_right_pressed) { v2_sll *savepoint = sb->savepoint_stack; if (savepoint) { - if (sb->causes_compute) - ui->flush_params = 1; *sb->min_value = savepoint->v.x; *sb->max_value = savepoint->v.y; sb->savepoint_stack = SLLPush(savepoint, ui->scale_bar_savepoint_freelist); @@ -2267,10 +2252,6 @@ scale_bar_interaction(BeamformerCtx *ctx, v2 mouse) if (mouse_wheel) { *sb->min_value += mouse_wheel * sb->scroll_scale.x; *sb->max_value += mouse_wheel * sb->scroll_scale.y; - *sb->min_value = MAX(sb->limits.x, *sb->min_value); - *sb->max_value = MIN(sb->limits.y, *sb->max_value); - if (sb->causes_compute) - ui->flush_params = 1; } } @@ -2319,15 +2300,14 @@ static void ui_begin_interact(BeamformerUI *ui, BeamformerInput *input, b32 scroll, b32 mouse_left_pressed) { InteractionState *is = &ui->interaction; - if (is->hot_type != IT_NONE) { - is->type = is->hot_type; - } else if (is->hot) { + if (is->hot) { switch (is->hot->type) { case VT_NULL: is->type = IT_NOP; break; case VT_B32: is->type = IT_SET; break; case VT_UI_REGION_SPLIT: { is->type = IT_DRAG; } break; case VT_UI_VIEW: { if (scroll) is->type = IT_SCROLL; } break; case VT_UI_BUTTON: { ui_button_interaction(ui, is->hot); } break; + case VT_SCALE_BAR: { is->type = IT_SET; } break; case VT_CYCLER: { if (scroll) is->type = IT_SCROLL; else is->type = IT_SET; @@ -2371,19 +2351,13 @@ ui_begin_interact(BeamformerUI *ui, BeamformerInput *input, b32 scroll, b32 mous default: INVALID_CODE_PATH; } } - if (is->type != IT_NONE) { + if (is->type != IT_NONE) is->active = is->hot; - if ((iptr)is->hot == (iptr)ui->scratch_variables) - ui->scratch_variable = ui->scratch_variables + 1; - else - ui->scratch_variable = ui->scratch_variables + 0; - } } -static void -ui_end_interact(BeamformerCtx *ctx, v2 mouse) +function void +ui_end_interact(BeamformerUI *ui, v2 mouse) { - BeamformerUI *ui = ctx->ui; InteractionState *is = &ui->interaction; switch (is->type) { case IT_NOP: break; @@ -2394,6 +2368,9 @@ ui_end_interact(BeamformerCtx *ctx, v2 mouse) } break; case VT_CYCLER: { is->active->u.cycler.state++; } break; case VT_B32: { is->active->u.b32 = !is->active->u.b32; } break; + case VT_SCALE_BAR: { + scale_bar_interaction(ui, &is->hot->u.scale_bar, mouse); + } break; case VT_BEAMFORMER_VARIABLE: { ASSERT(is->active->u.beamformer_variable.store_type == VT_B32); b32 *val = is->active->u.beamformer_variable.store; @@ -2405,7 +2382,6 @@ ui_end_interact(BeamformerCtx *ctx, v2 mouse) case IT_SCROLL: scroll_interaction(is->active, GetMouseWheelMoveV().y); break; case IT_TEXT: end_text_input(&ui->text_input_state, is->active); break; case IT_MENU: break; - case IT_SCALE_BAR: break; case IT_DRAG: break; default: INVALID_CODE_PATH; } @@ -2440,35 +2416,34 @@ ui_end_interact(BeamformerCtx *ctx, v2 mouse) } } -static void -ui_interact(BeamformerCtx *ctx, BeamformerInput *input) +function void +ui_interact(BeamformerUI *ui, BeamformerInput *input, uv2 window_size) { - BeamformerUI *ui = ctx->ui; InteractionState *is = &ui->interaction; b32 mouse_left_pressed = IsMouseButtonPressed(MOUSE_BUTTON_LEFT); b32 mouse_right_pressed = IsMouseButtonPressed(MOUSE_BUTTON_RIGHT); b32 wheel_moved = GetMouseWheelMoveV().y != 0; if (mouse_right_pressed || mouse_left_pressed || wheel_moved) { if (is->type != IT_NONE) - ui_end_interact(ctx, input->mouse); + ui_end_interact(ui, input->mouse); ui_begin_interact(ui, input, wheel_moved, mouse_left_pressed); } if (IsKeyPressed(KEY_ENTER) && is->type == IT_TEXT) - ui_end_interact(ctx, input->mouse); + ui_end_interact(ui, input->mouse); switch (is->type) { case IT_NONE: break; case IT_NOP: break; case IT_MENU: break; - case IT_SCROLL: ui_end_interact(ctx, input->mouse); break; - case IT_SET: ui_end_interact(ctx, input->mouse); break; + case IT_SCROLL: ui_end_interact(ui, input->mouse); break; + case IT_SET: ui_end_interact(ui, input->mouse); break; case IT_TEXT: update_text_input(&ui->text_input_state, is->active); break; case IT_DRAG: { if (!IsMouseButtonDown(MOUSE_BUTTON_LEFT) && !IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) { - ui_end_interact(ctx, input->mouse); + ui_end_interact(ui, input->mouse); } else { - v2 ws = (v2){.w = ctx->window_size.w, .h = ctx->window_size.h}; + v2 ws = {.w = window_size.w, .h = window_size.h}; v2 dMouse = sub_v2(input->mouse, input->last_mouse); dMouse = mul_v2(dMouse, (v2){.x = 1.0f / ws.w, .y = 1.0f / ws.h}); @@ -2492,11 +2467,9 @@ ui_interact(BeamformerCtx *ctx, BeamformerInput *input) } } } break; - case IT_SCALE_BAR: scale_bar_interaction(ctx, input->mouse); break; } - is->hot_type = IT_NONE; - is->hot = 0; + is->hot = 0; } static void @@ -2534,7 +2507,6 @@ ui_init(BeamformerCtx *ctx, Arena store) ui->font = LoadFontEx("assets/IBMPlexSans-Bold.ttf", 28, 0, 0); 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, @@ -2591,7 +2563,7 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformFrame *frame_to_draw /* NOTE: process interactions first because the user interacted with * the ui that was presented last frame */ - ui_interact(ctx, input); + ui_interact(ui, input, ctx->window_size); if (ui->flush_params) { validate_ui_parameters(&ui->params);