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}