code wiki / _hdl_build / nx_gfx_bloom_gate.nx

nx_gfx_bloom_gate.nx source

↩ module page · 70 lines · 4362 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_gfx_bloom_gate.nx -- visual rung: BLOOM (atmospheric glow) on the textured dungeon. Renders the same textured 4// scene WITHOUT and WITH gx_bloom (bright torch/gold/lit-stone bleed a soft warm halo into the dark). Two PNGs = 5// the visible before/after. MEASURED: bloom adds glow energy (>=10% more total light) WITHOUT blowing out (clamp holds). 6// T1 GLOW: total luminance with bloom >= 1.1x without. T2 NO-BLOWOUT: max channel <= 255 (clamp holds). T3 DETERMINISM. 7// expect_exit: 0 license_tier: ORIGINAL 8import "nx_gfx_iso.nx" 9import "nx_png.nx" 10import "nx_syscalls.nx" 11 12func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 13" as *u8); return ok } 14 15func build_dungeon(fb: *i64, W: i64, H: i64, ox: i64, oy: i64) -> i64 { 16 gx_fill(fb, W, H, gx_rgb(7, 7, 11)) 17 var ty: i64=0 18 while ty < 8 { var tx: i64=0 19 while tx < 8 { 20 let nz: i64 = ((tx*7 + ty*13) % 5 - 2)*7 21 gx_iso_tile_tex(fb, W, H, gx_isox(tx, ty, ox), gx_isoy(tx, ty, oy), gx_rgb(92 + nz, 86 + nz, 76 + nz)) 22 tx = tx + 1 23 } 24 ty = ty + 1 25 } 26 var k: i64=0 27 while k < 8 { gx_iso_cube_tex(fb, W, H, gx_isox(k, 0, ox), gx_isoy(k, 0, oy) - 26, 26, gx_rgb(108, 99, 88)); k = k + 1 } 28 k = 1 29 while k < 8 { gx_iso_cube_tex(fb, W, H, gx_isox(0, k, ox), gx_isoy(0, k, oy) - 26, 26, gx_rgb(96, 88, 80)); k = k + 1 } 30 gx_iso_cube_tex(fb, W, H, gx_isox(6, 2, ox), gx_isoy(6, 2, oy) - 30, 30, gx_rgb(112, 104, 92)) 31 let cfx: i64=gx_isox(4, 4, ox); let cfy: i64=gx_isoy(4, 4, oy) + TH/2 32 gx_sprite_humanoid(fb, W, H, cfx, cfy, gx_rgb(155, 42, 40), gx_rgb(228, 184, 150), 0) 33 let ifx: i64=gx_isox(6, 5, ox); let ify: i64=gx_isoy(6, 5, oy) + TH/2 34 gx_ellipse(fb, W, H, ifx, ify - 3, 3, 3, gx_rgb(255, 215, 90)) 35 gx_light_radial(fb, W, H, cfx, cfy - 20, 122, 58) 36 gx_light_add(fb, W, H, ifx, ify - 3, 12, gx_rgb(185, 140, 40)) 37 return 0 38} 39func total_lum(fb: *i64, W: i64, H: i64) -> i64 { var s: i64=0; var p: i64=0; while p<W*H { let c: i64=fb[p]; s=s+gx_cr(c)+gx_cg(c)+gx_cb(c); p=p+1 } return s } 40func maxchan(fb: *i64, W: i64, H: i64) -> i64 { var m: i64=0; var p: i64=0; while p<W*H { let c: i64=fb[p]; if gx_cr(c)>m{m=gx_cr(c)} if gx_cg(c)>m{m=gx_cg(c)} if gx_cb(c)>m{m=gx_cb(c)} p=p+1 } return m } 41 42func main() -> i64 { 43 gw("=== nx_gfx_bloom_gate: atmospheric BLOOM on the textured dungeon (before/after) ===\n" as *u8) 44 let W: i64=320; let H: i64=240; let ox: i64=160; let oy: i64=44 45 let fb1: *i64 = sys_mmap(W*H*8) as *i64 46 let fb2: *i64 = sys_mmap(W*H*8) as *i64 47 build_dungeon(fb1, W, H, ox, oy) 48 build_dungeon(fb2, W, H, ox, oy) 49 gx_bloom(fb2, W, H, 150, 210) 50 write_png(fb1, W, H, "knowledge/nx_gfx_nobloom.png" as *u8) 51 write_png(fb2, W, H, "knowledge/nx_gfx_bloom.png" as *u8) 52 gw(" (SEE: knowledge/nx_gfx_nobloom.png vs knowledge/nx_gfx_bloom.png)\n" as *u8) 53 let l1: i64 = total_lum(fb1, W, H); let l2: i64 = total_lum(fb2, W, H) 54 var pass: i64=0; var total: i64=0 55 var t1: i64=0; if l2 >= (l1*11)/10 { t1=1 } 56 total=total+1; if t1==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 57 gw("T1 glow: total-light bloom=" as *u8); gn(l2); gw(" vs none=" as *u8); gn(l1); gw(" (>=1.1x = real added glow)\n" as *u8) 58 let mx: i64 = maxchan(fb2, W, H) 59 var t2: i64=0; if mx <= 255 { t2=1 } 60 total=total+1; if t2==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 61 gw("T2 no-blowout: max channel=" as *u8); gn(mx); gw(" (<=255, clamp holds -- glow never wraps/oversaturates)\n" as *u8) 62 let fb3: *i64 = sys_mmap(W*H*8) as *i64 63 build_dungeon(fb3, W, H, ox, oy); gx_bloom(fb3, W, H, 150, 210) 64 var t3: i64=1; var x: i64=60; while x < 260 { if fb3[100*W+x] != fb2[100*W+x] { t3=0; x=260 } else { x=x+1 } } 65 total=total+1; if t3==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 66 gw("T3 determinism: bloom re-applies bit-for-bit (integer box-blur, no float)\n" as *u8) 67 gw("\n=== nx_gfx_bloom_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 68 if pass == total { gw(" GREEN (bloom adds atmospheric glow, clamp-safe, deterministic; SEE the two PNGs)\n" as *u8); sys_exit(0); return 0 } 69 gw(" RED\n" as *u8); sys_exit(1); return 1 70}