diff options
Diffstat (limited to 'src/texture.rs')
| -rw-r--r-- | src/texture.rs | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/texture.rs b/src/texture.rs new file mode 100644 index 0000000..bdbb15c --- /dev/null +++ b/src/texture.rs | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | use rand::Rng; | ||
| 2 | |||
| 3 | pub const TEX_SIZE: usize = 64; | ||
| 4 | |||
| 5 | /// Deterministic hash for coherent procedural noise. | ||
| 6 | fn hash(x: u32, y: u32, seed: u64) -> u64 { | ||
| 7 | let mut h = (x as u64).wrapping_mul(0x9e3779b9); | ||
| 8 | h = h.wrapping_add((y as u64).wrapping_mul(0x517cc1b727220a95)); | ||
| 9 | h = h.wrapping_add(seed); | ||
| 10 | h = (h ^ (h >> 33)).wrapping_mul(0xc6a4a7935bd1e995); | ||
| 11 | h = (h ^ (h >> 29)).wrapping_mul(0x5bd1e995); | ||
| 12 | h | ||
| 13 | } | ||
| 14 | |||
| 15 | /// Brown cracked wall texture — 64×64, brick pattern with mortar lines and fissures. | ||
| 16 | pub fn generate_wall_texture(rng: &mut impl Rng) -> Vec<u32> { | ||
| 17 | let seed = rng.gen::<u64>(); | ||
| 18 | let mut tex = vec![0u32; TEX_SIZE * TEX_SIZE]; | ||
| 19 | |||
| 20 | for y in 0..TEX_SIZE { | ||
| 21 | for x in 0..TEX_SIZE { | ||
| 22 | let h = hash(x as u32, y as u32, seed); | ||
| 23 | |||
| 24 | let r = 105u8.wrapping_add((h % 50) as u8); | ||
| 25 | let g = 55u8.wrapping_add(((h >> 8) % 35) as u8); | ||
| 26 | let b = 22u8.wrapping_add(((h >> 16) % 25) as u8); | ||
| 27 | |||
| 28 | // Brick mortar every 16 pixels | ||
| 29 | let mortar = y % 16 == 0 || y % 16 == 15; | ||
| 30 | |||
| 31 | let (r, g, b) = if mortar { | ||
| 32 | (42, 20, 8) | ||
| 33 | } else { | ||
| 34 | let crack_hash = hash(x.wrapping_add(1000) as u32, y as u32, seed); | ||
| 35 | let crack_val = (crack_hash % 100) as u8; | ||
| 36 | if crack_val < 8 { | ||
| 37 | // dark crack | ||
| 38 | let factor = 0.30 + (crack_val as f64 / 8.0) * 0.25; | ||
| 39 | ( | ||
| 40 | (r as f64 * factor) as u8, | ||
| 41 | (g as f64 * factor) as u8, | ||
| 42 | (b as f64 * factor) as u8, | ||
| 43 | ) | ||
| 44 | } else if crack_val < 14 { | ||
| 45 | // light crack highlight | ||
| 46 | ( | ||
| 47 | (r.saturating_add(25)).min(255), | ||
| 48 | (g.saturating_add(18)).min(255), | ||
| 49 | (b.saturating_add(10)).min(255), | ||
| 50 | ) | ||
| 51 | } else { | ||
| 52 | (r, g, b) | ||
| 53 | } | ||
| 54 | }; | ||
| 55 | |||
| 56 | tex[y * TEX_SIZE + x] = | ||
| 57 | 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | tex | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Gray stone-tile floor — 64×64, checkerboard with grout and subtle colour tint. | ||
| 64 | pub fn generate_floor_texture(rng: &mut impl Rng) -> Vec<u32> { | ||
| 65 | let seed = rng.gen::<u64>(); | ||
| 66 | let mut tex = vec![0u32; TEX_SIZE * TEX_SIZE]; | ||
| 67 | |||
| 68 | for y in 0..TEX_SIZE { | ||
| 69 | for x in 0..TEX_SIZE { | ||
| 70 | let h = hash(x as u32, y as u32, seed); | ||
| 71 | let h2 = hash(x.wrapping_add(2000) as u32, y.wrapping_add(2000) as u32, seed); | ||
| 72 | |||
| 73 | let tile_x = x / 16; | ||
| 74 | let tile_y = y / 16; | ||
| 75 | let is_light_tile = (tile_x + tile_y) % 2 == 0; | ||
| 76 | |||
| 77 | let local_x = x % 16; | ||
| 78 | let local_y = y % 16; | ||
| 79 | let is_grout = local_x == 0 || local_y == 0; | ||
| 80 | |||
| 81 | let base_gray: u8 = if is_light_tile { 115 } else { 95 }; | ||
| 82 | let noise = (h % 15) as u8; | ||
| 83 | |||
| 84 | let tint_r = (h2 % 8) as i16 - 4i16; | ||
| 85 | let tint_b = ((h2 >> 8) % 8) as i16 - 4i16; | ||
| 86 | |||
| 87 | let gray = if is_grout { | ||
| 88 | base_gray.saturating_sub(30).saturating_add(noise / 3) | ||
| 89 | } else { | ||
| 90 | base_gray.saturating_add(noise / 2) | ||
| 91 | }; | ||
| 92 | |||
| 93 | let r = (gray as i16 + tint_r).clamp(0, 255) as u8; | ||
| 94 | let g = gray; | ||
| 95 | let b = (gray as i16 + tint_b).clamp(0, 255) as u8; | ||
| 96 | |||
| 97 | tex[y * TEX_SIZE + x] = | ||
| 98 | 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | tex | ||
| 102 | } | ||
