diff --git a/src/game/mod.rs b/src/game/mod.rs index ee1360d..5ff5bed 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -104,7 +104,6 @@ impl Game { } // Send dirty chunks to renderer - // TODO: Only send chunks in rendering range // TODO: Unload chunks above certain radius self.world.update(); for (pos, chunk) in self.world.all_chunks() { diff --git a/src/renderer/buffers/content.rs b/src/renderer/buffers/content.rs index 8904696..70d7c14 100644 --- a/src/renderer/buffers/content.rs +++ b/src/renderer/buffers/content.rs @@ -4,17 +4,15 @@ use std::convert::TryInto; use cgmath::Vector3; use std::cmp::{min, max}; use crate::game::world::block::WorldBlock; +use super::nodes::{Nodes, NODE_TEX_SIZE, NODE_TEX_SIZE_QB}; //note: remember to update in main.frag pub const BLOCK_SIZE : usize = 32; // 32x32x32 block size pub const BLOCK_TEX_SIZE : usize = 40; // number of blocks in texture (32^3 = 1GB, 40^3 = 2GB) -pub const NODE_TEX_SIZE: usize = 128; // 32x32x32 nodes in texture const BLOCK_SIZE_QB: usize = BLOCK_SIZE*BLOCK_SIZE*BLOCK_SIZE; - const BLOCK_TEX_SIZE_SQ: usize = BLOCK_TEX_SIZE*BLOCK_TEX_SIZE; const BLOCK_TEX_SIZE_QB: usize = BLOCK_TEX_SIZE*BLOCK_TEX_SIZE*BLOCK_TEX_SIZE; -const NODE_TEX_SIZE_SQ: usize = NODE_TEX_SIZE*NODE_TEX_SIZE; -const NODE_TEX_SIZE_QB: usize = NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE; + pub struct ContentStats { pub node_tex_size: f64, // MB @@ -26,9 +24,8 @@ pub struct ContentStats { } pub struct Content { - node_buffer: Box<[u32]>, + nodes: Nodes, node_texture: wgpu::Texture, - node_dirty: bool, block_freed: Vec, block_freeidx: usize, block_texture: wgpu::Texture, @@ -39,9 +36,6 @@ pub struct Content { impl Content { pub fn new(device: &wgpu::Device) -> Self { - // Create node buffer - let node_buffer = vec![0_u32; (NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE) as usize].into_boxed_slice(); - // Create textures let node_texture = device.create_texture( &wgpu::TextureDescriptor { @@ -87,10 +81,11 @@ impl Content { ); // Done + let nodes = Nodes::new(); let block_freeidx = 0; let node_dirty = false; let block_freed = Vec::new(); - Self { node_buffer, node_dirty, block_freed, node_texture, block_freeidx, block_texture, bind_layout, bind_group } + Self { nodes, block_freed, node_texture, block_freeidx, block_texture, bind_layout, bind_group } } pub fn stats(&self) -> ContentStats { @@ -115,7 +110,7 @@ impl Content { // Get node let index = (block_pos.x + NODE_TEX_SIZE as i32 * (block_pos.y + NODE_TEX_SIZE as i32 * block_pos.z)) as usize; - let mut value = self.node_buffer[index] as usize; + let mut value = self.nodes.get_node(index) as usize; // Allocate new block if value == 0 { @@ -127,10 +122,8 @@ impl Content { } // Assign - self.node_buffer[index] = value as u32; self.block_freeidx = value; - // Mark node buffer as dirty - self.node_dirty = true; + self.nodes.set_node(index, value as u32); } // Calculate position in block texture @@ -152,54 +145,33 @@ impl Content { } pub fn shift(&mut self, offset: &Vector3) { - let timer = Instant::now(); - let mut result = vec![0_u32; self.node_buffer.len()].into_boxed_slice(); - let (ox, oy, oz) = (offset.x, offset.y, offset.z); - let size = NODE_TEX_SIZE as i32; + // let timer = Instant::now(); + // let mut result = vec![0_u32; self.node_buffer.len()].into_boxed_slice(); + // let (ox, oy, oz) = (offset.x, offset.y, offset.z); + // let size = NODE_TEX_SIZE as i32; - let a = max(0, -oz); - let b = min(size-oz, size); - println!("from {} to {}", a, b); + // let a = max(0, -oz); + // let b = min(size-oz, size); + // println!("from {} to {}", a, b); - for x in max(0, -ox)..min(size-ox, size) { - for y in max(0, -oy)..min(size-oy, size) { - for z in max(0, -oz)..min(size-oz, size) { - let idx0 = x + size * (y + size * z); - let idx1 = (x+ox) + size * ((y+oy) + size * (z+oz)); - result[idx1 as usize] = self.node_buffer[idx0 as usize]; - } - } - } + // for x in max(0, -ox)..min(size-ox, size) { + // for y in max(0, -oy)..min(size-oy, size) { + // for z in max(0, -oz)..min(size-oz, size) { + // let idx0 = x + size * (y + size * z); + // let idx1 = (x+ox) + size * ((y+oy) + size * (z+oz)); + // result[idx1 as usize] = self.node_buffer[idx0 as usize]; + // } + // } + // } - self.node_buffer = result; - self.node_dirty = true; - println!("Shifted node buffer by {:?} in {} ms", offset, timer.elapsed().as_millis()); + // self.node_buffer = result; + // self.node_dirty = true; + // println!("Shifted node buffer by {:?} in {} ms", offset, timer.elapsed().as_millis()); } - fn write_nodes(&mut self, queue: &wgpu::Queue, z: usize) { - // Convert u32 node buffer to u8 - let node_origin = wgpu::Origin3d{ x:0, y: 0, z: z as u32 }; - let node_size = wgpu::Extent3d { width: NODE_TEX_SIZE as u32, height: NODE_TEX_SIZE as u32, depth: 1 }; - let mut node_bytes = [0_u8; NODE_TEX_SIZE_SQ*4]; - let offset = NODE_TEX_SIZE_SQ*z; - LittleEndian::write_u32_into(&self.node_buffer[offset..offset+NODE_TEX_SIZE_SQ], &mut node_bytes); - - // Write nodes - queue.write_texture( - wgpu::TextureCopyView { texture: &self.node_texture, mip_level: 0, origin: node_origin }, &node_bytes, - wgpu::TextureDataLayout { offset: 0, bytes_per_row: 4*node_size.width, rows_per_image: node_size.height }, node_size - ); - } + pub fn update(&mut self, queue: &wgpu::Queue) { - if self.node_dirty { - self.node_dirty = false; - - let timer = Instant::now(); - for z in 0..NODE_TEX_SIZE { - self.write_nodes(queue, z); - } - println!("Write nodes: {}", timer.elapsed().as_secs_f32()); - } + self.nodes.update(queue, &self.node_texture); } } \ No newline at end of file diff --git a/src/renderer/buffers/mod.rs b/src/renderer/buffers/mod.rs index d49943e..15aa9ab 100644 --- a/src/renderer/buffers/mod.rs +++ b/src/renderer/buffers/mod.rs @@ -5,7 +5,7 @@ pub mod content; pub use content::Content; mod materials; pub use materials::Materials; - +pub mod nodes; pub struct Buffers { pub uniforms: Uniform, diff --git a/src/renderer/buffers/nodes.rs b/src/renderer/buffers/nodes.rs new file mode 100644 index 0000000..ef30676 --- /dev/null +++ b/src/renderer/buffers/nodes.rs @@ -0,0 +1,63 @@ +use byteorder::{LittleEndian, ByteOrder}; + +pub const NODE_TEX_SIZE: usize = 128; // 32x32x32 nodes in texture +pub const NODE_TEX_SIZE_SQ: usize = NODE_TEX_SIZE*NODE_TEX_SIZE; +pub const NODE_TEX_SIZE_QB: usize = NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE; + + +pub struct Nodes { + node_buffer_a: Box<[u32]>, + node_buffer_b: Box<[u32]>, + active_buffer: u8, + modified: bool +} + +impl Nodes { + pub fn new() -> Self { + Self { + node_buffer_a: vec![0_u32; NODE_TEX_SIZE_QB].into_boxed_slice(), + node_buffer_b: vec![0_u32; NODE_TEX_SIZE_QB].into_boxed_slice(), + active_buffer: 0, + modified: false + } + } + + pub fn get_node(&self, index: usize) -> u32 { + if self.active_buffer == 0 { self.node_buffer_a[index] } + else { self.node_buffer_b[index] } + } + + pub fn set_node(&mut self, index: usize, value: u32) { + if self.active_buffer == 0 { self.node_buffer_a[index] = value; } + else { self.node_buffer_b[index] = value; } + self.modified = true; + } + + pub fn update(&mut self, queue: &wgpu::Queue, texture: &wgpu::Texture) { + if self.modified { + self.modified = false; + + // Select target node buffer + let node_buffer; + if self.active_buffer == 0 { node_buffer = &self.node_buffer_a; } + else { node_buffer = &self.node_buffer_b; } + + // Write all nodes to gpu + for z in 0..NODE_TEX_SIZE { + + // Convert u32 node buffer to u8 + let node_origin = wgpu::Origin3d{ x:0, y: 0, z: z as u32 }; + let node_size = wgpu::Extent3d { width: NODE_TEX_SIZE as u32, height: NODE_TEX_SIZE as u32, depth: 1 }; + let mut node_bytes = [0_u8; NODE_TEX_SIZE_SQ*4]; + let offset = NODE_TEX_SIZE_SQ*z; + LittleEndian::write_u32_into(&node_buffer[offset..offset+NODE_TEX_SIZE_SQ], &mut node_bytes); + + // Write nodes + queue.write_texture( + wgpu::TextureCopyView { texture: texture, mip_level: 0, origin: node_origin }, &node_bytes, + wgpu::TextureDataLayout { offset: 0, bytes_per_row: 4*node_size.width, rows_per_image: node_size.height }, node_size + ); + } + } + } +} \ No newline at end of file diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 678193b..be821b1 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -117,7 +117,7 @@ impl Renderer { pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> { // Update uniform buffer - let half = (buffers::content::NODE_TEX_SIZE / 2) as i32; + 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());