From ff583a37242c576649642708207475815e64893c Mon Sep 17 00:00:00 2001 From: veclavtalica Date: Sat, 25 Jan 2025 02:32:05 +0300 Subject: [PATCH] article: circle-rasterization --- .../circle-rasterization/.static/circles.webp | Bin 0 -> 15458 bytes articles/circle-rasterization/page.mmd | 84 ++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 articles/circle-rasterization/.static/circles.webp create mode 100644 articles/circle-rasterization/page.mmd diff --git a/articles/circle-rasterization/.static/circles.webp b/articles/circle-rasterization/.static/circles.webp new file mode 100644 index 0000000000000000000000000000000000000000..f3bfd1e601f662b21a20161aa24d4bc5ae1f393e GIT binary patch literal 15458 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 literal 0 HcmV?d00001 diff --git a/articles/circle-rasterization/page.mmd b/articles/circle-rasterization/page.mmd new file mode 100644 index 0000000..9962fb3 --- /dev/null +++ b/articles/circle-rasterization/page.mmd @@ -0,0 +1,84 @@ +Title: Circle Rasterization +Brief: Investigation on fast grid-aligned circle rasterization. +Date: 1737757212 +Tags: Programming, Optimization, C +CSS: /style.css + +![](/articles/circle-rasterization/circles.webp) + +Currently drastically overthinking anything related to dream Minecraft-like game of mine, +and today it was all about chunk loading. Particularly, ideal way to infer which chunks +should be loaded based on distance to the viewer, instead of typical direct grid. + +For that circle rasterization is needed. I came up with following pieces of code, one reusable macro, +and others are meant to be directly copy pasted where needed: + +Macro: +```c +/* Emits `x` and `y` for every intersecting cell */ +/* We snap position to the nearest corner, which means there's no aliasing */ +/* It works great for integer radii */ +#define m_iter_circle_pixels(p_center_x, p_center_y, p_radius) \ + for (float y = (p_center_y + ceilf(p_radius)) - 1; y > (p_center_y - ceilf(p_radius)) - 1; --y) \ + for (float x = p_center_x - ceilf(sqrtf(p_radius * p_radius - (y - p_center_y + (y <= p_center_y)) * (y - p_center_y + (y <= p_center_y)))); \ + x < p_center_x + ceilf(sqrtf(p_radius * p_radius - (y - p_center_y + (y <= p_center_y)) * (y - p_center_y + (y <= p_center_y)))); ++x) +``` + +Floating point based one: +```c +float const rs = state->r * state->r; +float const cr = ceilf(state->r); +for (float iy = -cr; iy <= cr - 1; ++iy) { + float const dx = ceilf(sqrtf(rs - (iy + (iy <= 0)) * (iy + (iy <= 0)))); + for (float ix = -dx; ix < dx; ++ix) { + /* iy and ix are floating point offsets from (0, 0) */ + } +} +``` + +Integer math based one: +```c +/* Neat shorthand making integer based loops drastically faster */ +static int32_t ceil_sqrt(int32_t const n) { + int32_t res = 1; + #pragma clang loop unroll_count(8) + while(res * res < n) + res++; + return res; +} + +/* This one beats the float in raw performance, but might scale worse at increasing radii, assuming sqrt is a hardware intrinsic with known worst time */ +int32_t const rsi = (int32_t)state->r * (int32_t)state->r; +for (int32_t iy = -(int32_t)state->r; iy <= (int32_t)state->r - 1; ++iy) { + int32_t const dx = ceil_sqrt(rsi - (iy + (iy <= 0)) * (iy + (iy <= 0))); + for (int32_t ix = -dx; ix < dx; ++ix) { + /* iy and ix are integer offsets from (0, 0) */ + } +} +``` + +Integer math based with accumulated ceil(sqrt()), the fastest I could come up with: +```c +int32_t const rsi = (int32_t)state->r * (int32_t)state->r; +int32_t acc = 1; +for (int32_t iy = (int32_t)state->r - 1; iy >= 0; --iy) { + while (acc * acc < rsi - iy * iy) acc++; + for (int32_t ix = -acc; ix < acc; ++ix) { + /* lower portion */ + x = (float)ix; + y = (float)iy; + /* upper portion */ + x = (float)ix; + y = (float)-iy - 1; + } +} +``` + +Note that they assume center point at coordinate origin, quadrant symmetry and whole number radii. + +Benchmarks: +``` +Profile 'float' on average took: 0.001537s, worst case: 0.003272s, sample count: 277 +Profile 'int32_t' on average took: 0.000726s, worst case: 0.002293s, sample count: 277 +Profile 'int32_t acc' on average took: 0.000650s, worst case: 0.001732s, sample count: 277 +```