code wiki / (root) / nx_world_seed.nx

nx_world_seed.nx source

↩ module page · 132 lines · 4265 B

1// nx_world_seed.nx -- deterministic worldgen for voxel tissue. 2// 3// xorshift64 PRNG + procedural worldgen. Same seed = same world, 4// byte-for-byte. Foundation for Minecraft-equivalent procedural 5// terrain on T1/MCU — no float, no allocation, MCU-compatible. 6// 7// V1 generates a simple terrain: 8// z=0..2 : stone (palette idx 1) 9// z=3..h : dirt (idx 2) where h is per-column Q14 noise 10// z=h+1..z_max : air (idx 0) 11// 12// The "Q14 noise" is a cheap pseudo-Perlin: hash (x, y, seed) into 13// a height in [3, z_max). Not smooth, but deterministic + repeatable. 14// 15// Composes: 16// nx_tissue -- the world being filled 17// nx_palette -- voxel indices (0=air, 1=stone, 2=dirt, 3=grass) 18// nx_q14_math -- sin lookup for cheap noise 19 20import "nx_syscalls.nx" 21import "nx_tier.nx" 22import "nx_tissue.nx" 23import "nx_palette.nx" 24const NX_MAGIC_73856093: i64 = 73856093 25const NX_MAGIC_19349663: i64 = 19349663 26 27const NX_WS_PAL_AIR: nx_int = 0 28const NX_WS_PAL_STONE: nx_int = 1 29const NX_WS_PAL_DIRT: nx_int = 2 30const NX_WS_PAL_GRASS: nx_int = 3 31const NX_WS_PAL_WATER: nx_int = 4 32 33const NX_WS_OK: nx_int = 0 34const NX_WS_ERR_BAD_TISSUE: nx_int = 1 35 36// ===== Struct: NxWorldSeedState =================================== 37 38struct NxWorldSeedState { 39 seed: nx_size, 40 cursor: nx_size, // current PRNG state 41 cells_written: nx_int, 42} 43 44// ===== nx_xorshift64 ================================================ 45// 46// xorshift64* PRNG. Pure function: state in, state out. Deterministic 47// across hosts. Period ~2^64. 48 49func nx_xorshift64(state: nx_size) -> nx_size { 50 var x: nx_size = state 51 if x == 0 { x = 1 } // 0 is a fixed point; avoid 52 x = x ^ (x << 13) 53 x = x & 0xFFFFFFFFFFFFFFFF 54 x = x ^ ((x >> 7) & 0x01FFFFFFFFFFFFFF) 55 x = x ^ (x << 17) 56 x = x & 0xFFFFFFFFFFFFFFFF 57 return x 58} 59 60func nx_world_seed_state_new(seed: nx_size) -> *NxWorldSeedState { 61 let s: *NxWorldSeedState = (sys_mmap(24)) as *NxWorldSeedState 62 s.seed = seed 63 s.cursor = seed 64 if s.cursor == 0 { s.cursor = 1 } 65 s.cells_written = 0 66 return s 67} 68 69func nx_world_seed_next(s: *NxWorldSeedState) -> nx_size { 70 s.cursor = nx_xorshift64(s.cursor) 71 return s.cursor 72} 73 74// ===== _height_at ================================================== 75// 76// Pseudo-noise height function. Hash (x, y, seed) into a height in 77// [min_h, max_h). Not smooth (no interpolation between cells) but 78// deterministic + repeatable. 79 80func _height_at(seed: nx_size, x: nx_size, y: nx_size, 81 min_h: nx_size, max_h: nx_size) -> nx_size { 82 let mixed: nx_size = nx_xorshift64(seed + x * NX_MAGIC_73856093 + y * NX_MAGIC_19349663) 83 let range: nx_size = max_h - min_h 84 return min_h + (mixed - (mixed / range) * range) 85} 86 87// ===== nx_world_seed_generate ===================================== 88// 89// Fill the supplied tissue with terrain. Per-column height varies 90// via the noise function. Bottom NX_WS_PAL_STONE; column-top 91// NX_WS_PAL_GRASS; between NX_WS_PAL_DIRT; above air. 92 93func nx_world_seed_generate(world: *NxTissue, seed: nx_size) -> nx_int { 94 if (world as i64) == 0 { return NX_WS_ERR_BAD_TISSUE } 95 let min_h: nx_size = 3 96 var max_h: nx_size = world.dim_z - 2 97 if max_h < min_h + 1 { max_h = min_h + 1 } 98 99 var cells: nx_int = 0 100 var y: nx_size = 0 101 while y < world.dim_y { 102 var x: nx_size = 0 103 while x < world.dim_x { 104 let h: nx_size = _height_at(seed, x, y, min_h, max_h) 105 // Stone floor at z=0..2 106 var z: nx_size = 0 107 while z < 3 { 108 if z < world.dim_z { 109 nx_tissue_set(world, x, y, z, NX_WS_PAL_STONE) 110 cells = cells + 1 111 } 112 z = z + 1 113 } 114 // Dirt 3..h-1 115 while z < h { 116 if z < world.dim_z { 117 nx_tissue_set(world, x, y, z, NX_WS_PAL_DIRT) 118 cells = cells + 1 119 } 120 z = z + 1 121 } 122 // Grass top 123 if h < world.dim_z { 124 nx_tissue_set(world, x, y, h, NX_WS_PAL_GRASS) 125 cells = cells + 1 126 } 127 x = x + 1 128 } 129 y = y + 1 130 } 131 return cells 132}