Commit: 29d0e03ddc27128970bdde7a6890b001e77e59f1
Parent: 9792bfe783355418e55f9b520f5239394fd7bc72
Author: Randy Palamar
Date: Tue, 14 Jan 2025 08:15:44 -0700
ui: don't stretch the output when changing view region
To aid in this we now store the region used to beamform a
BeamformFrame in the struct. This will have other uses as well.
closes: #10
Diffstat:
4 files changed, 72 insertions(+), 32 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -507,13 +507,27 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformFrame *frame, u32 raw
glEndQuery(GL_TIME_ELAPSED);
}
+static BeamformFrame *
+start_beamform_compute_work(BeamformWork *work, ComputeShaderCtx *cs, BeamformerParametersFull *bpf)
+{
+ BeamformFrame *result = work->compute_ctx.frame;
+ if (bpf->upload) {
+ glNamedBufferSubData(cs->shared_ubo, 0, sizeof(bpf->raw), &bpf->raw);
+ bpf->upload = 0;
+ }
+
+ result->min_coordinate = bpf->raw.output_min_coordinate;
+ result->max_coordinate = bpf->raw.output_max_coordinate;
+
+ return result;
+}
+
static void
do_beamform_work(BeamformerCtx *ctx, Arena *a)
{
- BeamformerParameters *bp = &ctx->params->raw;
- BeamformWorkQueue *q = &ctx->beamform_work_queue;
- BeamformWork *work = beamform_work_queue_pop(q);
- ComputeShaderCtx *cs = &ctx->csctx;
+ BeamformWorkQueue *q = &ctx->beamform_work_queue;
+ BeamformWork *work = beamform_work_queue_pop(q);
+ ComputeShaderCtx *cs = &ctx->csctx;
while (work) {
switch (work->type) {
@@ -521,10 +535,7 @@ do_beamform_work(BeamformerCtx *ctx, Arena *a)
BeamformFrame *frame = work->compute_ctx.frame;
if (work->compute_ctx.first_pass) {
- if (ctx->params->upload) {
- glNamedBufferSubData(cs->shared_ubo, 0, sizeof(*bp), bp);
- ctx->params->upload = 0;
- }
+ start_beamform_compute_work(work, cs, ctx->params);
PartialComputeCtx *pc = &ctx->partial_compute_ctx;
pc->runtime = 0;
@@ -575,12 +586,7 @@ do_beamform_work(BeamformerCtx *ctx, Arena *a)
} break;
case BW_FULL_COMPUTE:
case BW_RECOMPUTE: {
- BeamformFrame *frame = work->compute_ctx.frame;
-
- if (ctx->params->upload) {
- glNamedBufferSubData(cs->shared_ubo, 0, sizeof(*bp), bp);
- ctx->params->upload = 0;
- }
+ BeamformFrame *frame = start_beamform_compute_work(work, cs, ctx->params);
u32 stage_count = ctx->params->compute_stages_count;
enum compute_shaders *stages = ctx->params->compute_stages;
@@ -737,7 +743,7 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step)
do_beamform_work(ctx, arena);
/* NOTE: draw output image texture using render fragment shader */
- b32 output_image_drawn;
+ BeamformFrame *frame_to_draw = 0;
BeginTextureMode(ctx->fsctx.output);
ClearBackground(PINK);
BeginShaderMode(ctx->fsctx.shader);
@@ -745,13 +751,14 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step)
glUseProgram(fs->shader.id);
u32 out_texture = 0;
if (bp->output_points.w > 1) {
- out_texture = ctx->averaged_frame.textures[0];
+ frame_to_draw = &ctx->averaged_frame;
+ out_texture = ctx->averaged_frame.textures[0];
} else {
- BeamformFrame *f = ctx->beamform_frames + ctx->displayed_frame_index;
+ frame_to_draw = ctx->beamform_frames + ctx->displayed_frame_index;
/* NOTE: verify we have actually beamformed something yet */
- if (f->dim.w) out_texture = f->textures[f->dim.w - 1];
+ if (frame_to_draw->dim.w)
+ out_texture = frame_to_draw->textures[frame_to_draw->dim.w - 1];
}
- output_image_drawn = out_texture != 0;
glBindTextureUnit(0, out_texture);
glUniform1f(fs->db_cutoff_id, fs->db);
glUniform1f(fs->threshold_id, fs->threshold);
@@ -768,7 +775,7 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step)
ctx->flags &= ~GEN_MIPMAPS;
}
- draw_ui(ctx, input, output_image_drawn);
+ draw_ui(ctx, input, frame_to_draw);
if (IsKeyPressed(KEY_R)) {
ctx->flags |= RELOAD_SHADERS;
diff --git a/beamformer.h b/beamformer.h
@@ -228,6 +228,12 @@ typedef struct {
* is always found in textures[dim.w - 1] */
u32 textures[MAX_MULTI_XDC_COUNT + 1];
uv4 dim;
+
+ /* NOTE: for use when displaying either prebeamformed frames or on the current frame
+ * when we intend to recompute on the next frame */
+ v4 min_coordinate;
+ v4 max_coordinate;
+
u32 mips;
} BeamformFrame;
diff --git a/ui.c b/ui.c
@@ -209,7 +209,7 @@ do_scale_bar(BeamformerUI *ui, Stream *buf, Variable var, v2 mouse, i32 directio
}
static void
-draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect)
+draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect, BeamformFrame *frame)
{
BeamformerUI *ui = ctx->ui;
BeamformerParameters *bp = &ctx->params->raw;
@@ -218,12 +218,6 @@ draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect)
Stream buf = arena_stream(&a);
Texture *output = &ctx->fsctx.output.texture;
- /* TODO: this depends on the direction being rendered (x vs y) */
- v2 output_dim = {
- .x = bp->output_max_coordinate.x - bp->output_min_coordinate.x,
- .y = bp->output_max_coordinate.z - bp->output_min_coordinate.z,
- };
-
v2 txt_s = measure_text(ui->small_font, s8("-288.8 mm"));
display_rect.pos.x += 0.02 * display_rect.size.w;
@@ -238,7 +232,17 @@ draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect)
vr.size.h = display_rect.size.h - pad;
vr.size.w = display_rect.size.w - pad;
- f32 aspect = output_dim.h / output_dim.w;
+ /* TODO(rnp): make this depend on the requested draw orientation (x-z or y-z or x-y) */
+ v2 output_dim = {
+ .x = frame->max_coordinate.x - frame->min_coordinate.x,
+ .y = frame->max_coordinate.z - frame->min_coordinate.z,
+ };
+ v2 requested_dim = {
+ .x = bp->output_max_coordinate.x - bp->output_min_coordinate.x,
+ .y = bp->output_max_coordinate.z - bp->output_min_coordinate.z,
+ };
+
+ f32 aspect = requested_dim.h / requested_dim.w;
if (display_rect.size.h < (vr.size.w * aspect) + pad) {
vr.size.w = vr.size.h / aspect;
} else {
@@ -247,7 +251,19 @@ draw_display_overlay(BeamformerCtx *ctx, Arena a, v2 mouse, Rect display_rect)
vr.pos.x += (display_rect.size.w - (vr.size.w + pad)) / 2;
vr.pos.y += (display_rect.size.h - (vr.size.h + pad)) / 2;
- Rectangle tex_r = { 0.0f, 0.0f, (f32)output->width, -(f32)output->height };
+ v2 pixels_per_meter = {
+ .w = (f32)output->width / output_dim.w,
+ .h = (f32)output->height / output_dim.h,
+ };
+
+ v2 texture_points = mul_v2(pixels_per_meter, requested_dim);
+ /* TODO(rnp): this also depends on x-y, y-z, x-z */
+ v2 texture_start = {
+ .x = pixels_per_meter.x * 0.5 * (output_dim.x - requested_dim.x),
+ .y = pixels_per_meter.y * (frame->max_coordinate.z - bp->output_max_coordinate.z),
+ };
+
+ Rectangle tex_r = {texture_start.x, texture_start.y, texture_points.x, -texture_points.y};
NPatchInfo tex_np = { tex_r, 0, 0, 0, 0, NPATCH_NINE_PATCH };
DrawTextureNPatch(*output, tex_np, vr.rl, (Vector2){0}, 0, WHITE);
@@ -1120,7 +1136,7 @@ ui_init(BeamformerCtx *ctx, Arena store)
}
static void
-draw_ui(BeamformerCtx *ctx, BeamformerInput *input, b32 draw_display)
+draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformFrame *frame_to_draw)
{
BeamformerUI *ui = ctx->ui;
@@ -1144,8 +1160,8 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input, b32 draw_display)
rr.pos.x = lr.pos.x + lr.size.w;
draw_settings_ui(ctx, lr, mouse);
- if (draw_display)
- draw_display_overlay(ctx, ui->arena_for_frame, mouse, rr);
+ if (frame_to_draw->dim.w)
+ draw_display_overlay(ctx, ui->arena_for_frame, mouse, rr, frame_to_draw);
draw_debug_overlay(ctx, ui->arena_for_frame, lr);
EndDrawing();
}
diff --git a/util.c b/util.c
@@ -366,6 +366,17 @@ magnitude_v2(v2 a)
return result;
}
+static v4
+sub_v4(v4 a, v4 b)
+{
+ v4 result;
+ result.x = a.x - b.x;
+ result.y = a.y - b.y;
+ result.z = a.z - b.z;
+ result.w = a.w - b.w;
+ return result;
+}
+
static f64
parse_f64(s8 s)
{