ogl_beamforming

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

Commit: 4745b839c6ea4cbcbbe5d2c32af65e294c1442b5
Parent: bef621fa14ac73e312ee176bbad54ffb854475f7
Author: Randy Palamar
Date:   Tue, 26 Nov 2024 16:44:57 -0700

add ruler display interaction

Diffstat:
Mbeamformer.h | 2+-
Mmain_generic.c | 2++
Mui.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mutil.c | 31+++++++++++++++++++++++++++++++
Mutil.h | 5++++-
5 files changed, 98 insertions(+), 38 deletions(-)

diff --git a/beamformer.h b/beamformer.h @@ -69,7 +69,7 @@ typedef struct { Variable active; u32 hot_state; u32 state; - b32 var_changed_last_frame; + v2 last_mouse_click_p; } InteractionState; typedef struct { diff --git a/main_generic.c b/main_generic.c @@ -62,6 +62,8 @@ main(void) reload_shaders(&ctx, temp_memory); } + input.last_mouse = input.mouse; + input.mouse.rl = GetMousePosition(); input.pipe_data_available = os_poll_pipe(data_pipe); beamformer_frame_step(&ctx, &temp_memory, &input); diff --git a/ui.c b/ui.c @@ -143,7 +143,8 @@ do_text_input_listing(s8 prefix, s8 suffix, Variable var, BeamformerUI *ui, Rect v2 mouse, f32 *hover_t) { InputState *is = &ui->text_input_state; - b32 text_input_active = ui->interaction.active.store == var.store; + b32 text_input_active = (ui->interaction.state == IS_TEXT) && + (var.store == ui->interaction.active.store); Arena arena = ui->arena_for_frame; Stream buf = arena_stream(&arena); @@ -678,6 +679,8 @@ ui_end_interact(BeamformerCtx *ctx, BeamformerUI *ui) } } break; case IS_DISPLAY: + is->last_mouse_click_p = (v2){0}; + /* FALLTHROUGH */ case IS_SCROLL: { f32 delta = GetMouseWheelMove() * is->active.scroll_scale; switch (is->active.type) { @@ -714,33 +717,29 @@ ui_end_interact(BeamformerCtx *ctx, BeamformerUI *ui) static void ui_interact(BeamformerCtx *ctx, BeamformerInput *input) { - BeamformerUI *ui = ctx->ui; - InteractionState *is = &ui->interaction; - if (is->state != IS_NONE) { - if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { + BeamformerUI *ui = ctx->ui; + InteractionState *is = &ui->interaction; + b32 mouse_left_pressed = IsMouseButtonPressed(MOUSE_BUTTON_LEFT); + b32 wheel_moved = GetMouseWheelMove(); + if (mouse_left_pressed || wheel_moved) { + if (is->state != IS_NONE) ui_end_interact(ctx, ui); - ui_begin_interact(ui, input, 0); - } + ui_begin_interact(ui, input, wheel_moved); + } - if (GetMouseWheelMove()) { - ui_end_interact(ctx, ui); - ui_begin_interact(ui, input, 1); - } + if (IsKeyPressed(KEY_ENTER) && is->state == IS_TEXT) + ui_end_interact(ctx, ui); - if (IsKeyPressed(KEY_ENTER)) + switch (is->state) { + case IS_DISPLAY: { + b32 should_end = wheel_moved || IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) || + (is->active.store != is->hot.store); + if (should_end) { ui_end_interact(ctx, ui); - - } else { - if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { - ui_begin_interact(ui, input, 0); + } else if (mouse_left_pressed) { + is->last_mouse_click_p = input->mouse; } - if (GetMouseWheelMove()) { - ui_begin_interact(ui, input, 1); - } - } - - switch (is->state) { - case IS_DISPLAY: ui_end_interact(ctx, ui); break; + } break; case IS_SCROLL: ui_end_interact(ctx, ui); break; case IS_SET: ui_end_interact(ctx, ui); break; case IS_TEXT: update_text_input(&ui->text_input_state); break; @@ -796,18 +795,20 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input) .y = bp->output_max_coordinate.z - bp->output_min_coordinate.z, }; - v2 mouse = { .rl = GetMousePosition() }; + v2 mouse = input->mouse; Rect wr = {.size = {.w = (f32)ctx->window_size.w, .h = (f32)ctx->window_size.h}}; Rect lr = wr, rr = wr; lr.size.w = INFO_COLUMN_WIDTH; rr.size.w = wr.size.w - lr.size.w; rr.pos.x = lr.pos.x + lr.size.w; + Rect vr = INVERTED_INFINITY_RECT; if (output_dim.x > 1e-6 && output_dim.y > 1e-6) { Stream buf = stream_alloc(&ui->arena_for_frame, 64); stream_append_f64(&buf, -188.8f, 10); stream_append_s8(&buf, s8(" mm")); v2 txt_s = measure_text(ui->small_font, stream_to_s8(&buf)); + buf.widx = 0; rr.pos.x += 0.02 * rr.size.w; rr.pos.y += 0.02 * rr.size.h; @@ -817,7 +818,7 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input) f32 tick_len = 20; f32 pad = 1.2 * txt_s.x + tick_len; - Rect vr = rr; + vr = rr; vr.pos.x += 0.5 * txt_s.y; vr.pos.y += 0.5 * txt_s.y; vr.size.h = rr.size.h - pad; @@ -836,17 +837,6 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input) NPatchInfo tex_np = { tex_r, 0, 0, 0, 0, NPATCH_NINE_PATCH }; DrawTextureNPatch(*output, tex_np, vr.rl, (Vector2){0}, 0, WHITE); - 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; - is->hot.f32_limits = (v2){.y = 240}; - is->hot.flags = V_GEN_MIPMAPS; - is->hot.display_scale = 1; - is->hot.scroll_scale = 1; - } - static f32 txt_colour_t[2]; for (u32 i = 0; i < 2; i++) { u32 line_count = vr.size.E[i] / (1.5 * txt_s.h); @@ -906,5 +896,39 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input) draw_settings_ui(ctx, lr, mouse); draw_debug_overlay(ctx, ui->arena_for_frame, lr); + + 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; + is->hot.f32_limits = (v2){.y = 240}; + is->hot.flags = V_GEN_MIPMAPS; + is->hot.display_scale = 1; + is->hot.scroll_scale = 1; + + /* NOTE: check and draw Ruler */ + if (CheckCollisionPointRec(is->last_mouse_click_p.rl, vr.rl)) { + Stream buf = arena_stream(&ui->arena_for_frame); + + Color colour = colour_from_normalized(HOVERED_COLOUR); + DrawCircleV(is->last_mouse_click_p.rl, 3, colour); + DrawLineEx(mouse.rl, is->last_mouse_click_p.rl, 2, colour); + v2 pixels_to_mm = output_dim; + pixels_to_mm.x /= vr.size.x * 1e-3; + pixels_to_mm.y /= vr.size.y * 1e-3; + + v2 pixel_delta = sub_v2(is->last_mouse_click_p, mouse); + v2 mm_delta = mul_v2(pixels_to_mm, pixel_delta); + + stream_append_f64(&buf, magnitude_v2(mm_delta), 100); + stream_append_s8(&buf, s8(" mm")); + v2 txt_p = is->last_mouse_click_p; + v2 txt_s = measure_text(ui->small_font, stream_to_s8(&buf)); + if (pixel_delta.y < 0) txt_p.y -= txt_s.y; + if (pixel_delta.x < 0) txt_p.x -= txt_s.x; + draw_text(ui->small_font, stream_to_s8(&buf), txt_p, 0, colour); + } + } EndDrawing(); } diff --git a/util.c b/util.c @@ -325,6 +325,37 @@ normalize_v3(v3 a) return result; } +static v2 +sub_v2(v2 a, v2 b) +{ + v2 result = { + .x = a.x - b.x, + .y = a.y - b.y, + }; + return result; +} + +static v2 +mul_v2(v2 a, v2 b) +{ + v2 result = { + .x = a.x * b.x, + .y = a.y * b.y, + }; + return result; +} + + +static f32 +magnitude_v2(v2 a) +{ + v4 result; + __m128 av = _mm_set_ps(0, 0, a.x, a.y); + av = _mm_mul_ps(av, av); + _mm_store_ps(result.E, _mm_sqrt_ps(_mm_hadd_ps(av, av))); + return result.x; +} + static f64 parse_f64(s8 s) { diff --git a/util.h b/util.h @@ -51,7 +51,8 @@ #define MEGABYTE (1024ULL * 1024ULL) #define GIGABYTE (1024ULL * 1024ULL * 1024ULL) -#define U32_MAX (0xFFFFFFFFUL) +#define U32_MAX (0xFFFFFFFFUL) +#define F32_INFINITY (__builtin_inff()) typedef char c8; typedef uint8_t u8; @@ -143,6 +144,8 @@ typedef union { struct { v2 pos, size; }; Rectangle rl; } Rect; +#define INVERTED_INFINITY_RECT (Rect){.pos = {.x = -F32_INFINITY, .y = -F32_INFINITY}, \ + .size = {.x = -F32_INFINITY, .y = -F32_INFINITY}} typedef struct { iptr file;