diff --git a/engine/world_generation/src/lib.rs b/engine/world_generation/src/lib.rs index afe097a..a47f467 100644 --- a/engine/world_generation/src/lib.rs +++ b/engine/world_generation/src/lib.rs @@ -94,6 +94,8 @@ pub mod prelude { return chunk.temperature[pos.to_chunk_local_index()]; } } + pub const ATTRIBUTE_PACKED_VERTEX_DATA: MeshVertexAttribute = + MeshVertexAttribute::new("PackedVertexData", 988540817, VertexFormat::Uint32); pub const ATTRIBUTE_TEXTURE_INDEX: MeshVertexAttribute = MeshVertexAttribute::new("TextureIndex", 988540917, VertexFormat::Uint32); diff --git a/engine/world_generation/src/mesh_generator.rs b/engine/world_generation/src/mesh_generator.rs index 95517eb..676036b 100644 --- a/engine/world_generation/src/mesh_generator.rs +++ b/engine/world_generation/src/mesh_generator.rs @@ -102,7 +102,131 @@ 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_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], @@ -187,12 +311,12 @@ fn create_tile_wall( uvs.push((Vec2::new(1., pos.y - height) / TEX_MULTI) + tex_off); } -fn pack_vertex_data(offset: IVec2, vert: usize, tex: u32) -> u32 { +fn pack_vertex_data(offset: UVec2, vert: usize, tex: u32) -> u32 { //4 bits vert //6 + 6 bits offset //12 bits texture - let mut data = offset.x as u32; - data += (offset.y as u32) << 6; + let mut data = offset.x; + data += (offset.y) << 6; data += (vert as u32) << (6 + 6); data += tex << (6 + 6 + 4); diff --git a/game/main/src/shader_extensions/chunk_material.rs b/game/main/src/shader_extensions/chunk_material.rs index fdd8842..e726aad 100644 --- a/game/main/src/shader_extensions/chunk_material.rs +++ b/game/main/src/shader_extensions/chunk_material.rs @@ -1,8 +1,10 @@ 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; #[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] pub struct ChunkMaterial { @@ -15,4 +17,24 @@ impl MaterialExtension for ChunkMaterial { fn fragment_shader() -> ShaderRef { "shaders/world/chunk.wgsl".into() } + + fn vertex_shader() -> ShaderRef { + "shaders/world/chunk_packed.wgsl".into() + } + + fn specialize( + _pipeline: &bevy::pbr::MaterialExtensionPipeline, + descriptor: &mut bevy::render::render_resource::RenderPipelineDescriptor, + layout: &bevy::render::mesh::MeshVertexBufferLayout, + _key: bevy::pbr::MaterialExtensionKey, + ) -> Result<(), bevy::render::render_resource::SpecializedMeshPipelineError> { + let vertex_layout = layout.get_layout(&[ + Mesh::ATTRIBUTE_POSITION.at_shader_location(0), + Mesh::ATTRIBUTE_UV_0.at_shader_location(1), + Mesh::ATTRIBUTE_NORMAL.at_shader_location(2), + ATTRIBUTE_PACKED_VERTEX_DATA.at_shader_location(7), + ])?; + descriptor.vertex.buffers = vec![vertex_layout]; + Ok(()) + } }