terrain_forge/algorithms/
noise_fill.rs

1use crate::noise::{Perlin, Simplex, Value, Worley};
2use crate::{Algorithm, Grid, Tile};
3
4#[derive(Debug, Clone, Copy, Default)]
5pub enum NoiseType {
6    #[default]
7    Perlin,
8    Simplex,
9    Value,
10    Worley,
11}
12
13#[derive(Debug, Clone)]
14pub struct NoiseFillConfig {
15    pub noise: NoiseType,
16    pub frequency: f64,
17    pub threshold: f64,
18}
19
20impl Default for NoiseFillConfig {
21    fn default() -> Self {
22        Self {
23            noise: NoiseType::Perlin,
24            frequency: 0.08,
25            threshold: 0.0,
26        }
27    }
28}
29
30pub struct NoiseFill {
31    config: NoiseFillConfig,
32}
33
34impl NoiseFill {
35    pub fn new(config: NoiseFillConfig) -> Self {
36        Self { config }
37    }
38}
39
40impl Default for NoiseFill {
41    fn default() -> Self {
42        Self::new(NoiseFillConfig::default())
43    }
44}
45
46impl Algorithm<Tile> for NoiseFill {
47    fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
48        let (w, h) = (grid.width(), grid.height());
49
50        match self.config.noise {
51            NoiseType::Perlin => {
52                let noise = Perlin::new(seed).with_frequency(self.config.frequency);
53                fill_from_noise(grid, w, h, &noise, self.config.threshold);
54            }
55            NoiseType::Simplex => {
56                let noise = Simplex::new(seed).with_frequency(self.config.frequency);
57                fill_from_noise(grid, w, h, &noise, self.config.threshold);
58            }
59            NoiseType::Value => {
60                let noise = Value::new(seed).with_frequency(self.config.frequency);
61                fill_from_noise(grid, w, h, &noise, self.config.threshold);
62            }
63            NoiseType::Worley => {
64                let noise = Worley::new(seed).with_frequency(self.config.frequency);
65                fill_from_noise(grid, w, h, &noise, self.config.threshold);
66            }
67        }
68
69        // Keep borders as walls for consistency with standard algorithms.
70        if w > 0 && h > 0 {
71            for x in 0..w {
72                grid.set(x as i32, 0, Tile::Wall);
73                grid.set(x as i32, (h - 1) as i32, Tile::Wall);
74            }
75            for y in 0..h {
76                grid.set(0, y as i32, Tile::Wall);
77                grid.set((w - 1) as i32, y as i32, Tile::Wall);
78            }
79        }
80    }
81
82    fn name(&self) -> &'static str {
83        "NoiseFill"
84    }
85}
86
87fn fill_from_noise<N: crate::noise::NoiseSource>(
88    grid: &mut Grid<Tile>,
89    w: usize,
90    h: usize,
91    noise: &N,
92    threshold: f64,
93) {
94    for y in 0..h {
95        for x in 0..w {
96            let value = noise.sample(x as f64, y as f64);
97            let tile = if value >= threshold {
98                Tile::Floor
99            } else {
100                Tile::Wall
101            };
102            grid.set(x as i32, y as i32, tile);
103        }
104    }
105}