randscape/
lib.rs

1pub mod generators;
2pub mod grid;
3pub mod wfc;
4
5pub mod third_party {
6    pub use noise;
7    pub use serde;
8    pub use vek;
9}
10
11#[cfg(test)]
12mod tests {
13    use crate::{
14        generators::{
15            GridGenetator, Kernel33Generator, NoiseGenerator, OffsetLocationGenerator,
16            RemapGenerator, SubGenerator, ThresholdGenerator,
17        },
18        grid::{Grid, GridDirection},
19    };
20    use image::{GrayImage, RgbImage};
21    use noise::{Fbm, MultiFractal, ScalePoint, SuperSimplex, Worley};
22    use serde::{Deserialize, Serialize};
23    use vek::Vec2;
24
25    const SIZE: usize = 512;
26
27    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
28    enum Terrain {
29        Water,
30        Sand,
31        Grass,
32        Mountain,
33    }
34
35    fn gradient_generator(location: Vec2<usize>, size: Vec2<usize>, _: f64) -> f64 {
36        let center = size / 2;
37        let x = location.x.abs_diff(center.x) as f64;
38        let y = location.y.abs_diff(center.y) as f64;
39        let result = (x / center.x as f64).max(y / center.y as f64);
40        result * result
41    }
42
43    struct OffsetsGenerator<'a> {
44        pub source: &'a Grid<f64>,
45        pub scale: f64,
46    }
47
48    impl GridGenetator<Vec2<isize>> for OffsetsGenerator<'_> {
49        fn generate(
50            &mut self,
51            location: Vec2<usize>,
52            _: Vec2<usize>,
53            _: Vec2<isize>,
54            _: &Grid<Vec2<isize>>,
55        ) -> Vec2<isize> {
56            let left = self
57                .source
58                .get(
59                    self.source
60                        .location_offset(location, GridDirection::West, 1)
61                        .unwrap_or(location),
62                )
63                .unwrap_or_default();
64            let right = self
65                .source
66                .get(
67                    self.source
68                        .location_offset(location, GridDirection::East, 1)
69                        .unwrap_or(location),
70                )
71                .unwrap_or_default();
72            let top = self
73                .source
74                .get(
75                    self.source
76                        .location_offset(location, GridDirection::North, 1)
77                        .unwrap_or(location),
78                )
79                .unwrap_or_default();
80            let bottom = self
81                .source
82                .get(
83                    self.source
84                        .location_offset(location, GridDirection::South, 1)
85                        .unwrap_or(location),
86                )
87                .unwrap_or_default();
88            Vec2 {
89                x: ((right - left) * self.scale) as isize,
90                y: ((bottom - top) * self.scale) as isize,
91            }
92        }
93    }
94
95    fn generate_terrain(size: Vec2<usize>) -> Grid<Terrain> {
96        let mut grid = Grid::<f64>::generate(
97            size,
98            NoiseGenerator::new(
99                Fbm::<SuperSimplex>::default()
100                    .set_octaves(9)
101                    .set_frequency(0.008),
102            ),
103        );
104        grid.apply_all(RemapGenerator {
105            from: -1.0..1.0,
106            to: 0.0..1.0,
107        });
108        let gradient = grid.fork_generate(gradient_generator);
109        grid.apply_all(SubGenerator { other: &gradient });
110        grid.map(|_, _, value| {
111            if value > 0.5 {
112                Terrain::Mountain
113            } else if value > 0.2 {
114                Terrain::Grass
115            } else if value > 0.15 {
116                Terrain::Sand
117            } else {
118                Terrain::Water
119            }
120        })
121    }
122
123    fn generate_tunnels(size: Vec2<usize>) -> Grid<bool> {
124        let offsets = Grid::<f64>::generate(
125            size,
126            NoiseGenerator::new(ScalePoint::new(SuperSimplex::default()).set_scale(0.04)),
127        );
128        let offsets = Grid::<Vec2<isize>>::generate(
129            offsets.size(),
130            OffsetsGenerator {
131                source: &offsets,
132                scale: 20.0,
133            },
134        );
135        let mut thresholds = Grid::<f64>::generate(
136            size,
137            NoiseGenerator::new(ScalePoint::new(SuperSimplex::default()).set_scale(0.02)),
138        );
139        thresholds.apply_all(RemapGenerator {
140            from: -1.0..1.0,
141            to: 0.0..0.4,
142        });
143        let mut grid = Grid::<f64>::generate(
144            size,
145            OffsetLocationGenerator {
146                generator: &mut NoiseGenerator::new(Worley::default().set_frequency(0.04)),
147                offsets: &offsets,
148            },
149        );
150        grid.apply_all(RemapGenerator {
151            from: -1.0..1.0,
152            to: 0.0..1.0,
153        });
154        grid.apply_all(Kernel33Generator::edge_detection(&grid.clone()));
155        grid.apply_all(ThresholdGenerator::Constant {
156            threshold: 1.0e-4,
157            value_upper: 1.0,
158            value_lower: 0.0,
159        });
160        for _ in 0..1 {
161            grid.apply_all(Kernel33Generator::gaussian_blur(&grid.clone()));
162        }
163        grid.apply_all(ThresholdGenerator::Samples {
164            thresholds: &thresholds,
165            value_upper: 1.0,
166            value_lower: 0.0,
167        });
168        grid.map(|_, _, value| value >= 0.5)
169    }
170
171    #[test]
172    fn test_pcg_island() {
173        let terrain = generate_terrain(SIZE.into());
174        let tunnels = generate_tunnels(SIZE.into());
175
176        let (size, buffer) = terrain.into_inner();
177        let buffer = buffer
178            .into_iter()
179            .enumerate()
180            .flat_map(|(index, value)| match value {
181                Terrain::Mountain => {
182                    let location = tunnels.location(index);
183                    if tunnels.get(location).unwrap() {
184                        [64, 64, 64]
185                    } else {
186                        [128, 128, 128]
187                    }
188                }
189                Terrain::Grass => [0, 128, 0],
190                Terrain::Sand => [192, 192, 128],
191                Terrain::Water => [0, 0, 128],
192            })
193            .collect();
194        let image = RgbImage::from_vec(size.x as _, size.y as _, buffer).unwrap();
195        image.save("./resources/island.png").unwrap();
196    }
197
198    #[test]
199    fn test_pcg_tunnels() {
200        let tunnels = generate_tunnels(SIZE.into());
201
202        let (size, buffer) = tunnels.into_inner();
203        let buffer = buffer
204            .into_iter()
205            .map(|value| if value { 255 } else { 0 })
206            .collect();
207        let image = GrayImage::from_vec(size.x as _, size.y as _, buffer).unwrap();
208        image.save("./resources/caves.png").unwrap();
209    }
210
211    #[test]
212    fn test_serde() {
213        fn is_serde<T: Serialize + for<'d> Deserialize<'d>>() {}
214
215        is_serde::<Grid<usize>>();
216        is_serde::<Grid<f64>>();
217
218        let grid = Grid::new(Vec2::new(10, 10), 0usize);
219        let serialized = serde_json::to_string(&grid).unwrap();
220        let deserialized: Grid<usize> = serde_json::from_str(&serialized).unwrap();
221        assert_eq!(grid.size(), deserialized.size());
222        assert_eq!(grid.buffer(), deserialized.buffer());
223
224        let grid = Grid::new(Vec2::new(10, 10), 0.0f64);
225        let serialized = serde_json::to_string(&grid).unwrap();
226        let deserialized: Grid<f64> = serde_json::from_str(&serialized).unwrap();
227        assert_eq!(grid.size(), deserialized.size());
228        assert_eq!(grid.buffer(), deserialized.buffer());
229    }
230}