use rand::Rng; pub const TEX_SIZE: usize = 64; /// Deterministic hash for coherent procedural noise. fn hash(x: u32, y: u32, seed: u64) -> u64 { let mut h = (x as u64).wrapping_mul(0x9e3779b9); h = h.wrapping_add((y as u64).wrapping_mul(0x517cc1b727220a95)); h = h.wrapping_add(seed); h = (h ^ (h >> 33)).wrapping_mul(0xc6a4a7935bd1e995); h = (h ^ (h >> 29)).wrapping_mul(0x5bd1e995); h } /// Brown cracked wall texture — 64×64, brick pattern with mortar lines and fissures. pub fn generate_wall_texture(rng: &mut impl Rng) -> Vec { let seed = rng.gen::(); let mut tex = vec![0u32; TEX_SIZE * TEX_SIZE]; for y in 0..TEX_SIZE { for x in 0..TEX_SIZE { let h = hash(x as u32, y as u32, seed); let r = 105u8.wrapping_add((h % 50) as u8); let g = 55u8.wrapping_add(((h >> 8) % 35) as u8); let b = 22u8.wrapping_add(((h >> 16) % 25) as u8); // Brick mortar every 16 pixels let mortar = y % 16 == 0 || y % 16 == 15; let (r, g, b) = if mortar { (42, 20, 8) } else { let crack_hash = hash(x.wrapping_add(1000) as u32, y as u32, seed); let crack_val = (crack_hash % 100) as u8; if crack_val < 8 { // dark crack let factor = 0.30 + (crack_val as f64 / 8.0) * 0.25; ( (r as f64 * factor) as u8, (g as f64 * factor) as u8, (b as f64 * factor) as u8, ) } else if crack_val < 14 { // light crack highlight ( (r.saturating_add(25)).min(255), (g.saturating_add(18)).min(255), (b.saturating_add(10)).min(255), ) } else { (r, g, b) } }; tex[y * TEX_SIZE + x] = 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); } } tex } /// Gray stone-tile floor with a dark hole in the centre — the exit staircase. pub fn generate_exit_texture(rng: &mut impl Rng) -> Vec { let mut tex = generate_floor_texture(rng); let cx = TEX_SIZE as f64 / 2.0; let cy = TEX_SIZE as f64 / 2.0; let hole_radius = TEX_SIZE as f64 * 0.35; let fade_zone = TEX_SIZE as f64 * 0.08; for y in 0..TEX_SIZE { for x in 0..TEX_SIZE { let dx = x as f64 - cx; let dy = y as f64 - cy; let dist = (dx * dx + dy * dy).sqrt(); if dist < hole_radius { // Deep black void. let edge = (dist / hole_radius).clamp(0.0, 1.0); // Slight blueish tint near the edge for depth. let r = (8.0 * (1.0 - edge)) as u8; let g = (6.0 * (1.0 - edge)) as u8; let b = (12.0 * edge + 4.0 * (1.0 - edge)) as u8; tex[y * TEX_SIZE + x] = 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); } else if dist < hole_radius + fade_zone { // Fade zone: blend from floor to darkness. let t = ((dist - hole_radius) / fade_zone).clamp(0.0, 1.0); let floor_color = tex[y * TEX_SIZE + x]; let fr = ((floor_color >> 16) & 0xFF) as f64; let fg = ((floor_color >> 8) & 0xFF) as f64; let fb = (floor_color & 0xFF) as f64; let r = (fr * t + 8.0 * (1.0 - t)) as u8; let g = (fg * t + 6.0 * (1.0 - t)) as u8; let b = (fb * t + 12.0 * (1.0 - t)) as u8; tex[y * TEX_SIZE + x] = 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); } } } tex } /// Gray stone-tile floor — 64×64, checkerboard with grout and subtle colour tint. pub fn generate_floor_texture(rng: &mut impl Rng) -> Vec { let seed = rng.gen::(); let mut tex = vec![0u32; TEX_SIZE * TEX_SIZE]; for y in 0..TEX_SIZE { for x in 0..TEX_SIZE { let h = hash(x as u32, y as u32, seed); let h2 = hash( x.wrapping_add(2000) as u32, y.wrapping_add(2000) as u32, seed, ); let tile_x = x / 16; let tile_y = y / 16; let is_light_tile = (tile_x + tile_y) % 2 == 0; let local_x = x % 16; let local_y = y % 16; let is_grout = local_x == 0 || local_y == 0; let base_gray: u8 = if is_light_tile { 115 } else { 95 }; let noise = (h % 15) as u8; let tint_r = (h2 % 8) as i16 - 4i16; let tint_b = ((h2 >> 8) % 8) as i16 - 4i16; let gray = if is_grout { base_gray.saturating_sub(30).saturating_add(noise / 3) } else { base_gray.saturating_add(noise / 2) }; let r = (gray as i16 + tint_r).clamp(0, 255) as u8; let g = gray; let b = (gray as i16 + tint_b).clamp(0, 255) as u8; tex[y * TEX_SIZE + x] = 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); } } tex }