Commit: 5ac2a90a2b3883eb96737f47db6edbdbd1bdff33
Parent: e545a88bf8f442a63a96d52d221b082fff119f1b
Author: Randy Palamar
Date: Wed, 9 Jul 2025 22:45:30 -0600
ui: fancier live control power slider
Diffstat:
M | intrinsics.c | | | 20 | ++++++++++++++++---- |
M | math.c | | | 44 | ++++++++++++++++++++++++++++++++++++++++++-- |
M | ui.c | | | 5 | +++-- |
3 files changed, 61 insertions(+), 8 deletions(-)
diff --git a/intrinsics.c b/intrinsics.c
@@ -138,31 +138,43 @@ ctz_u32(u32 a)
typedef float32x4_t f32x4;
typedef int32x4_t i32x4;
+#define add_f32x4(a, b) vaddq_f32(a, b)
#define cvt_i32x4_f32x4(a) vcvtq_f32_s32(a)
#define cvt_f32x4_i32x4(a) vcvtq_s32_f32(a)
+#define div_f32x4(a, b) vdivq_f32(a, b)
#define dup_f32x4(f) vdupq_n_f32(f)
+#define floor_f32x4(a) vrndmq_f32(a)
#define load_f32x4(a) vld1q_f32(a)
#define load_i32x4(a) vld1q_s32(a)
+#define max_f32x4(a, b) vmaxq_f32(a, b)
+#define min_f32x4(a, b) vminq_f32(a, b)
#define mul_f32x4(a, b) vmulq_f32(a, b)
#define set_f32x4(a, b, c, d) vld1q_f32((f32 []){d, c, b, a})
#define sqrt_f32x4(a) vsqrtq_f32(a)
-#define store_f32x4(a, o) vst1q_f32(o, a)
-#define store_i32x4(a, o) vst1q_s32(o, a)
+#define store_f32x4(o, a) vst1q_f32(o, a)
+#define store_i32x4(o, a) vst1q_s32(o, a)
+#define sub_f32x4(a, b) vsubq_f32(a, b)
#elif ARCH_X64
#include <immintrin.h>
typedef __m128 f32x4;
typedef __m128i i32x4;
+#define add_f32x4(a, b) _mm_add_ps(a, b)
#define cvt_i32x4_f32x4(a) _mm_cvtepi32_ps(a)
#define cvt_f32x4_i32x4(a) _mm_cvtps_epi32(a)
+#define div_f32x4(a, b) _mm_div_ps(a, b)
#define dup_f32x4(f) _mm_set1_ps(f)
+#define floor_f32x4(a) _mm_floor_ps(a)
#define load_f32x4(a) _mm_loadu_ps(a)
#define load_i32x4(a) _mm_loadu_si128((i32x4 *)a)
+#define max_f32x4(a, b) _mm_max_ps(a, b)
+#define min_f32x4(a, b) _mm_min_ps(a, b)
#define mul_f32x4(a, b) _mm_mul_ps(a, b)
#define set_f32x4(a, b, c, d) _mm_set_ps(a, b, c, d)
#define sqrt_f32x4(a) _mm_sqrt_ps(a)
-#define store_f32x4(a, o) _mm_storeu_ps(o, a)
-#define store_i32x4(a, o) _mm_storeu_si128((i32x4 *)o, a)
+#define store_f32x4(o, a) _mm_storeu_ps(o, a)
+#define store_i32x4(o, a) _mm_storeu_si128((i32x4 *)o, a)
+#define sub_f32x4(a, b) _mm_sub_ps(a, b)
#endif
diff --git a/math.c b/math.c
@@ -5,7 +5,7 @@ fill_kronecker_sub_matrix(i32 *out, i32 out_stride, i32 scale, i32 *b, uv2 b_dim
for (u32 i = 0; i < b_dim.y; i++) {
for (u32 j = 0; j < b_dim.x; j += 4, b += 4) {
f32x4 vb = cvt_i32x4_f32x4(load_i32x4(b));
- store_i32x4(cvt_f32x4_i32x4(mul_f32x4(vscale, vb)), out + j);
+ store_i32x4(out + j, cvt_f32x4_i32x4(mul_f32x4(vscale, vb)));
}
out += out_stride;
}
@@ -199,7 +199,6 @@ v2_magnitude(v2 a)
return result;
}
-
function v3
cross(v3 a, v3 b)
{
@@ -562,3 +561,44 @@ obb_raycast(m4 obb_orientation, v3 obb_size, v3 obb_center, ray ray)
return result;
}
+
+function v4
+hsv_to_rgb(v4 hsv)
+{
+ /* f(k(n)) = V - V*S*max(0, min(k, min(4 - k, 1)))
+ * k(n) = fmod((n + H * 6), 6)
+ * (R, G, B) = (f(n = 5), f(n = 3), f(n = 1))
+ */
+ align_as(16) f32 nval[4] = {5.0f, 3.0f, 1.0f, 0.0f};
+ f32x4 n = load_f32x4(nval);
+ f32x4 H = dup_f32x4(hsv.x);
+ f32x4 S = dup_f32x4(hsv.y);
+ f32x4 V = dup_f32x4(hsv.z);
+ f32x4 six = dup_f32x4(6);
+
+ f32x4 t = add_f32x4(n, mul_f32x4(six, H));
+ f32x4 rem = floor_f32x4(div_f32x4(t, six));
+ f32x4 k = sub_f32x4(t, mul_f32x4(rem, six));
+
+ t = min_f32x4(sub_f32x4(dup_f32x4(4), k), dup_f32x4(1));
+ t = max_f32x4(dup_f32x4(0), min_f32x4(k, t));
+ t = mul_f32x4(t, mul_f32x4(S, V));
+
+ v4 rgba;
+ store_f32x4(rgba.E, sub_f32x4(V, t));
+ rgba.a = hsv.a;
+ return rgba;
+}
+
+function f32
+ease_cubic(f32 t)
+{
+ f32 result;
+ if (t < 0.5f) {
+ result = 4.0f * t * t * t;
+ } else {
+ f32 c = -2.0f * t + 2.0f;
+ result = 1.0f - c * c * c / 2.0f;
+ }
+ return result;
+}
diff --git a/ui.c b/ui.c
@@ -2727,10 +2727,11 @@ draw_live_controls_view(BeamformerUI *ui, Arena arena, Variable *var, Rect r, v2
v2 at = {{text_off, r.pos.y}};
+ v4 hsv_power_slider = {{0.35 * ease_cubic(1.0f - lip->transmit_power), 0.65f, 0.65f, 1}};
at.y += draw_text(s8("Power:"), at, &text_spec).y;
at.x = slider_off;
at.y += draw_variable_slider(ui, &lv->transmit_power, (Rect){.pos = at, .size = slider_size},
- lip->transmit_power, g_colour_palette[2], mouse);
+ lip->transmit_power, hsv_to_rgb(hsv_power_slider), mouse);
at.x = text_off;
at.y += draw_text(s8("TGC:"), at, &text_spec).y;
@@ -2759,7 +2760,7 @@ draw_live_controls_view(BeamformerUI *ui, Arena arena, Variable *var, Rect r, v2
if (lv->save_button_blink_t <= 0.0f) lv->save_button_blink_scale = BLINK_SPEED;
v4 border_colour = BORDER_COLOUR;
- if (active) border_colour = v4_lerp(border_colour, FOCUSED_COLOUR, lv->save_button_blink_t);
+ if (active) border_colour = v4_lerp(border_colour, FOCUSED_COLOUR, ease_cubic(lv->save_button_blink_t));
at.y += ui->font.baseSize * 0.25;
at.y += draw_fancy_button(ui, &lv->save_button, label, (Rect){.pos = at, .size = button_size},