diff --git a/src/game/world.rs b/src/game/world.rs index 5365279..8e5b4d8 100644 --- a/src/game/world.rs +++ b/src/game/world.rs @@ -36,10 +36,12 @@ impl World { pub fn update_loaded_chunks(&mut self, around_position: Vec2, options: &GameOptions, display: &Display) { let render_dist = options.render_distance as i32 + 1; let inside_chunk = (around_position / CHUNK_SIZE as f32).as_ivec2(); + //Mark all chunks for unload for (_, chunk) in &mut self.chunks { chunk.desired = ChunkState::Unload; } + //Load new/update chunks in range for x in -render_dist..=render_dist { for z in -render_dist..=render_dist { @@ -54,34 +56,47 @@ impl World { } else { chunk.desired = ChunkState::Rendered; } + if matches!(chunk.state, ChunkState::Nothing) { + self.thread.queue_load(position); + } + if matches!(chunk.state, ChunkState::Loaded) && matches!(chunk.desired, ChunkState::Rendered) { + fn all_some<'a>(x: [Option<&'a Chunk>; 4]) -> Option<[&'a Chunk; 4]> { + Some([x[0]?, x[1]?, x[2]?, x[3]?]) + } + if let Some(neighbors) = all_some(self.chunk_neighbors(chunk.position)) { + if { + neighbors[0].block_data.is_some() && + neighbors[1].block_data.is_some() && + neighbors[2].block_data.is_some() && + neighbors[3].block_data.is_some() + } { + self.thread.queue_mesh(chunk, neighbors); + } + } + } } } - //State up/downgrades are handled here! - self.chunks.retain(|&position, chunk| { + + //Handle Unload + self.chunks.retain(|_, chunk| !matches!(chunk.desired, ChunkState::Unload)); + + //State downgrades + for (_, chunk) in &mut self.chunks { match chunk.desired { - // Any => Unload downgrade - ChunkState::Unload => { - return false - }, // Any => Nothing downgrade ChunkState::Nothing => { chunk.block_data = None; - chunk.vertex_buffer = None; + chunk.mesh = None; chunk.state = ChunkState::Nothing; }, - // Nothing => Loading => Loaded upgrade - ChunkState::Loaded if matches!(chunk.state, ChunkState::Nothing) => { - self.thread.queue_load(position); - }, //Render => Loaded downgrade ChunkState::Loaded if matches!(chunk.state, ChunkState::Rendering | ChunkState::Rendered) => { - chunk.vertex_buffer = None; + chunk.mesh = None; chunk.state = ChunkState::Loaded; }, _ => () } - true - }); + } //Apply changes from threads self.thread.apply_tasks(&mut self.chunks, display); } diff --git a/src/game/world/chunk.rs b/src/game/world/chunk.rs index 94cac94..0cb5f14 100644 --- a/src/game/world/chunk.rs +++ b/src/game/world/chunk.rs @@ -1,5 +1,5 @@ use glam::IVec2; -use glium::VertexBuffer; +use glium::{VertexBuffer, IndexBuffer}; use crate::game::{ blocks::Block, shaders::chunk::Vertex as ChunkVertex @@ -18,12 +18,11 @@ pub enum ChunkState { } pub type ChunkData = [[[Block; CHUNK_SIZE]; CHUNK_HEIGHT]; CHUNK_SIZE]; -pub type ChunkMesh = VertexBuffer; pub struct Chunk { pub position: IVec2, pub block_data: Option, - pub vertex_buffer: Option<(bool, ChunkMesh)>, + pub mesh: Option<(bool, VertexBuffer, IndexBuffer)>, pub state: ChunkState, pub desired: ChunkState, } @@ -32,7 +31,7 @@ impl Chunk { Self { position, block_data: None, - vertex_buffer: None, + mesh: None, state: ChunkState::Nothing, desired: ChunkState::Nothing, } diff --git a/src/game/world/thread.rs b/src/game/world/thread.rs index 38e59d3..5465a05 100644 --- a/src/game/world/thread.rs +++ b/src/game/world/thread.rs @@ -1,5 +1,5 @@ use glam::IVec2; -use glium::{Display, VertexBuffer}; +use glium::{Display, VertexBuffer, IndexBuffer, index::PrimitiveType}; use std::{ thread::{self, JoinHandle}, collections::HashMap, @@ -17,7 +17,7 @@ pub struct WorldThreading { //Options are needed here to take ownership, //None values should never appear here! pub load_tasks: HashMap>>, - pub mesh_tasks: HashMap>>>, + pub mesh_tasks: HashMap, Vec)>>>, } impl WorldThreading { pub fn new() -> Self { @@ -93,11 +93,12 @@ impl WorldThreading { } log::info!("mesh: done {}", position); let handle = mem::take(handle).unwrap(); - let data = handle.join().unwrap(); + let (shape, index) = handle.join().unwrap(); let chunk = chunks.get_mut(position).unwrap(); - chunk.vertex_buffer = Some(( + chunk.mesh = Some(( true, - VertexBuffer::immutable(display, &data).expect("Failed to build VertexBuffer") + VertexBuffer::immutable(display, &shape).expect("Failed to build VertexBuffer"), + IndexBuffer::immutable(display, PrimitiveType::TrianglesList, &index).expect("Failed to build IndexBuffer") )); chunk.state = ChunkState::Rendered; false diff --git a/src/game/world/thread/mesh_gen.rs b/src/game/world/thread/mesh_gen.rs index 70fdd06..e91715a 100644 --- a/src/game/world/thread/mesh_gen.rs +++ b/src/game/world/thread/mesh_gen.rs @@ -1,7 +1,9 @@ use glam::IVec2; -use crate::game::world::chunk::{Chunk, ChunkData}; +use crate::game::world::chunk::ChunkData; use crate::game::shaders::chunk::Vertex as ChunkVertex; -pub fn generate_mesh(position: IVec2, chunk_data: ChunkData, neighbors: [ChunkData; 4]) -> Vec { - vec![] +pub fn generate_mesh(position: IVec2, chunk_data: ChunkData, neighbors: [ChunkData; 4]) -> (Vec, Vec) { + let vertex = Vec::new(); + let index = Vec::new(); + (vertex, index) }