ogl_beamforming

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

Commit: 223e791a6234b6113ac20d3d3c7e837ce29e14ec
Parent: de5d92ffcbd2af099955a08ba6b6dea31df670dc
Author: Randy Palamar
Date:   Wed,  8 Jan 2025 22:12:24 -0700

ui: pass scale bars through the interaction system

Diffstat:
Mbeamformer.h | 25+++++++++++++++++++++++++
Mui.c | 95++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
2 files changed, 98 insertions(+), 22 deletions(-)

diff --git a/beamformer.h b/beamformer.h @@ -30,6 +30,9 @@ #define RECT_BTN_ROUNDNESS 0.3f #define RECT_BTN_BORDER_WIDTH 6.0f +/* TODO: multiple views */ +#define MAX_DISPLAYS 1 + enum program_flags { SHOULD_EXIT = 1 << 0, RELOAD_SHADERS = 1 << 1, @@ -74,6 +77,11 @@ enum ruler_state { RS_HOLD, }; +enum scale_bar_directions { + SB_LATERAL, + SB_AXIAL, +}; + typedef struct { Variable hot; Variable next_hot; @@ -82,6 +90,20 @@ typedef struct { u32 state; } InteractionState; +typedef struct v2_SLL { + struct v2_SLL *next; + v2 v; +} v2_SLL; + +typedef struct { + f32 *min_value, *max_value; + v2_SLL *save_point_stack; + f32 zoom_starting_point; + f32 hover_t; + f32 pixels_to_value; + b32 scroll_both; +} ScaleBar; + typedef struct { TempArena frame_temporary_arena; Arena arena_for_frame; @@ -94,6 +116,9 @@ typedef struct { InteractionState interaction; InputState text_input_state; + ScaleBar scale_bars[MAX_DISPLAYS][2]; + v2_SLL *scale_bar_savepoint_freelist; + v2 ruler_start_p; v2 ruler_stop_p; u32 ruler_state; diff --git a/ui.c b/ui.c @@ -150,14 +150,12 @@ draw_ruler(BeamformerUI *ui, Stream *buf, v2 start_point, v2 end_point, rlPopMatrix(); } -/* TODO: drop these when the below is fully making use of the interaction code */ -static void ui_start_compute(BeamformerCtx *); - static void draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect) { BeamformerUI *ui = ctx->ui; BeamformerParameters *bp = &ctx->params->raw; + InteractionState *is = &ui->interaction; Stream buf = arena_stream(&a); Texture *output = &ctx->fsctx.output.texture; @@ -195,8 +193,6 @@ draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect) NPatchInfo tex_np = { tex_r, 0, 0, 0, 0, NPATCH_NINE_PATCH }; DrawTextureNPatch(*output, tex_np, vr.rl, (Vector2){0}, 0, WHITE); - static f32 txt_colour_t[2]; - u32 line_count = vr.size.x / (1.5 * ui->small_font_height); v2 start_pos = vr.pos; start_pos.y += vr.size.y; @@ -207,13 +203,14 @@ draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect) Rect tick_rect = {.pos = start_pos, .size = vr.size}; tick_rect.size.y = RULER_TEXT_PAD + RULER_TICK_LENGTH + txt_s.x; - /* TODO: pass this through the interaction system */ - if (hover_text(mouse, tick_rect, txt_colour_t + 0, 1)) { - f32 size_delta = GetMouseWheelMoveV().y * 0.5e-3; - bp->output_min_coordinate.x -= size_delta; - bp->output_max_coordinate.x += size_delta; - if (size_delta) - ui_start_compute(ctx); + ScaleBar *sb = ui->scale_bars[0] + SB_LATERAL; + sb->scroll_both = 1; + if (hover_text(mouse, tick_rect, &sb->hover_t, 1)) { + is->hot_state = IS_SCALE_BAR; + is->hot.store = sb; + is->hot.f32_limits = (v2){.x = -1, .y = 1}; + is->hot.flags = V_CAUSES_COMPUTE; + is->hot.scroll_scale = 0.5e-3; } f32 mm = bp->output_min_coordinate.x * 1e3; @@ -221,7 +218,7 @@ draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect) draw_ruler(ui, &buf, start_pos, end_pos, mm, mm_end, line_count, s8(" mm"), colour_from_normalized(FG_COLOUR), - colour_from_normalized(lerp_v4(FG_COLOUR, HOVERED_COLOUR, txt_colour_t[0]))); + colour_from_normalized(lerp_v4(FG_COLOUR, HOVERED_COLOUR, sb->hover_t))); line_count = vr.size.y / (1.5 * ui->small_font_height); start_pos = vr.pos; @@ -233,12 +230,14 @@ draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect) tick_rect = (Rect){.pos = start_pos, .size = vr.size}; tick_rect.size.x = RULER_TEXT_PAD + RULER_TICK_LENGTH + txt_s.x; - /* TODO: pass this through the interaction system */ - if (hover_text(mouse, tick_rect, txt_colour_t + 1, 1)) { - f32 size_delta = GetMouseWheelMoveV().y * 1e-3; - bp->output_max_coordinate.z += size_delta; - if (size_delta) - ui_start_compute(ctx); + sb = ui->scale_bars[0] + SB_AXIAL; + sb->scroll_both = 0; + if (hover_text(mouse, tick_rect, &sb->hover_t, 1)) { + is->hot_state = IS_SCALE_BAR; + is->hot.store = sb; + is->hot.f32_limits = (v2){.x = 0, .y = 1}; + is->hot.flags = V_CAUSES_COMPUTE; + is->hot.scroll_scale = 1e-3; } mm = bp->output_min_coordinate.z * 1e3; @@ -246,10 +245,9 @@ draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect) draw_ruler(ui, &buf, end_pos, start_pos, mm_end, mm, line_count, s8(" mm"), colour_from_normalized(FG_COLOUR), - colour_from_normalized(lerp_v4(FG_COLOUR, HOVERED_COLOUR, txt_colour_t[1]))); + colour_from_normalized(lerp_v4(FG_COLOUR, HOVERED_COLOUR, sb->hover_t))); if (CheckCollisionPointRec(mouse.rl, vr.rl)) { - InteractionState *is = &ui->interaction; is->hot_state = IS_DISPLAY; is->hot.store = &ctx->fsctx.threshold; is->hot.type = VT_F32; @@ -861,6 +859,48 @@ display_interaction(BeamformerUI *ui, v2 mouse) } static void +scale_bar_interaction_end(BeamformerUI *ui) +{ + InteractionState *is = &ui->interaction; + ScaleBar *sb = is->active.store; + b32 is_hot = is->hot_state == IS_SCALE_BAR; + f32 mouse_wheel = GetMouseWheelMoveV().y * is->active.scroll_scale; + + /* TODO: this should only happen on right click */ + sb->zoom_starting_point = F32_INFINITY; + + /* TODO: if right click load saved state */ + /* TODO: if left click do nothing */ + + if (is_hot && mouse_wheel) { + v2 limits = is->active.f32_limits; + *sb->min_value -= mouse_wheel * sb->scroll_both; + *sb->max_value += mouse_wheel; + *sb->min_value = MAX(limits.x, *sb->min_value); + *sb->max_value = MIN(limits.y, *sb->max_value); + } +} + +static void +scale_bar_interaction(BeamformerCtx *ctx, v2 mouse) +{ + BeamformerUI *ui = ctx->ui; + InteractionState *is = &ui->interaction; + ScaleBar *sb = is->active.store; + b32 is_hot = is->hot_state == IS_SCALE_BAR; + b32 mouse_left_pressed = IsMouseButtonPressed(MOUSE_BUTTON_LEFT); + + /* TODO: convert mouse to coord_space */ + if (is_hot && mouse_left_pressed) { + if (sb->zoom_starting_point == F32_INFINITY) { + /* TODO: push new starting point */ + } else { + /* TODO: push new savepoint and set values */ + } + } +} + +static void ui_begin_interact(BeamformerUI *ui, BeamformerInput *input, b32 scroll, b32 mouse_left_pressed) { InteractionState *is = &ui->interaction; @@ -923,7 +963,8 @@ ui_end_interact(BeamformerCtx *ctx, v2 mouse) } break; } } break; - case IS_TEXT: end_text_input(&ui->text_input_state, &is->active); break; + case IS_SCALE_BAR: scale_bar_interaction_end(ui); break; + case IS_TEXT: end_text_input(&ui->text_input_state, &is->active); break; } if (is->active.flags & V_CAUSES_COMPUTE) @@ -966,6 +1007,7 @@ ui_interact(BeamformerCtx *ctx, BeamformerInput *input) } } } break; + case IS_SCALE_BAR: scale_bar_interaction(ctx, input->mouse); break; } is->hot_state = IS_NONE; @@ -999,6 +1041,15 @@ ui_init(BeamformerCtx *ctx, Arena store) ui->font_height = measure_text(ui->font, s8("8\\W")).h; ui->small_font_height = measure_text(ui->small_font, s8("8\\W")).h; + + /* TODO: multiple views */ + ui->scale_bars[0][SB_LATERAL].min_value = &ctx->params->raw.output_min_coordinate.x; + ui->scale_bars[0][SB_LATERAL].max_value = &ctx->params->raw.output_max_coordinate.x; + ui->scale_bars[0][SB_AXIAL].min_value = &ctx->params->raw.output_min_coordinate.z; + ui->scale_bars[0][SB_AXIAL].max_value = &ctx->params->raw.output_max_coordinate.z; + + ui->scale_bars[0][SB_LATERAL].zoom_starting_point = F32_INFINITY; + ui->scale_bars[0][SB_AXIAL].zoom_starting_point = F32_INFINITY; } static void