code wiki / (root) / nx_worldgen.nx

nx_worldgen.nx source

↩ module page · 483 lines · 26086 B

1// nx_worldgen.nx -- ★SOVEREIGN INFINIGEN, RUNG 1: procedural NATURE (operator 2026-07-08, sharing princeton-vl/ 2// infinigen: "build a WORLD full of living people, animals, environments, weather"). Infinigen = seed->procedural 3// photoreal 3D, NO ML, NO external assets -- EXACTLY our doctrine. This is the nature/"hello world" module: a 4// seed grows a whole LANDSCAPE -- fBm terrain (grass/rock/snow by height+slope) + water (lakes/sea) + sky gradient 5// + sun + procedural clouds + atmospheric fog. All INTEGER, sovereign, our own heightfield ray-marcher. Different 6// seed = different world; a weather param retints sun/sky/fog (clear / sunset / overcast). license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_itrig.nx" 9const WG_MAGIC_374761393: i64 = 374761393 10const WG_MAGIC_668265263: i64 = 668265263 11const WG_MAGIC_65536: i64 = 65536 12const WG_MAGIC_4000: i64 = 4000 13const WG_MAGIC_1024: i64 = 1024 14const WG_MAGIC_32768: i64 = 32768 15const WG_MAGIC_2900: i64 = 2900 16const WG_MAGIC_1048576: i64 = 1048576 17const WG_MAGIC_3000: i64 = 3000 18const WG_MAGIC_40000: i64 = 40000 19const WG_MAGIC_1050: i64 = 1050 20const WG_MAGIC_4096: i64 = 4096 21const WG_MAGIC_9999: i64 = 9999 22const WG_MAGIC_60000: i64 = 60000 23const WG_MAGIC_2000000000: i64 = 2000000000 24const WG_MAGIC_1800: i64 = 1800 25const WG_MAGIC_1500: i64 = 1500 26const WG_MAGIC_1350: i64 = 1350 27const WG_MAGIC_1100: i64 = 1100 28 29const WG_W: i64 = 1280 // 2x render -> the page downscales it = free anti-aliasing 30const WG_H: i64 = 768 31const WG_FOCAL: i64 = 720 32const WG_HORIZON: i64 = 92 // shifts the horizon down (look slightly over the land) 33const WATER: i64 = 0 // water level (world units) 34const HSCALE: i64 = 4600 35const SNOW: i64 = 2620 36 37func wg_isqrt(v: i64) -> i64 { if v<=0 {return 0} var x: i64=v; var y: i64=(x+1)/2; while y<x {x=y; y=(x+v/x)/2} return x } 38func wg_abs(v: i64) -> i64 { if v<0 {return 0-v} return v } 39func wg_min(a: i64, b: i64) -> i64 { if a<b {return a} return b } 40func wg_max(a: i64, b: i64) -> i64 { if a>b {return a} return b } 41func wg_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v } 42 43func wg_hash(ix: i64, iz: i64, seed: i64) -> i64 { 44 var h: i64 = (ix + seed*7)*WG_MAGIC_374761393 + (iz - seed*3)*WG_MAGIC_668265263 + ix*iz*97 + seed*13 45 if h < 0 { h = 0 - h } 46 return h % WG_MAGIC_65536 47} 48func wg_smooth(t: i64) -> i64 { return t*t*(768 - 2*t)/WG_MAGIC_65536 } // smoothstep, t in 0..256 -> 0..256 49func wg_vnoise(x256: i64, z256: i64, seed: i64) -> i64 { 50 let ix: i64 = x256 >> 8; let iz: i64 = z256 >> 8 51 let fx: i64 = x256 & 255; let fz: i64 = z256 & 255 52 let sx: i64 = wg_smooth(fx); let sz: i64 = wg_smooth(fz) 53 let v00: i64 = wg_hash(ix,iz,seed); let v10: i64 = wg_hash(ix+1,iz,seed) 54 let v01: i64 = wg_hash(ix,iz+1,seed); let v11: i64 = wg_hash(ix+1,iz+1,seed) 55 let a: i64 = v00 + (v10-v00)*sx/256 56 let b: i64 = v01 + (v11-v01)*sx/256 57 return a + (b-a)*sz/256 58} 59// fractal Brownian motion -> 0..1024 60func wg_fbm(wx: i64, wz: i64, seed: i64) -> i64 { 61 let cx: i64 = wx*256/WG_MAGIC_4000; let cz: i64 = wz*256/WG_MAGIC_4000 62 var sum: i64 = 0; var amp: i64 = 512; var norm: i64 = 0; var o: i64 = 0 63 while o < 5 { 64 sum = sum + wg_vnoise(cx << o, cz << o, seed + o*131) * amp / WG_MAGIC_65536 65 norm = norm + amp; amp = amp/2; o = o + 1 66 } 67 return sum*WG_MAGIC_1024/norm 68} 69func wg_terrain_h(wx: i64, wz: i64, seed: i64) -> i64 { return (wg_fbm(wx,wz,seed) - 402) * HSCALE / WG_MAGIC_1024 } 70 71// weather -> params array [sundx,sundy,sundz(fx1024 unit), sunr,sung,sunb, skyzr,skyzg,skyzb, skyhr,skyhg,skyhb, fog, cloud] 72func wg_weather(mode: i64, W: *i64) -> i64 { 73 // default CLEAR day: sun upper-right 74 W[0]=520; W[1]=620; W[2]=560; W[3]=255; W[4]=248; W[5]=228 75 W[6]=64; W[7]=120; W[8]=210; W[9]=176; W[10]=205; W[11]=232; W[12]=44; W[13]=42 76 if mode == 1 { // SUNSET: low warm sun, warm sky 77 W[0]=780; W[1]=180; W[2]=560; W[3]=255; W[4]=170; W[5]=96 78 W[6]=40; W[7]=70; W[8]=150; W[9]=250; W[10]=150; W[11]=96; W[12]=60; W[13]=54 79 } 80 if mode == 2 { // OVERCAST: high diffuse, grey sky, heavy fog+cloud 81 W[0]=300; W[1]=760; W[2]=400; W[3]=210; W[4]=212; W[5]=214 82 W[6]=150; W[7]=158; W[8]=168; W[9]=196; W[10]=200; W[11]=205; W[12]=90; W[13]=110 83 } 84 let l: i64 = wg_isqrt(W[0]*W[0]+W[1]*W[1]+W[2]*W[2]) 85 if l > 0 { W[0]=W[0]*WG_MAGIC_1024/l; W[1]=W[1]*WG_MAGIC_1024/l; W[2]=W[2]*WG_MAGIC_1024/l } 86 return 0 87} 88 89// sun penumbra at a surface point (the soft-shadow march, shared by the pixel loop AND the GI cache): march 90// toward the sun tracking min(clearance/dist); 0 = fully shadowed .. 1024 = fully lit. Wp = weather (sun dir). 91func wg_sun_pen(seed: i64, hx: i64, hy: i64, hz: i64, Wp: *i64) -> i64 { 92 var pen: i64 = WG_MAGIC_1024 93 var sh2: i64 = 300 94 var ss: i64 = 0 95 while ss < 30 { 96 let qx: i64 = hx + Wp[0]*sh2/WG_MAGIC_1024 97 let qy: i64 = hy + Wp[1]*sh2/WG_MAGIC_1024 98 let qz: i64 = hz + Wp[2]*sh2/WG_MAGIC_1024 99 let clr: i64 = qy - wg_terrain_h(qx, qz, seed) + 10 100 if clr < 0 { pen = 0; ss = 999 } 101 else { 102 let p2: i64 = clr*WG_MAGIC_32768/sh2 103 if p2 < pen { pen = p2 } 104 sh2 = sh2 + 160 + sh2/9 105 if qy > WG_MAGIC_2900 { ss = 999 } 106 } 107 if ss != 999 { ss = ss + 1 } 108 } 109 if pen > WG_MAGIC_1024 { pen = WG_MAGIC_1024 } 110 return pen 111} 112 113// ★R3 GI: a SINGLE-BOUNCE IRRADIANCE CACHE (the classic technique, integer): a coarse world grid stores each 114// cell's SUN-LIT outgoing radiance (albedo x direct light); pixels gather from nearby cells with cosine + falloff 115// weighting -> coloured bounce light (sunlit grass bleeds green into shade). HONEST LABEL: one bounce, no 116// bounce-visibility test, coarse cells -- an approximation, not path tracing. wg_set_gi(0) disables (byte- 117// identical off path). 118const GI_N: i64 = 96 // cells per axis 119const GI_CS: i64 = 500 // world units per cell 120const GI_X0: i64 = 0 - 24000 // grid origin (covers the visible near field) 121const GI_Z0: i64 = 0 122static WG_GION: i64 123static WG_GIC: i64 // cache ptr: GI_N*GI_N cells x 2 i64 {packed rgb radiance, height} 124func wg_set_gi(on: i64) -> i64 { WG_GION = on; return 0 } 125func wg_gi_build(seed: i64, biome: i64, Wp: *i64) -> i64 { 126 if WG_GIC == 0 { WG_GIC = sys_mmap(GI_N*GI_N*2*8) as i64 } 127 let C: *i64 = WG_GIC as *i64 128 var j: i64 = 0 129 while j < GI_N { 130 var i: i64 = 0 131 while i < GI_N { 132 let wx: i64 = GI_X0 + i*GI_CS + GI_CS/2 133 let wz: i64 = GI_Z0 + j*GI_CS + GI_CS/2 134 let hh: i64 = wg_terrain_h(wx, wz, seed) 135 // cell normal (coarse) 136 let e: i64 = 120 137 let hl: i64 = wg_terrain_h(wx-e, wz, seed); let hr2: i64 = wg_terrain_h(wx+e, wz, seed) 138 let hd: i64 = wg_terrain_h(wx, wz-e, seed); let hu: i64 = wg_terrain_h(wx, wz+e, seed) 139 var nx: i64 = (hl-hr2)*WG_MAGIC_1024/(2*e); var ny: i64 = WG_MAGIC_1024; var nz: i64 = (hd-hu)*WG_MAGIC_1024/(2*e) 140 let nl: i64 = wg_isqrt(nx*nx+ny*ny+nz*nz) 141 if nl > 0 { nx=nx*WG_MAGIC_1024/nl; ny=ny*WG_MAGIC_1024/nl; nz=nz*WG_MAGIC_1024/nl } 142 // cell albedo (low-frequency biome palette: grass/rock/sand/snow by height+slope, no speckle) 143 var cr: i64 = 70; var cg: i64 = 104; var cb: i64 = 50 144 if biome == 1 { cr=196; cg=160; cb=110 } 145 if biome == 2 { cr=214; cg=224; cb=236 } 146 if biome == 3 { cr=150; cg=104; cb=44 } 147 var snowline: i64 = SNOW 148 if biome == 2 { snowline = 300 } 149 if ny < 640 { cr=118; cg=104; cb=94 } 150 if biome != 1 { if hh > snowline { if ny > 600 { cr=234; cg=240; cb=248 } } } 151 if hh < WATER { cr=24; cg=74; cb=116 } 152 // direct sun radiance at the cell (Lambert x penumbra), plus a small ambient floor 153 var nd: i64 = (nx*Wp[0]+ny*Wp[1]+nz*Wp[2])/WG_MAGIC_1024 154 if nd < 0 { nd = 0 } 155 var pen: i64 = WG_MAGIC_1024 156 if hh >= WATER { pen = wg_sun_pen(seed, wx, hh+14, wz, Wp) } 157 let lit: i64 = 20 + nd*95*pen/WG_MAGIC_1048576 158 var rr: i64 = cr*lit/100 159 var rg: i64 = cg*lit/100 160 var rb: i64 = cb*lit/100 161 if rr > 255 { rr = 255 } 162 if rg > 255 { rg = 255 } 163 if rb > 255 { rb = 255 } 164 C[(j*GI_N+i)*2] = rr + rg*256 + rb*WG_MAGIC_65536 165 C[(j*GI_N+i)*2+1] = hh 166 i = i + 1 167 } 168 j = j + 1 169 } 170 return 0 171} 172// gather bounce irradiance at a surface point with unit normal (nx,ny,nz fx1024). out[0..2] = rgb irradiance. 173func wg_gi_gather(hx: i64, hy: i64, hz: i64, nx: i64, ny: i64, nz: i64, out: *i64) -> i64 { 174 out[0]=0; out[1]=0; out[2]=0 175 if WG_GION == 0 { return 0 } 176 if WG_GIC == 0 { return 0 } 177 let C: *i64 = WG_GIC as *i64 178 let ci: i64 = (hx - GI_X0) / GI_CS 179 let cj: i64 = (hz - GI_Z0) / GI_CS 180 if ci < 2 { return 0 } 181 if cj < 2 { return 0 } 182 if ci > GI_N-3 { return 0 } 183 if cj > GI_N-3 { return 0 } 184 var sr: i64 = 0 185 var sg: i64 = 0 186 var sb: i64 = 0 187 var wsum: i64 = 0 188 var oj: i64 = 0 - 2 189 while oj <= 2 { 190 var oi: i64 = 0 - 2 191 while oi <= 2 { 192 var ring: i64 = oi 193 if ring < 0 { ring = 0 - ring } 194 var aj: i64 = oj 195 if aj < 0 { aj = 0 - aj } 196 if aj > ring { ring = aj } 197 if ring >= 1 { // exclude the self cell; use rings 1-2 198 let ii: i64 = ci + oi 199 let jj: i64 = cj + oj 200 let crad: i64 = C[(jj*GI_N+ii)*2] 201 let chh: i64 = C[(jj*GI_N+ii)*2+1] 202 let dxg: i64 = (GI_X0 + ii*GI_CS + GI_CS/2) - hx 203 let dyg: i64 = chh - hy 204 let dzg: i64 = (GI_Z0 + jj*GI_CS + GI_CS/2) - hz 205 let dl: i64 = wg_isqrt(dxg*dxg + dyg*dyg + dzg*dzg) 206 if dl > 60 { 207 var cosr: i64 = (nx*dxg + ny*dyg + nz*dzg)/dl // fx1024 cos at the receiver 208 if cosr > 0 { 209 let fall: i64 = GI_CS*WG_MAGIC_1024/(GI_CS + dl) // gentle distance falloff (fx1024) 210 let w: i64 = cosr*fall/WG_MAGIC_1024 211 sr = sr + (crad & 255)*w 212 sg = sg + ((crad >> 8) & 255)*w 213 sb = sb + ((crad >> 16) & 255)*w 214 wsum = wsum + WG_MAGIC_1024 215 } 216 } 217 } 218 oi = oi + 1 219 } 220 oj = oj + 1 221 } 222 if wsum == 0 { return 0 } 223 out[0] = sr/wsum 224 out[1] = sg/wsum 225 out[2] = sb/wsum 226 return 0 227} 228 229func wg_sky(dx: i64, dy: i64, dz: i64, Wp: *i64, oc: *i64) -> i64 { 230 var up: i64 = dy; if up<0 {up=0} 231 let zr: i64 = Wp[6]; let zg: i64 = Wp[7]; let zb: i64 = Wp[8] 232 let hr: i64 = Wp[9]; let hg: i64 = Wp[10]; let hb: i64 = Wp[11] 233 var r: i64 = hr + (zr-hr)*up/WG_MAGIC_1024; var g: i64 = hg + (zg-hg)*up/WG_MAGIC_1024; var b: i64 = hb + (zb-hb)*up/WG_MAGIC_1024 234 // sun glow + disk 235 let sd: i64 = (dx*Wp[0]+dy*Wp[1]+dz*Wp[2])/WG_MAGIC_1024 236 if sd > 800 { 237 let gl: i64 = (sd-800)*100/224 238 r = r + (Wp[3]-r)*gl/100; g = g + (Wp[4]-g)*gl/100; b = b + (Wp[5]-b)*gl/100 239 } 240 if sd > 1012 { r=Wp[3]; g=Wp[4]; b=Wp[5] } 241 // procedural clouds (fBm on the ray projected to a high plane) 242 if dy > 40 { 243 let px: i64 = dx*WG_MAGIC_3000/dy; let pz: i64 = dz*WG_MAGIC_3000/dy 244 let c: i64 = wg_fbm(px+WG_MAGIC_40000, pz+WG_MAGIC_40000, 7) 245 let thr: i64 = WG_MAGIC_1024 - Wp[13]*5 246 if c > thr { 247 let cf: i64 = wg_min((c-thr)*100/200, 100) * up/WG_MAGIC_1024 248 r = r + (238-r)*cf/100; g = g + (240-g)*cf/100; b = b + (242-b)*cf/100 249 } 250 } 251 oc[0]=wg_clamp(r,0,255); oc[1]=wg_clamp(g,0,255); oc[2]=wg_clamp(b,0,255) 252 return 0 253} 254 255// ★R1 DIVERSITY: BIOMES (census critic: "1 fBm biome family"). biome: 0 TEMPERATE (the original) · 1 DESERT 256// (sand/red-rock, no snow) · 2 ARCTIC (snow-dominant, ice water) · 3 AUTUMN (warm foliage). Same terrain 257// machinery; a biome = a palette + snowline row. 258// ★R2 GT ANNOTATIONS: the renderer emits CV ground truth alongside the image (their GroundTruthAnnotations 259// use-case): seg (0 sky / 1 terrain / 2 water), nrm (surface normal packed rgb: 128 + n*127/1024 per axis; 260// 0 for sky), depth (hit distance; BIG for sky). Occlusion boundaries derive from depth discontinuities. 261// ★R4 CAMERA RIG: cam = [dcamx, dcamy, dcamz, yaw] offsets/orientation over the auto terrain-following base 262// (cam 0/absent -> the original fixed +z view, byte-identical). A trajectory is a sequence of cam vectors -> 263// animation; reprojecting a pixel's world point through a second cam -> exact optical-flow GT (see wg_project). 264// render a world. Writes fb (WG_W*WG_H) + depth + seg + nrm. 265func wg_cam_base_y(seed: i64) -> i64 { return wg_max(WATER, wg_terrain_h(0,0,seed)) + WG_MAGIC_1050 } 266func worldgen_render_full(seed: i64, mode: i64, biome: i64, cam: *i64, fb: *i64, depth: *i64, seg: *i64, nrm: *i64) -> i64 { 267 let Wp: *i64 = sys_mmap(32*8) as *i64 268 wg_weather(mode, Wp) 269 if WG_GION == 1 { wg_gi_build(seed, biome, Wp) } // R3: refresh the bounce cache for this frame 270 let gio: *i64 = sys_mmap(32) as *i64 271 let oc: *i64 = sys_mmap(32) as *i64 272 let camx: i64 = cam[0] 273 let camy: i64 = wg_cam_base_y(seed) + cam[1] 274 let camz0: i64 = cam[2] 275 let yaw: i64 = cam[3] 276 let sy4: i64 = it_sin4096(yaw) 277 let cy4: i64 = it_cos4096(yaw) 278 var py: i64 = 0 279 while py < WG_H { 280 var px: i64 = 0 281 while px < WG_W { 282 let sxo: i64 = px - WG_W/2 283 let syo: i64 = (WG_H/2 - py) - WG_HORIZON 284 var dx: i64 = WG_FOCAL*sy4/WG_MAGIC_4096 + sxo*cy4/WG_MAGIC_4096 285 var dy: i64 = syo 286 var dz: i64 = WG_FOCAL*cy4/WG_MAGIC_4096 - sxo*sy4/WG_MAGIC_4096 287 let dl: i64 = wg_isqrt(dx*dx+dy*dy+dz*dz) 288 dx = dx*WG_MAGIC_1024/dl; dy = dy*WG_MAGIC_1024/dl; dz = dz*WG_MAGIC_1024/dl 289 // march the heightfield 290 var t: i64 = 200 291 var hit: i64 = 0 292 var hx: i64 = 0; var hy: i64 = 0; var hz: i64 = 0; var hh: i64 = 0 293 var step: i64 = 0 294 while step < 220 { 295 let wx: i64 = camx + dx*t/WG_MAGIC_1024 296 let wy: i64 = camy + dy*t/WG_MAGIC_1024 297 let wz: i64 = camz0 + dz*t/WG_MAGIC_1024 298 let th: i64 = wg_terrain_h(wx, wz, seed) 299 if wy < th { hit=1; hx=wx; hy=wy; hz=wz; hh=th; step=WG_MAGIC_9999 } 300 else { t = t + 55 + t/48; if t > WG_MAGIC_60000 { step=WG_MAGIC_9999 } } 301 if step != WG_MAGIC_9999 { step = step + 1 } 302 } 303 var r: i64 = 0; var g: i64 = 0; var b: i64 = 0 304 // water intercept (ray crosses y=WATER going down) 305 var twater: i64 = 0 306 if dy < 0 { twater = (WATER - camy)*WG_MAGIC_1024/dy } 307 let water_in_front: i64 = (twater > 0) & ((hit == 0) | (twater < t)) 308 // decide surface 309 var surf: i64 = 0 // 0 sky, 1 terrain, 2 water 310 if hit == 1 { if hh >= WATER { surf = 1 } } 311 if (surf == 0) & (water_in_front == 1) { surf = 2 } 312 if (hit == 1) & (hh < WATER) & (water_in_front == 1) { surf = 2 } 313 314 var dpt: i64 = WG_MAGIC_2000000000 315 if surf == 1 { dpt = t } 316 if surf == 2 { dpt = twater } 317 depth[py*WG_W+px] = dpt 318 seg[py*WG_W+px] = surf // GT: 0 sky / 1 terrain / 2 water 319 var nrmv: i64 = 0 // GT normal (sky = 0) 320 if surf == 2 { nrmv = 128 + 255*256 + 128*WG_MAGIC_65536 } // water: straight up 321 nrm[py*WG_W+px] = nrmv 322 323 if surf == 1 { 324 // terrain normal 325 let e: i64 = 24 326 let hl: i64 = wg_terrain_h(hx-e, hz, seed); let hr2: i64 = wg_terrain_h(hx+e, hz, seed) 327 let hd: i64 = wg_terrain_h(hx, hz-e, seed); let hu: i64 = wg_terrain_h(hx, hz+e, seed) 328 var nx: i64 = (hl-hr2)*WG_MAGIC_1024/(2*e); var ny: i64 = WG_MAGIC_1024; var nz: i64 = (hd-hu)*WG_MAGIC_1024/(2*e) 329 // micro-relief bump from fine noise -> surface texture caught by the lighting (not a smooth blob) 330 let bb0: i64 = wg_vnoise((hx+6)*256/55, hz*256/55, seed+31) - wg_vnoise((hx-6)*256/55, hz*256/55, seed+31) 331 let bb1: i64 = wg_vnoise(hx*256/55, (hz+6)*256/55, seed+31) - wg_vnoise(hx*256/55, (hz-6)*256/55, seed+31) 332 nx = nx - bb0*5/100; nz = nz - bb1*5/100 333 let nl: i64 = wg_isqrt(nx*nx+ny*ny+nz*nz) 334 // GT normal (unit, packed rgb) -- written before shading consumes nx/ny/nz 335 if nl > 0 { 336 let ux2: i64 = nx*WG_MAGIC_1024/nl 337 let uy2: i64 = ny*WG_MAGIC_1024/nl 338 let uz2: i64 = nz*WG_MAGIC_1024/nl 339 nrm[py*WG_W+px] = (128 + ux2*127/WG_MAGIC_1024) + (128 + uy2*127/WG_MAGIC_1024)*256 + (128 + uz2*127/WG_MAGIC_1024)*WG_MAGIC_65536 340 } 341 if nl>0 { nx=nx*WG_MAGIC_1024/nl; ny=ny*WG_MAGIC_1024/nl; nz=nz*WG_MAGIC_1024/nl } 342 var nd: i64 = (nx*Wp[0]+ny*Wp[1]+nz*Wp[2])/WG_MAGIC_1024 // fx1024 Lambert (0..WG_MAGIC_1024) 343 if nd<0 {nd=0} 344 // ★P3 SOFT SHADOWS (penumbra): the shared sun-march helper (also feeds the GI cache) -- 345 // edges soften with occluder distance; only DIRECT light is occluded (ambient stays). 346 let pen: i64 = wg_sun_pen(seed, hx, hy, hz, Wp) 347 // ★P3 r2 SKY-VISIBILITY ambient (cheap GI): surrounding ridges block skylight -> valleys and 348 // hollows receive less ambient. Horizon slope sampled 4 directions x 3 distances; sv 0..1024. 349 var slmax: i64 = 0 350 var sd2: i64 = 0 351 while sd2 < 4 { 352 var ddx: i64 = 0 353 var ddz: i64 = 0 354 if sd2 == 0 { ddx = 1 } 355 if sd2 == 1 { ddx = 0-1 } 356 if sd2 == 2 { ddz = 1 } 357 if sd2 == 3 { ddz = 0-1 } 358 var dq: i64 = 200 359 while dq <= WG_MAGIC_1800 { 360 let th2: i64 = wg_terrain_h(hx + ddx*dq, hz + ddz*dq, seed) 361 let sl: i64 = (th2 - hy) * WG_MAGIC_1024 / dq 362 if sl > slmax { slmax = sl } 363 dq = dq * 3 364 } 365 sd2 = sd2 + 1 366 } 367 if slmax > WG_MAGIC_1024 { slmax = WG_MAGIC_1024 } 368 var sv: i64 = WG_MAGIC_1024 - slmax*6/10 369 if sv < 420 { sv = 420 } 370 let lit: i64 = 42*sv/WG_MAGIC_1024 + nd*82*pen/WG_MAGIC_1048576 // sky-vis ambient + penumbra-scaled direct 371 // base colour by BIOME, with per-location vegetation variation 372 let nv2: i64 = wg_vnoise(hx*256/WG_MAGIC_1500, hz*256/WG_MAGIC_1500, seed+99) 373 var cr: i64 = 60 + nv2*44/WG_MAGIC_65536; var cg: i64 = 94 + nv2*50/WG_MAGIC_65536; var cb: i64 = 42 + nv2*22/WG_MAGIC_65536 374 var rockr: i64 = 112; var rockg: i64 = 101; var rockb: i64 = 92 375 var snowline: i64 = SNOW 376 var snowon: i64 = 1 377 if biome == 1 { // DESERT: sand base, red rock, no snow 378 cr = 188 + nv2*36/WG_MAGIC_65536; cg = 154 + nv2*30/WG_MAGIC_65536; cb = 104 + nv2*18/WG_MAGIC_65536 379 rockr = 152; rockg = 96; rockb = 66 380 snowon = 0 381 } 382 if biome == 2 { // ARCTIC: snow base, blue-grey rock 383 cr = 212 + nv2*24/WG_MAGIC_65536; cg = 222 + nv2*20/WG_MAGIC_65536; cb = 234 + nv2*14/WG_MAGIC_65536 384 rockr = 96; rockg = 106; rockb = 120 385 snowline = 300 386 } 387 if biome == 3 { // AUTUMN: warm mixed foliage 388 cr = 128 + nv2*70/WG_MAGIC_65536; cg = 84 + nv2*44/WG_MAGIC_65536; cb = 30 + nv2*16/WG_MAGIC_65536 389 rockr = 118; rockg = 100; rockb = 86 390 } 391 // alpine: higher -> browner (vegetation thins out); skip where base is already snow/sand 392 if biome == 0 { if hh > WG_MAGIC_1350 { let m: i64 = wg_min((hh-WG_MAGIC_1350)*100/WG_MAGIC_1100, 100); cr=cr+(124-cr)*m/100; cg=cg+(110-cg)*m/100; cb=cb+(94-cb)*m/100 } } 393 if biome == 3 { if hh > WG_MAGIC_1350 { let m: i64 = wg_min((hh-WG_MAGIC_1350)*100/WG_MAGIC_1100, 100); cr=cr+(124-cr)*m/100; cg=cg+(104-cg)*m/100; cb=cb+(88-cb)*m/100 } } 394 if ny < 640 { cr=rockr; cg=rockg; cb=rockb } // steep -> exposed rock 395 if hh < WATER+130 { cr=198; cg=186; cb=152 } // shoreline sand 396 if snowon == 1 { if (hh > snowline) & (ny > 600) { cr=234; cg=240; cb=248 } } // snow: high AND gentle 397 // fine surface speckle (grass blades / dirt / rock grain) 398 let tex2: i64 = wg_vnoise(hx*256/24, hz*256/24, seed+53) 399 let tv: i64 = (tex2-WG_MAGIC_32768)*26/WG_MAGIC_65536 400 cr = cr + tv; cg = cg + tv*11/10; cb = cb + tv*6/10 401 r = cr*lit/100; g = cg*lit/100; b = cb*lit/100 402 // ★R3 GI: gather single-bounce irradiance from the cache; couple through the receiver albedo 403 // (green light on green grass reinforces; green light on snow shows as a green tint -- physical) 404 wg_gi_gather(hx, hy, hz, nx, ny, nz, gio) 405 r = r + cr*gio[0]*3/512 406 g = g + cg*gio[1]*3/512 407 b = b + cb*gio[2]*3/512 408 b = b + (WG_MAGIC_1024-pen)*9/WG_MAGIC_1024 // shade is sky-lit -> subtle cool tint 409 // atmospheric fog toward horizon-sky by distance 410 let fog: i64 = wg_min(t*Wp[12]/WG_MAGIC_60000, 100) 411 r = r + (Wp[9]-r)*fog/100; g = g + (Wp[10]-g)*fog/100; b = b + (Wp[11]-b)*fog/100 412 } 413 if surf == 2 { 414 // water: deep blue blended with sky reflection + sun glint (arctic = icy pale) 415 wg_sky(dx, 0-dy, dz, Wp, oc) // reflected sky (mirror y) 416 var dwr: i64 = 24; var dwg: i64 = 74; var dwb: i64 = 116 417 if biome == 2 { dwr = 118; dwg = 160; dwb = 190 } 418 if biome == 1 { dwr = 30; dwg = 96; dwb = 104 } 419 r = (dwr + oc[0])/2; g = (dwg + oc[1])/2; b = (dwb + oc[2])/2 420 let sd: i64 = (dx*Wp[0]-dy*Wp[1]+dz*Wp[2])/WG_MAGIC_1024 421 if sd > 990 { r=wg_min(r+120,255); g=wg_min(g+110,255); b=wg_min(b+90,255) } 422 let fog: i64 = wg_min(twater*Wp[12]/WG_MAGIC_60000, 100) 423 r = r + (Wp[9]-r)*fog/100; g = g + (Wp[10]-g)*fog/100; b = b + (Wp[11]-b)*fog/100 424 } 425 if surf == 0 { wg_sky(dx, dy, dz, Wp, oc); r=oc[0]; g=oc[1]; b=oc[2] } 426 fb[py*WG_W+px] = wg_clamp(r,0,255) + wg_clamp(g,0,255)*256 + wg_clamp(b,0,255)*WG_MAGIC_65536 427 px = px + 1 428 } 429 py = py + 1 430 } 431 return 0 432} 433// ★R4 camera helpers (the inverse pair the flow GT reuses, so gate + renderer share exact math): 434// wg_ray = the normalized fx1024 ray direction for a pixel (depends only on pixel + yaw); 435// wg_project = screen coords of a world point through cam=[dx,dy,dz,yaw] (returns -1 in out[2] if behind). 436func wg_ray(px: i64, py: i64, yaw: i64, out: *i64) -> i64 { 437 let sy4: i64 = it_sin4096(yaw) 438 let cy4: i64 = it_cos4096(yaw) 439 let sxo: i64 = px - WG_W/2 440 let syo: i64 = (WG_H/2 - py) - WG_HORIZON 441 var dx: i64 = WG_FOCAL*sy4/WG_MAGIC_4096 + sxo*cy4/WG_MAGIC_4096 442 var dy: i64 = syo 443 var dz: i64 = WG_FOCAL*cy4/WG_MAGIC_4096 - sxo*sy4/WG_MAGIC_4096 444 let dl: i64 = wg_isqrt(dx*dx+dy*dy+dz*dz) 445 if dl > 0 { dx = dx*WG_MAGIC_1024/dl; dy = dy*WG_MAGIC_1024/dl; dz = dz*WG_MAGIC_1024/dl } 446 out[0]=dx; out[1]=dy; out[2]=dz 447 return 0 448} 449func wg_project(seed: i64, cam: *i64, Px: i64, Py: i64, Pz: i64, out: *i64) -> i64 { 450 let camx: i64 = cam[0] 451 let camy: i64 = wg_cam_base_y(seed) + cam[1] 452 let camz0: i64 = cam[2] 453 let yaw: i64 = cam[3] 454 let sy4: i64 = it_sin4096(yaw) 455 let cy4: i64 = it_cos4096(yaw) 456 let rx: i64 = Px - camx 457 let ry: i64 = Py - camy 458 let rz: i64 = Pz - camz0 459 let zc: i64 = (rx*sy4 + rz*cy4)/WG_MAGIC_4096 // forward distance 460 out[2] = 0 - 1 461 if zc <= 16 { return 0 } // behind the camera 462 let xc: i64 = (rx*cy4 - rz*sy4)/WG_MAGIC_4096 // right offset 463 out[0] = WG_W/2 + WG_FOCAL*xc/zc 464 out[1] = WG_H/2 - WG_HORIZON - WG_FOCAL*ry/zc 465 out[2] = zc 466 return 0 467} 468 469// back-compat wrappers: fixed camera / no annotations / temperate biome / no depth buffer 470func worldgen_render_bd(seed: i64, mode: i64, biome: i64, fb: *i64, depth: *i64) -> i64 { 471 let s: *i64 = sys_mmap(WG_W*WG_H*8) as *i64 472 let n: *i64 = sys_mmap(WG_W*WG_H*8) as *i64 473 let cam: *i64 = sys_mmap(4*8) as *i64 // [0,0,0,0] = the original fixed +z camera (identical) 474 return worldgen_render_full(seed, mode, biome, cam, fb, depth, s, n) 475} 476func worldgen_render_d(seed: i64, mode: i64, fb: *i64, depth: *i64) -> i64 { return worldgen_render_bd(seed, mode, 0, fb, depth) } 477func worldgen_render(seed: i64, mode: i64, fb: *i64) -> i64 { 478 let d: *i64 = sys_mmap(WG_W*WG_H*8) as *i64 479 worldgen_render_bd(seed, mode, 0, fb, d) 480 return 0 481} 482func wg_w() -> i64 { return WG_W } 483func wg_h() -> i64 { return WG_H }