diff --git a/src/game/mod.rs b/src/game/mod.rs index 97f4906..d241d3e 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -8,7 +8,7 @@ use winit::event::Event; use player::Player; use world::World; -const RENDER_DIST: i32 = 3; +pub const RENDER_DIST: i32 = 3; pub enum GameState { Paused, @@ -61,18 +61,18 @@ impl Game { if dir.x != 0 { dir = Vector3{x: dir.x.clamp(-1, 1), y:0, z:0 } } else if dir.y != 0 { dir = Vector3{x:0, y:dir.y.clamp(-1, 1), z:0 } } else if dir.z != 0 { dir = Vector3{x:0, y:0, z:dir.z.clamp(-1, 1) } } - else { } + else { self.prev_chunk_pos = Some(prev_chunk_pos+dir); return; } - if dir.x != 0 || dir.y != 0 || dir.z != 0 { - // Shift world - renderer.shift(dir * world::chunk::SIZE as i32); - // Load chunks at the edge - let center = chunk_pos.clone() + RENDER_DIST*dir; - let mask = Vector3{x: dir.x.abs(), y: dir.y.abs(), z: dir.z.abs()}; - for a in -RENDER_DIST..RENDER_DIST+1 { - let pos = center + Vector3{x: mask.z*a, y: 0, z: mask.x*a}; - self.world.load_chunk(pos); - } + // Shift world + println!("Shiftin by {:?}", dir); + renderer.shift(dir * world::chunk::SIZE as i32); + + // Load chunks at the edge + let center = chunk_pos.clone() + RENDER_DIST*dir; + let mask = Vector3{x: dir.x.abs(), y: dir.y.abs(), z: dir.z.abs()}; + for a in -RENDER_DIST..RENDER_DIST+1 { + let pos = center + Vector3{x: mask.z*a, y: 0, z: mask.x*a}; + self.world.load_chunk(pos); } self.prev_chunk_pos = Some(prev_chunk_pos+dir); @@ -117,11 +117,12 @@ impl Game { self.world.update(); // Send dirty chunks to renderer - // TODO: Unload chunks above certain radius - for (pos, chunk) in self.world.all_chunks() { - if chunk.dirty { - chunk.write_to(renderer, pos * world::chunk::SIZE as i32); - chunk.dirty = false; + if chunk_pos == self.prev_chunk_pos.unwrap_or(chunk_pos) { + for (pos, chunk) in self.world.all_chunks() { + if chunk.dirty { + renderer.write_chunk(pos, chunk); + chunk.dirty = false; + } } } } diff --git a/src/game/world/chunk.rs b/src/game/world/chunk.rs index 72020f7..3a1935e 100644 --- a/src/game/world/chunk.rs +++ b/src/game/world/chunk.rs @@ -43,7 +43,7 @@ impl WorldChunk { // Header let (header_bytes, bytes) = bytes.split_at(128); let file_ver = header_bytes[0]; - let num_blocks = LittleEndian::read_u32(&header_bytes[1..5]) as usize; + let mut num_blocks = LittleEndian::read_u32(&header_bytes[1..5]) as usize; assert_eq!(file_ver, 1); // Nodes @@ -57,7 +57,8 @@ impl WorldChunk { // Blocks let mut block_bytes = vec![0_u8; num_blocks*block::SIZE_QB]; if lz4::decompress(&block_bytes_compressed, &mut block_bytes[0..num_blocks*block::SIZE_QB]).is_err() { - + println!("Decompression failed"); + num_blocks = 0; } for i in 0..num_blocks { @@ -124,10 +125,4 @@ impl WorldChunk { // Return block reference &mut self.blocks[(value-1) as usize] } - - pub fn write_to(&self, renderer: &mut dyn RendererView, offset: Vector3) { - for (blpos, block) in self.all_blocks() { - renderer.write(&(offset + blpos), block); - } - } } \ No newline at end of file diff --git a/src/renderer/buffers/content.rs b/src/renderer/buffers/content.rs index c804769..0cdb4d4 100644 --- a/src/renderer/buffers/content.rs +++ b/src/renderer/buffers/content.rs @@ -102,6 +102,7 @@ impl Content { } pub fn free(&mut self, block_pos: Vector3) { + // 0,0 at node buffer center let half = NODE_TEX_SIZE as i32 / 2; let pos = block_pos + &Vector3{x: half, y: half, z: half}; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index be821b1..8451a5b 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -89,8 +89,6 @@ impl Renderer { // Other let start = std::time::Instant::now(); let world_offset = Vector3{x:0, y:0, z:0}; - - println!("Renderer initialized"); Self { surface, device, queue, swapchain_desc, swapchain, texture, raytrace_pass, postprocess_pass, ui, buffers, camera, start, world_offset } } @@ -118,9 +116,8 @@ impl Renderer { // Update uniform buffer let half = (buffers::nodes::NODE_TEX_SIZE / 2) as i32; - let offset = Vector3{x: (self.world_offset.x + half) as f32, y: (self.world_offset.y + half) as f32, z: (self.world_offset.z + half) as f32 }; - - self.buffers.uniforms.values.update(&self.camera, offset, self.start.elapsed().as_secs_f32()); + let cam_offset = Vector3{x: (self.world_offset.x + half) as f32, y: (self.world_offset.y + half) as f32, z: (self.world_offset.z + half) as f32 }; + self.buffers.uniforms.values.update(&self.camera, cam_offset, self.start.elapsed().as_secs_f32()); self.queue.write_buffer(&self.buffers.uniforms.buffer, 0, bytemuck::cast_slice(&[self.buffers.uniforms.values])); // Update content diff --git a/src/renderer/renderer_view.rs b/src/renderer/renderer_view.rs index b2617bc..4e9fd02 100644 --- a/src/renderer/renderer_view.rs +++ b/src/renderer/renderer_view.rs @@ -1,29 +1,52 @@ use crate::renderer::UserInterface; use crate::renderer::camera::CameraTransform; use crate::Renderer; -use crate::game::world::block::WorldBlock; +use crate::{game, game::world::{chunk, chunk::WorldChunk, block::WorldBlock}}; use cgmath::Vector3; pub trait RendererView { - fn write(&mut self, block_pos: &Vector3, block: &WorldBlock); + fn write_chunk(&mut self, chunk_pos: &Vector3, chunk: &WorldChunk); fn shift(&mut self, offset: Vector3); fn get_camera_transform(&mut self) -> &mut dyn CameraTransform; fn get_ui(&mut self) -> &mut UserInterface; fn get_world_offset(&self) -> Vector3; - fn free(&mut self, block_pos: Vector3); + fn free_chunk(&mut self, chunk_pos: Vector3); } impl RendererView for Renderer { - fn write(&mut self, block_pos: &Vector3, block: &WorldBlock) { - let block_pos = block_pos + (self.world_offset); - self.buffers.content.write(&self.queue, &block_pos, block); + fn write_chunk(&mut self, chunk_pos: &Vector3, chunk: &WorldChunk) { + // Calculate chunk position in renderer space + let chunk_off = self.world_offset / chunk::SIZE as i32; + let pos = chunk_pos + chunk_off; + // Make sure we are withing current world bounds + if pos.x.abs() > game::RENDER_DIST { println!("out of bounds! x: {}", pos.x); return; } + if pos.y.abs() > game::RENDER_DIST { println!("out of bounds! y: {}", pos.y); return; } + if pos.z.abs() > game::RENDER_DIST { println!("out of bounds! z: {}", pos.z); return; } + // Write chunk to renderer + println!("write chunk {:?}", pos); + let pos = pos * chunk::SIZE as i32; + for (block_pos, block) in chunk.all_blocks() { + self.buffers.content.write(&self.queue, &(block_pos + pos), block); + } } - fn free(&mut self, block_pos: Vector3) { - self.buffers.content.free(block_pos); + fn free_chunk(&mut self, chunk_pos: Vector3) { + // Free all blocks within chunk + let size = chunk::SIZE as i32; + let pos = chunk_pos * size; + for x in 0..size { + for y in 0..size { + for z in 0..size { + self.buffers.content.free(pos + Vector3{x, y, z}); + } + } + } } + /* + * offset: By how much to shift the world, in blocks + */ fn shift(&mut self, offset: Vector3) { self.buffers.content.shift(&-offset); self.world_offset -= offset;