HDR Additive Bloom
Rendering & Graphics
Six drifting glows summed per cell on a Super Nintendo using saturating
(overflow-checked) addition — where the lights pile up the field blows out to white
instead of wrapping, the high-dynamic-range "bloom" look, done entirely in 8-bit integers via
__builtin_add_overflow. Runs automatically; no joypad needed. Written in C and
compiled with the llvm-mos-based 65816
toolchain (+mos-a16, 16-bit accumulator mode).
Self-running demo — the lights drift and blow out on their own.
Click the screen to focus, then watch. Tab away and it pauses.
What it is
Each of six lights stamps a soft radial glow into an 8-bit intensity field every frame. The glows are added together — but with a twist: the add saturates. Instead of a byte wrapping from 255 back to 0 (which would make bright spots suddenly go dark), the add detects the overflow and clamps to 255:
static inline uint8_t sat_add8(uint8_t a, uint8_t b) {
uint8_t r;
return __builtin_add_overflow(a, b, &r) ? 0xFF : r; // ← adc; bcs
}
// per light, per kernel cell in its footprint:
field[y*W + x] = sat_add8(field[y*W + x], glow[...]); // overlaps clamp to white The field is then mapped through a black → blue → magenta → orange → white ramp. Isolated lights show the falloff colours; where two or more overlap, the sum pins at 255 and the ramp tops out at pure white — exactly the "blown-out highlight" of HDR bloom, with no floating point anywhere.
Compiler stress-test
| Item | What it exercises |
|---|---|
| __builtin_add_overflow | The saturating add: sum two bytes, and if the add carries out (would exceed 255) clamp to 255 instead of wrapping. Lowers to an add-with-carry then a carry-flag branch. |
| adc; bcs | On the 65816 the overflow check is a carry-out test — `adc` (add with carry) then `bcs` (branch if carry set) to the clamp. A flag-testing add sequence no other battery demo runs. |
| HDR / bloom | Because the adds saturate, regions where several glows overlap pile up past 255 and pin at pure white — the "blown-out highlight" look of high-dynamic-range bloom, done in 8-bit integers. |
| rep/sep | Mode-switch brackets mark 16-bit accumulator sections under +mos-a16 (the Q4 light-position math). No 32-bit multiply or divide on the hot path — this is a flag/control test. |
Overflow-checked / saturating arithmetic is a flag-testing add sequence — carry and
overflow flags tested and branched on — that no earlier demo in the battery exercised (their
adds either can't overflow in range or wrap silently). It compiles correctly here: the
__builtin_add_overflow lowers to adc + a carry branch across the
default 8-bit, +mos-a16 and +mos-xy16 backends, all
-verify-machineinstrs clean.
Written in C with the llvm-mos 65816 toolchain and verified against bsnes-jg
(and MAME where the SPC700 IPL is present). Hit Verify fidelity to reproduce the build
gate's WRAM assert (gate CRC 0xF951 — a rotate-XOR fold of the clamped-cell count
+ a field sample) live in this tab. No far pointers — the same source passes every way: host ==
default == +mos-a16 == +mos-xy16 == bsnes-jg.