Commit: d93ee2a1092dceaf552f960c356c145e36b2f8c2
Parent: 61f780dc2b0d0c865bfc66cbf6217d4ac0a7da15
Author: Randy Palamar
Date: Fri, 6 Sep 2024 17:09:27 -0600
fix the coordinate system
What we refer to as Z in experiments now corresponds to Z in the
output image. This took way longer than it needed to due to OpenGL
thinking that someone would want to bind a single slice of
TEXTURE_3D (TEXTURE_2D_ARRAY exists for that purpose).
Diffstat:
10 files changed, 89 insertions(+), 82 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -6,9 +6,10 @@ static void
alloc_output_image(BeamformerCtx *ctx)
{
BeamformerParameters *bp = &ctx->params->raw;
- ctx->out_data_dim.x = ORONE(bp->output_points.x);
- ctx->out_data_dim.y = ORONE(bp->output_points.y);
- ctx->out_data_dim.z = ORONE(bp->output_points.z);
+ ctx->out_data_dim.x = round_down_power_of_2(ORONE(bp->output_points.x));
+ ctx->out_data_dim.y = round_down_power_of_2(ORONE(bp->output_points.y));
+ ctx->out_data_dim.z = round_down_power_of_2(ORONE(bp->output_points.z));
+ bp->output_points = ctx->out_data_dim;
/* NOTE: allocate storage for beamformed output data;
* this is shared between compute and fragment shaders */
@@ -24,7 +25,8 @@ alloc_output_image(BeamformerCtx *ctx)
glTexStorage3D(GL_TEXTURE_3D, ctx->out_texture_mips, GL_RG32F, odim.x, odim.y, odim.z);
UnloadRenderTexture(ctx->fsctx.output);
- ctx->fsctx.output = LoadRenderTexture(odim.x, odim.y);
+ /* TODO: select odim.x vs odim.y */
+ ctx->fsctx.output = LoadRenderTexture(odim.x, odim.z);
GenTextureMipmaps(&ctx->fsctx.output.texture);
//SetTextureFilter(ctx->fsctx.output.texture, TEXTURE_FILTER_ANISOTROPIC_8X);
//SetTextureFilter(ctx->fsctx.output.texture, TEXTURE_FILTER_TRILINEAR);
@@ -158,7 +160,7 @@ do_compute_shader(BeamformerCtx *ctx, enum compute_shaders shader)
u32 width = ctx->out_data_dim.x >> i;
u32 height = ctx->out_data_dim.y >> i;
u32 depth = ctx->out_data_dim.z >> i;
- glDispatchCompute(ORONE(width / 32), ORONE(height / 32), ORONE(depth));
+ glDispatchCompute(ORONE(width / 32), ORONE(height), ORONE(depth / 32));
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
}
break;
@@ -166,13 +168,13 @@ do_compute_shader(BeamformerCtx *ctx, enum compute_shaders shader)
case CS_UFORCES:
glActiveTexture(GL_TEXTURE0 + ctx->out_texture_unit);
glBindTexture(GL_TEXTURE_3D, ctx->out_texture);
- glBindImageTexture(ctx->out_texture_unit, ctx->out_texture, 0, GL_FALSE, 0,
+ glBindImageTexture(ctx->out_texture_unit, ctx->out_texture, 0, GL_TRUE, 0,
GL_WRITE_ONLY, GL_RG32F);
glUniform1i(csctx->out_data_tex_id, ctx->out_texture_unit);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, csctx->rf_data_ssbos[input_ssbo_idx]);
glDispatchCompute(ORONE(ctx->out_data_dim.x / 32),
- ORONE(ctx->out_data_dim.y / 32),
- ORONE(ctx->out_data_dim.z));
+ ctx->out_data_dim.y,
+ ORONE(ctx->out_data_dim.z / 32));
break;
default: ASSERT(0);
}
diff --git a/beamformer_parameters.h b/beamformer_parameters.h
@@ -18,9 +18,9 @@ typedef struct {
f32 lpf_coefficients[64]; /* Low Pass Filter Cofficients */
uv4 dec_data_dim; /* Samples * Channels * Acquisitions; last element ignored */
uv4 output_points; /* Width * Height * Depth; last element ignored */
+ v4 output_min_coordinate; /* [m] Back-Top-Left corner of output region (w ignored) */
+ v4 output_max_coordinate; /* [m] Front-Bottom-Right corner of output region (w ignored)*/
uv2 rf_raw_dim; /* Raw Data Dimensions */
- v2 output_min_xz; /* [m] Top left corner of output region */
- v2 output_max_xz; /* [m] Bottom right corner of output region */
v2 xdc_min_xy; /* [m] Min center of transducer elements */
v2 xdc_max_xy; /* [m] Max center of transducer elements */
u32 channel_offset; /* Offset into channel_mapping: 0 or 128 (rows or columns) */
@@ -31,5 +31,5 @@ typedef struct {
f32 focal_depth; /* [m] */
f32 time_offset; /* pulse length correction time [s] */
u32 uforces; /* mode is UFORCES (1) or FORCES (0) */
- f32 off_axis_pos; /* Where on the 3rd axis to render the image (Hercules only)*/
+ f32 _pad[2];
} BeamformerParameters;
diff --git a/shaders/2d_hercules.glsl b/shaders/2d_hercules.glsl
@@ -1,6 +1,6 @@
/* See LICENSE for license details. */
#version 460 core
-layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
+layout(local_size_x = 32, local_size_y = 1, local_size_z = 32) in;
layout(std430, binding = 1) readonly restrict buffer buffer_1 {
vec2 rf_data[];
@@ -12,9 +12,9 @@ layout(std140, binding = 0) uniform parameters {
vec4 lpf_coefficients[16]; /* Low Pass Filter Cofficients */
uvec4 dec_data_dim; /* Samples * Channels * Acquisitions; last element ignored */
uvec4 output_points; /* Width * Height * Depth; last element ignored */
+ vec4 output_min_coord; /* [m] Top left corner of output region */
+ vec4 output_max_coord; /* [m] Bottom right corner of output region */
uvec2 rf_raw_dim; /* Raw Data Dimensions */
- vec2 output_min_xz; /* [m] Top left corner of output region */
- vec2 output_max_xz; /* [m] Bottom right corner of output region */
vec2 xdc_min_xy; /* [m] Min center of transducer elements */
vec2 xdc_max_xy; /* [m] Max center of transducer elements */
uint channel_offset; /* Offset into channel_mapping: 0 or 128 (rows or columns) */
@@ -25,10 +25,9 @@ layout(std140, binding = 0) uniform parameters {
float focal_depth; /* [m] */
float time_offset; /* pulse length correction time [s] */
uint uforces; /* mode is UFORCES (1) or FORCES (0) */
- float off_axis_pos; /* Where on the 3rd axis to render the image (Hercules only) */
};
-layout(rg32f, location = 1) uniform image3D u_out_data_tex;
+layout(rg32f, location = 1) uniform writeonly image3D u_out_data_tex;
#define C_SPLINE 0.5
@@ -66,19 +65,17 @@ vec2 cubic(uint ridx, float x)
void main()
{
- vec2 pixel = vec2(gl_GlobalInvocationID.xy);
+ vec3 voxel = vec3(gl_GlobalInvocationID.xyz);
ivec3 out_coord = ivec3(gl_GlobalInvocationID.xyz);
ivec3 out_data_dim = imageSize(u_out_data_tex);
/* NOTE: Convert pixel to physical coordinates */
vec2 xdc_size = abs(xdc_max_xy - xdc_min_xy);
- vec2 output_size = abs(output_max_xz - output_min_xz);
-
- /* TODO: for now assume y-dimension is along transducer center */
- vec3 image_point = vec3(
- output_min_xz.x + pixel.x * output_size.x / out_data_dim.x,
- off_axis_pos,
- output_min_xz.y + pixel.y * output_size.y / out_data_dim.y
+ vec4 output_size = abs(output_max_coord - output_min_coord);
+ vec3 image_point = vec3(
+ output_min_coord.x + voxel.x * output_size.x / out_data_dim.x,
+ output_min_coord.y + voxel.y * output_size.y / out_data_dim.y,
+ output_min_coord.z + voxel.z * output_size.z / out_data_dim.z
);
/* NOTE: used for constant F# dynamic receive apodization. This is implemented as:
@@ -88,15 +85,14 @@ void main()
* \ |z_e - z_i|/
*
* where x,z_e are transducer element positions and x,z_i are image positions. */
- float f_num = output_size.y / output_size.x;
+ float f_num = output_size.z / output_size.x;
float apod_arg = f_num * 0.5 * radians(360) / abs(image_point.z);
/* NOTE: for I-Q data phase correction */
float iq_time_scale = (lpf_order > 0)? radians(360) * center_frequency : 0;
vec3 starting_dist = vec3(image_point.x - xdc_min_xy.x, image_point.y - xdc_min_xy.y, image_point.z);
- float dx = xdc_size.x / float(dec_data_dim.y);
- float dy = xdc_size.y / float(dec_data_dim.y);
+ vec3 delta = vec3(xdc_size.x / float(dec_data_dim.y), xdc_size.y / float(dec_data_dim.y), 0);
float dzsign = sign(image_point.z - focal_depth);
/* NOTE: offset correcting for both pulse length and low pass filtering */
@@ -104,14 +100,17 @@ void main()
vec2 sum = vec2(0);
vec3 rdist = starting_dist;
- /* NOTE: skip first acquisition in uforces since its garbage */
- uint ridx = dec_data_dim.y * dec_data_dim.x * uforces;
- for (uint i = uforces; i < dec_data_dim.z; i++) {
+
+ int direction = 1;
+ uint ridx = 0;
+ /* NOTE: For Each Acquistion in Raw Data */
+ for (uint i = 0; i < dec_data_dim.z; i++) {
uint base_idx = (i - uforces) / 4;
uint sub_idx = (i - uforces) % 4;
float transmit_dist = image_point.z;
+ /* NOTE: For Each Virtual Source */
for (uint j = 0; j < dec_data_dim.y; j++) {
float dist = transmit_dist + length(rdist);
float time = dist / speed_of_sound + time_correction;
@@ -121,14 +120,17 @@ void main()
a = a * a;
vec2 p = cubic(ridx, time * sampling_frequency);
+ /* NOTE: tribal knowledge; this is a problem with the imaging sequence */
+ if (i == 0) p *= inversesqrt(128);
//p *= vec2(cos(iq_time_scale * time), sin(iq_time_scale * time));
sum += p;
- rdist.y -= dy;
- ridx += dec_data_dim.x;
+
+ rdist[direction] -= delta[direction];
+ ridx += dec_data_dim.x;
}
- rdist.y = starting_dist.y;
- rdist.x -= dx;
+ rdist[direction] = starting_dist[direction];
+ rdist[(~direction) & 1] -= delta[(~direction) & 1];
}
float val = length(sum);
imageStore(u_out_data_tex, out_coord, vec4(val, val, 0, 0));
diff --git a/shaders/demod.glsl b/shaders/demod.glsl
@@ -16,9 +16,9 @@ layout(std140, binding = 0) uniform parameters {
vec4 lpf_coefficients[16]; /* Low Pass Filter Cofficients */
uvec4 dec_data_dim; /* Samples * Channels * Acquisitions; last element ignored */
uvec4 output_points; /* Width * Height * Depth; last element ignored */
+ vec4 output_min_coord; /* [m] Top left corner of output region */
+ vec4 output_max_coord; /* [m] Bottom right corner of output region */
uvec2 rf_raw_dim; /* Raw Data Dimensions */
- vec2 output_min_xz; /* [m] Top left corner of output region */
- vec2 output_max_xz; /* [m] Bottom right corner of output region */
vec2 xdc_min_xy; /* [m] Min center of transducer elements */
vec2 xdc_max_xy; /* [m] Max center of transducer elements */
uint channel_offset; /* Offset into channel_mapping: 0 or 128 (rows or columns) */
@@ -29,7 +29,6 @@ layout(std140, binding = 0) uniform parameters {
float focal_depth; /* [m] */
float time_offset; /* pulse length correction time [s] */
uint uforces; /* mode is UFORCES (1) or FORCES (0) */
- float off_axis_pos; /* Where on the 3rd axis to render the image (Hercules only) */
};
void main()
diff --git a/shaders/hadamard.glsl b/shaders/hadamard.glsl
@@ -20,9 +20,9 @@ layout(std140, binding = 0) uniform parameters {
vec4 lpf_coefficients[16]; /* Low Pass Filter Cofficients */
uvec4 dec_data_dim; /* Samples * Channels * Acquisitions; last element ignored */
uvec4 output_points; /* Width * Height * Depth; last element ignored */
+ vec4 output_min_coord; /* [m] Top left corner of output region */
+ vec4 output_max_coord; /* [m] Bottom right corner of output region */
uvec2 rf_raw_dim; /* Raw Data Dimensions */
- vec2 output_min_xz; /* [m] Top left corner of output region */
- vec2 output_max_xz; /* [m] Bottom right corner of output region */
vec2 xdc_min_xy; /* [m] Min center of transducer elements */
vec2 xdc_max_xy; /* [m] Max center of transducer elements */
uint channel_offset; /* Offset into channel_mapping: 0 or 128 (rows or columns) */
@@ -33,7 +33,6 @@ layout(std140, binding = 0) uniform parameters {
float focal_depth; /* [m] */
float time_offset; /* pulse length correction time [s] */
uint uforces; /* mode is UFORCES (1) or FORCES (0) */
- float off_axis_pos; /* Where on the 3rd axis to render the image (Hercules only) */
};
void main()
diff --git a/shaders/min_max.glsl b/shaders/min_max.glsl
@@ -3,11 +3,11 @@
/* NOTE: Does a binary search in 3D for smallest and largest output values */
#version 460 core
-layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
+layout(local_size_x = 32, local_size_y = 1, local_size_z = 32) in;
-layout(rg32f, location = 1) uniform image3D u_out_data_tex;
-layout(rg32f, location = 2) uniform image3D u_mip_view_tex;
-layout(location = 3) uniform int u_mip_map = 0;
+layout(rg32f, location = 1) uniform readonly image3D u_out_data_tex;
+layout(rg32f, location = 2) uniform writeonly image3D u_mip_view_tex;
+layout(location = 3) uniform int u_mip_map = 0;
void main()
{
diff --git a/shaders/render.glsl b/shaders/render.glsl
@@ -19,16 +19,19 @@ vec3 hsv2rgb(vec3 hsv)
void main()
{
ivec3 out_data_dim = textureSize(u_out_data_tex, 0);
- ivec2 coord = ivec2(fragTexCoord * out_data_dim.xy);
+
+ /* TODO: select between x and y with potentially a slice if viewing rendered volumes */
+ ivec2 coord = ivec2(fragTexCoord * vec2(out_data_dim.xz));
vec2 min_max = texelFetch(u_out_data_tex, ivec3(0), textureQueryLevels(u_out_data_tex) - 1).xy;
- float smp = texelFetch(u_out_data_tex, ivec3(coord.x, coord.y, 0), 0).x;
- float absmax = max(abs(min_max.y), abs(min_max.x));
+ ivec3 smp_coord = ivec3(coord.x, 0, coord.y);
+ float smp = texelFetch(u_out_data_tex, smp_coord, 0).x;
+ float absmax = max(abs(min_max.y), abs(min_max.x));
smp = 20 * log(abs(smp) / absmax) / log(10);
smp = clamp(smp, u_db_cutoff, 0) / u_db_cutoff;
smp = 1 - smp;
- //v_out_colour = vec4(hsv2rgb(vec3(360 * smp + 120, 0.8, 0.95)), 1);
+ //v_out_colour = vec4(hsv2rgb(vec3(360 * smp, 0.8, 0.95)), 1);
v_out_colour = vec4(smp, smp, smp, 1);
}
diff --git a/shaders/uforces.glsl b/shaders/uforces.glsl
@@ -1,6 +1,6 @@
/* See LICENSE for license details. */
#version 460 core
-layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
+layout(local_size_x = 32, local_size_y = 1, local_size_z = 32) in;
layout(std430, binding = 1) readonly restrict buffer buffer_1 {
vec2 rf_data[];
@@ -12,9 +12,9 @@ layout(std140, binding = 0) uniform parameters {
vec4 lpf_coefficients[16]; /* Low Pass Filter Cofficients */
uvec4 dec_data_dim; /* Samples * Channels * Acquisitions; last element ignored */
uvec4 output_points; /* Width * Height * Depth; last element ignored */
+ vec4 output_min_coord; /* [m] Top left corner of output region */
+ vec4 output_max_coord; /* [m] Bottom right corner of output region */
uvec2 rf_raw_dim; /* Raw Data Dimensions */
- vec2 output_min_xz; /* [m] Top left corner of output region */
- vec2 output_max_xz; /* [m] Bottom right corner of output region */
vec2 xdc_min_xy; /* [m] Min center of transducer elements */
vec2 xdc_max_xy; /* [m] Max center of transducer elements */
uint channel_offset; /* Offset into channel_mapping: 0 or 128 (rows or columns) */
@@ -25,10 +25,9 @@ layout(std140, binding = 0) uniform parameters {
float focal_depth; /* [m] */
float time_offset; /* pulse length correction time [s] */
uint uforces; /* mode is UFORCES (1) or FORCES (0) */
- float off_axis_pos; /* Where on the 3rd axis to render the image (Hercules only) */
};
-layout(rg32f, location = 1) uniform image3D u_out_data_tex;
+layout(rg32f, location = 1) writeonly uniform image3D u_out_data_tex;
#define C_SPLINE 0.5
@@ -66,19 +65,17 @@ vec2 cubic(uint ridx, float x)
void main()
{
- vec2 pixel = vec2(gl_GlobalInvocationID.xy);
- ivec3 out_coord = ivec3(gl_GlobalInvocationID.xyz);
+ vec3 voxel = vec3(gl_GlobalInvocationID);
+ ivec3 out_coord = ivec3(gl_GlobalInvocationID);
ivec3 out_data_dim = imageSize(u_out_data_tex);
- /* NOTE: Convert pixel to physical coordinates */
+ /* NOTE: Convert voxel to physical coordinates */
vec2 xdc_size = abs(xdc_max_xy - xdc_min_xy);
- vec2 output_size = abs(output_max_xz - output_min_xz);
-
- /* TODO: for now assume y-dimension is along transducer center */
- vec3 image_point = vec3(
- output_min_xz.x + pixel.x * output_size.x / out_data_dim.x,
- 0,
- output_min_xz.y + pixel.y * output_size.y / out_data_dim.y
+ vec4 output_size = abs(output_max_coord - output_min_coord);
+ vec3 image_point = vec3(
+ output_min_coord.x + voxel.x * output_size.x / out_data_dim.x,
+ output_min_coord.y + voxel.y * output_size.y / out_data_dim.y,
+ output_min_coord.z + voxel.z * output_size.z / out_data_dim.z
);
/* NOTE: used for constant F# dynamic receive apodization. This is implemented as:
@@ -88,7 +85,7 @@ void main()
* \ |z_e - z_i|/
*
* where x,z_e are transducer element positions and x,z_i are image positions. */
- float f_num = output_size.y / output_size.x;
+ float f_num = output_size.z / output_size.x;
float apod_arg = f_num * 0.5 * radians(360) / abs(image_point.z);
/* NOTE: for I-Q data phase correction */
@@ -96,7 +93,6 @@ void main()
vec2 starting_dist = vec2(image_point.x - xdc_min_xy.x, image_point.z);
float dx = xdc_size.x / float(dec_data_dim.y);
- float dzsign = sign(image_point.z);
/* NOTE: offset correcting for both pulse length and low pass filtering */
float time_correction = time_offset + lpf_order / sampling_frequency;
@@ -109,7 +105,7 @@ void main()
uint sub_idx = (i - uforces) % 4;
vec3 focal_point = vec3(uforces_channels[base_idx][sub_idx] * dx + xdc_min_xy.x, 0, 0);
- float transmit_dist = dzsign * distance(image_point, focal_point);
+ float transmit_dist = distance(image_point, focal_point);
vec2 rdist = starting_dist;
for (uint j = 0; j < dec_data_dim.y; j++) {
diff --git a/ui.c b/ui.c
@@ -331,8 +331,8 @@ draw_settings_ui(BeamformerCtx *ctx, Arena arena, Rect r, v2 mouse)
{
BeamformerParameters *bp = &ctx->params->raw;
- f32 minx = bp->output_min_xz.x + 1e-6, maxx = bp->output_max_xz.x - 1e-6;
- f32 minz = bp->output_min_xz.y + 1e-6, maxz = bp->output_max_xz.y - 1e-6;
+ f32 minx = bp->output_min_coordinate.x + 1e-6, maxx = bp->output_max_coordinate.x - 1e-6;
+ f32 minz = bp->output_min_coordinate.z + 1e-6, maxz = bp->output_max_coordinate.z - 1e-6;
Rect draw_r = r;
draw_r.pos.y += 20;
@@ -355,26 +355,22 @@ draw_settings_ui(BeamformerCtx *ctx, Arena arena, Rect r, v2 mouse)
draw_r = do_text_input_listing(s8("Speed of Sound:"), s8("[m/s]"), bmv, ctx, arena,
draw_r, mouse, hover_t + idx++);
- bmv = (BPModifiableValue){&bp->output_min_xz.x, (v2){.x = -1e3, .y = maxx}, 1e3, 1};
+ bmv = (BPModifiableValue){&bp->output_min_coordinate.x, (v2){.x = -1e3, .y = maxx}, 1e3, 1};
draw_r = do_text_input_listing(s8("Min X Point:"), s8("[mm]"), bmv, ctx, arena,
draw_r, mouse, hover_t + idx++);
- bmv = (BPModifiableValue){&bp->output_max_xz.x, (v2){.x = minx, .y = 1e3}, 1e3, 1};
+ bmv = (BPModifiableValue){&bp->output_max_coordinate.x, (v2){.x = minx, .y = 1e3}, 1e3, 1};
draw_r = do_text_input_listing(s8("Max X Point:"), s8("[mm]"), bmv, ctx, arena,
draw_r, mouse, hover_t + idx++);
- bmv = (BPModifiableValue){&bp->output_min_xz.y, (v2){.y = maxz}, 1e3, 1};
+ bmv = (BPModifiableValue){&bp->output_min_coordinate.z, (v2){.y = maxz}, 1e3, 1};
draw_r = do_text_input_listing(s8("Min Z Point:"), s8("[mm]"), bmv, ctx, arena,
draw_r, mouse, hover_t + idx++);
- bmv = (BPModifiableValue){&bp->output_max_xz.y, (v2){.x = minz, .y = 1e3}, 1e3, 1};
+ bmv = (BPModifiableValue){&bp->output_max_coordinate.z, (v2){.x = minz, .y = 1e3}, 1e3, 1};
draw_r = do_text_input_listing(s8("Max Z Point:"), s8("[mm]"), bmv, ctx, arena,
draw_r, mouse, hover_t + idx++);
- bmv = (BPModifiableValue){&bp->off_axis_pos, (v2){.x = minx * 2, .y = maxx * 2}, 1e3, 1};
- draw_r = do_text_input_listing(s8("Y Position:"), s8("[mm]"), bmv, ctx, arena,
- draw_r, mouse, hover_t + idx++);
-
bmv = (BPModifiableValue){&ctx->fsctx.db, (v2){.x = -120}, 1, 0};
draw_r = do_text_input_listing(s8("Dynamic Range:"), s8("[dB]"), bmv, ctx, arena,
draw_r, mouse, hover_t + idx++);
@@ -479,8 +475,8 @@ draw_ui(BeamformerCtx *ctx, Arena arena)
Texture *output = &ctx->fsctx.output.texture;
v2 output_dim = {
- .x = bp->output_max_xz.x - bp->output_min_xz.x,
- .y = bp->output_max_xz.y - bp->output_min_xz.y,
+ .x = bp->output_max_coordinate.x - bp->output_min_coordinate.x,
+ .y = bp->output_max_coordinate.z - bp->output_min_coordinate.z,
};
v2 mouse = { .rl = GetMousePosition() };
@@ -546,13 +542,16 @@ draw_ui(BeamformerCtx *ctx, Arena arena)
Rect tick_rect = {.pos = start_pos, .size = vr.size};
tick_rect.size.E[!i] = 10 + tick_len + txt_s.x;
+ /* TODO: don't do this nonsense; this code will need to get
+ * split into a seperate function */
+ u32 coord_idx = i == 0? 0 : 2;
if (CheckCollisionPointRec(mouse.rl, tick_rect.rl)) {
f32 scale[2] = {0.5e-3, 1e-3};
f32 size_delta = GetMouseWheelMove() * scale[i];
/* TODO: smooth scroll this? */
- if (i == 0)
- bp->output_min_xz.E[i] -= size_delta;
- bp->output_max_xz.E[i] += size_delta;
+ if (coord_idx== 0)
+ bp->output_min_coordinate.E[coord_idx] -= size_delta;
+ bp->output_max_coordinate.E[coord_idx] += size_delta;
if (size_delta) {
ctx->flags |= DO_COMPUTE;
ctx->params->upload = 1;
@@ -564,7 +563,7 @@ draw_ui(BeamformerCtx *ctx, Arena arena)
}
CLAMP01(txt_colour_t[i]);
- f32 mm = bp->output_min_xz.E[i] * 1e3;
+ f32 mm = bp->output_min_coordinate.E[coord_idx] * 1e3;
f32 mm_inc = inc * output_dim.E[i] * 1e3 / vr.size.E[i];
Color txt_colour = colour_from_normalized(lerp_v4(FG_COLOUR, HOVERED_COLOUR,
diff --git a/util.c b/util.c
@@ -58,6 +58,13 @@ uv4_equal(uv4 a, uv4 b)
return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
}
+static u32
+round_down_power_of_2(u32 a)
+{
+ u32 result = 0x80000000UL >> _lzcnt_u32(a);
+ return result;
+}
+
static void
fill_hadamard(i32 *m, u32 dim)
{