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}