diff --git a/engine/world_generation/src/lib.rs b/engine/world_generation/src/lib.rs index abd9ebf..e67fd94 100644 --- a/engine/world_generation/src/lib.rs +++ b/engine/world_generation/src/lib.rs @@ -2,15 +2,51 @@ pub mod biome_painter; pub mod heightmap; pub mod hex_utils; pub mod mesh_generator; +pub mod packed_mesh_generator; pub mod tile_manager; pub mod tile_mapper; pub mod prelude { - use crate::hex_utils::HexCoord; - use bevy::math::{IVec2, UVec2}; + use crate::hex_utils::{HexCoord, INNER_RADIUS, OUTER_RADIUS}; + use bevy::math::{IVec2, UVec2, Vec2, Vec3}; use bevy::prelude::Resource; use bevy::render::mesh::MeshVertexAttribute; use bevy::render::render_resource::VertexFormat; + pub const TEX_MULTI: Vec2 = Vec2::new(1000., 1.); + + pub const HEX_CORNERS: [Vec3; 6] = [ + Vec3::new(0., 0., OUTER_RADIUS), + Vec3::new(INNER_RADIUS, 0., 0.5 * OUTER_RADIUS), + Vec3::new(INNER_RADIUS, 0., -0.5 * OUTER_RADIUS), + Vec3::new(0., 0., -OUTER_RADIUS), + Vec3::new(-INNER_RADIUS, 0., -0.5 * OUTER_RADIUS), + Vec3::new(-INNER_RADIUS, 0., 0.5 * OUTER_RADIUS), + ]; + + pub const HEX_NORMALS: [Vec3; 6] = [ + Vec3::new( + INNER_RADIUS / 2., + 0., + (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / 2., + ), + Vec3::Z, + Vec3::new( + INNER_RADIUS / -2., + 0., + (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / 2., + ), + Vec3::new( + INNER_RADIUS / -2., + 0., + (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / -2., + ), + Vec3::NEG_Z, + Vec3::new( + INNER_RADIUS / 2., + 0., + (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / -2., + ), + ]; pub struct GenerationConfig { pub noise_scale: f64, diff --git a/engine/world_generation/src/mesh_generator.rs b/engine/world_generation/src/mesh_generator.rs index 6cdd44c..8b3e7a9 100644 --- a/engine/world_generation/src/mesh_generator.rs +++ b/engine/world_generation/src/mesh_generator.rs @@ -2,10 +2,7 @@ use crate::biome_painter::BiomePainterAsset; use crate::hex_utils::HexCoord; use crate::tile_manager::TileAsset; use crate::tile_mapper::TileMapperAsset; -use crate::{ - hex_utils::{offset3d_to_world, INNER_RADIUS, OUTER_RADIUS}, - prelude::*, -}; +use crate::{hex_utils::offset3d_to_world, prelude::*}; use bevy::{ prelude::*, render::{ @@ -13,41 +10,79 @@ use bevy::{ render_asset::RenderAssetUsages, }, }; -use std::vec::Vec; -const HEX_CORNERS: [Vec3; 6] = [ - Vec3::new(0., 0., OUTER_RADIUS), - Vec3::new(INNER_RADIUS, 0., 0.5 * OUTER_RADIUS), - Vec3::new(INNER_RADIUS, 0., -0.5 * OUTER_RADIUS), - Vec3::new(0., 0., -OUTER_RADIUS), - Vec3::new(-INNER_RADIUS, 0., -0.5 * OUTER_RADIUS), - Vec3::new(-INNER_RADIUS, 0., 0.5 * OUTER_RADIUS), -]; +pub fn generate_chunk_collider(chunk: &Chunk, map: &Map) -> (Vec, Vec<[u32; 3]>) { + let vertex_count: usize = Chunk::SIZE * Chunk::SIZE * 6; + let mut verts = Vec::with_capacity(vertex_count); + let mut indices = Vec::with_capacity(vertex_count); + 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 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); + create_tile_collider(tile_pos, &mut verts, &mut indices, &neighbors); + } + } + return (verts, indices); +} -const HEX_NORMALS: [Vec3; 6] = [ - Vec3::new( - INNER_RADIUS / 2., - 0., - (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / 2., - ), - Vec3::Z, - Vec3::new( - INNER_RADIUS / -2., - 0., - (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / 2., - ), - Vec3::new( - INNER_RADIUS / -2., - 0., - (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / -2., - ), - Vec3::NEG_Z, - Vec3::new( - INNER_RADIUS / 2., - 0., - (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / -2., - ), -]; +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]; + verts.push(p); + } + for i in 0..3 { + let off = i * 2; + + indices.push([off + idx, ((off + 1) % 6) + idx, ((off + 2) % 6) + idx]); + } + + indices.push([idx, idx + 2, idx + 4]); + + for i in 0..neighbors.len() { + let cur_n = neighbors[i]; + match cur_n { + Some(n_height) => { + if n_height < pos.y { + create_tile_wall_collider( + idx, + Vec3::new(pos.x, n_height, pos.z), + i, + verts, + indices, + ); + } + } + _ => {} + } + } +} + +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]); + verts.push(pos + HEX_CORNERS[(dir + 1) % 6]); + + indices.push([idx, idx + 1, idx2]); + indices.push([idx, idx2 + 1, idx2]); +} pub fn generate_chunk_mesh( chunk: &Chunk, @@ -102,132 +137,6 @@ pub fn generate_chunk_mesh( return mesh; } -pub fn generate_packed_chunk_mesh( - chunk: &Chunk, - map: &Map, - painter: &BiomePainterAsset, - tiles: &Res>, - mappers: &Res>, -) -> Mesh { - let vertex_count: usize = Chunk::SIZE * Chunk::SIZE * 6; - let mut packed_data = Vec::with_capacity(vertex_count); - let mut indices = Vec::with_capacity(vertex_count); - let mut heights = Vec::with_capacity(vertex_count); - - for z in 0..Chunk::SIZE { - for x in 0..Chunk::SIZE { - 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 n = map.get_neighbors(&coord); - let biome = mappers.get(painter.sample_biome(moisture, temperature)); - let tile_handle = biome.unwrap().sample_tile(height); - let tile = tiles.get(tile_handle).unwrap(); - - create_packed_tile( - UVec2::new(x as u32, z as u32), - height, - &n, - &mut packed_data, - &mut indices, - &mut heights, - tile.texture_id, - tile.side_texture_id, - ); - } - } - - let mesh = Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD, - ) - .with_inserted_attribute(ATTRIBUTE_PACKED_VERTEX_DATA, packed_data) - .with_inserted_attribute(ATTRIBUTE_VERTEX_HEIGHT, heights) - .with_inserted_indices(Indices::U32(indices)); - return mesh; -} - -const TEX_MULTI: Vec2 = Vec2::new(1000., 1.); - -fn create_packed_tile( - offset: UVec2, - height: f32, - neighbors: &[Option; 6], - packed_data: &mut Vec, - indices: &mut Vec, - heights: &mut Vec, - texture_index: u32, - side_texture_index: u32, -) { - let idx = packed_data.len() as u32; - - packed_data.push(pack_vertex_data(offset, 0, texture_index)); - heights.push(height); - for i in 0..6 { - packed_data.push(pack_vertex_data(offset, i + 1, texture_index)); - indices.push(idx); - indices.push(idx + 1 + i as u32); - indices.push(idx + 1 + ((i as u32 + 1) % 6)); - heights.push(height); - } - - for i in 0..neighbors.len() { - let cur_n = neighbors[i]; - match cur_n { - Some(n_height) => { - if n_height < height { - create_packed_tile_wall( - offset, - height, - n_height, - i, - packed_data, - indices, - heights, - side_texture_index, - ); - } - } - _ => {} - } - } -} - -fn create_packed_tile_wall( - offset: UVec2, - height_top: f32, - height_bottom: f32, - side: usize, - packed_data: &mut Vec, - indices: &mut Vec, - heights: &mut Vec, - side_texture_index: u32, -) { - let idx = packed_data.len() as u32; - - let side_2 = ((side + 1) % 6) + 1; - packed_data.push(pack_vertex_data(offset, side + 1, side_texture_index)); - packed_data.push(pack_vertex_data(offset, side_2, side_texture_index)); - packed_data.push(pack_vertex_data(offset, side + 1, side_texture_index)); - packed_data.push(pack_vertex_data(offset, side_2, side_texture_index)); - - heights.push(height_top); - heights.push(height_top); - heights.push(height_bottom); - heights.push(height_bottom); - - indices.push(idx); - indices.push(idx + 2); - indices.push(idx + 1); - - indices.push(idx + 1); - indices.push(idx + 2); - indices.push(idx + 3); -} - fn create_tile( pos: Vec3, neighbors: &[Option; 6], @@ -243,19 +152,22 @@ fn create_tile( let side_tex_off = Vec2::new(side_texture_index as f32, 0.); let idx = verts.len() as u32; - uvs.push((uv_offset / TEX_MULTI) + tex_off); - verts.push(pos); - normals.push(Vec3::Y); for i in 0..6 { let p = pos + HEX_CORNERS[i]; verts.push(p); let uv = (HEX_CORNERS[i].xz() / 2.) + uv_offset; uvs.push((uv / TEX_MULTI) + tex_off); - indices.push(idx); - indices.push(idx + 1 + i as u32); - indices.push(idx + 1 + ((i as u32 + 1) % 6)); normals.push(Vec3::Y); } + for i in 0..3 { + let off = i * 2; + indices.push(off + idx); + indices.push(((off + 1) % 6) + idx); + indices.push(((off + 2) % 6) + idx); + } + indices.push(idx); + indices.push(idx + 2); + indices.push(idx + 4); for i in 0..neighbors.len() { let cur_n = neighbors[i]; @@ -311,15 +223,3 @@ fn create_tile_wall( uvs.push((Vec2::new(0., pos.y - height) / TEX_MULTI) + tex_off); uvs.push((Vec2::new(1., pos.y - height) / TEX_MULTI) + tex_off); } - -fn pack_vertex_data(offset: UVec2, vert: usize, tex: u32) -> u32 { - //6 + 6 bits offset - //4 bits vert - //12 bits texture - let mut data = offset.x; - data += (offset.y) << 6; - data += (vert as u32) << (6 + 6); - data += tex << (6 + 6 + 4); - - return data; -} diff --git a/engine/world_generation/src/packed_mesh_generator.rs b/engine/world_generation/src/packed_mesh_generator.rs new file mode 100644 index 0000000..77e109d --- /dev/null +++ b/engine/world_generation/src/packed_mesh_generator.rs @@ -0,0 +1,148 @@ +use crate::biome_painter::BiomePainterAsset; +use crate::hex_utils::HexCoord; +use crate::prelude::*; +use crate::tile_manager::TileAsset; +use crate::tile_mapper::TileMapperAsset; +use bevy::{ + prelude::*, + render::{ + mesh::{Indices, PrimitiveTopology}, + render_asset::RenderAssetUsages, + }, +}; + +pub fn generate_packed_chunk_mesh( + chunk: &Chunk, + map: &Map, + painter: &BiomePainterAsset, + tiles: &Res>, + mappers: &Res>, +) -> Mesh { + let vertex_count: usize = Chunk::SIZE * Chunk::SIZE * 6; + let mut packed_data = Vec::with_capacity(vertex_count); + let mut indices = Vec::with_capacity(vertex_count); + let mut heights = Vec::with_capacity(vertex_count); + + for z in 0..Chunk::SIZE { + for x in 0..Chunk::SIZE { + 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 n = map.get_neighbors(&coord); + let biome = mappers.get(painter.sample_biome(moisture, temperature)); + let tile_handle = biome.unwrap().sample_tile(height); + let tile = tiles.get(tile_handle).unwrap(); + + create_packed_tile( + UVec2::new(x as u32, z as u32), + height, + &n, + &mut packed_data, + &mut indices, + &mut heights, + tile.texture_id, + tile.side_texture_id, + ); + } + } + + let mesh = Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD, + ) + .with_inserted_attribute(ATTRIBUTE_PACKED_VERTEX_DATA, packed_data) + .with_inserted_attribute(ATTRIBUTE_VERTEX_HEIGHT, heights) + .with_inserted_indices(Indices::U32(indices)); + return mesh; +} + +fn create_packed_tile( + offset: UVec2, + height: f32, + neighbors: &[Option; 6], + packed_data: &mut Vec, + indices: &mut Vec, + heights: &mut Vec, + texture_index: u32, + side_texture_index: u32, +) { + let idx = packed_data.len() as u32; + + packed_data.push(pack_vertex_data(offset, 0, texture_index)); + heights.push(height); + for i in 0..6 { + packed_data.push(pack_vertex_data(offset, i + 1, texture_index)); + indices.push(idx); + indices.push(idx + 1 + i as u32); + indices.push(idx + 1 + ((i as u32 + 1) % 6)); + heights.push(height); + } + + for i in 0..neighbors.len() { + let cur_n = neighbors[i]; + match cur_n { + Some(n_height) => { + if n_height < height { + create_packed_tile_wall( + offset, + height, + n_height, + i, + packed_data, + indices, + heights, + side_texture_index, + ); + } + } + _ => {} + } + } +} + +fn create_packed_tile_wall( + offset: UVec2, + height_top: f32, + height_bottom: f32, + side: usize, + packed_data: &mut Vec, + indices: &mut Vec, + heights: &mut Vec, + side_texture_index: u32, +) { + let idx = packed_data.len() as u32; + + let side_2 = ((side + 1) % 6) + 1; + packed_data.push(pack_vertex_data(offset, side + 1, side_texture_index)); + packed_data.push(pack_vertex_data(offset, side_2, side_texture_index)); + packed_data.push(pack_vertex_data(offset, side + 1, side_texture_index)); + packed_data.push(pack_vertex_data(offset, side_2, side_texture_index)); + + heights.push(height_top); + heights.push(height_top); + heights.push(height_bottom); + heights.push(height_bottom); + + indices.push(idx); + indices.push(idx + 2); + indices.push(idx + 1); + + indices.push(idx + 1); + indices.push(idx + 2); + indices.push(idx + 3); +} + +fn pack_vertex_data(offset: UVec2, vert: usize, tex: u32) -> u32 { + //6 + 6 bits offset + //4 bits vert + //12 bits texture + let mut data = offset.x; + data += (offset.y) << 6; + data += (vert as u32) << (6 + 6); + data += tex << (6 + 6 + 4); + + return data; +} diff --git a/game/main/src/main.rs b/game/main/src/main.rs index 22a1955..f2e7f15 100644 --- a/game/main/src/main.rs +++ b/game/main/src/main.rs @@ -1,3 +1,4 @@ +use bevy::pbr::wireframe::WireframePlugin; use bevy::prelude::*; use bevy::render::texture::{ImageAddressMode, ImageFilterMode, ImageSamplerDescriptor}; use bevy::window::PresentMode; @@ -32,6 +33,7 @@ fn main() { }, }), WorldInspectorPlugin::new(), + WireframePlugin, PhosGamePlugin, )) .run(); diff --git a/game/main/src/phos.rs b/game/main/src/phos.rs index 11b2c7e..7394727 100644 --- a/game/main/src/phos.rs +++ b/game/main/src/phos.rs @@ -1,10 +1,15 @@ use crate::prelude::*; use crate::shader_extensions::chunk_material::ChunkMaterial; use bevy::asset::LoadState; -use bevy::pbr::ExtendedMaterial; -use bevy::{pbr::CascadeShadowConfig, prelude::*}; +use bevy::pbr::{ExtendedMaterial, PbrPlugin}; +use bevy::{ + pbr::{wireframe::WireframeConfig, CascadeShadowConfig}, + prelude::*, +}; +use bevy_rapier3d::dynamics::{RigidBody, Velocity}; +use bevy_rapier3d::geometry::{Collider, Restitution}; use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin}; -use bevy_rapier3d::render::RapierDebugRenderPlugin; +use camera_system::prelude::PhosCamera; use camera_system::PhosCameraPlugin; use iyes_perf_ui::prelude::*; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; @@ -12,6 +17,7 @@ use world_generation::biome_painter::{ BiomePainterAsset, BiomePainterLoadState, BiomePainterPlugin, }; use world_generation::hex_utils::offset_to_world; +use world_generation::mesh_generator::generate_chunk_collider; use world_generation::tile_manager::{TileAsset, TileAssetLoadState, TileAssetPlugin, TileManager}; use world_generation::tile_mapper::{TileMapperAsset, TileMapperAssetPlugin, TileMapperLoadState}; use world_generation::{ @@ -32,7 +38,7 @@ impl Plugin for PhosGamePlugin { .add_systems(Startup, (load_textures, load_tiles, create_map).chain()); //Systems - Update - app.add_systems(Update, (finalize_texture, spawn_map)); + app.add_systems(Update, (finalize_texture, spawn_map, spawn_sphere)); //Perf UI app.add_plugins(bevy::diagnostic::FrameTimeDiagnosticsPlugin) @@ -45,12 +51,17 @@ impl Plugin for PhosGamePlugin { app.add_plugins(TileMapperAssetPlugin); app.add_plugins(BiomePainterPlugin); //Physics - app.add_plugins(RapierPhysicsPlugin::::default()) - .add_plugins(RapierDebugRenderPlugin::default()); + app.add_plugins(RapierPhysicsPlugin::::default()); + // .add_plugins(RapierDebugRenderPlugin::default()); + + app.insert_resource(WireframeConfig { + global: false, + default_color: Color::hex("FF0064").unwrap(), + }); } } -fn init_game(mut commands: Commands) { +fn init_game(mut commands: Commands, mut materials: ResMut>) { commands.spawn(( PerfUiRoot::default(), PerfUiEntryFPS::default(), @@ -65,7 +76,7 @@ fn init_game(mut commands: Commands) { ..default() }, cascade_shadow_config: CascadeShadowConfig { - bounds: vec![500., 1000., 2000., 5000.], + bounds: vec![500., 1000., 1500., 2000.], ..default() }, transform: Transform::from_xyz(500., 260.0, 500.).looking_at(Vec3::ZERO, Vec3::Y), @@ -74,6 +85,13 @@ fn init_game(mut commands: Commands) { commands.insert_resource(PhosMap::default()); commands.insert_resource(TileManager::default()); + + let sphere_mat = StandardMaterial { + base_color: Color::CYAN, + ..default() + }; + let handle = materials.add(sphere_mat); + commands.insert_resource(SphereMat(handle)); } fn load_textures(mut commands: Commands, asset_server: Res) { @@ -221,14 +239,16 @@ fn spawn_map( .map(|chunk: &Chunk| { 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.), ); }) .collect(); - for (mesh, pos) in chunk_meshes { + for (mesh, (col_verts, col_indicies), pos) in chunk_meshes { commands.spawn(( MaterialMeshBundle { mesh: meshes.add(mesh), @@ -237,30 +257,36 @@ fn spawn_map( ..default() }, PhosChunk, + Collider::trimesh(col_verts, col_indicies), )); } - - // for chunk in &heightmap.chunks { - // let mesh = generate_chunk_mesh( - // &chunk, - // &heightmap, - // b_painter.unwrap(), - // &tile_assets, - // &tile_mappers, - // ); - // let pos = offset_to_world(chunk.chunk_offset * Chunk::SIZE as i32, 0.); - // commands.spawn(( - // MaterialMeshBundle { - // mesh: meshes.add(mesh), - // material: chunk_material.clone(), - // transform: Transform::from_translation(pos), - // ..default() - // }, - // PhosChunk::from_translation(pos), - // )); - // } } +#[derive(Resource)] +struct SphereMat(Handle); + +fn spawn_sphere( + mut commands: Commands, + cam: Query<&Transform, With>, + keyboard_input: Res>, + mut meshes: ResMut>, + mat: Res, +) { + if keyboard_input.just_pressed(KeyCode::KeyF) { + let cam_transform = cam.single(); + commands.spawn(( + MaterialMeshBundle { + mesh: meshes.add(Sphere::new(0.5)), + material: mat.0.clone(), + transform: Transform::from_translation(cam_transform.translation), + ..default() + }, + Collider::ball(0.5), + RigidBody::Dynamic, + Velocity::linear(cam_transform.forward() * 100.), + )); + } +} // fn render_distance_system( // mut chunks: Query<(&PhosChunk, &mut Visibility)>, // camera: Query<&Transform, With>, diff --git a/game/main/src/shader_extensions/chunk_material.rs b/game/main/src/shader_extensions/chunk_material.rs index 0d05a5c..223c4f6 100644 --- a/game/main/src/shader_extensions/chunk_material.rs +++ b/game/main/src/shader_extensions/chunk_material.rs @@ -1,10 +1,8 @@ use bevy::asset::{Asset, Handle}; use bevy::pbr::MaterialExtension; use bevy::reflect::TypePath; -use bevy::render::mesh::Mesh; use bevy::render::render_resource::{AsBindGroup, ShaderRef}; use bevy::render::texture::Image; -use world_generation::prelude::{ATTRIBUTE_PACKED_VERTEX_DATA, ATTRIBUTE_VERTEX_HEIGHT}; #[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] pub struct ChunkMaterial {