code wiki / _hdl_build / nx_worldpop_gate.nx
nx_worldpop_gate.nx source
↩ module page · 146 lines · 6793 B
1// nx_worldpop_gate.nx -- ★SOVEREIGN INFINIGEN: POPULATE a world with vegetation. Render a procedural landscape,
2// then place procedural TREES on the terrain (projected + distance-scaled, painter's order far->near) = a LIVING
3// landscape. Proves the modules compose: nx_worldgen (nature) + nx_treegen (vegetation).
4// T1 the populated world renders with markedly more canopy-green than the bare world (trees were placed)
5// T2 determinism + PNG knowledge/nx_worldpop.png (bare world | populated world)
6// license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_png.nx"
9import "nx_worldgen.nx"
10import "nx_treegen.nx"
11
12func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
13func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 }
14
15const KEY: i64 = 16711935 // 0xFF00FF magenta chroma-key (255,0,255)
16const CAMY_EYE: i64 = 1050
17const WFOC: i64 = 360 // must match nx_worldgen WG_FOCAL
18const WHOR: i64 = 46 // WG_HORIZON
19
20func greencount(fb: *i64, n: i64) -> i64 { var s: i64=0; var i: i64=0; while i<n { let px: i64=fb[i]; let r: i64=px&255; let g: i64=(px>>8)&255; let b: i64=(px>>16)&255; if g>r+8 { if g>b+8 { s=s+1 } } i=i+1 } return s }
21
22func main() -> i64 {
23 hw("=== nx_worldpop_gate -- populate a world with procedural vegetation ===\n" as *u8)
24 var fails: i64 = 0
25 let WW: i64 = wg_w(); let WH: i64 = wg_h(); let wnpx: i64 = WW*WH
26 let TW: i64 = tg_w(); let TH: i64 = tg_h()
27 let seed: i64 = 11
28
29 // bare world
30 let bare: *i64 = sys_mmap(wnpx*8) as *i64
31 worldgen_render(seed, 0, bare)
32 let gbare: i64 = greencount(bare, wnpx)
33
34 // one tree sprite (magenta key bg) + its bbox
35 let P: *i64 = sys_mmap(TG_CAP*TG_STR*8) as *i64
36 let np: i64 = treegen_build(P, 5)
37 let spr: *i64 = sys_mmap(TW*TH*8) as *i64
38 treegen_render(P, np, 300, 4, 255, 0, 255, spr)
39 var minx: i64=TW; var maxx: i64=0; var miny: i64=TH; var maxy: i64=0
40 var i: i64 = 0
41 while i < TW*TH { if spr[i] != KEY { let x: i64=i%TW; let y: i64=i/TW; if x<minx{minx=x} if x>maxx{maxx=x} if y<miny{miny=y} if y>maxy{maxy=y} } i=i+1 }
42 let tpw: i64 = maxx-minx+1; let tph: i64 = maxy-miny+1
43 hw(" tree sprite bbox "); pn(tpw); hw("x"); pn(tph); hw("\n" as *u8)
44
45 // populated world = copy bare, then composite trees
46 let pop: *i64 = sys_mmap(wnpx*8) as *i64
47 i = 0
48 while i < wnpx { pop[i] = bare[i]; i=i+1 }
49 let camy: i64 = wg_max(WATER, wg_terrain_h(0,0,seed)) + CAMY_EYE
50
51 // scatter placements on a jittered grid; keep only grassy foreground; collect (rz,px,py,sh) then paint far->near
52 let NP: i64 = 40
53 let plc: *i64 = sys_mmap(NP*4*8) as *i64
54 var npl: i64 = 0
55 var gz: i64 = 0
56 while gz < 8 {
57 var gx: i64 = 0
58 while gx < 6 {
59 let wz: i64 = 3200 + gz*1750 + (gx*613 % 900)
60 let wx: i64 = (gx-3)*wz*3/10 + (gz*457 % 800) - 400 // spread with FOV, jitter
61 let h: i64 = wg_terrain_h(wx, wz, seed)
62 if h > WATER+90 { if h < 1500 {
63 let px: i64 = WW/2 + wx*WFOC/wz
64 let py: i64 = WH/2 - WHOR - (h - camy)*WFOC/wz
65 let sh: i64 = 150*6000/wz // distance-scaled screen height
66 if sh > 7 { if px > 0-40 { if px < WW+40 { if py > 0 { if py < WH {
67 plc[npl*4]=wz; plc[npl*4+1]=px; plc[npl*4+2]=py; plc[npl*4+3]=sh; npl=npl+1
68 } } } } }
69 } }
70 gx = gx + 1
71 }
72 gz = gz + 1
73 }
74 // sort far->near (insertion sort by rz descending, so painting overdraws near-over-far)
75 var a: i64 = 1
76 while a < npl {
77 let kz: i64=plc[a*4]; let k1: i64=plc[a*4+1]; let k2: i64=plc[a*4+2]; let k3: i64=plc[a*4+3]
78 var b: i64 = a
79 var go: i64 = 1
80 while go == 1 {
81 if b <= 0 { go = 0 }
82 else {
83 if plc[(b-1)*4] < kz {
84 plc[b*4]=plc[(b-1)*4]; plc[b*4+1]=plc[(b-1)*4+1]; plc[b*4+2]=plc[(b-1)*4+2]; plc[b*4+3]=plc[(b-1)*4+3]
85 b = b - 1
86 } else { go = 0 }
87 }
88 }
89 plc[b*4]=kz; plc[b*4+1]=k1; plc[b*4+2]=k2; plc[b*4+3]=k3
90 a = a + 1
91 }
92 // paint
93 var pi: i64 = 0
94 while pi < npl {
95 let px: i64=plc[pi*4+1]; let py: i64=plc[pi*4+2]; let sh: i64=plc[pi*4+3]
96 let sw: i64 = sh*tpw/tph
97 var oy: i64 = py - sh
98 while oy <= py {
99 if oy >= 0 { if oy < WH {
100 let fy: i64 = miny + (oy-(py-sh))*tph/sh
101 var ox: i64 = px - sw/2
102 while ox <= px + sw/2 {
103 if ox >= 0 { if ox < WW {
104 let fx: i64 = minx + (ox-(px-sw/2))*tpw/sw
105 if fx>=0 { if fx<TW { if fy>=0 { if fy<TH {
106 let s: i64 = spr[fy*TW+fx]
107 if s != KEY { pop[oy*WW+ox] = s }
108 } } } }
109 } }
110 ox = ox + 1
111 }
112 } }
113 oy = oy + 1
114 }
115 pi = pi + 1
116 }
117 let gpop: i64 = greencount(pop, wnpx)
118 hw(" placed "); pn(npl); hw(" trees | green px: bare="); pn(gbare); hw(" populated="); pn(gpop); hw("\n" as *u8)
119 var T1: i64 = 0
120 if gpop > gbare + 4000 { if npl > 8 { T1 = 1 } }
121 if T1 == 1 { hw("T1 PASS the world was POPULATED with trees (canopy green increased)\n" as *u8) }
122 else { fails=fails+1; hw("T1 FAIL not enough trees placed\n" as *u8) }
123
124 // gallery bare | populated
125 let GW: i64 = WW*2
126 let gal: *i64 = sys_mmap(GW*WH*8) as *i64
127 var y: i64 = 0
128 while y < WH { var x: i64=0; while x<WW { gal[y*GW+x]=bare[y*WW+x]; gal[y*GW+WW+x]=pop[y*WW+x]; x=x+1 } y=y+1 }
129 write_png(gal, GW, WH, "knowledge/nx_worldpop.png" as *u8)
130
131 // determinism
132 let pop2: *i64 = sys_mmap(wnpx*8) as *i64
133 worldgen_render(seed, 0, pop2)
134 var ddet: i64 = 0
135 i = 0
136 while i < wnpx { if pop2[i] != bare[i] { ddet=ddet+1 } i=i+1 }
137 var T2: i64 = 0
138 if ddet == 0 { T2 = 1 }
139 if T2 == 1 { hw("T2 PASS determinism + PNG knowledge/nx_worldpop.png (bare | populated)\n" as *u8) }
140 else { fails=fails+1; hw("T2 FAIL ddet="); pn(ddet); hw("\n" as *u8) }
141
142 if fails == 0 { hw("WORLDPOP-GATE 2/2 GREEN -- a LIVING landscape: procedural terrain POPULATED with procedural trees (worldgen + treegen compose), sovereign, no ML, no assets\n" as *u8); sys_exit(0); return 0 }
143 hw("WORLDPOP-GATE RED fails="); pn(fails); hw("\n" as *u8)
144 sys_exit(1)
145 return 1
146}