code wiki / (root) / nx_voxel_native.nx

nx_voxel_native.nx source

↩ module page · 362 lines · 13750 B

1// nx_voxel_native.nx -- PLAYABLE first-person RAYCAST voxel explorer (the 3rd game mode: 2// the operator's "minecraft stuff"). A procgen world (driven by the REAL nx_world_seed 3// terrain procgen) rendered first-person via per-column raymarch with truecolor depth 4// shading, walk + turn. Native (nx_cc->nxasm_x86, no gcc), terminal-rendered, hostable. 5// 6// HONEST LADDER PLACEMENT (operator: weak-voxel < our-minecraftclone < Minecraft < Unreal 7// procgen): this is a SOVEREIGN first-person voxel walker -- well above the static 1bpp 8// substrate demo, but far below Minecraft (no block place/break/craft/infinite-chunks/ 9// lighting/save) and far below Unreal-class procgen. The procgen here = nx_world_seed 10// heightmap (a real Nishi organ); biome/feature procgen (nx_procgen_biome/features) + 11// chunked infinite world + block editing are NAMED next rungs, not claimed here. 12// 13// LAWS: <=6 args/func, flat ifs, no &&/||, integer-only. Reuses engine-lib terminal helpers. 14// license_tier: ORIGINAL 15import "nx_tier.nx" 16import "nx_syscalls.nx" 17import "nx_palette.nx" 18import "nx_tissue.nx" 19import "nx_world_seed.nx" 20import "nx_game_engine_lib.nx" 21const K_MAGIC_1092: i64 = 1092 22const K_MAGIC_1189: i64 = 1189 23const K_MAGIC_1285: i64 = 1285 24const K_MAGIC_1380: i64 = 1380 25const K_MAGIC_1474: i64 = 1474 26const K_MAGIC_1567: i64 = 1567 27const K_MAGIC_1660: i64 = 1660 28const K_MAGIC_1751: i64 = 1751 29const K_MAGIC_1842: i64 = 1842 30const K_MAGIC_1931: i64 = 1931 31const K_MAGIC_2019: i64 = 2019 32const K_MAGIC_2106: i64 = 2106 33const K_MAGIC_2191: i64 = 2191 34const K_MAGIC_2276: i64 = 2276 35const K_MAGIC_2359: i64 = 2359 36const K_MAGIC_2440: i64 = 2440 37const K_MAGIC_2520: i64 = 2520 38const K_MAGIC_2598: i64 = 2598 39const K_MAGIC_2675: i64 = 2675 40const K_MAGIC_2751: i64 = 2751 41const K_MAGIC_2824: i64 = 2824 42const K_MAGIC_2896: i64 = 2896 43const K_MAGIC_2967: i64 = 2967 44const K_MAGIC_3035: i64 = 3035 45const K_MAGIC_3102: i64 = 3102 46const K_MAGIC_3166: i64 = 3166 47const K_MAGIC_3229: i64 = 3229 48const K_MAGIC_3290: i64 = 3290 49const K_MAGIC_3349: i64 = 3349 50const K_MAGIC_3406: i64 = 3406 51const K_MAGIC_3461: i64 = 3461 52const K_MAGIC_3513: i64 = 3513 53const K_MAGIC_3564: i64 = 3564 54const K_MAGIC_3612: i64 = 3612 55const K_MAGIC_3659: i64 = 3659 56const K_MAGIC_3703: i64 = 3703 57const K_MAGIC_3745: i64 = 3745 58const K_MAGIC_3784: i64 = 3784 59const K_MAGIC_3822: i64 = 3822 60const K_MAGIC_3857: i64 = 3857 61const K_MAGIC_3889: i64 = 3889 62const K_MAGIC_3920: i64 = 3920 63const K_MAGIC_3948: i64 = 3948 64const K_MAGIC_3973: i64 = 3973 65const K_MAGIC_3996: i64 = 3996 66const K_MAGIC_4017: i64 = 4017 67const K_MAGIC_4036: i64 = 4036 68const K_MAGIC_4052: i64 = 4052 69const K_MAGIC_4065: i64 = 4065 70const K_MAGIC_4076: i64 = 4076 71const K_MAGIC_4085: i64 = 4085 72const K_MAGIC_4091: i64 = 4091 73const K_MAGIC_4095: i64 = 4095 74const K_MAGIC_4096: i64 = 4096 75const K_MAGIC_2048: i64 = 2048 76const K_MAGIC_12345: i64 = 12345 77const K_MAGIC_8192: i64 = 8192 78const K_MAGIC_131072: i64 = 131072 79const K_MAGIC_1024: i64 = 1024 80 81// state st[]: 0=px(q8) 1=py(q8) 2=ang(0..255) 3=rng ; map 24x24 u8 at st+2048 ; qtab 65 i64 at st+4096 82 83func vx_qfill(q: *i64) -> i64 { 84 q[0]=0; q[1]=101; q[2]=201; q[3]=301; q[4]=401; q[5]=501; q[6]=601; q[7]=700; q[8]=799; q[9]=897; q[10]=995; q[11]=K_MAGIC_1092; q[12]=K_MAGIC_1189 85 q[13]=K_MAGIC_1285; q[14]=K_MAGIC_1380; q[15]=K_MAGIC_1474; q[16]=K_MAGIC_1567; q[17]=K_MAGIC_1660; q[18]=K_MAGIC_1751; q[19]=K_MAGIC_1842; q[20]=K_MAGIC_1931; q[21]=K_MAGIC_2019; q[22]=K_MAGIC_2106; q[23]=K_MAGIC_2191; q[24]=K_MAGIC_2276; q[25]=K_MAGIC_2359 86 q[26]=K_MAGIC_2440; q[27]=K_MAGIC_2520; q[28]=K_MAGIC_2598; q[29]=K_MAGIC_2675; q[30]=K_MAGIC_2751; q[31]=K_MAGIC_2824; q[32]=K_MAGIC_2896; q[33]=K_MAGIC_2967; q[34]=K_MAGIC_3035; q[35]=K_MAGIC_3102; q[36]=K_MAGIC_3166; q[37]=K_MAGIC_3229; q[38]=K_MAGIC_3290 87 q[39]=K_MAGIC_3349; q[40]=K_MAGIC_3406; q[41]=K_MAGIC_3461; q[42]=K_MAGIC_3513; q[43]=K_MAGIC_3564; q[44]=K_MAGIC_3612; q[45]=K_MAGIC_3659; q[46]=K_MAGIC_3703; q[47]=K_MAGIC_3745; q[48]=K_MAGIC_3784; q[49]=K_MAGIC_3822; q[50]=K_MAGIC_3857; q[51]=K_MAGIC_3889 88 q[52]=K_MAGIC_3920; q[53]=K_MAGIC_3948; q[54]=K_MAGIC_3973; q[55]=K_MAGIC_3996; q[56]=K_MAGIC_4017; q[57]=K_MAGIC_4036; q[58]=K_MAGIC_4052; q[59]=K_MAGIC_4065; q[60]=K_MAGIC_4076; q[61]=K_MAGIC_4085; q[62]=K_MAGIC_4091; q[63]=K_MAGIC_4095; q[64]=K_MAGIC_4096 89 return 0 90} 91func vx_qtab(st: *i64) -> *i64 { return ((st as i64) + K_MAGIC_4096) as *i64 } 92func vx_sin(q: *i64, a0: i64) -> i64 { 93 let a: i64 = a0 & 255 94 let quad: i64 = a >> 6 95 let idx: i64 = a & 63 96 if quad == 0 { return q[idx] } 97 if quad == 1 { return q[64 - idx] } 98 if quad == 2 { return 0 - q[idx] } 99 return 0 - q[64 - idx] 100} 101func vx_cos(q: *i64, a: i64) -> i64 { return vx_sin(q, a + 64) } 102 103func vx_cell(st: *i64, x: i64, y: i64) -> i64 { 104 if x < 0 { return 1 } 105 if y < 0 { return 1 } 106 if x >= 24 { return 1 } 107 if y >= 24 { return 1 } 108 let m: *u8 = ((st as i64) + K_MAGIC_2048) as *u8 109 return m[y * 24 + x] as i64 110} 111func vx_set(st: *i64, x: i64, y: i64, v: i64) -> i64 { 112 let m: *u8 = ((st as i64) + K_MAGIC_2048) as *u8 113 m[y * 24 + x] = v as u8 114 return 0 115} 116 117func vx_build(st: *i64, seed: i64) -> i64 { 118 st[3] = seed 119 let world: *NxTissue = nx_tissue_new(24, 24, 8, NX_BPP_3) 120 nx_world_seed_generate(world, seed) 121 var y: i64 = 0 122 while y < 24 { 123 var x: i64 = 0 124 while x < 24 { 125 var top: i64 = 0 - 1 126 var surf: i64 = 1 127 var z: i64 = 7 128 while z >= 0 { 129 if top < 0 { 130 let b: i64 = nx_tissue_get(world, x, y, z) 131 if b != 0 { top = z; surf = b } 132 } 133 z = z - 1 134 } 135 var border: i64 = 0 136 if x == 0 { border = 1 } 137 if y == 0 { border = 1 } 138 if x == 23 { border = 1 } 139 if y == 23 { border = 1 } 140 var solid: i64 = 0 141 if border == 1 { solid = 1; surf = 1 } 142 if border == 0 { if top >= 5 { solid = 1 } } 143 if solid == 1 { vx_set(st, x, y, surf) } else { vx_set(st, x, y, 0) } 144 x = x + 1 145 } 146 y = y + 1 147 } 148 // clear a spawn pocket at center 149 vx_set(st, 12, 12, 0); vx_set(st, 12, 11, 0); vx_set(st, 11, 12, 0) 150 vx_set(st, 13, 12, 0); vx_set(st, 12, 13, 0); vx_set(st, 11, 11, 0); vx_set(st, 13, 13, 0) 151 st[0] = 12 * 256 + 128 152 st[1] = 12 * 256 + 128 153 st[2] = 0 154 return 0 155} 156func vx_init(st: *i64, seed: i64) -> i64 { 157 vx_qfill(vx_qtab(st)) 158 vx_build(st, seed) 159 st[5] = 3 160 return 0 161} 162 163// look: march the CENTER ray; record the first solid cell hit (st[6],st[7]) and the last 164// air cell before it (st[8],st[9]) for placing. Short reach (~3 cells) like Minecraft. 165// st[10] = 1 if something is in reach. 166func vx_look(st: *i64, q: *i64) -> i64 { 167 let dx: i64 = vx_cos(q, st[2]) 168 let dy: i64 = vx_sin(q, st[2]) 169 var pcx: i64 = st[0] >> 8 170 var pcy: i64 = st[1] >> 8 171 st[10] = 0 172 var s: i64 = 2 173 while s < 36 { 174 let d: i64 = s * 24 175 let cx: i64 = (st[0] + ((dx * d) >> 12)) >> 8 176 let cy: i64 = (st[1] + ((dy * d) >> 12)) >> 8 177 let c: i64 = vx_cell(st, cx, cy) 178 if c != 0 { st[6] = cx; st[7] = cy; st[8] = pcx; st[9] = pcy; st[10] = 1; s = 900 } 179 if c == 0 { pcx = cx; pcy = cy } 180 s = s + 1 181 } 182 return 0 183} 184func vx_break(st: *i64) -> i64 { 185 if st[10] == 1 { vx_set(st, st[6], st[7], 0) } 186 return 0 187} 188func vx_place(st: *i64) -> i64 { 189 if st[10] == 1 { 190 var ok: i64 = 1 191 if st[8] == (st[0] >> 8) { if st[9] == (st[1] >> 8) { ok = 0 } } 192 if vx_cell(st, st[8], st[9]) != 0 { ok = 0 } 193 if ok == 1 { vx_set(st, st[8], st[9], st[5]) } 194 } 195 return 0 196} 197func vx_blockname(st: *i64, buf: *u8, off: *i64) -> i64 { 198 if st[5] == 1 { bput(buf, off, "STONE" as *u8) } 199 if st[5] == 2 { bput(buf, off, "DIRT" as *u8) } 200 if st[5] == 3 { bput(buf, off, "GRASS" as *u8) } 201 if st[5] == 4 { bput(buf, off, "WATER" as *u8) } 202 return 0 203} 204 205func vx_move(st: *i64, q: *i64, fwd: i64) -> i64 { 206 let dx: i64 = vx_cos(q, st[2]) 207 let dy: i64 = vx_sin(q, st[2]) 208 let nx: i64 = st[0] + ((dx * 56 * fwd) >> 12) 209 let ny: i64 = st[1] + ((dy * 56 * fwd) >> 12) 210 if vx_cell(st, nx >> 8, st[1] >> 8) == 0 { st[0] = nx } 211 if vx_cell(st, st[0] >> 8, ny >> 8) == 0 { st[1] = ny } 212 return 0 213} 214func vx_turn(st: *i64, d: i64) -> i64 { st[2] = (st[2] + d) & 255; return 0 } 215 216func vx_basecol(cell: i64) -> i64 { 217 if cell == 1 { return (130 << 16) | (130 << 8) | 145 } 218 if cell == 2 { return (150 << 16) | (104 << 8) | 60 } 219 if cell == 3 { return (70 << 16) | (180 << 8) | 80 } 220 if cell == 4 { return (60 << 16) | (110 << 8) | 200 } 221 return (120 << 16) | (120 << 8) | 120 222} 223func vx_shade(rgb: i64, f: i64) -> i64 { 224 let r: i64 = (((rgb >> 16) & 255) * f) / 255 225 let g: i64 = (((rgb >> 8) & 255) * f) / 255 226 let b: i64 = ((rgb & 255) * f) / 255 227 return (r << 16) | (g << 8) | b 228} 229 230// cast one column: returns packed (top<<20)|(bot<<12)| nothing; we instead fill via out arrays. 231func vx_cast_col(st: *i64, q: *i64, c: i64, ctop: *i64, cbot: *i64, ccol: *i64) -> i64 { 232 let off_ang: i64 = c - 32 233 let rayang: i64 = st[2] + off_ang 234 let dx: i64 = vx_cos(q, rayang) 235 let dy: i64 = vx_sin(q, rayang) 236 var s: i64 = 1 237 var hit: i64 = 0 238 var cell: i64 = 0 239 var dq8: i64 = 0 240 while s < 170 { 241 dq8 = s * 24 242 let wx: i64 = st[0] + ((dx * dq8) >> 12) 243 let wy: i64 = st[1] + ((dy * dq8) >> 12) 244 cell = vx_cell(st, wx >> 8, wy >> 8) 245 if cell != 0 { hit = 1; s = 999 } 246 if cell == 0 { s = s + 1 } 247 } 248 let perp: i64 = (dq8 * vx_cos(q, off_ang)) >> 12 249 var dcells: i64 = perp >> 8 250 if dcells < 1 { dcells = 1 } 251 var h: i64 = (28 * 7) / dcells 252 if h > 28 { h = 28 } 253 if hit == 0 { h = 0 } 254 let top: i64 = (28 - h) / 2 255 ctop[c] = top 256 cbot[c] = top + h 257 var f: i64 = 255 - dcells * 11 258 if f < 45 { f = 45 } 259 ccol[c] = vx_shade(vx_basecol(cell), f) 260 return 0 261} 262 263func vx_render(buf: *u8, st: *i64, ctop: *i64, cbot: *i64, ccol: *i64) -> i64 { 264 let q: *i64 = vx_qtab(st) 265 let off: *i64 = sys_mmap(16) as *i64 266 off[0] = 0 267 bput_clear(buf, off) 268 bput(buf, off, " NISHI VOXEL first-person raycast over nx_world_seed procgen facing " as *u8) 269 bputn(buf, off, st[2]); bputc(buf, off, 10); bputc(buf, off, 10) 270 var c: i64 = 0 271 while c < 64 { vx_cast_col(st, q, c, ctop, cbot, ccol); c = c + 1 } 272 var r: i64 = 0 273 while r < 28 { 274 var last: i64 = 0 - 1 275 bput(buf, off, " " as *u8) 276 var x: i64 = 0 277 while x < 64 { 278 var rgb: i64 = 0 279 if r < ctop[x] { rgb = (50 << 16) | (72 << 8) | 110 } 280 if r >= ctop[x] { if r < cbot[x] { rgb = ccol[x] } } 281 if r >= cbot[x] { rgb = (34 << 16) | (30 << 8) | 28 } 282 if rgb != last { 283 bput_bg(buf, off, (rgb >> 16) & 255, (rgb >> 8) & 255, rgb & 255) 284 last = rgb 285 } 286 var ch: i64 = 32 287 if r == 14 { if x == 32 { ch = 43 } } 288 if ch == 43 { bput_fg(buf, off, 255, 255, 255); bputc(buf, off, 43); last = 0 - 1 } else { bputc(buf, off, 32) } 289 x = x + 1 290 } 291 bput_reset(buf, off); bputc(buf, off, 10) 292 r = r + 1 293 } 294 bputc(buf, off, 10) 295 bput(buf, off, " w/s walk a/d turn f BREAK g PLACE block at crosshair 1-4 select r regen q quit" as *u8); bputc(buf, off, 10) 296 bput(buf, off, " selected block: " as *u8); vx_blockname(st, buf, off) 297 bput(buf, off, " (+ = aim; break/place a block, then walk through the hole you dug)" as *u8); bputc(buf, off, 10) 298 sys_write(1, buf, off[0]) 299 return 0 300} 301 302func vx_input(st: *i64, key: i64) -> i64 { 303 let q: *i64 = vx_qtab(st) 304 if key == 0 { vx_move(st, q, 1) } 305 if key == 1 { vx_move(st, q, 0 - 1) } 306 if key == 2 { vx_turn(st, 0 - 6) } 307 if key == 3 { vx_turn(st, 6) } 308 if key == 7 { vx_look(st, q); vx_break(st) } 309 if key == 8 { vx_look(st, q); vx_place(st) } 310 if key == 10 { st[5] = 1 } 311 if key == 11 { st[5] = 2 } 312 if key == 12 { st[5] = 3 } 313 if key == 13 { st[5] = 4 } 314 if key == 6 { vx_build(st, st[3] + K_MAGIC_12345); st[5] = 3 } 315 return 0 316} 317func vx_key(c: i64) -> i64 { 318 if c == 119 { return 0 } 319 if c == 115 { return 1 } 320 if c == 97 { return 2 } 321 if c == 100 { return 3 } 322 if c == 102 { return 7 } 323 if c == 103 { return 8 } 324 if c == 49 { return 10 } 325 if c == 50 { return 11 } 326 if c == 51 { return 12 } 327 if c == 52 { return 13 } 328 if c == 114 { return 6 } 329 return 9 330} 331 332func main() -> i64 { 333 let st: *i64 = sys_mmap(K_MAGIC_8192) as *i64 334 let orig: *u8 = sys_mmap(128) 335 let raw: *u8 = sys_mmap(128) 336 let is_tty: i64 = term_raw_on(orig, raw) 337 vx_init(st, sys_now_ms()) 338 let buf: *u8 = sys_mmap(K_MAGIC_131072) 339 let ib: *u8 = sys_mmap(8) 340 let ctop: *i64 = sys_mmap(K_MAGIC_1024) as *i64 341 let cbot: *i64 = sys_mmap(K_MAGIC_1024) as *i64 342 let ccol: *i64 = sys_mmap(K_MAGIC_1024) as *i64 343 var running: i64 = 1 344 while running == 1 { 345 vx_render(buf, st, ctop, cbot, ccol) 346 let n: i64 = sys_read(0, ib, 1) 347 if n <= 0 { running = 0 } 348 if n > 0 { 349 let c: i64 = ib[0] as i64 350 if c == 113 { running = 0 } 351 if c == 81 { running = 0 } 352 if c != 113 { if c != 81 { vx_input(st, vx_key(c)) } } 353 } 354 } 355 if is_tty == 1 { term_raw_off(orig) } 356 let off: *i64 = sys_mmap(16) as *i64 357 off[0] = 0 358 bput_clear(buf, off); bput(buf, off, "thanks for exploring -- NISHI VOXEL\n" as *u8) 359 sys_write(1, buf, off[0]) 360 sys_exit(0) 361 return 0 362}