Saturating-Cast Kaleidoscope
Rendering & Graphics
A 6-fold hex kaleidoscope on a Super Nintendo whose colours are driven by saturating float-to-int
casts: fminf/fmaxf clamp a float intensity into the int16 range, then
(int16_t) truncates — with the
llvm-mos legalizer at line 502 inserting a NaN
guard automatically. Saturated outer tiles form crisp flat-colour plateaus; inner tiles show the
colour gradient as phase sweeps. Compiler stress-test #77, the first demo to call
fminf/fmaxf.
Self-running — saturation boundary pulses through the mandala as phase sweeps.
Click the screen to focus, then watch. Tab away and it pauses.
What it is
Each tile maps to a hex axial coordinate triple (q, r, s=−q−r); sorting the absolute values |q|,|r|,|s| folds the grid into the first sextant, giving 6-fold symmetry without trigonometry. A float intensity is then computed from the sorted triple and an advancing phase: intensity = a²·200 − b²·50 + phase. For large a (outer rings) the intensity exceeds the int16 range and saturates; for inner tiles the cast stays in-range and the 4 colour levels visible. As phase sweeps continuously, the saturation boundary pulses in and out.
// Per-tile colour in the 6-fold hex kaleidoscope: // q=tx-8, r=ty-8, s=-q-r (hex axial coords) // a,b,c = sort(|q|,|r|,|s|) (first sextant → 6-fold symmetry) float fa = (float)a; float a2 = fa * fa; // __mulsf3: 0..225 float tb = (float)b * (float)b * 50.0f; // __mulsf3 x2 float raw = a2 * 200.0f - tb; // __mulsf3 + __subsf3 float intensity = raw + phase_f; // __addsf3 // Saturating cast: float lo = fminf(32767.0f, intensity); // G_FMINNUM float hi = fmaxf(-32768.0f, lo); // G_FMAXNUM int16_t iv = (int16_t)hi; // G_FPTOSI (legalizer inserts NaN guard) // colour = top 2 bits of (iv shifted to unsigned): colour = (uint8_t)((uint16_t)(iv + 32768) >> 14); // → INT16_MIN→0, [-16384,-1]→1, [0,16383]→2, [16384,INT16_MAX]→3
Compiler stress-test
| Item | What it exercises |
|---|---|
| G_FMINNUM | fminf(32767.0f, x) lowers to G_FMINNUM → SDK fminf (math.cc:18 in llvm-mos-sdk). On the 65816 this is a function call to the soft-float min comparison, not an inline instruction. This is the first demo in the battery to call fminf/fmaxf. |
| G_FMAXNUM | fmaxf(-32768.0f, lo) lowers to G_FMAXNUM → SDK fmaxf (math.cc:19). Together with G_FMINNUM, this creates the two-sided clamp that prevents the int16 cast from hitting undefined behaviour on out-of-range floats. |
| G_FPTOSI + legalizer :502 | (int16_t)hi lowers to G_FPTOSI. The MOS legalizer at line 502 inserts a NaN guard (buildIsFPClass(fcNan) + G_SELECT) so that a NaN input maps to INT16_MIN instead of UB. This is distinct from demo #44 (integer __builtin_add_overflow / G_UADDO) and #59 (exact 64-bit round-trip, no clamp). |
| saturation plateaus | Tiles with large a (Chebyshev hex distance from centre) compute a² × 200 which exceeds INT16_MAX = 32767 well before the edge — so those tiles saturate to colour 3 (gold). When phase_f is strongly negative, all tiles saturate to INT16_MIN → colour 0 (indigo). The phase sweeps continuously, so the saturation boundary pulses in and out across the mandala. |
| 6-fold symmetry | Hex axial coordinates (q, r, s=−q−r) have intrinsic 6-fold rotational symmetry when |q|, |r|, |s| are sorted. Tiles that are rotations of each other in hexagonal space share the same (a, b, c) triple and therefore the same intensity, giving a kaleidoscope without any trigonometry. |
Written in C with the llvm-mos 65816 toolchain and verified against bsnes-jg and MAME.
Hit Verify fidelity to reproduce the build gate's WRAM assert (gate CRC 0xC8CF —
16-phase × 8-tile rotating-XOR fold of sc_tile_color) live in this tab. No far
pointers — host == default == +mos-a16 == +mos-xy16, -verify clean.