diff --git a/src/game/mod.rs b/src/game/mod.rs index 3573ee9..ab9e7c4 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -2,7 +2,7 @@ mod camera_controller; mod player; pub mod world; use crate::renderer::renderer_view::RendererView; -use cgmath::Point3; +use cgmath::Vector3; use winit::event::Event; use player::Player; use world::World; @@ -19,7 +19,7 @@ pub struct Game { #[allow(unused)] world: World, - prev_pos: Option> + prev_pos: Option> } impl Game { @@ -64,16 +64,16 @@ impl Game { // Update chunks let pos = camera.get_position(); - let pos = Point3{x: pos.x as i32, y: pos.y as i32, z: pos.z as i32}; + let pos = Vector3{x: pos.x as i32, y: pos.y as i32, z: pos.z as i32}; if self.prev_pos == None || self.prev_pos != Some(pos) { self.prev_pos = Some(pos); renderer.get_ui().set_text("World", 0, format!("Position: {}, {}, {}", pos.x, pos.y, pos.z)); - // Load sphere of chunks around player (TODO) - let chunk_pos = Point3{x: pos.x / 32, y: pos.y / 32, z: pos.z / 32}; + // Load sphere of chunks around player + let chunk_pos = pos / 32;//Vector3{x: pos.x / 32, y: pos.y / 32, z: pos.z / 32}; if self.world.load_chunk(chunk_pos) { - - renderer.write(, block: &WorldBlock) + let chunk = self.world.get_chunk(&chunk_pos).unwrap(); + chunk.write_to(renderer, chunk_pos * 32); } } } diff --git a/src/game/world/block.rs b/src/game/world/block.rs index fb96597..d28146f 100644 --- a/src/game/world/block.rs +++ b/src/game/world/block.rs @@ -1,4 +1,4 @@ -use cgmath::Point3; +use cgmath::Vector3; pub const SIZE: usize = 32; pub const SIZE_QB: usize = SIZE*SIZE*SIZE; @@ -16,7 +16,7 @@ impl WorldBlock { } } - pub fn set(&mut self, voxel_pos: Point3, value: u8) { + pub fn set(&mut self, voxel_pos: Vector3, value: u8) { self.materials[voxel_pos.x + SIZE * (voxel_pos.y + SIZE * voxel_pos.z)] = value; } } \ No newline at end of file diff --git a/src/game/world/chunk.rs b/src/game/world/chunk.rs index 9290c26..22e280c 100644 --- a/src/game/world/chunk.rs +++ b/src/game/world/chunk.rs @@ -1,6 +1,7 @@ +use crate::game::RendererView; use byteorder::LittleEndian; use byteorder::ByteOrder; -use cgmath::Point3; +use cgmath::Vector3; use lzzzz::lz4; use crate::game::world::{WorldBlock, block}; @@ -23,7 +24,7 @@ pub struct WorldChunk { impl WorldChunk { pub fn new() -> Self { Self { - nodes: vec![0_u32; SIZE_QB as usize].into_boxed_slice(), + nodes: vec![0_u32; SIZE_QB].into_boxed_slice(), blocks: Vec::new() } } @@ -85,7 +86,7 @@ impl WorldChunk { } #[allow(unused)] - pub fn all_blocks(&self) -> Vec<(Point3, &WorldBlock)> { + pub fn all_blocks(&self) -> Vec<(Vector3, &WorldBlock)> { self.nodes.iter().enumerate() .filter(|(_, n)| **n != 0) .map(|(index, node)| { @@ -96,17 +97,16 @@ impl WorldChunk { let y = idx / SIZE; let x = idx % SIZE; - let pos = Point3{x: x as u32, y: y as u32, z: z as u32}; - + let pos = Vector3{x: x as i32, y: y as i32, z: z as i32}; let block = &self.blocks[(*node-1) as usize]; (pos, block) }) .collect() } - pub fn get_block_mut(&mut self, block_pos: &Point3) -> &mut WorldBlock { + pub fn get_block_mut(&mut self, block_pos: &Vector3) -> &mut WorldBlock { // Get block index - let index = (block_pos.x + SIZE as u32 * (block_pos.y + SIZE as u32 * block_pos.z)) as usize; + let index = (block_pos.x + SIZE as i32 * (block_pos.y + SIZE as i32 * block_pos.z)) as usize; let mut value = self.nodes[index]; // Allocate new block if value == 0 { @@ -118,11 +118,17 @@ impl WorldChunk { &mut self.blocks[(value-1) as usize] } - pub fn get_block(&self, block_pos: &Point3) -> &WorldBlock { + pub fn get_block(&self, block_pos: &Vector3) -> &WorldBlock { // Get block index - let index = (block_pos.x + SIZE as u32 * (block_pos.y + SIZE as u32 * block_pos.z)) as usize; + let index = (block_pos.x + SIZE as i32 * (block_pos.y + SIZE as i32 * block_pos.z)) as usize; let value = self.nodes[index]; // Return block reference &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/game/world/generator.rs b/src/game/world/generator.rs index 46991ff..b5489a3 100644 --- a/src/game/world/generator.rs +++ b/src/game/world/generator.rs @@ -1,4 +1,4 @@ -use cgmath::Point3; +use cgmath::Vector3; use noise::{Perlin, NoiseFn}; use rand::{Rng, prelude::ThreadRng}; @@ -39,7 +39,7 @@ impl WorldGen { /* * Generate block */ - pub fn generate(block_pos: &Point3, block: &mut WorldBlock) { + pub fn generate(block_pos: &Vector3, block: &mut WorldBlock) { let mut rng = rand::thread_rng(); let noise = Perlin::new(); @@ -52,7 +52,7 @@ impl WorldGen { let h = map[x][z]; //let h = 16; // testing for y in 0..h { - block.set(Point3{x, y, z}, 2); + block.set(Vector3{x, y, z}, 2); } } } diff --git a/src/game/world/mod.rs b/src/game/world/mod.rs index e4ce073..85c7d62 100644 --- a/src/game/world/mod.rs +++ b/src/game/world/mod.rs @@ -1,11 +1,12 @@ mod generator; pub mod chunk; pub mod block; +use std::time::Instant; use std::path::PathBuf; use std::io::Write; use std::io::Read; use std::fs; -use cgmath::Point3; +use cgmath::{Point3, Vector3}; use std::collections::HashMap; use generator::WorldGen; use chunk::WorldChunk; @@ -19,11 +20,7 @@ struct WorldData { pub struct World { data: WorldData, - chunks: HashMap, WorldChunk>, -} - -fn point_abs(p: &Point3) -> Point3 { - Point3 {x: p.x.abs() as u32, y: p.y.abs() as u32, z: p.z.abs() as u32 } + chunks: HashMap, WorldChunk>, } impl World { @@ -35,12 +32,12 @@ impl World { } } - pub fn all_blocks(&self) -> Vec<(Point3, &WorldBlock)> { + pub fn all_blocks(&self) -> Vec<(Vector3, &WorldBlock)> { self.chunks.iter().map(|(chunk_pos, chunk)| { let off = chunk_pos * chunk::SIZE as i32; - let result: Vec<(Point3, &WorldBlock)> = chunk.all_blocks().iter().map(|(pos, block)| { + let result: Vec<(Vector3, &WorldBlock)> = chunk.all_blocks().iter().map(|(pos, block)| { ( - Point3{x: off.x+pos.x as i32, y: off.y+pos.y as i32, z: off.z+pos.z as i32}, + Vector3{x: off.x+pos.x as i32, y: off.y+pos.y as i32, z: off.z+pos.z as i32}, *block ) }).collect(); @@ -50,18 +47,14 @@ impl World { pub fn save(&self) { // Get directory - let mut dir = dirs::data_local_dir().unwrap(); - dir.push("Voxelgame"); + let dir = dirs::data_local_dir().unwrap().join("Voxelgame"); fs::create_dir_all(&dir).expect("Failed to create directory"); // Save all chunks for (pos, chunk) in self.chunks.iter() { - let bytes = chunk.to_bytes(); - let filename = format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z); - let path: PathBuf = [dir.to_str().unwrap(), &filename].iter().collect(); - + let path = dir.with_file_name(format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z)); let mut file = fs::File::create(path).expect("Failed to create file"); - file.write(&bytes).unwrap(); + file.write(&chunk.to_bytes()).unwrap(); } // Save metadata @@ -72,41 +65,56 @@ impl World { } /* - * Loads chunk and displays it in the world. + * Loads chunk into memory * It will try to load the chunk from file, and if that fails it will generate the chunk and save it. */ - pub fn load_chunk(&mut self, pos: Point3) -> Option<&WorldChunk> { + pub fn load_chunk(&mut self, pos: Vector3) ->bool { // Abort if chunk is already loaded if let Some(_) = self.chunks.get(&pos) { - return None; + return false; } // Try loading chunk from file let filename = format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z); let filepath = dirs::data_local_dir().unwrap().join("Voxelgame").with_file_name(filename); if filepath.is_file() { + let timer = Instant::now(); let mut buff = Vec::new(); let mut file = fs::File::open(filepath).expect("Failed to open file"); file.read_to_end(&mut buff).expect("Failed to read file"); let chunk = WorldChunk::from_bytes(buff); self.chunks.insert(pos, chunk); - println!("Chunk at {:?} loaded", pos); - return Some(&chunk); + println!("Chunk at {:?} loaded ({} ms)", pos, timer.elapsed().as_millis()); + return true; } // Try generating chunk + let timer0 = Instant::now(); let mut chunk = WorldChunk::new(); for x in 0..32 { for z in 0..32 { - let bpos = &Point3::{x,y:0,z}; + let bpos = Vector3::{x,y:0,z}; let block = chunk.get_block_mut(&bpos); - let wpos = &Point3::{ x: pos.x+bpos.x as i32, y: pos.y+bpos.y as i32, z: pos.z+bpos.z as i32}; - WorldGen::generate(wpos, block); + WorldGen::generate(&(pos*32 + bpos), block); } } + + // Save + let timer1 = Instant::now(); + let dir = dirs::data_local_dir().unwrap().join("Voxelgame"); + fs::create_dir_all(&dir).expect("Failed to create directory"); + let path = dir.with_file_name(format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z)); + let mut file = fs::File::create(path).expect("Failed to create file"); + file.write(&chunk.to_bytes()).unwrap(); + + // Add to list self.chunks.insert(pos, chunk); - println!("Chunk at {:?} generated", pos); - Some(&chunk) + + // Stats + let t1 = timer1.elapsed().as_millis(); + let t0 = timer0.elapsed().as_millis() - t1; + println!("Chunk at {:?} generated ({} ms) and saved ({} ms)", pos, t0, t1); + true } pub fn load(&mut self) -> bool { @@ -124,14 +132,18 @@ impl World { } #[allow(unused)] - pub fn get_block(&mut self, block_wpos: &Point3) -> Option<&WorldBlock> { + pub fn get_block(&mut self, block_wpos: &Vector3) -> Option<&WorldBlock> { // Split world space to chunk and block space let ch_pos = block_wpos / chunk::SIZE as i32; - let bl_pos = point_abs(block_wpos) % chunk::SIZE as u32; + let bl_pos = block_wpos % chunk::SIZE as i32; // Return block if exists if let Some(chunk) = self.chunks.get_mut(&ch_pos) { return Some(chunk.get_block(&bl_pos)); } None } + + pub fn get_chunk(&mut self, chunk_wpos: &Vector3) -> Option<&mut WorldChunk> { + self.chunks.get_mut(chunk_wpos) + } } \ No newline at end of file diff --git a/src/renderer/buffers/content.rs b/src/renderer/buffers/content.rs index d6eca7e..45f359a 100644 --- a/src/renderer/buffers/content.rs +++ b/src/renderer/buffers/content.rs @@ -1,7 +1,7 @@ use std::time::Instant; use byteorder::{ByteOrder, LittleEndian}; use std::convert::TryInto; -use cgmath::Point3; +use cgmath::Vector3; use crate::game::world::block::WorldBlock; //note: remember to update in main.frag @@ -102,10 +102,10 @@ impl Content { } #[allow(unused)] - pub fn write(&mut self, queue: &wgpu::Queue, block_pos: &Point3, block: &WorldBlock) { + pub fn write(&mut self, queue: &wgpu::Queue, block_pos: &Vector3, block: &WorldBlock) { // Get node - let index = (block_pos.x + NODE_TEX_SIZE as u32 * (block_pos.y + NODE_TEX_SIZE as u32 * block_pos.z)) as usize; + 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; // Allocate new block diff --git a/src/renderer/renderer_view.rs b/src/renderer/renderer_view.rs index 26b9874..a26148f 100644 --- a/src/renderer/renderer_view.rs +++ b/src/renderer/renderer_view.rs @@ -2,17 +2,17 @@ use crate::renderer::UserInterface; use crate::renderer::camera::CameraTransform; use crate::Renderer; use crate::game::world::block::WorldBlock; -use cgmath::Point3; +use cgmath::Vector3; pub trait RendererView { - fn write(&mut self, block_pos: &Point3, block: &WorldBlock); + fn write(&mut self, block_pos: &Vector3, block: &WorldBlock); fn get_camera_transform(&mut self) -> &mut dyn CameraTransform; fn get_ui(&mut self) -> &mut UserInterface; } impl RendererView for Renderer { - fn write(&mut self, block_pos: &Point3, block: &WorldBlock) { + fn write(&mut self, block_pos: &Vector3, block: &WorldBlock) { self.buffers.content.write(&self.queue, block_pos, block) }