From fa0ae8509f3f2d8a76b58ffc8f5c8dea384d0144 Mon Sep 17 00:00:00 2001 From: Amatsugu Date: Tue, 2 Jul 2024 22:56:11 -0400 Subject: [PATCH] preparation for improved biome generation --- engine/world_generation/src/map/biome_map.rs | 84 ++++++++++++++++++++ engine/world_generation/src/map/config.rs | 4 +- engine/world_generation/src/map/mod.rs | 3 +- engine/world_generation/src/tile_mapper.rs | 2 + game/main/src/map_rendering/map_init.rs | 1 + 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 engine/world_generation/src/map/biome_map.rs diff --git a/engine/world_generation/src/map/biome_map.rs b/engine/world_generation/src/map/biome_map.rs new file mode 100644 index 0000000..188e3e0 --- /dev/null +++ b/engine/world_generation/src/map/biome_map.rs @@ -0,0 +1,84 @@ +use bevy::math::UVec2; + +use super::chunk::Chunk; + +pub struct BiomeMap { + pub height: usize, + pub width: usize, + pub chunks: Vec<[Vec; Chunk::AREA]>, +} + +impl BiomeMap { + pub fn new(size: UVec2) -> Self { + return BiomeMap { + height: size.y as usize, + width: size.x as usize, + chunks: Vec::with_capacity(size.length_squared() as usize), + }; + } + + pub fn blend(&mut self, count: usize) { + 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(); + } + return a.iter().zip(b).map(|v| v.0 + v.1).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]; + } + + pub fn get_kernel(&self, x: i32, y: i32) -> [Option<&Vec>; 9] { + return [ + self.get_biome(x - 1, y - 1), + self.get_biome(x, y - 1), + self.get_biome(x + 1, y - 1), + self.get_biome(x - 1, y), + self.get_biome(x, y), + self.get_biome(x + 1, y), + self.get_biome(x - 1, y + 1), + self.get_biome(x, y + 1), + self.get_biome(x + 1, y + 1), + ]; + } + + pub fn get_biome(&self, x: i32, y: i32) -> Option<&Vec> { + if x < 0 || y < 0 { + return None; + } + if x >= self.width as i32 || y >= self.height as i32 { + 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]); + } +} diff --git a/engine/world_generation/src/map/config.rs b/engine/world_generation/src/map/config.rs index 4ae9214..062dd15 100644 --- a/engine/world_generation/src/map/config.rs +++ b/engine/world_generation/src/map/config.rs @@ -1,5 +1,6 @@ use bevy::prelude::*; use bevy_inspector_egui::InspectorOptions; +use serde::{Deserialize, Serialize}; use super::chunk::Chunk; @@ -9,6 +10,7 @@ pub struct GenerationConfig { pub noise_scale: f64, pub sea_level: f64, pub border_size: f32, + pub biome_blend: usize, pub size: UVec2, pub layers: Vec, } @@ -22,7 +24,7 @@ impl GenerationConfig { } } -#[derive(Reflect, InspectorOptions)] +#[derive(Reflect, InspectorOptions, Serialize, Deserialize, Debug)] pub struct GeneratorLayer { pub strength: f64, pub min_value: f64, diff --git a/engine/world_generation/src/map/mod.rs b/engine/world_generation/src/map/mod.rs index 6e29e3e..dc19c18 100644 --- a/engine/world_generation/src/map/mod.rs +++ b/engine/world_generation/src/map/mod.rs @@ -1,4 +1,5 @@ pub mod chunk; pub mod mesh_chunk; pub mod config; -pub mod map; \ No newline at end of file +pub mod map; +pub mod biome_map; \ No newline at end of file diff --git a/engine/world_generation/src/tile_mapper.rs b/engine/world_generation/src/tile_mapper.rs index 9c19c53..9c2d4b3 100644 --- a/engine/world_generation/src/tile_mapper.rs +++ b/engine/world_generation/src/tile_mapper.rs @@ -6,6 +6,7 @@ use bevy::{ }; use serde::{Deserialize, Serialize}; +use crate::prelude::GeneratorLayer; use crate::tile_manager::TileAsset; pub struct TileMapper; @@ -16,6 +17,7 @@ pub struct TileMapperAsset { pub tiles: Vec>, pub tiles_path: Vec, pub thresholds: Vec, + pub generator_layers: Vec } impl TileMapperAsset { diff --git a/game/main/src/map_rendering/map_init.rs b/game/main/src/map_rendering/map_init.rs index c0a8699..c3822fc 100644 --- a/game/main/src/map_rendering/map_init.rs +++ b/game/main/src/map_rendering/map_init.rs @@ -183,6 +183,7 @@ fn create_heightmap( mut next_state: ResMut>, ) { let config = GenerationConfig { + biome_blend: 3, layers: vec![ GeneratorLayer { base_roughness: 2.14,