hassium_utils/
noise_map_generator.rs

1use crate::grid_2d::Grid2d;
2use noise::{NoiseFn, OpenSimplex, Seedable};
3use std::ops::Range;
4
5#[derive(Clone)]
6pub struct NoiseMapGenerator {
7    seed: u32,
8    chunk_size: usize,
9    zoom: f64,
10    generator: OpenSimplex,
11}
12
13impl NoiseMapGenerator {
14    pub fn new(seed: u32, chunk_size: usize, zoom: f64) -> Self {
15        Self {
16            seed,
17            chunk_size: chunk_size.max(1),
18            zoom,
19            generator: OpenSimplex::new().set_seed(seed),
20        }
21    }
22
23    pub fn seed(&self) -> u32 {
24        self.seed
25    }
26
27    pub fn chunk_size(&self) -> usize {
28        self.chunk_size
29    }
30
31    pub fn zoom(&self) -> f64 {
32        self.zoom
33    }
34
35    pub fn sample_raw(&self, x: f64, y: f64, z: f64) -> f64 {
36        self.generator.get([x, y, z]) + 1.0 * 0.5
37    }
38
39    pub fn sample(
40        &self,
41        coord: (isize, isize),
42        (col, row): (usize, usize),
43        margin: usize,
44        depth: f64,
45    ) -> f64 {
46        let col = col % (self.chunk_size + margin * 2);
47        let row = row % (self.chunk_size + margin * 2);
48        let x = self.zoom * (coord.0 as f64 * self.chunk_size as f64 + col as f64 - margin as f64)
49            / self.chunk_size as f64;
50        let y = self.zoom * (coord.1 as f64 * self.chunk_size as f64 + row as f64 - margin as f64)
51            / self.chunk_size as f64;
52        self.sample_raw(x, y, depth)
53    }
54
55    #[inline]
56    pub fn build_chunk(&self, coord: (isize, isize), margin: usize) -> Grid2d<f64> {
57        self.build_chunk_with_depth(coord, margin, 0.0)
58    }
59
60    pub fn build_chunk_with_depth(
61        &self,
62        coord: (isize, isize),
63        margin: usize,
64        depth: f64,
65    ) -> Grid2d<f64> {
66        let mut cells = Vec::with_capacity(self.chunk_size * self.chunk_size);
67        let mcs = self.chunk_size + margin * 2;
68        for row in 0..mcs {
69            for col in 0..mcs {
70                cells.push(self.sample(coord, (col, row), margin, depth));
71            }
72        }
73        Grid2d::with_cells(mcs, cells)
74    }
75
76    #[inline]
77    pub fn build_chunks(&self, coord: Range<(isize, isize)>) -> Grid2d<f64> {
78        self.build_chunks_with_depth(coord, 0.0)
79    }
80
81    pub fn build_chunks_with_depth(&self, coord: Range<(isize, isize)>, depth: f64) -> Grid2d<f64> {
82        let xs = (coord.end.0 - coord.start.0) as usize;
83        let ys = (coord.end.1 - coord.start.1) as usize;
84        let mut cells = Vec::with_capacity(self.chunk_size * self.chunk_size * xs * ys);
85        for row in 0..(self.chunk_size * ys) {
86            for col in 0..(self.chunk_size * xs) {
87                let xc = coord.start.0 + (col / self.chunk_size) as isize;
88                let yc = coord.start.1 + (row / self.chunk_size) as isize;
89                cells.push(self.sample(
90                    (xc, yc),
91                    (col % self.chunk_size, row % self.chunk_size),
92                    0,
93                    depth,
94                ));
95            }
96        }
97        Grid2d::with_cells(self.chunk_size * xs, cells)
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn test_print_ascii() {
107        let gen = NoiseMapGenerator::new(0, 8, 4.0);
108
109        fn print_chunk(chunk: Grid2d<f64>) {
110            for row in 0..chunk.rows() {
111                let cells = chunk
112                    .get_row_cells(row)
113                    .unwrap()
114                    .into_iter()
115                    .map(|f| if f >= 0.5 { '#' } else { ' ' })
116                    .collect::<String>();
117                println!("|{}|", cells);
118            }
119        }
120
121        // let chunk = gen.build_chunks((-2, 0)..(3, 2));
122        let chunk = gen.build_chunk((0, 0), 1);
123        print_chunk(chunk.clone());
124        println!("");
125        print_chunk(chunk.get_part((1, 1)..(9, 9)));
126    }
127}