diff --git a/engine/world_generation/src/chunk_colliders.rs b/engine/world_generation/src/chunk_colliders.rs index 54cf1df..2bc15ea 100644 --- a/engine/world_generation/src/chunk_colliders.rs +++ b/engine/world_generation/src/chunk_colliders.rs @@ -11,9 +11,8 @@ pub fn generate_chunk_collider(chunk: &Chunk, map: &Map) -> (Vec, Vec<[u32 for z in 0..Chunk::SIZE { for x in 0..Chunk::SIZE { let height = chunk.heights[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 coord = + HexCoord::from_offset(IVec2::new(x as i32, z as i32) + (chunk.chunk_offset * Chunk::SIZE as i32)); let neighbors = map.get_neighbors(&coord); let off_pos = Vec3::new(x as f32, height, z as f32); let tile_pos = offset3d_to_world(off_pos); @@ -23,12 +22,7 @@ pub fn generate_chunk_collider(chunk: &Chunk, map: &Map) -> (Vec, Vec<[u32 return (verts, indices); } -fn create_tile_collider( - pos: Vec3, - verts: &mut Vec, - indices: &mut Vec<[u32; 3]>, - neighbors: &[Option; 6], -) { +fn create_tile_collider(pos: Vec3, verts: &mut Vec, indices: &mut Vec<[u32; 3]>, neighbors: &[Option; 6]) { let idx = verts.len() as u32; for i in 0..6 { let p = pos + HEX_CORNERS[i]; @@ -66,13 +60,7 @@ fn create_tile_collider( } } -fn create_tile_wall_collider( - idx: u32, - pos: Vec3, - dir: usize, - verts: &mut Vec, - indices: &mut Vec<[u32; 3]>, -) { +fn create_tile_wall_collider(idx: u32, pos: Vec3, dir: usize, verts: &mut Vec, indices: &mut Vec<[u32; 3]>) { let idx2 = verts.len() as u32; verts.push(pos + HEX_CORNERS[dir]); diff --git a/engine/world_generation/src/hex_utils.rs b/engine/world_generation/src/hex_utils.rs index 41c6be5..05cadff 100644 --- a/engine/world_generation/src/hex_utils.rs +++ b/engine/world_generation/src/hex_utils.rs @@ -28,6 +28,10 @@ pub fn offset_to_hex(offset: IVec2) -> IVec3 { return v; } +pub fn offset_to_index(offset: IVec2, width: usize) -> usize { + return offset.x as usize + offset.y as usize * width; +} + pub fn snap_to_hex_grid(world_pos: Vec3) -> Vec3 { return offset_to_world(world_to_offset_pos(world_pos), world_pos.y); } diff --git a/engine/world_generation/src/mesh_generator.rs b/engine/world_generation/src/mesh_generator.rs index 4ea2e27..d723073 100644 --- a/engine/world_generation/src/mesh_generator.rs +++ b/engine/world_generation/src/mesh_generator.rs @@ -11,8 +11,6 @@ use bevy::{ }, }; - - pub fn generate_chunk_mesh( chunk: &Chunk, map: &Map, @@ -33,9 +31,8 @@ pub fn generate_chunk_mesh( let temperature = chunk.temperature[x + z * Chunk::SIZE]; let off_pos = Vec3::new(x as f32, height, z as f32); let tile_pos = offset3d_to_world(off_pos); - let coord = HexCoord::from_offset( - IVec2::new(x as i32, z as i32) + (chunk.chunk_offset * Chunk::SIZE as i32), - ); + 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); let biome = mappers.get(painter.sample_biome(moisture, temperature)); let tile_handle = biome.unwrap().sample_tile(height); diff --git a/engine/world_generation/src/packed_mesh_generator.rs b/engine/world_generation/src/packed_mesh_generator.rs index 77e109d..823f484 100644 --- a/engine/world_generation/src/packed_mesh_generator.rs +++ b/engine/world_generation/src/packed_mesh_generator.rs @@ -28,9 +28,8 @@ pub fn generate_packed_chunk_mesh( let height = chunk.heights[x + z * Chunk::SIZE]; let moisture = chunk.moisture[x + z * Chunk::SIZE]; let temperature = chunk.temperature[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 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); let biome = mappers.get(painter.sample_biome(moisture, temperature)); let tile_handle = biome.unwrap().sample_tile(height); diff --git a/game/main/src/main.rs b/game/main/src/main.rs index 025f1f6..e193a2e 100644 --- a/game/main/src/main.rs +++ b/game/main/src/main.rs @@ -6,7 +6,7 @@ use bevy_inspector_egui::quick::WorldInspectorPlugin; use phos::PhosGamePlugin; mod camera_system; -mod map_init; +mod map_rendering; mod phos; mod prelude; mod shader_extensions; diff --git a/game/main/src/map_rendering/chunk_rebuild.rs b/game/main/src/map_rendering/chunk_rebuild.rs new file mode 100644 index 0000000..3ae55f3 --- /dev/null +++ b/game/main/src/map_rendering/chunk_rebuild.rs @@ -0,0 +1,90 @@ +use bevy::prelude::*; +use bevy_rapier3d::geometry::{Collider, TriMeshFlags}; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +use world_generation::{ + biome_painter::BiomePainterAsset, + chunk_colliders::generate_chunk_collider, + hex_utils::{self, offset_to_world, SHORT_DIAGONAL}, + mesh_generator::generate_chunk_mesh, + prelude::{Chunk, Map}, + tile_manager::TileAsset, + tile_mapper::TileMapperAsset, +}; + +use crate::{ + prelude::{ChunkAtlas, PhosChunk, PhosChunkRegistry}, + utlis::render_distance_system::RenderDistanceVisibility, +}; + +use super::prelude::CurrentBiomePainter; +pub struct ChunkRebuildPlugin; + +impl Plugin for ChunkRebuildPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(ChunkRebuildQueue::default()); + app.add_systems(PostUpdate, chunk_rebuilder); + } +} + +#[derive(Resource, Default)] +pub struct ChunkRebuildQueue { + pub queue: Vec, +} + +fn chunk_rebuilder( + mut commands: Commands, + mut queue: ResMut, + mut chunks: ResMut, + atlas: Res, + heightmap: Res, + tile_assets: Res>, + tile_mappers: Res>, + mut meshes: ResMut>, + biome_painters: Res>, + painter: Res, +) { + for chunk_index in &queue.queue { + let chunk = chunks.chunks[*chunk_index]; + commands.entity(chunk).despawn(); + } + + let b_painter = biome_painters.get(painter.handle.clone()); + + let cur_painter = b_painter.unwrap(); + + let chunk_meshes: Vec<_> = queue + .queue + .par_iter() + .map(|idx| { + let chunk = &heightmap.chunks[*idx]; + let mesh = generate_chunk_mesh(chunk, &heightmap, cur_painter, &tile_assets, &tile_mappers); + let collision = generate_chunk_collider(chunk, &heightmap); + return ( + mesh, + collision, + offset_to_world(chunk.chunk_offset * Chunk::SIZE as i32, 0.), + hex_utils::offset_to_index(chunk.chunk_offset, heightmap.width), + ); + }) + .collect(); + + for (mesh, (col_verts, col_indicies), pos, index) in chunk_meshes { + let chunk = commands.spawn(( + MaterialMeshBundle { + mesh: meshes.add(mesh), + material: atlas.chunk_material_handle.clone(), + transform: Transform::from_translation(pos), + ..default() + }, + PhosChunk::new(index), + RenderDistanceVisibility::default().with_offset(Vec3::new( + (Chunk::SIZE / 2) as f32 * SHORT_DIAGONAL, + 0., + (Chunk::SIZE / 2) as f32 * 1.5, + )), + Collider::trimesh_with_flags(col_verts, col_indicies, TriMeshFlags::MERGE_DUPLICATE_VERTICES), + )); + chunks.chunks[index] = chunk.id(); + } + queue.queue.clear(); +} diff --git a/game/main/src/map_init.rs b/game/main/src/map_rendering/map_init.rs similarity index 88% rename from game/main/src/map_init.rs rename to game/main/src/map_rendering/map_init.rs index b01ca33..5c3f5e8 100644 --- a/game/main/src/map_init.rs +++ b/game/main/src/map_rendering/map_init.rs @@ -1,4 +1,4 @@ -use bevy::{asset::LoadState, pbr::ExtendedMaterial, prelude::*}; +use bevy::{asset::LoadState, log::tracing_subscriber::registry, pbr::ExtendedMaterial, prelude::*}; use bevy_inspector_egui::quick::ResourceInspectorPlugin; use bevy_rapier3d::geometry::{Collider, TriMeshFlags}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; @@ -6,7 +6,7 @@ use world_generation::{ biome_painter::*, chunk_colliders::generate_chunk_collider, heightmap::generate_heightmap, - hex_utils::{offset_to_world, SHORT_DIAGONAL}, + hex_utils::{self, offset_to_world, SHORT_DIAGONAL}, mesh_generator::generate_chunk_mesh, prelude::*, tile_manager::*, @@ -15,11 +15,13 @@ use world_generation::{ use crate::{ camera_system::components::*, - prelude::{ChunkAtlas, PhosChunk, PhosMap}, + prelude::{ChunkAtlas, PhosChunk, PhosChunkRegistry, PhosMap}, shader_extensions::chunk_material::ChunkMaterial, utlis::render_distance_system::RenderDistanceVisibility, }; +use super::prelude::CurrentBiomePainter; + pub struct MapInitPlugin; impl Plugin for MapInitPlugin { @@ -58,12 +60,10 @@ fn load_textures( water_material: water_material, }); } -#[derive(Resource)] -struct Painter(Handle); fn load_tiles(mut commands: Commands, asset_server: Res) { let handle: Handle = asset_server.load("biome_painters/terra.biomes.json"); - commands.insert_resource(Painter(handle)); + commands.insert_resource(CurrentBiomePainter { handle }); } fn finalize_texture( @@ -71,7 +71,7 @@ fn finalize_texture( mut atlas: ResMut, mut map: ResMut, mut images: ResMut>, - painter: Res, + painter: Res, painter_load: Res, tile_load: Res, mut chunk_materials: ResMut>>, @@ -88,7 +88,7 @@ fn finalize_texture( if asset_server.load_state(atlas.handle.clone()) != LoadState::Loaded { return; } - if asset_server.load_state(painter.0.clone()) != LoadState::Loaded { + if asset_server.load_state(painter.handle.clone()) != LoadState::Loaded { return; } let image = images.get_mut(&atlas.handle).unwrap(); @@ -198,12 +198,12 @@ fn spawn_map( tile_assets: Res>, tile_mappers: Res>, biome_painters: Res>, - painter: Res, + painter: Res, ) { if !map.ready || !map.regenerate { return; } - let b_painter = biome_painters.get(painter.0.clone()); + let b_painter = biome_painters.get(painter.handle.clone()); map.regenerate = false; let cur_painter = b_painter.unwrap(); @@ -218,19 +218,22 @@ fn spawn_map( mesh, collision, offset_to_world(chunk.chunk_offset * Chunk::SIZE as i32, 0.), + hex_utils::offset_to_index(chunk.chunk_offset, heightmap.width), ); }) .collect(); - for (mesh, (col_verts, col_indicies), pos) in chunk_meshes { - commands.spawn(( + let mut registry = PhosChunkRegistry::new(chunk_meshes.len()); + + for (mesh, (col_verts, col_indicies), pos, index) in chunk_meshes { + let chunk = commands.spawn(( MaterialMeshBundle { mesh: meshes.add(mesh), material: atlas.chunk_material_handle.clone(), transform: Transform::from_translation(pos), ..default() }, - PhosChunk, + PhosChunk::new(index), RenderDistanceVisibility::default().with_offset(Vec3::new( (Chunk::SIZE / 2) as f32 * SHORT_DIAGONAL, 0., @@ -238,6 +241,7 @@ fn spawn_map( )), Collider::trimesh_with_flags(col_verts, col_indicies, TriMeshFlags::MERGE_DUPLICATE_VERTICES), )); + registry.chunks.push(chunk.id()); } commands.spawn((PbrBundle { @@ -250,6 +254,8 @@ fn spawn_map( material: atlas.water_material.clone(), ..default() },)); + + commands.insert_resource(registry); } fn despawn_map( diff --git a/game/main/src/map_rendering/mod.rs b/game/main/src/map_rendering/mod.rs new file mode 100644 index 0000000..44fe72b --- /dev/null +++ b/game/main/src/map_rendering/mod.rs @@ -0,0 +1,4 @@ +pub mod chunk_rebuild; +pub mod map_init; +pub mod prelude; +pub mod terraforming_test; diff --git a/game/main/src/map_rendering/prelude.rs b/game/main/src/map_rendering/prelude.rs new file mode 100644 index 0000000..2d19549 --- /dev/null +++ b/game/main/src/map_rendering/prelude.rs @@ -0,0 +1,7 @@ +use bevy::prelude::*; +use world_generation::biome_painter::BiomePainterAsset; + +#[derive(Resource)] +pub struct CurrentBiomePainter { + pub handle: Handle, +} diff --git a/game/main/src/map_rendering/terraforming_test.rs b/game/main/src/map_rendering/terraforming_test.rs new file mode 100644 index 0000000..b8d46e7 --- /dev/null +++ b/game/main/src/map_rendering/terraforming_test.rs @@ -0,0 +1,37 @@ +use bevy::prelude::*; +use bevy_rapier3d::{pipeline::QueryFilter, plugin::RapierContext}; +use world_generation::{hex_utils::HexCoord, prelude::Map}; + +use crate::camera_system::components::PhosCamera; + +use super::chunk_rebuild::ChunkRebuildQueue; + +pub struct TerraFormingTestPlugin; + +impl Plugin for TerraFormingTestPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Update, deform); + } +} + +fn deform( + cam: Query<&Transform, With>, + keyboard: Res>, + rapier_context: Res, + mut heightmap: ResMut, + mut rebuild: ResMut, +) { + if !keyboard.pressed(KeyCode::KeyF) { + return; + } + + let cam_transform = cam.single(); + let fwd: Vec3 = cam_transform.forward().into(); + + let collision = rapier_context.cast_ray(cam_transform.translation, fwd, 100., true, QueryFilter::only_fixed()); + + if let Some((entity, dist)) = collision { + let contact_point = cam_transform.translation + (fwd * dist); + let contact_coord = HexCoord::from_world_pos(contact_point); + } +} diff --git a/game/main/src/phos.rs b/game/main/src/phos.rs index 2c3e81d..526057a 100644 --- a/game/main/src/phos.rs +++ b/game/main/src/phos.rs @@ -1,7 +1,7 @@ use crate::camera_system::camera_plugin::PhosCameraPlugin; use crate::camera_system::components::PhosCamera; -use crate::map_init::MapInitPlugin; -use crate::prelude::*; +use crate::map_rendering::chunk_rebuild::ChunkRebuildPlugin; +use crate::map_rendering::map_init::MapInitPlugin; use crate::shader_extensions::chunk_material::ChunkMaterial; use crate::utlis::render_distance_system::RenderDistancePlugin; use bevy::pbr::ExtendedMaterial; @@ -26,6 +26,7 @@ impl Plugin for PhosGamePlugin { MapInitPlugin, MaterialPlugin::>::default(), RenderDistancePlugin, + ChunkRebuildPlugin, )); //Systems - Startup diff --git a/game/main/src/prelude.rs b/game/main/src/prelude.rs index d68400e..292bd40 100644 --- a/game/main/src/prelude.rs +++ b/game/main/src/prelude.rs @@ -22,4 +22,25 @@ pub struct PhosMap { } #[derive(Component)] -pub struct PhosChunk; +pub struct PhosChunk { + pub index: usize, +} + +impl PhosChunk { + pub fn new(index: usize) -> Self { + return Self { index }; + } +} + +#[derive(Resource, Default)] +pub struct PhosChunkRegistry { + pub chunks: Vec, +} + +impl PhosChunkRegistry { + pub fn new(size: usize) -> Self { + return Self { + chunks: Vec::with_capacity(size), + }; + } +}