use vulkanalia::prelude::v1_0::*; use anyhow::Result; use cgmath::{vec2, vec3}; use std::collections::HashMap; use crate::app_data::AppData; use crate::buffer; use crate::vertex; use crate::primitives::cube::Cube; extern crate rand; use rand::Rng; const CHUNK_SIZE: usize = 100; #[derive(Clone, Debug, Default)] pub struct Scene { pub vertices: Vec<vertex::Vertex>, pub indices: Vec<u32>, pub vertex_buffer: vk::Buffer, pub vertex_buffer_memory: vk::DeviceMemory, pub index_buffer: vk::Buffer, pub index_buffer_memory: vk::DeviceMemory, } impl Scene { pub unsafe fn prepare_data(&mut self, instance: &vulkanalia::Instance, device: &vulkanalia::Device, data: &AppData) -> Result<()> { let mut rng = rand::thread_rng(); let grid_size = CHUNK_SIZE as i32; // todo store the chunks somewhere (or only use them as intermediary for neighbouthood calculation idc) let mut chunks = vec![Chunk::create()?]; //todo use the 14 vertice box method. Not using geometry shaders seems to be faster... make this a setting? // have cube elements with a method asking for vertices, while giving a primitive type -> method for preferred primitive type as well as one collecting all primitives for x_index in 0..grid_size { for y_index in 0..grid_size { let shade = (rng.gen_range(0..25) as f32) / 100.0; let cube = Cube { pos: vec3(x_index as f32, y_index as f32, 0.0), color: vec3(shade, 1.0, shade), tex_coord: vec2(0.0, 0.0) }; chunks[0].set_cube(cube); } } let chunk = &chunks[0]; let chunk_iter = ChunkIter::create(chunk)?; for item in chunk_iter { let index = self.vertices.len(); match item { Some(cube) => { cube.draw(&data.topology, index, self); } None => {} } } (self.vertex_buffer, self.vertex_buffer_memory) = buffer::create_vertex_buffer(instance, device, &data, &self.vertices)?; (self.index_buffer, self.index_buffer_memory) = buffer::create_index_buffer(&instance, &device, &data, &self.indices)?; Ok(()) } pub unsafe fn destroy(&mut self, device: &vulkanalia::Device) { device.destroy_buffer(self.index_buffer, None); device.free_memory(self.index_buffer_memory, None); device.destroy_buffer(self.vertex_buffer, None); device.free_memory(self.vertex_buffer_memory, None); } } #[derive(Clone, Debug)] struct Chunk { //todo change to hashmap? blocks: HashMap<cgmath::Vector3<u32>, Cube>, } impl Chunk { pub fn create() -> Result<Self> { let mut map = HashMap::new(); Ok(Self { blocks: map }) } pub fn set_cube(&mut self, cube: Cube) { let x = cube.pos.x as usize; let y = cube.pos.y as usize; let z = cube.pos.z as usize; assert!(x < CHUNK_SIZE, "x value out of range!"); assert!(y < CHUNK_SIZE, "y value out of range!"); assert!(z < CHUNK_SIZE, "z value out of range!"); self.blocks.insert(vec3(x as u32, y as u32, z as u32), cube); } pub fn clear_cube(&mut self, x: usize, y: usize, z: usize) { assert!(x < CHUNK_SIZE, "x value out of range!"); assert!(y < CHUNK_SIZE, "y value out of range!"); assert!(z < CHUNK_SIZE, "z value out of range!"); self.blocks.remove(&vec3(x as u32, y as u32, z as u32)); } } struct ChunkIter<'a> { iter_x: usize, iter_y: usize, iter_z: usize, chunk: &'a Chunk } impl<'a> ChunkIter<'a> { pub fn create(chunk: &'a Chunk) -> Result<Self> { Ok(Self { iter_x: 0, iter_y: 0, iter_z: 0, chunk }) } } impl<'a> Iterator for ChunkIter<'a> { type Item = Option<&'a Cube>; fn next(&mut self) -> Option<Self::Item> { if self.iter_x < CHUNK_SIZE && self.iter_y < CHUNK_SIZE && self.iter_z < CHUNK_SIZE { let result = self.chunk.blocks.get(&vec3(self.iter_x as u32, self.iter_y as u32, self.iter_z as u32)); self.iter_x += 1; if self.iter_x >= CHUNK_SIZE { self.iter_x = 0; self.iter_y += 1; } if self.iter_y >= CHUNK_SIZE { self.iter_y = 0; self.iter_z += 1; } return Some(result.clone()) } self.iter_x = 0; self.iter_y = 0; self.iter_z = 0; None } }