code wiki / (root) / nx_wasmvoxel.nx

nx_wasmvoxel.nx source

↩ module page · 222 lines · 8713 B

1// nx_wasmvoxel.nx -- a VOXEL TERRAIN in the WASM/BROWSER memory model: an 8x8 heightmap (two procedural hills, 2// height-banded grass/rock/snow) of f32-projected voxel columns, painter-sorted far->near, integer-filled to a 3// fixed-offset framebuffer. Same sovereign chain as the cube (nx_compile_wat -> nx_wat_compiler -> .wasm). JS owns 4// trig + blits the fb to <canvas>; wasm owns the world + the hardware f32 math. license_tier: ORIGINAL 5import "nx_f32_hw.nx" 6const O_MAGIC_65536: i64 = 65536 7const O_MAGIC_16777216: i64 = 16777216 8 9const W: i64 = 128 10const H: i64 = 128 11const HWc: i64 = 64 12const HHc: i64 = 64 13const SCALE: i64 = 9 14const N: i64 = 8 15const O_FB: i64 = 0 16const O_RY: i64 = 131072 17const O_RX: i64 = 131200 18const O_R: i64 = 131328 19const O_VTMP: i64 = 131456 20const O_OTMP: i64 = 131488 21const O_SX: i64 = 131520 22const O_SY: i64 = 131584 23const O_CIDX: i64 = 131648 24const O_CZ: i64 = 132160 25const O_CX: i64 = 132672 26const O_CZW: i64 = 133184 27const O_CH: i64 = 133696 28const O_FACES: i64 = 134208 29 30func imin(a: i64, b: i64) -> i64 { if a < b { return a } return b } 31func imax(a: i64, b: i64) -> i64 { if a > b { return a } return b } 32func min3(a: i64, b: i64, c: i64) -> i64 { return imin(a, imin(b, c)) } 33func max3(a: i64, b: i64, c: i64) -> i64 { return imax(a, imax(b, c)) } 34func same_sign3(a: i64, b: i64, c: i64) -> i64 { 35 if a >= 0 { if b >= 0 { if c >= 0 { return 1 } } } 36 if a <= 0 { if b <= 0 { if c <= 0 { return 1 } } } 37 return 0 38} 39func fbp() -> *i64 { return (O_FB as i64) as *i64 } 40func fratio(num: i64, den: i64) -> i64 { return f32_div(f32_of(num), f32_of(den)) } 41func fill_tri(x0: i64, y0: i64, x1: i64, y1: i64, x2: i64, y2: i64, col: i64) -> i64 { 42 let fb: *i64 = fbp() 43 let area: i64 = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 44 if area == 0 { return 0 } 45 let minx: i64 = imax(0, min3(x0, x1, x2)) 46 let maxx: i64 = imin(W - 1, max3(x0, x1, x2)) 47 let miny: i64 = imax(0, min3(y0, y1, y2)) 48 let maxy: i64 = imin(H - 1, max3(y0, y1, y2)) 49 var py: i64 = miny 50 while py <= maxy { 51 var px: i64 = minx 52 while px <= maxx { 53 let e0: i64 = (x2 - x1) * (py - y1) - (y2 - y1) * (px - x1) 54 let e1: i64 = (x0 - x2) * (py - y2) - (y0 - y2) * (px - x2) 55 let e2: i64 = (x1 - x0) * (py - y0) - (y1 - y0) * (px - x0) 56 if same_sign3(e0, e1, e2) == 1 { fb[py * W + px] = col } 57 px = px + 1 58 } 59 py = py + 1 60 } 61 return 0 62} 63func rot_nz(R: *i64, lx: i64, ly: i64, lz: i64) -> i64 { 64 let v: *i64 = (O_VTMP as i64) as *i64 65 let o: *i64 = (O_OTMP as i64) as *i64 66 v[0] = lx; v[1] = ly; v[2] = lz; v[3] = f32_of(0) 67 m4_vec4(R, v, o) 68 return o[2] 69} 70func shade(nz: i64) -> i64 { 71 var z: i64 = nz 72 if (z & 0x80000000) != 0 { z = f32_of(0) } 73 return 50 + f32_int(f32_mul(z, f32_of(190))) 74} 75func packc(r: i64, g: i64, b: i64, br: i64) -> i64 { 76 let rr: i64 = (r * br) / 255 77 let gg: i64 = (g * br) / 255 78 let bb: i64 = (b * br) / 255 79 return rr + gg * 256 + bb * O_MAGIC_65536 + 255 * O_MAGIC_16777216 80} 81// procedural terrain: two mounds, integer math, height 1..5 82func hcol(gx: i64, gz: i64) -> i64 { 83 let d1: i64 = (gx - 3) * (gx - 3) + (gz - 3) * (gz - 3) 84 var h: i64 = 5 - d1 / 3 85 let d2: i64 = (gx - 6) * (gx - 6) + (gz - 5) * (gz - 5) 86 let h2: i64 = 4 - d2 / 3 87 if h2 > h { h = h2 } 88 if h < 1 { h = 1 } 89 return h 90} 91// rotated normal-z for a face index (top/+X/-X/+Z/-Z) 92func face_nz(R: *i64, fidx: i64) -> i64 { 93 if fidx == 0 { return rot_nz(R, f32_of(0), f32_of(1), f32_of(0)) } 94 if fidx == 1 { return rot_nz(R, f32_of(1), f32_of(0), f32_of(0)) } 95 if fidx == 2 { return rot_nz(R, f32_neg(f32_of(1)), f32_of(0), f32_of(0)) } 96 if fidx == 3 { return rot_nz(R, f32_of(0), f32_of(0), f32_of(1)) } 97 return rot_nz(R, f32_of(0), f32_of(0), f32_neg(f32_of(1))) 98} 99// base rgb (packed r|g<<8|b<<16) by height band; top=grass/rock/snow, side=dirt/rock/snow-shadow 100func basergb(hh: i64, top: i64) -> i64 { 101 if top == 1 { 102 if hh >= 4 { return 210 + 220 * 256 + 235 * O_MAGIC_65536 } 103 if hh == 3 { return 118 + 120 * 256 + 130 * O_MAGIC_65536 } 104 return 74 + 150 * 256 + 70 * O_MAGIC_65536 105 } 106 if hh >= 4 { return 140 + 150 * 256 + 170 * O_MAGIC_65536 } 107 if hh == 3 { return 80 + 82 * 256 + 92 * O_MAGIC_65536 } 108 return 104 + 80 * 256 + 52 * O_MAGIC_65536 109} 110// render the world. ycos/ysin = spin, xcos/xsin = tilt (cos/sin * 1000; JS owns trig). 111func render(ycos: i64, ysin: i64, xcos: i64, xsin: i64) -> i64 { 112 let fb: *i64 = fbp() 113 let bg: i64 = 120 + 150 * 256 + 200 * O_MAGIC_65536 + 255 * O_MAGIC_16777216 114 var i: i64 = 0 115 while i < W * H { fb[i] = bg; i = i + 1 } 116 let Ry: *i64 = (O_RY as i64) as *i64 117 let Rx: *i64 = (O_RX as i64) as *i64 118 let R: *i64 = (O_R as i64) as *i64 119 m4_roty(fratio(ycos, 1000), fratio(ysin, 1000), Ry) 120 m4_rotx(fratio(xcos, 1000), fratio(xsin, 1000), Rx) 121 m4_mul(Rx, Ry, R) 122 let FA: *i64 = (O_FACES as i64) as *i64 123 FA[0] = 2; FA[1] = 3; FA[2] = 7; FA[3] = 6 124 FA[4] = 1; FA[5] = 5; FA[6] = 7; FA[7] = 3 125 FA[8] = 0; FA[9] = 2; FA[10] = 6; FA[11] = 4 126 FA[12] = 4; FA[13] = 5; FA[14] = 7; FA[15] = 6 127 FA[16] = 0; FA[17] = 1; FA[18] = 3; FA[19] = 2 128 let fhalf: i64 = f32_div(f32_of(1), f32_of(2)) 129 let fnhalf: i64 = f32_neg(fhalf) 130 let fcy: i64 = f32_div(f32_of(5), f32_of(2)) 131 let fc35: i64 = f32_div(f32_of(7), f32_of(2)) 132 let fsc: i64 = f32_of(SCALE) 133 let CIDX: *i64 = (O_CIDX as i64) as *i64 134 let CZ: *i64 = (O_CZ as i64) as *i64 135 let CX: *i64 = (O_CX as i64) as *i64 136 let CZW: *i64 = (O_CZW as i64) as *i64 137 let CH: *i64 = (O_CH as i64) as *i64 138 let v: *i64 = (O_VTMP as i64) as *i64 139 let o: *i64 = (O_OTMP as i64) as *i64 140 // pass 1: column world coords, height, center depth 141 var gz: i64 = 0 142 while gz < N { 143 var gx: i64 = 0 144 while gx < N { 145 let ci: i64 = gz * N + gx 146 let wx: i64 = f32_sub(f32_of(gx), fc35) 147 let wz: i64 = f32_sub(f32_of(gz), fc35) 148 let hh: i64 = hcol(gx, gz) 149 CX[ci] = wx; CZW[ci] = wz; CH[ci] = hh; CIDX[ci] = ci 150 v[0] = wx; v[1] = f32_neg(fcy); v[2] = wz; v[3] = f32_of(0) 151 m4_vec4(R, v, o) 152 CZ[ci] = f32_int(f32_mul(o[2], f32_of(1000))) 153 gx = gx + 1 154 } 155 gz = gz + 1 156 } 157 let ncol: i64 = N * N 158 // pass 2: selection-sort column indices by depth ascending (far first) 159 var p: i64 = 0 160 while p < ncol { 161 var mn: i64 = p 162 var q: i64 = p + 1 163 while q < ncol { 164 if CZ[CIDX[q]] < CZ[CIDX[mn]] { mn = q } 165 q = q + 1 166 } 167 let t: i64 = CIDX[p]; CIDX[p] = CIDX[mn]; CIDX[mn] = t 168 p = p + 1 169 } 170 let SX: *i64 = (O_SX as i64) as *i64 171 let SY: *i64 = (O_SY as i64) as *i64 172 // pass 3: draw far->near, each column's 8 corners projected then 5 faces (sides, then top last) 173 var dp: i64 = 0 174 while dp < ncol { 175 let ci: i64 = CIDX[dp] 176 let wx: i64 = CX[ci] 177 let wz: i64 = CZW[ci] 178 let hh: i64 = CH[ci] 179 var k: i64 = 0 180 while k < 8 { 181 let bx: i64 = k & 1 182 let by: i64 = (k >> 1) & 1 183 let bz: i64 = (k >> 2) & 1 184 var lx: i64 = f32_add(wx, fnhalf) 185 if bx == 1 { lx = f32_add(wx, fhalf) } 186 var ya: i64 = f32_neg(fcy) 187 if by == 1 { ya = f32_sub(f32_of(hh), fcy) } 188 var lz: i64 = f32_add(wz, fnhalf) 189 if bz == 1 { lz = f32_add(wz, fhalf) } 190 v[0] = lx; v[1] = ya; v[2] = lz; v[3] = f32_of(0) 191 m4_vec4(R, v, o) 192 SX[k] = HWc + f32_int(f32_mul(o[0], fsc)) 193 SY[k] = HHc - f32_int(f32_mul(o[1], fsc)) 194 k = k + 1 195 } 196 var fo: i64 = 0 197 while fo < 5 { 198 var fidx: i64 = fo + 1 199 if fo == 4 { fidx = 0 } 200 let nz: i64 = face_nz(R, fidx) 201 let br: i64 = shade(nz) 202 var top: i64 = 0 203 if fidx == 0 { top = 1 } 204 let rgb: i64 = basergb(hh, top) 205 let col: i64 = packc(rgb & 255, (rgb >> 8) & 255, (rgb >> 16) & 255, br) 206 let fb4: i64 = fidx * 4 207 let i0: i64 = FA[fb4] 208 let i1: i64 = FA[fb4 + 1] 209 let i2: i64 = FA[fb4 + 2] 210 let i3: i64 = FA[fb4 + 3] 211 fill_tri(SX[i0], SY[i0], SX[i1], SY[i1], SX[i2], SY[i2], col) 212 fill_tri(SX[i0], SY[i0], SX[i2], SY[i2], SX[i3], SY[i3], col) 213 fo = fo + 1 214 } 215 dp = dp + 1 216 } 217 return 0 218} 219func fb_off() -> i64 { return O_FB } 220func ww() -> i64 { return W } 221func hh() -> i64 { return H } 222func main() -> i64 { return 0 }