diff --git a/engine/world_generation/src/map/biome_map.rs b/engine/world_generation/src/map/biome_map.rs index 188e3e0..ae6815a 100644 --- a/engine/world_generation/src/map/biome_map.rs +++ b/engine/world_generation/src/map/biome_map.rs @@ -1,54 +1,59 @@ use bevy::math::UVec2; +use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use super::chunk::Chunk; pub struct BiomeMap { pub height: usize, pub width: usize, - pub chunks: Vec<[Vec; Chunk::AREA]>, + pub biome_count: usize, + pub tiles: Vec>, } impl BiomeMap { - pub fn new(size: UVec2) -> Self { + pub fn new(size: UVec2, biome_count: usize) -> Self { return BiomeMap { - height: size.y as usize, - width: size.x as usize, - chunks: Vec::with_capacity(size.length_squared() as usize), + height: size.y as usize * Chunk::SIZE, + width: size.x as usize * Chunk::SIZE, + biome_count, + tiles: Vec::with_capacity(size.x as usize * size.y as usize * Chunk::AREA), }; } pub fn blend(&mut self, count: usize) { + assert!(count != 0, "Count cannot be 0"); for _ in 0..count { self.blend_once(); } } fn blend_once(&mut self) { - for y in 0..self.height { - for x in 0..self.width { - let kernel = self.get_kernel(x as i32, y as i32); - let r = kernel.iter().filter_map(|f| *f).fold(Vec::new(), |a, b| { - if a.len() != b.len() { - return b.iter().map(|f| *f).collect(); + let t: Vec<_> = (0..self.height) + .into_par_iter() + .map(|y| { + let mut new_tiles = Vec::with_capacity(self.width); + for x in 0..self.width { + let kernel = self.get_kernel(x as i32, y as i32); + let r = kernel + .iter() + .filter_map(|f| *f) + .fold(vec![0.; self.biome_count], |a, b| { + return a.iter().zip(b).map(|v| v.0 + v.1).collect(); + }); + + let sum: f32 = r.iter().sum(); + if sum == 0. { + new_tiles.push(vec![0.; self.biome_count]); + continue; } - return a.iter().zip(b).map(|v| v.0 + v.1).collect(); - }); + new_tiles.push(r.iter().map(|f| f / sum).collect()); + } + return new_tiles; + }) + .flatten() + .collect(); - let sum: f32 = r.iter().sum(); - - *self.get_biome_mut(x, y) = r.iter().map(|f| f / sum).collect(); - } - } - } - - fn get_biome_mut(&mut self, x: usize, y: usize) -> &mut Vec { - let cx = x as usize / Chunk::SIZE; - let cy = y as usize / Chunk::SIZE; - let chunk_index = cy * self.width as usize + cx; - let ix = x as usize - (x as usize * Chunk::SIZE); - let iy = y as usize - (y as usize * Chunk::SIZE); - let index = iy * self.width as usize + ix; - return &mut self.chunks[chunk_index][index]; + self.tiles = t; } pub fn get_kernel(&self, x: i32, y: i32) -> [Option<&Vec>; 9] { @@ -73,12 +78,30 @@ impl BiomeMap { return None; } - let cx = x as usize / Chunk::SIZE; - let cy = y as usize / Chunk::SIZE; - let chunk_index = cy * self.width as usize + cx; - let ix = x as usize - (x as usize * Chunk::SIZE); - let iy = y as usize - (y as usize * Chunk::SIZE); - let index = iy * self.width as usize + ix; - return Some(&self.chunks[chunk_index][index]); + return Some(&self.tiles[x as usize + y as usize * self.width]); + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn biome_blend() { + let mut biome = BiomeMap::new(UVec2::ONE * 16, 8); + + for y in 0..biome.height { + for x in 0..biome.width { + let mut b = vec![0.; biome.biome_count]; + let i = x / Chunk::SIZE; + let z = y / Chunk::SIZE; + let idx = (i + z) % biome.biome_count; + b[idx] = 1.; + biome.tiles.push(b); + } + } + + biome.blend(8); } }