code wiki / _hdl_build / nx_f32_voxel_gate.nx

nx_f32_voxel_gate.nx source

↩ module page · 260 lines · 10087 B

1// nx_f32_voxel_gate.nx -- R4b/R4c: a PERSPECTIVE, TEXTURED, Z-BUFFERED procedural voxel LANDSCAPE on the 2// sovereign hardware-f32 software path (NishiLang -> nx_cc_sovereign(f32) -> nxasm -> native ELF; NO gcc/GPU/ 3// wasm/VM). Value-noise terrain, neighbour face-culling, height biomes (water/grass/stone/snow), directional 4// shade, f32 mat4 camera + f32 perspective divide, per-pixel z-buffer, 24-bit BMP out. exit 0 = rendered. 5// license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_f32_hw.nx" 8 9const W: i64 = 320 10const H: i64 = 240 11const HW: i64 = 160 12const HH: i64 = 120 13const N: i64 = 14 14const TN: i64 = 4 15const FOCAL: i64 = 300 16const PUSH: i64 = 24 17const ZFAR: i64 = 1073741824 18 19func imin(a: i64, b: i64) -> i64 { if a < b { return a } return b } 20func imax(a: i64, b: i64) -> i64 { if a > b { return a } return b } 21func min3(a: i64, b: i64, c: i64) -> i64 { return imin(a, imin(b, c)) } 22func max3(a: i64, b: i64, c: i64) -> i64 { return imax(a, imax(b, c)) } 23func iabs(a: i64) -> i64 { if a < 0 { return 0 - a } return a } 24func clamp255(v: i64) -> i64 { if v < 0 { return 0 } if v > 255 { return 255 } return v } 25func same_sign3(a: i64, b: i64, c: i64) -> i64 { 26 if a >= 0 { if b >= 0 { if c >= 0 { return 1 } } } 27 if a <= 0 { if b <= 0 { if c <= 0 { return 1 } } } 28 return 0 29} 30func fratio(num: i64, den: i64) -> i64 { return f32_div(f32_of(num), f32_of(den)) } 31 32// ---- procedural terrain: bilinear value noise, smooth rolling hills 1..6 ---- 33func lat(ix: i64, iz: i64) -> i64 { var n: i64 = (ix * 71 + iz * 191 + ix * iz * 7) % 6; if n < 0 { n = n + 6 } return n } 34func terrain_h(gx: i64, gz: i64) -> i64 { 35 let L: i64 = 4 36 let bx: i64 = gx + 200 37 let bz: i64 = gz + 200 38 let ix: i64 = bx / L 39 let iz: i64 = bz / L 40 let fx: i64 = (bx % L) * 256 / L 41 let fz: i64 = (bz % L) * 256 / L 42 let h00: i64 = lat(ix, iz) 43 let h10: i64 = lat(ix + 1, iz) 44 let h01: i64 = lat(ix, iz + 1) 45 let h11: i64 = lat(ix + 1, iz + 1) 46 let a: i64 = h00 * 256 + (h10 - h00) * fx 47 let b: i64 = h01 * 256 + (h11 - h01) * fx 48 var h: i64 = (a * 256 + (b - a) * fz) / 65536 + 1 49 if h < 1 { h = 1 } 50 if h > 6 { h = 6 } 51 return h 52} 53// neighbour height, but out-of-grid = 0 so the world's outer walls always draw. 54func hN(gx: i64, gz: i64) -> i64 { 55 if gx < 0 { return 0 } 56 if gz < 0 { return 0 } 57 if gx >= N { return 0 } 58 if gz >= N { return 0 } 59 return terrain_h(gx, gz) 60} 61// top-face biome colour by height, packed R+G*256+B*65536. 62func top_color(h: i64) -> i64 { 63 if h <= 1 { return 64 + 116 * 256 + 204 * 65536 } // water 64 if h >= 6 { return 236 + 238 * 256 + 245 * 65536 } // snow 65 if h == 5 { return 122 + 118 * 256 + 112 * 65536 } // rock 66 return 96 + 172 * 256 + 76 * 65536 // grass 67} 68func side_color(h: i64) -> i64 { 69 if h <= 1 { return 58 + 104 * 256 + 188 * 65536 } // water 70 if h >= 5 { return 110 + 106 * 256 + 100 * 65536 } // stone 71 return 134 + 98 * 256 + 60 * 65536 // dirt 72} 73 74func texel_col(baseR: i64, baseG: i64, baseB: i64, u: i64, v: i64, bright: i64) -> i64 { 75 let n: i64 = ((u * 7 + v * 13 + u * v * 5) % 7) - 3 76 let r: i64 = clamp255(baseR + n * 8) 77 let g: i64 = clamp255(baseG + n * 8) 78 let b: i64 = clamp255(baseB + n * 8) 79 return ((r * bright) / 255) + ((g * bright) / 255) * 256 + ((b * bright) / 255) * 65536 80} 81 82func fill_ztex(fb: *i64, zb: *i64, t: *i64, br: i64, bg: i64, bb: i64, bright: i64) -> i64 { 83 let x0: i64 = t[0]; let y0: i64 = t[1]; let d0: i64 = t[2]; let u0: i64 = t[3]; let v0: i64 = t[4] 84 let x1: i64 = t[5]; let y1: i64 = t[6]; let d1: i64 = t[7]; let u1: i64 = t[8]; let v1: i64 = t[9] 85 let x2: i64 = t[10]; let y2: i64 = t[11]; let d2: i64 = t[12]; let u2: i64 = t[13]; let v2: i64 = t[14] 86 let area: i64 = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 87 if area == 0 { return 0 } 88 let minx: i64 = imax(0, min3(x0, x1, x2)) 89 let maxx: i64 = imin(W - 1, max3(x0, x1, x2)) 90 let miny: i64 = imax(0, min3(y0, y1, y2)) 91 let maxy: i64 = imin(H - 1, max3(y0, y1, y2)) 92 var py: i64 = miny 93 while py <= maxy { 94 var px: i64 = minx 95 while px <= maxx { 96 let e0: i64 = (x2 - x1) * (py - y1) - (y2 - y1) * (px - x1) 97 let e1: i64 = (x0 - x2) * (py - y2) - (y0 - y2) * (px - x2) 98 let e2: i64 = (x1 - x0) * (py - y0) - (y1 - y0) * (px - x0) 99 if same_sign3(e0, e1, e2) == 1 { 100 let d: i64 = (e0 * d0 + e1 * d1 + e2 * d2) / area 101 let idx: i64 = py * W + px 102 if d < zb[idx] { 103 zb[idx] = d 104 let u: i64 = (e0 * u0 + e1 * u1 + e2 * u2) / area 105 let v: i64 = (e0 * v0 + e1 * v1 + e2 * v2) / area 106 fb[idx] = texel_col(br, bg, bb, u, v, bright) 107 } 108 } 109 px = px + 1 110 } 111 py = py + 1 112 } 113 return 0 114} 115 116func project(R: *i64, iwx: i64, iwy: i64, iwz: i64, out: *i64) -> i64 { 117 let v: *i64 = sys_mmap(32) as *i64 118 let r: *i64 = sys_mmap(32) as *i64 119 v[0] = f32_sub(f32_of(iwx), fratio(N, 2)) 120 v[1] = f32_sub(f32_of(iwy), f32_of(2)) 121 v[2] = f32_sub(f32_of(iwz), fratio(N, 2)) 122 v[3] = f32_of(0) 123 m4_vec4(R, v, r) 124 let pz: i64 = f32_add(r[2], f32_of(PUSH)) 125 if (pz & 0x80000000) != 0 { out[3] = 0; return 0 } 126 let zi: i64 = f32_int(f32_mul(pz, f32_of(64))) 127 if zi <= 0 { out[3] = 0; return 0 } 128 out[0] = HW + f32_int(f32_div(f32_mul(r[0], f32_of(FOCAL)), pz)) 129 out[1] = HH - f32_int(f32_div(f32_mul(r[1], f32_of(FOCAL)), pz)) 130 out[2] = zi 131 out[3] = 1 132 return 0 133} 134// directional light from above-front (world space): brightness from the LOCAL normal . light (integer). 135func shade_local(lnx: i64, lny: i64, lnz: i64) -> i64 { 136 var d: i64 = lnx * 1 + lny * 3 + lnz * 2 137 if d < 0 { d = 0 } 138 return clamp255(64 + d * 50) 139} 140 141func draw_face(fb: *i64, zb: *i64, sx: *i64, sy: *i64, sd: *i64, sok: *i64, 142 a: i64, b: i64, c: i64, dd: i64, lnx: i64, lny: i64, lnz: i64, col: i64) -> i64 { 143 if sok[a] == 0 { return 0 } 144 if sok[b] == 0 { return 0 } 145 if sok[c] == 0 { return 0 } 146 if sok[dd] == 0 { return 0 } 147 let bright: i64 = shade_local(lnx, lny, lnz) 148 let br: i64 = col & 0xff 149 let bg: i64 = (col >> 8) & 0xff 150 let bb: i64 = (col >> 16) & 0xff 151 let t: *i64 = sys_mmap(15 * 8) as *i64 152 t[0] = sx[a]; t[1] = sy[a]; t[2] = sd[a]; t[3] = 0; t[4] = 0 153 t[5] = sx[b]; t[6] = sy[b]; t[7] = sd[b]; t[8] = TN; t[9] = 0 154 t[10] = sx[c]; t[11] = sy[c]; t[12] = sd[c]; t[13] = TN; t[14] = TN 155 fill_ztex(fb, zb, t, br, bg, bb, bright) 156 t[0] = sx[a]; t[1] = sy[a]; t[2] = sd[a]; t[3] = 0; t[4] = 0 157 t[5] = sx[c]; t[6] = sy[c]; t[7] = sd[c]; t[8] = TN; t[9] = TN 158 t[10] = sx[dd]; t[11] = sy[dd]; t[12] = sd[dd]; t[13] = 0; t[14] = TN 159 fill_ztex(fb, zb, t, br, bg, bb, bright) 160 return 0 161} 162// draw a terrain column with neighbour face-culling + biome colours. 163func draw_col(fb: *i64, zb: *i64, R: *i64, gx: i64, gz: i64) -> i64 { 164 let h: i64 = terrain_h(gx, gz) 165 let sx: *i64 = sys_mmap(8 * 8) as *i64 166 let sy: *i64 = sys_mmap(8 * 8) as *i64 167 let sd: *i64 = sys_mmap(8 * 8) as *i64 168 let sok: *i64 = sys_mmap(8 * 8) as *i64 169 var k: i64 = 0 170 while k < 8 { 171 let dx: i64 = k & 1 172 let dy: i64 = (k >> 1) & 1 173 let dz: i64 = (k >> 2) & 1 174 let o: *i64 = sys_mmap(32) as *i64 175 project(R, gx + dx, dy * h, gz + dz, o) 176 sx[k] = o[0]; sy[k] = o[1]; sd[k] = o[2]; sok[k] = o[3] 177 k = k + 1 178 } 179 let tc: i64 = top_color(h) 180 let sc: i64 = side_color(h) 181 draw_face(fb, zb, sx, sy, sd, sok, 2, 3, 7, 6, 0, 1, 0, tc) // top 182 if hN(gx + 1, gz) < h { draw_face(fb, zb, sx, sy, sd, sok, 1, 5, 7, 3, 1, 0, 0, sc) } 183 if hN(gx - 1, gz) < h { draw_face(fb, zb, sx, sy, sd, sok, 0, 4, 6, 2, 0 - 1, 0, 0, sc) } 184 if hN(gx, gz + 1) < h { draw_face(fb, zb, sx, sy, sd, sok, 4, 5, 7, 6, 0, 0, 1, sc) } 185 if hN(gx, gz - 1) < h { draw_face(fb, zb, sx, sy, sd, sok, 0, 1, 3, 2, 0, 0, 0 - 1, sc) } 186 return 0 187} 188 189func put_u32le(b: *u8, o: i64, v: i64) -> i64 { 190 b[o] = (v & 0xff) as u8 191 b[o + 1] = ((v >> 8) & 0xff) as u8 192 b[o + 2] = ((v >> 16) & 0xff) as u8 193 b[o + 3] = ((v >> 24) & 0xff) as u8 194 return 0 195} 196func write_bmp(fb: *i64, path: *u8) -> i64 { 197 let pix: i64 = W * H * 3 198 let total: i64 = 54 + pix 199 let b: *u8 = sys_mmap(total) as *u8 200 b[0] = 66 as u8 201 b[1] = 77 as u8 202 put_u32le(b, 2, total) 203 put_u32le(b, 10, 54) 204 put_u32le(b, 14, 40) 205 put_u32le(b, 18, W) 206 put_u32le(b, 22, H) 207 b[26] = 1 as u8 208 b[28] = 24 as u8 209 put_u32le(b, 34, pix) 210 var o: i64 = 54 211 var ry: i64 = 0 212 while ry < H { 213 let syrow: i64 = H - 1 - ry 214 var x: i64 = 0 215 while x < W { 216 let c: i64 = fb[syrow * W + x] 217 b[o] = ((c >> 16) & 0xff) as u8 218 b[o + 1] = ((c >> 8) & 0xff) as u8 219 b[o + 2] = (c & 0xff) as u8 220 o = o + 3 221 x = x + 1 222 } 223 ry = ry + 1 224 } 225 let fd: i64 = sys_openat_wr(path, 0x1a4) 226 if fd < 0 { return 0 - 1 } 227 sys_write(fd, b, total) 228 sys_close(fd) 229 return 0 230} 231 232func main() -> i64 { 233 let fb: *i64 = sys_mmap(W * H * 8) as *i64 234 let zb: *i64 = sys_mmap(W * H * 8) as *i64 235 let sky: i64 = 142 + 186 * 256 + 228 * 65536 236 var i: i64 = 0 237 while i < W * H { 238 fb[i] = sky 239 zb[i] = ZFAR 240 i = i + 1 241 } 242 let Ry: *i64 = sys_mmap(128) as *i64 243 let Rx: *i64 = sys_mmap(128) as *i64 244 let R: *i64 = sys_mmap(128) as *i64 245 m4_roty(fratio(819, 1000), fratio(574, 1000), Ry) 246 m4_rotx(fratio(819, 1000), f32_neg(fratio(574, 1000)), Rx) // ~35deg pitch down -> look over the landscape 247 m4_mul(Rx, Ry, R) 248 249 var gz: i64 = 0 250 while gz < N { 251 var gx: i64 = 0 252 while gx < N { 253 draw_col(fb, zb, R, gx, gz) 254 gx = gx + 1 255 } 256 gz = gz + 1 257 } 258 write_bmp(fb, "web_assets/_game_build/f32voxel.bmp" as *u8) 259 return 0 260}