From c690303387861fc6954b5174c1f8c77df43d3564 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Sat, 8 Jul 2023 20:12:09 -0700 Subject: modules/shapes: introduce an approximate atan2f() Taken from this excellent post: https://mazzo.li/posts/vectorized-atan2.html While I haven't gone full vectorized, just getting rid of the regular atan2f() call will be a big improvement. This just adds the functionality, nothing is calling it yet. --- src/modules/shapes/shapes.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/modules') diff --git a/src/modules/shapes/shapes.c b/src/modules/shapes/shapes.c index 6de14ee..236861c 100644 --- a/src/modules/shapes/shapes.c +++ b/src/modules/shapes/shapes.c @@ -113,6 +113,45 @@ static void shapes_prepare_frame(til_module_context_t *context, til_stream_t *st } +/* simple approximation taken from https://mazzo.li/posts/vectorized-atan2.html */ +static inline float atan_scalar_approximation(float x) { + /* TODO: this is probably more terms/precision than needed, but when I try just dropping some, + * the circle+slight pinches gets artifacts. So leaving for now, probably needs slightly different + * values for fewer terms. + */ + float a1 = 0.99997726f; + float a3 = -0.33262347f; + float a5 = 0.19354346f; + float a7 = -0.11643287f; + float a9 = 0.05265332f; + float a11 = -0.01172120f; + float x_sq = x*x; + + return x * (a1 + x_sq * (a3 + x_sq * (a5 + x_sq * (a7 + x_sq * (a9 + x_sq * a11))))); +} + + +static float atan2_approx(float y, float x) { + // Ensure input is in [-1, +1] + int swap = fabs(x) < fabs(y); + float atan_input = (swap ? x : y) / (swap ? y : x); + + // Approximate atan + float res = atan_scalar_approximation(atan_input); + + // If swapped, adjust atan output + res = swap ? (atan_input >= 0.0f ? M_PI_2 : -M_PI_2) - res : res; + + // Adjust quadrants + if (x < 0.0f && y >= 0.0f) + res = M_PI + res; // 2nd quadrant + else if (x < 0.0f && y < 0.0f) + res = -M_PI + res; // 3rd quadrant + + return res; +} + + static void shapes_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr) { shapes_context_t *ctxt = (shapes_context_t *)context; -- cgit v1.2.1