diff --git a/engine/world_generation/src/generators/packed_mesh_generator.rs b/engine/world_generation/src/generators/packed_mesh_generator.rs index 8660bc9..c32b085 100644 --- a/engine/world_generation/src/generators/packed_mesh_generator.rs +++ b/engine/world_generation/src/generators/packed_mesh_generator.rs @@ -1,4 +1,5 @@ use crate::hex_utils::HexCoord; +use crate::map::biome_map::{self, BiomeChunk, BiomeMap}; use crate::prelude::*; use crate::tile_manager::TileAsset; use crate::tile_mapper::TileMapperAsset; @@ -14,6 +15,7 @@ use bevy::{ pub fn generate_packed_chunk_mesh( chunk: &Chunk, map: &Map, + biome_chunk: &BiomeChunk, painter: &BiomePainterAsset, tiles: &Res>, biomes: &Res>, @@ -27,7 +29,7 @@ pub fn generate_packed_chunk_mesh( for z in 0..Chunk::SIZE { for x in 0..Chunk::SIZE { let height = chunk.heights[x + z * Chunk::SIZE]; - let data = chunk.biome_data[x + z * Chunk::SIZE]; + let data = biome_chunk.data[x + z * Chunk::SIZE]; let coord = HexCoord::from_offset(IVec2::new(x as i32, z as i32) + (chunk.chunk_offset * Chunk::SIZE as i32)); let n = map.get_neighbors(&coord); diff --git a/engine/world_generation/src/heightmap.rs b/engine/world_generation/src/heightmap.rs index 4312ba6..4160dce 100644 --- a/engine/world_generation/src/heightmap.rs +++ b/engine/world_generation/src/heightmap.rs @@ -10,14 +10,15 @@ use crate::biome_painter::BiomePainter; use crate::map::biome_map::{BiomeChunk, BiomeData, BiomeMap}; use crate::prelude::*; -pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePainter) -> Map { - let biomes = &generate_biomes(cfg, seed, painter); +pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePainter) -> (Map, BiomeMap) { + let biomes = generate_biomes(cfg, seed, painter); + let biomes_borrow = &biomes; // let mut chunks: Vec = Vec::with_capacity(cfg.size.length_squared() as usize); let chunks: Vec = (0..cfg.size.y) .into_par_iter() .flat_map(|z| { (0..cfg.size.x).into_par_iter().map(move |x| { - let biome_chunk = &biomes.chunks[x as usize + z as usize * cfg.size.x as usize]; + let biome_chunk = &biomes_borrow.chunks[x as usize + z as usize * cfg.size.x as usize]; return generate_chunk(x, z, cfg, seed, &biome_chunk, painter); }) }) @@ -33,14 +34,18 @@ pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePain } } - return Map { - chunks, - height: cfg.size.y as usize, - width: cfg.size.x as usize, - sea_level: cfg.sea_level as f32, - min_level: min, - max_level: max, - }; + return ( + Map { + chunks, + height: cfg.size.y as usize, + width: cfg.size.x as usize, + sea_level: cfg.sea_level as f32, + min_level: min, + max_level: max, + biome_count: painter.biomes.len(), + }, + biomes, + ); } pub fn generate_biomes(cfg: &GenerationConfig, seed: u32, biome_painter: &BiomePainter) -> BiomeMap { @@ -186,7 +191,6 @@ pub fn generate_chunk( } return Chunk { heights: result, - biome_data: data, biome_id: biome_ids, chunk_offset: IVec2::new(chunk_x as i32, chunk_z as i32), max_level: max, diff --git a/engine/world_generation/src/map/biome_map.rs b/engine/world_generation/src/map/biome_map.rs index 213ba55..4fda922 100644 --- a/engine/world_generation/src/map/biome_map.rs +++ b/engine/world_generation/src/map/biome_map.rs @@ -1,10 +1,13 @@ -use bevy::math::{UVec2, Vec3}; +use bevy::{ + math::{UVec2, Vec3}, + prelude::Resource, +}; use noise::NoiseFn; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use super::chunk::Chunk; -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct BiomeMap { pub height: usize, pub width: usize, diff --git a/engine/world_generation/src/map/chunk.rs b/engine/world_generation/src/map/chunk.rs index ef37799..f83d185 100644 --- a/engine/world_generation/src/map/chunk.rs +++ b/engine/world_generation/src/map/chunk.rs @@ -7,7 +7,7 @@ use super::biome_map::BiomeData; pub struct Chunk { pub heights: [f32; Chunk::AREA], pub textures: [[u32; 2]; Chunk::AREA], - pub biome_data: [BiomeData; Chunk::AREA], + // pub biome_data: [BiomeData; Chunk::AREA], pub biome_id: [usize; Chunk::AREA], pub chunk_offset: IVec2, pub min_level: f32, @@ -19,7 +19,7 @@ impl Default for Chunk { Self { heights: [0.; Chunk::AREA], textures: [[0; 2]; Chunk::AREA], - biome_data: [BiomeData::default(); Chunk::AREA], + // biome_data: [BiomeData::default(); Chunk::AREA], biome_id: [0; Chunk::AREA], chunk_offset: Default::default(), min_level: 0.0, diff --git a/engine/world_generation/src/map/map.rs b/engine/world_generation/src/map/map.rs index b344ee5..cf690f5 100644 --- a/engine/world_generation/src/map/map.rs +++ b/engine/world_generation/src/map/map.rs @@ -16,6 +16,7 @@ pub struct Map { pub sea_level: f32, pub min_level: f32, pub max_level: f32, + pub biome_count: usize, } impl Map { @@ -72,7 +73,18 @@ impl Map { return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE); } - pub fn get_biome(&self, pos: &HexCoord) -> &BiomeData { + + pub fn get_biome_id(&self, pos: &HexCoord) -> usize { + assert!( + self.is_in_bounds(pos), + "The provided coordinate is not within the map bounds" + ); + + let chunk = &self.chunks[pos.to_chunk_index(self.width)]; + return chunk.biome_id[pos.to_chunk_local_index()]; + } + /* + pub fn get_biome_noise(&self, pos: &HexCoord) -> &BiomeData { assert!( self.is_in_bounds(pos), "The provided coordinate is not within the map bounds" @@ -111,6 +123,7 @@ impl Map { let chunk = &self.chunks[pos.to_chunk_index(self.width)]; return chunk.biome_data[pos.to_chunk_local_index()].continentality; } + */ pub fn get_center(&self) -> Vec3 { let w = self.get_world_width(); diff --git a/engine/world_generation/src/map/map_utils.rs b/engine/world_generation/src/map/map_utils.rs index 3dc58e6..de7745d 100644 --- a/engine/world_generation/src/map/map_utils.rs +++ b/engine/world_generation/src/map/map_utils.rs @@ -2,9 +2,13 @@ use bevy::{math::VectorSpace, prelude::*}; use image::ImageBuffer; use rayon::prelude::*; -use crate::hex_utils::HexCoord; +use crate::{biome_painter::BiomePainter, hex_utils::HexCoord}; -use super::{biome_map::BiomeMap, chunk::Chunk, map::Map}; +use super::{ + biome_map::{self, BiomeMap}, + chunk::Chunk, + map::Map, +}; pub fn render_image( size: UVec2, @@ -60,51 +64,58 @@ pub fn update_map(map: &Map, smooth: f32, image: &mut ImageBuffer smooth { - if d > 0.0 { - color.lightness += 0.1; - } else if d < 0.0 { - color.lightness -= 0.1; - } - } else { - if d.abs() <= smooth { - d /= smooth; - if d > 0.0 { - let c2: LinearRgba = color.with_lightness(color.lightness + 0.1).into(); - color = LinearRgba::lerp(&color.into(), c2, d).into(); - } else { - let c2: LinearRgba = color.with_lightness(color.lightness - 0.1).into(); - color = LinearRgba::lerp(&color.into(), c2, d.abs()).into(); - } - } - } + color = get_height_color_blend(color, height, h2, smooth); } *pixel = to_pixel(&color.into()); }); } -pub fn render_biome_map(map: &Map) -> ImageBuffer, Vec> { +fn get_height_color_blend(base_color: Hsla, height: f32, height2: f32, smooth: f32) -> Hsla { + let mut color = base_color; + let mut d = height2 - height; + if smooth == 0.0 || d.abs() > smooth { + if d > 0.0 { + color.lightness += 0.1; + } else if d < 0.0 { + color.lightness -= 0.1; + } + } else { + if d.abs() <= smooth { + d /= smooth; + if d > 0.0 { + let c2: LinearRgba = color.with_lightness(color.lightness + 0.1).into(); + color = LinearRgba::lerp(&color.into(), c2, d).into(); + } else { + let c2: LinearRgba = color.with_lightness(color.lightness - 0.1).into(); + color = LinearRgba::lerp(&color.into(), c2, d.abs()).into(); + } + } + } + + return color; +} + +pub fn render_biome_noise_map(map: &BiomeMap) -> ImageBuffer, Vec> { let mut image = ImageBuffer::new( map.width as u32 * Chunk::SIZE as u32, map.height as u32 * Chunk::SIZE as u32, ); - update_biome_map(map, &mut image); + update_biome_noise_map(map, &mut image); return image; } -pub fn update_biome_map(map: &Map, image: &mut ImageBuffer, Vec>) { +pub fn update_biome_noise_map(map: &BiomeMap, image: &mut ImageBuffer, Vec>) { image.par_enumerate_pixels_mut().for_each(|(x, y, pixel)| { - let coord = HexCoord::from_grid_pos(x as usize, y as usize); - let tile = map.get_biome(&coord); + let tile = map.get_biome_data(x as usize, y as usize); let color = LinearRgba::rgb( tile.temperature / 100.0, @@ -114,3 +125,31 @@ pub fn update_biome_map(map: &Map, image: &mut ImageBuffer, Vec< *pixel = to_pixel(&color); }); } + +pub fn render_biome_map(map: &Map, biome_map: &BiomeMap) -> ImageBuffer, Vec> { + let mut image = ImageBuffer::new( + map.width as u32 * Chunk::SIZE as u32, + map.height as u32 * Chunk::SIZE as u32, + ); + update_biome_map(map, biome_map, &mut image); + return image; +} + +pub fn update_biome_map(map: &Map, biome_map: &BiomeMap, image: &mut ImageBuffer, Vec>) { + let map_biome_count = map.biome_count as f32; + image.par_enumerate_pixels_mut().for_each(|(x, y, pixel)| { + let coord = HexCoord::from_grid_pos(x as usize, y as usize); + let biome_blend = biome_map.get_biome(x as i32, y as i32); + let right = coord.get_neighbor(1); + let biome_id = map.get_biome_id(&coord) as f32; + let hue = (biome_id / map_biome_count) * 360.0; + let mut color = Hsla::hsl(hue, 0.8, 0.9); + if map.is_in_bounds(&right) { + let h1 = map.sample_height(&coord); + let h2 = map.sample_height(&right); + color = get_height_color_blend(color, h1, h2, 0.5); + } + + *pixel = to_pixel(&color.into()); + }); +} diff --git a/game/main/src/map_rendering/map_init.rs b/game/main/src/map_rendering/map_init.rs index 10a8ea8..74a8119 100644 --- a/game/main/src/map_rendering/map_init.rs +++ b/game/main/src/map_rendering/map_init.rs @@ -16,7 +16,10 @@ use world_generation::{ biome_painter::*, heightmap::generate_heightmap, hex_utils::{offset_to_index, SHORT_DIAGONAL}, - map::map_utils::{render_biome_map, render_map}, + map::{ + biome_map::{self, BiomeMap}, + map_utils::{render_biome_noise_map, render_map}, + }, prelude::*, tile_manager::*, tile_mapper::*, @@ -211,13 +214,14 @@ fn create_heightmap( size: UVec2::splat(16), // size: UVec2::splat(1), }; - let heightmap = generate_heightmap(&config, 42069, &biome_painter); + let (heightmap, biome_map) = generate_heightmap(&config, 42069, &biome_painter); let (mut cam_t, cam_entity) = cam.single_mut(); cam_t.translation = heightmap.get_center(); commands.entity(cam_entity).insert(CameraBounds::from_size(config.size)); commands.insert_resource(heightmap); + commands.insert_resource(biome_map); commands.insert_resource(config); next_state.set(GeneratorState::SpawnMap); } @@ -297,6 +301,7 @@ fn spawn_map( fn despawn_map( mut commands: Commands, mut heightmap: ResMut, + mut biome_map: ResMut, cfg: Res, chunks: Query>, mut next_state: ResMut>, @@ -306,6 +311,6 @@ fn despawn_map( commands.entity(chunk).despawn(); } - *heightmap = generate_heightmap(&cfg, 4, &biome_painter); + (*heightmap, *biome_map) = generate_heightmap(&cfg, 4, &biome_painter); next_state.set(GeneratorState::SpawnMap); }