code wiki / _hdl_build / nx_mesh_terrain_gate.nx

nx_mesh_terrain_gate.nx source

↩ module page · 202 lines · 7941 B

1// nx_mesh_terrain_gate.nx -- proves the renderer is NOT voxel-bound: a smooth TRIANGULATED heightfield mesh 2// (not cubes) on the same sovereign f32 raster path. Same value-noise terrain as the voxel world, but rendered 3// as a continuous low-poly surface: per-grid-point f32 height, 2 triangles per cell, slope-based flat shading, 4// height biomes, perspective + z-buffer. exit 0 = rendered. Writes mesh_terrain.bmp. license_tier: ORIGINAL 5import "nx_syscalls.nx" 6import "nx_f32_hw.nx" 7 8const W: i64 = 320 9const H: i64 = 240 10const HW: i64 = 160 11const HH: i64 = 120 12const GRID: i64 = 22 13const FOCAL: i64 = 340 14const PUSH: i64 = 40 15const ZFAR: i64 = 1073741824 16 17func imin(a: i64, b: i64) -> i64 { if a < b { return a } return b } 18func imax(a: i64, b: i64) -> i64 { if a > b { return a } return b } 19func min3(a: i64, b: i64, c: i64) -> i64 { return imin(a, imin(b, c)) } 20func max3(a: i64, b: i64, c: i64) -> i64 { return imax(a, imax(b, c)) } 21func clamp255(v: i64) -> i64 { if v < 0 { return 0 } if v > 255 { return 255 } return v } 22func same_sign3(a: i64, b: i64, c: i64) -> i64 { 23 if a >= 0 { if b >= 0 { if c >= 0 { return 1 } } } 24 if a <= 0 { if b <= 0 { if c <= 0 { return 1 } } } 25 return 0 26} 27func fratio(num: i64, den: i64) -> i64 { return f32_div(f32_of(num), f32_of(den)) } 28 29// smooth bilinear value noise -> centi-height (0..~500 = 0..5 world units). Continuous => smooth surface. 30func vlat(ix: i64, iz: i64) -> i64 { var n: i64 = (ix * 131 + iz * 197 + ix * iz * 13 + 1290) % 256; if n < 0 { n = n + 256 } return n } 31func hcenti(i: i64, j: i64) -> i64 { 32 let L: i64 = 5 33 let bx: i64 = i + 200 34 let bz: i64 = j + 200 35 let ix: i64 = bx / L 36 let iz: i64 = bz / L 37 let fx: i64 = (bx % L) * 256 / L 38 let fz: i64 = (bz % L) * 256 / L 39 let h00: i64 = vlat(ix, iz) 40 let h10: i64 = vlat(ix + 1, iz) 41 let h01: i64 = vlat(ix, iz + 1) 42 let h11: i64 = vlat(ix + 1, iz + 1) 43 let a: i64 = h00 * 256 + (h10 - h00) * fx 44 let b: i64 = h01 * 256 + (h11 - h01) * fx 45 return (a * 256 + (b - a) * fz) / 65536 * 2 // 0..510 46} 47// z-buffered flat-colour triangle (depth interpolated; no texture). 48func fill_flat(fb: *i64, zb: *i64, x0: i64, y0: i64, d0: i64, x1: i64, y1: i64, d1: i64, x2: i64, y2: i64, d2: i64, col: i64) -> i64 { 49 let area: i64 = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 50 if area == 0 { return 0 } 51 let minx: i64 = imax(0, min3(x0, x1, x2)) 52 let maxx: i64 = imin(W - 1, max3(x0, x1, x2)) 53 let miny: i64 = imax(0, min3(y0, y1, y2)) 54 let maxy: i64 = imin(H - 1, max3(y0, y1, y2)) 55 var py: i64 = miny 56 while py <= maxy { 57 var px: i64 = minx 58 while px <= maxx { 59 let e0: i64 = (x2 - x1) * (py - y1) - (y2 - y1) * (px - x1) 60 let e1: i64 = (x0 - x2) * (py - y2) - (y0 - y2) * (px - x2) 61 let e2: i64 = (x1 - x0) * (py - y0) - (y1 - y0) * (px - x0) 62 if same_sign3(e0, e1, e2) == 1 { 63 let d: i64 = (e0 * d0 + e1 * d1 + e2 * d2) / area 64 let idx: i64 = py * W + px 65 if d < zb[idx] { zb[idx] = d; fb[idx] = col } 66 } 67 px = px + 1 68 } 69 py = py + 1 70 } 71 return 0 72} 73// project world (f32 x, integer-centi height hy, f32 z) -> out [sx, sy, depth, ok]. 74func projh(R: *i64, i: i64, hy: i64, j: i64, out: *i64) -> i64 { 75 let v: *i64 = sys_mmap(32) as *i64 76 let r: *i64 = sys_mmap(32) as *i64 77 v[0] = f32_sub(f32_of(i), fratio(GRID, 2)) 78 v[1] = f32_sub(f32_div(f32_of(hy), f32_of(100)), f32_of(2)) 79 v[2] = f32_sub(f32_of(j), fratio(GRID, 2)) 80 v[3] = f32_of(0) 81 m4_vec4(R, v, r) 82 let pz: i64 = f32_add(r[2], f32_of(PUSH)) 83 if (pz & 0x80000000) != 0 { out[3] = 0; return 0 } 84 let zi: i64 = f32_int(f32_mul(pz, f32_of(64))) 85 if zi <= 0 { out[3] = 0; return 0 } 86 out[0] = HW + f32_int(f32_div(f32_mul(r[0], f32_of(FOCAL)), pz)) 87 out[1] = HH - f32_int(f32_div(f32_mul(r[1], f32_of(FOCAL)), pz)) 88 out[2] = zi 89 out[3] = 1 90 return 0 91} 92// biome colour by average centi-height, shaded by slope (flat=bright, steep=dark). 93func tri_color(ha: i64, hb: i64, hc: i64) -> i64 { 94 let avg: i64 = (ha + hb + hc) / 3 95 let spread: i64 = max3(ha, hb, hc) - min3(ha, hb, hc) 96 let bright: i64 = clamp255(235 - spread * 2) 97 var r: i64 = 96; var g: i64 = 172; var b: i64 = 76 // grass 98 if avg < 120 { r = 64; g = 116; b = 204 } // water 99 if avg >= 360 { r = 120; g = 116; b = 110 } // rock 100 if avg >= 450 { r = 236; g = 238; b = 245 } // snow 101 return ((r * bright) / 255) + ((g * bright) / 255) * 256 + ((b * bright) / 255) * 65536 102} 103func put_u32le(b: *u8, o: i64, v: i64) -> i64 { 104 b[o] = (v & 0xff) as u8 105 b[o + 1] = ((v >> 8) & 0xff) as u8 106 b[o + 2] = ((v >> 16) & 0xff) as u8 107 b[o + 3] = ((v >> 24) & 0xff) as u8 108 return 0 109} 110func write_bmp(fb: *i64, path: *u8) -> i64 { 111 let pix: i64 = W * H * 3 112 let total: i64 = 54 + pix 113 let b: *u8 = sys_mmap(total) as *u8 114 b[0] = 66 as u8 115 b[1] = 77 as u8 116 put_u32le(b, 2, total) 117 put_u32le(b, 10, 54) 118 put_u32le(b, 14, 40) 119 put_u32le(b, 18, W) 120 put_u32le(b, 22, H) 121 b[26] = 1 as u8 122 b[28] = 24 as u8 123 put_u32le(b, 34, pix) 124 var o: i64 = 54 125 var ry: i64 = 0 126 while ry < H { 127 let syrow: i64 = H - 1 - ry 128 var x: i64 = 0 129 while x < W { 130 let c: i64 = fb[syrow * W + x] 131 b[o] = ((c >> 16) & 0xff) as u8 132 b[o + 1] = ((c >> 8) & 0xff) as u8 133 b[o + 2] = (c & 0xff) as u8 134 o = o + 3 135 x = x + 1 136 } 137 ry = ry + 1 138 } 139 let fd: i64 = sys_openat_wr(path, 0x1a4) 140 if fd < 0 { return 0 - 1 } 141 sys_write(fd, b, total) 142 sys_close(fd) 143 return 0 144} 145 146func main() -> i64 { 147 let fb: *i64 = sys_mmap(W * H * 8) as *i64 148 let zb: *i64 = sys_mmap(W * H * 8) as *i64 149 let sky: i64 = 142 + 186 * 256 + 228 * 65536 150 var i: i64 = 0 151 while i < W * H { fb[i] = sky; zb[i] = ZFAR; i = i + 1 } 152 153 let Ry: *i64 = sys_mmap(128) as *i64 154 let Rx: *i64 = sys_mmap(128) as *i64 155 let R: *i64 = sys_mmap(128) as *i64 156 m4_roty(fratio(819, 1000), fratio(574, 1000), Ry) 157 m4_rotx(fratio(819, 1000), f32_neg(fratio(574, 1000)), Rx) 158 m4_mul(Rx, Ry, R) 159 160 // project every grid vertex once; store screen x,y,depth,ok + its centi-height. 161 let np: i64 = GRID * GRID 162 let vx: *i64 = sys_mmap(np * 8) as *i64 163 let vy: *i64 = sys_mmap(np * 8) as *i64 164 let vd: *i64 = sys_mmap(np * 8) as *i64 165 let vok: *i64 = sys_mmap(np * 8) as *i64 166 let vh: *i64 = sys_mmap(np * 8) as *i64 167 var j: i64 = 0 168 while j < GRID { 169 var ii: i64 = 0 170 while ii < GRID { 171 let g: i64 = j * GRID + ii 172 let hh: i64 = hcenti(ii, j) 173 let o: *i64 = sys_mmap(32) as *i64 174 projh(R, ii, hh, j, o) 175 vx[g] = o[0]; vy[g] = o[1]; vd[g] = o[2]; vok[g] = o[3]; vh[g] = hh 176 ii = ii + 1 177 } 178 j = j + 1 179 } 180 // 2 triangles per cell. 181 var cj: i64 = 0 182 while cj < GRID - 1 { 183 var ci: i64 = 0 184 while ci < GRID - 1 { 185 let a: i64 = cj * GRID + ci 186 let b: i64 = cj * GRID + ci + 1 187 let c: i64 = (cj + 1) * GRID + ci + 1 188 let dd: i64 = (cj + 1) * GRID + ci 189 if vok[a] == 1 { if vok[b] == 1 { if vok[c] == 1 { if vok[dd] == 1 { 190 let col1: i64 = tri_color(vh[a], vh[b], vh[c]) 191 fill_flat(fb, zb, vx[a], vy[a], vd[a], vx[b], vy[b], vd[b], vx[c], vy[c], vd[c], col1) 192 let col2: i64 = tri_color(vh[a], vh[c], vh[dd]) 193 fill_flat(fb, zb, vx[a], vy[a], vd[a], vx[c], vy[c], vd[c], vx[dd], vy[dd], vd[dd], col2) 194 } } } } 195 ci = ci + 1 196 } 197 cj = cj + 1 198 } 199 write_bmp(fb, "web_assets/_game_build/mesh_terrain.bmp" as *u8) 200 if fb[(H / 2) * W + (W / 2)] == sky { return 1 } 201 return 0 202}