From eb3742e21d93aab80bf81ad9aef1d75fe8175d28 Mon Sep 17 00:00:00 2001 From: Arkitu <85173315+Arkitu@users.noreply.github.com> Date: Thu, 12 Jun 2025 21:52:30 +0200 Subject: [PATCH] chunks generation (not tested) --- src/map.rs | 162 +++++++++++++++++++++++++++++------------------ src/map/cells.rs | 16 ++++- 2 files changed, 115 insertions(+), 63 deletions(-) diff --git a/src/map.rs b/src/map.rs index d496c0c..ad49046 100644 --- a/src/map.rs +++ b/src/map.rs @@ -7,6 +7,7 @@ use bevy::{ picking::PickSet, prelude::*, render::mesh::{Indices, PrimitiveTopology}, + utils::HashMap, }; use noise::{Fbm, MultiFractal, NoiseFn, Perlin}; use rand::{thread_rng, Rng, SeedableRng}; @@ -45,8 +46,9 @@ pub const REAL_WIDTH: f32 = 8000.; pub const CELL_AREA: f32 = REAL_HEIGHT * REAL_WIDTH / CELLS as f32; pub const CELLS_TARGET_NUMBER: usize = 100_000; pub const CHUNKS_RESOLUTION: usize = 2; -pub const CELLS_PER_CHUNK: usize = CELLS_TARGET_NUMBER / CHUNKS_RESOLUTION.pow(2); -pub const CELLS: usize = CELLS_PER_CHUNK * CHUNKS_RESOLUTION.pow(2); +pub const CHUNKS: usize = CHUNKS_RESOLUTION.pow(2); +pub const CELLS_PER_CHUNK: usize = CELLS_TARGET_NUMBER / CHUNKS; +pub const CELLS: usize = CELLS_PER_CHUNK * CHUNKS; #[derive(Resource)] struct Seed(u32); @@ -58,7 +60,7 @@ pub struct Voronoi(voronoice::Voronoi); pub struct MapMarker; #[derive(Component)] -struct MapMeshColors(Vec<[f32; 4]>); +struct MeshColors(Vec<[f32; 4]>); #[derive(Resource)] pub struct CellsEntities(Vec); @@ -105,10 +107,8 @@ fn setup( let mut cells = Vec::with_capacity(CELLS); let z_noise = Fbm::::new(seed.0); let moisture_noise = Fbm::::new(seed.0 + 1).set_frequency(2.); - let mut res = 0; for i in 0..CELLS { let c = voronoi.cell(i); - res += c.iter_neighbors().count(); let site = c.site_position(); let z = get_altitude(&z_noise, &[site.x as f32, site.y as f32]); let _m = ( @@ -131,17 +131,27 @@ fn setup( vertices: vec![], }); } - dbg!(res as f64 / CELLS as f64); - let mut poss = Vec::new(); - let mut indices = Vec::new(); + // let mut poss = [Vec::new(); CHUNKS]; + let mut indices: [Vec; CHUNKS] = std::array::from_fn(|_| Vec::new()); // let mut normals = Vec::new(); - for (i, pos) in voronoi.sites().iter().enumerate() { - let z = get_altitude(&z_noise, &[pos.x as f32, pos.y as f32]); - poss.push(Vec3::new(pos.x as f32, pos.y as f32, z)); - cells[i].vertices.push(i); - } + let mut poss = voronoi.sites().chunks_exact(CELLS_PER_CHUNK).map(|ch| { + ch.iter() + .map(|pos| { + let z = get_altitude(&z_noise, &[pos.x as f32, pos.y as f32]); + Vec3::new(pos.x as f32, pos.y as f32, z) + }) + .collect::>() + }); + let mut poss: [Vec; CHUNKS] = std::array::from_fn(|_| poss.next().unwrap()); + + // for (i, pos) in voronoi.sites().iter().enumerate() { + // let z = get_altitude(&z_noise, &[pos.x as f32, pos.y as f32]); + // poss.push(Vec3::new(pos.x as f32, pos.y as f32, z)); + // cells[i].vertices.push(i); + // } + // let mut hybrid_cells: HashMap = HashMap::new(); for t in voronoi.triangulation().triangles.chunks_exact(3) { let on_hull = t .iter() @@ -151,7 +161,53 @@ fn setup( if on_hull > 0 { continue; } - indices.extend_from_slice(&[t[2] as u32, t[1] as u32, t[0] as u32]); + let mut chs = t.iter().map(|c| Cell::chunk_from_id(*c)); + let chs: [usize; 3] = std::array::from_fn(|_| chs.next().unwrap()); + // Add vertex to chunk if it is from an external chunk but we need it for a triangle. Else, just make the triangle + if chs[1] == chs[2] && chs[0] != chs[1] { + poss[chs[1]].push(poss[chs[0]][t[0] % CELLS_PER_CHUNK]); + // hybrid_cells.insert(chs[0], chs[1]); + indices[chs[1]].push((poss[chs[1]].len() - 1) as u32); + } else { + indices[chs[0]].push((t[0] % CELLS_PER_CHUNK) as u32); + } + if chs[0] == chs[2] && chs[1] != chs[0] { + poss[chs[0]].push(poss[chs[1]][t[1] % CELLS_PER_CHUNK]); + // hybrid_cells.insert(chs[1], chs[0]); + indices[chs[0]].push((poss[chs[0]].len() - 1) as u32); + } else { + indices[chs[1]].push((t[1] % CELLS_PER_CHUNK) as u32); + } + if chs[0] == chs[1] && chs[2] != chs[0] { + poss[chs[0]].push(poss[chs[2]][t[2] % CELLS_PER_CHUNK]); + // hybrid_cells.insert(chs[2], chs[0]); + indices[chs[0]].push((poss[chs[0]].len() - 1) as u32); + } else { + indices[chs[2]].push((t[2] % CELLS_PER_CHUNK) as u32); + } + } + let mut cells_entities = Vec::with_capacity(cells.len()); + for cell in cells { + let kind = cell.kind; + // let id = cell.voronoi_id; + let mut cmd = cmds.spawn(cell); + // if let Some(ch) = hybrid_cells.get(&id) { + // cmd.insert(GhostCell(*ch)); + // } + match kind { + CellKind::Grass | CellKind::Forest => { + cmd.insert(( + Wealth(0), + Regeneration { + last_update: Duration::ZERO, + full_growth_duration: kind.regen_full_growth_duration(), + }, + )); + } + _ => {} + } + cmd.observe(self::cells::on_click); + cells_entities.push(cmd.id()); } // indices.extend(voronoi.triangulation().triangles.iter().map(|t| *t as u32)); @@ -176,63 +232,47 @@ fn setup( // cd.vertices.extend_from_slice(&[i, i + v, i + v + 1]); // } // } + for (poss, indices) in poss.into_iter().zip(indices.into_iter()) { + let colors = vec![[0.; 4]; poss.len()]; + let mut mesh = Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetUsages::default(), + ) + // Add 4 vertices, each with its own position attribute (coordinate in + // 3D space), for each of the corners of the parallelogram. + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, poss) + .with_inserted_attribute(Mesh::ATTRIBUTE_COLOR, colors.clone()) + // .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_indices(Indices::U32(indices)); - let colors = vec![[0.; 4]; poss.len()]; - let mut mesh = Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetUsages::default(), - ) - // Add 4 vertices, each with its own position attribute (coordinate in - // 3D space), for each of the corners of the parallelogram. - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, poss) - .with_inserted_attribute(Mesh::ATTRIBUTE_COLOR, colors.clone()) - // .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) - .with_inserted_indices(Indices::U32(indices)); + mesh.compute_smooth_normals(); - mesh.compute_smooth_normals(); - - let mut cells_entities = Vec::with_capacity(cells.len()); - - cmds.spawn(( - Mesh3d(meshes.add(mesh)), - // StandardMaterial - // MeshMaterial3d(materials.add(StandardMaterial::default())), - MeshMaterial3d(materials.add(CellMaterial { - base: StandardMaterial::default(), - extension: CellMaterialExtension {}, - })), - Transform::default(), - MapMeshColors(colors), - MeshNeedsUpdate(true), - MapMarker, - )); - - for cell in cells { - let kind = cell.kind; - let mut cmd = cmds.spawn(cell); - match kind { - CellKind::Grass | CellKind::Forest => { - cmd.insert(( - Wealth(0), - Regeneration { - last_update: Duration::ZERO, - full_growth_duration: kind.regen_full_growth_duration(), - }, - )); - } - _ => {} - } - cmd.observe(self::cells::on_click); - cells_entities.push(cmd.id()); + cmds.spawn(( + Mesh3d(meshes.add(mesh)), + // StandardMaterial + // MeshMaterial3d(materials.add(StandardMaterial::default())), + MeshMaterial3d(materials.add(CellMaterial { + base: StandardMaterial { + alpha_mode: AlphaMode::Mask(0.5), + ..Default::default() + }, + extension: CellMaterialExtension {}, + })), + Transform::default(), + MeshColors(colors), + MeshNeedsUpdate(true), + MapMarker, + )); } cmds.insert_resource(Voronoi(voronoi)); cmds.insert_resource(CellsEntities(cells_entities)); } +// TODO: update this to take chunks into account fn update_map_mesh( cells: Query<(&Cell, Option<&Wealth>)>, - mut map: Query<(&Mesh3d, &mut MapMeshColors, &mut MeshNeedsUpdate), With>, + mut map: Query<(&Mesh3d, &mut MeshColors, &mut MeshNeedsUpdate), With>, mut meshes: ResMut>, ) { let (mesh, mut cols, mut needs_update) = map.single_mut(); diff --git a/src/map/cells.rs b/src/map/cells.rs index 54d5dc8..0ff5cba 100644 --- a/src/map/cells.rs +++ b/src/map/cells.rs @@ -7,7 +7,7 @@ use crate::{time::GameTime, ui::CurrentAction}; use super::{ animals::Animal, AnimalKind, CellsEntities, MapMarker, MeshNeedsUpdate, Voronoi, - AVERAGE_NEIGHBORS_NUMBER, CELL_AREA, + AVERAGE_NEIGHBORS_NUMBER, CELLS_PER_CHUNK, CELL_AREA, }; pub mod material; @@ -59,7 +59,7 @@ pub struct Cell { pub vertices: Vec, } impl Cell { - pub fn color(&self, wealth: u8) -> [f32; 4] { + pub const fn color(&self, wealth: u8) -> [f32; 4] { match self.kind { CellKind::Sea => [0., 0., 1., 1.], CellKind::Beach => [0.82, 0.84, 0.51, 1.], @@ -79,8 +79,20 @@ impl Cell { ], } } + pub const fn chunk_from_id(id: usize) -> usize { + id / CELLS_PER_CHUNK + } + pub const fn chunk(&self) -> usize { + Self::chunk_from_id(self.voronoi_id) + } } +// #[derive(Component)] +// /// Cell that's in another chunk but needs to be there to form a triangle +// pub struct GhostCell { +// pub chunk: +// }; + #[derive(Component)] pub struct Wealth(pub u8);