Combined node and block buffer into one struct: content.

This commit is contained in:
Piotrek
2021-05-06 14:40:47 +02:00
parent d34196a6bd
commit cb2379786c
12 changed files with 150 additions and 352 deletions
+3 -3
View File
@@ -1,8 +1,8 @@
mod camera_controller; mod camera_controller;
mod world; pub mod world;
use cgmath::{SquareMatrix, Point3, InnerSpace}; use cgmath::{SquareMatrix, Point3, InnerSpace};
use winit::event::Event; use winit::event::Event;
use crate::renderer::{camera::CameraTransform, RenderSpace}; use crate::renderer::{camera::CameraTransform};
use camera_controller::CameraController; use camera_controller::CameraController;
use world::World; use world::World;
@@ -17,7 +17,7 @@ pub struct App {
} }
impl App { impl App {
pub fn new(renderer: &mut dyn RenderSpace) -> Self { pub fn new() -> Self {
let mut app = Self { let mut app = Self {
camera_controller: CameraController::new(), camera_controller: CameraController::new(),
world: World::new("default".to_string()) world: World::new("default".to_string())
+1 -1
View File
@@ -1,8 +1,8 @@
use cgmath::Point3; use cgmath::Point3;
pub const SIZE: usize = 32; pub const SIZE: usize = 32;
#[derive(Clone)] #[derive(Clone)]
pub struct WorldBlock { pub struct WorldBlock {
pub materials: [u8;(SIZE*SIZE*SIZE) as usize] pub materials: [u8;(SIZE*SIZE*SIZE) as usize]
+3 -2
View File
@@ -19,11 +19,12 @@ impl WorldChunk {
pub fn get_block(&mut self, block_pos: &Point3<u32>) -> &mut WorldBlock { pub fn get_block(&mut self, block_pos: &Point3<u32>) -> &mut WorldBlock {
// Get block index // Get block index
let index = block_pos.x + SIZE * (block_pos.y + SIZE * block_pos.z); let index = (block_pos.x + SIZE * (block_pos.y + SIZE * block_pos.z)) as usize;
let mut value = self.nodes[index as usize]; let mut value = self.nodes[index];
// Allocate new block // Allocate new block
if value == 0 { if value == 0 {
value = (self.blocks.len() + 1) as u32; value = (self.blocks.len() + 1) as u32;
self.nodes[index] = value;
self.blocks.push(WorldBlock::new()); self.blocks.push(WorldBlock::new());
} }
// Return block reference // Return block reference
+2 -2
View File
@@ -1,6 +1,6 @@
mod generator; mod generator;
mod chunk; pub mod chunk;
mod block; pub mod block;
use cgmath::Point3; use cgmath::Point3;
use std::collections::HashMap; use std::collections::HashMap;
use generator::WorldGen; use generator::WorldGen;
+1 -1
View File
@@ -24,7 +24,7 @@ fn main() {
.expect("Failed to create window"); .expect("Failed to create window");
let mut renderer = futures::executor::block_on(Renderer::new(&window)); let mut renderer = futures::executor::block_on(Renderer::new(&window));
let mut app = App::new(&mut renderer); let mut app = App::new();
// Stats // Stats
let mut fps_timer = std::time::Instant::now(); let mut fps_timer = std::time::Instant::now();
-139
View File
@@ -1,139 +0,0 @@
use std::convert::TryInto;
use cgmath::Point3;
use crate::renderer::{buffers, buffers::{BLOCK_SIZE, BLOCK_TEX_SIZE, BLOCK_TEX_LEN, BLOCK_LEN, BLOCK_ARR_LEN}};
#[derive(Clone)]
pub struct RenderBlock {
pub id: usize,
pub data: [u8;BLOCK_LEN]
}
impl RenderBlock {
pub fn new() -> Self {
Self { id: 0, data: [0_u8;BLOCK_LEN] }
}
pub fn set(&mut self, voxel_pos: Point3<usize>, value: u8) {
self.data[voxel_pos.x + buffers::BLOCK_SIZE * (voxel_pos.y + buffers::BLOCK_SIZE * voxel_pos.z)] = value;
}
}
pub struct Blocks {
blocks: Box<[RenderBlock]>,
free_block: usize,
texture: wgpu::Texture,
pub bind_layout: wgpu::BindGroupLayout,
pub bind_group: wgpu::BindGroup
}
impl Blocks {
/*
* Create buffer in memory and gpu
*/
pub fn new(device: &wgpu::Device) -> Self {
// Create texture
let block_tex_dim = BLOCK_TEX_SIZE * BLOCK_SIZE;
let size = wgpu::Extent3d { width: BLOCK_SIZE as u32, height: block_tex_dim as u32, depth: block_tex_dim as u32 };
let texture = device.create_texture(
&wgpu::TextureDescriptor {
size: size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D3,
format: wgpu::TextureFormat::R8Uint,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, // STORAGE?
label: Some("block texture"),
}
);
// Bind layout
let bind_layout = device.create_bind_group_layout(
&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture { multisampled: false, view_dimension: wgpu::TextureViewDimension::D3, sample_type: wgpu::TextureSampleType::Uint },
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: false, filtering: false },
count: None,
},
],
label: Some("Node texture layout"),
}
);
// Bind group
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Nearest, min_filter: wgpu::FilterMode::Nearest, mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
let bind_group = device.create_bind_group(
&wgpu::BindGroupDescriptor {
layout: &bind_layout,
entries: &[
wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::TextureView(&view) },
wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::Sampler(&sampler) }
],
label: Some("block texture group"),
}
);
// Data
let mut blocks = vec![RenderBlock::new(); BLOCK_ARR_LEN].into_boxed_slice();
for (i, b) in blocks.iter_mut().enumerate() { b.id = i; }
println!("Blocks size: {} MB, max: {}", BLOCK_TEX_LEN as f32 / 1024.0 / 1024.0, BLOCK_ARR_LEN);
// Done
Self { blocks, texture, bind_layout, bind_group, free_block: 0 }
}
/*
* Writes block to gpu
*/
pub fn write(&mut self, queue: &wgpu::Queue, block_id: usize) {
// Get block from id
let block = &self.blocks[block_id];
// Calculate block position in texture
let y = (block.id%BLOCK_TEX_SIZE * BLOCK_SIZE) as u32;
let z = (block.id/BLOCK_TEX_SIZE * BLOCK_SIZE) as u32;
let block_origin = wgpu::Origin3d{ x:0, y, z };
let block_size = wgpu::Extent3d{ width: BLOCK_SIZE as u32, height: BLOCK_SIZE as u32, depth: BLOCK_SIZE as u32 };
let block_bytes : [u8;BLOCK_LEN] = block.data.try_into().unwrap();
// Write to texture
queue.write_texture(
wgpu::TextureCopyView { texture: &self.texture, mip_level: 0, origin: block_origin },
&block_bytes,
wgpu::TextureDataLayout { offset: 0, bytes_per_row: block_size.width, rows_per_image: block_size.height },
block_size
);
}
pub fn get(&mut self, block_id: usize) -> &mut RenderBlock {
&mut self.blocks[block_id]
}
/*
* Allocates new block
*/
pub fn alloc(&mut self) -> &mut RenderBlock {
// Make sure we still have some free blocks
if self.free_block >= BLOCK_ARR_LEN { panic!("No more free blocks! we should consider reusing blocks..."); }
self.free_block += 1;
&mut self.blocks[self.free_block - 1]
}
}
+121
View File
@@ -0,0 +1,121 @@
use byteorder::{ByteOrder, LittleEndian};
use std::convert::TryInto;
use cgmath::Point3;
use crate::app::world::block::WorldBlock;
pub const BLOCK_SIZE : usize = 32; // 32x32x32 block size
pub const BLOCK_TEX_SIZE : usize = 64; // 64x64 blocks in texture
pub const NODE_TEX_SIZE: usize = 48; // 32x32x32 nodes in texture
pub struct Content {
node_buffer: Box<[u32]>,
node_texture: wgpu::Texture,
block_freeidx: usize,
block_texture: wgpu::Texture,
pub bind_layout: wgpu::BindGroupLayout,
pub bind_group: wgpu::BindGroup
}
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 {
mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D3,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, label: None,
size: wgpu::Extent3d{ width: NODE_TEX_SIZE as u32, height: NODE_TEX_SIZE as u32, depth: NODE_TEX_SIZE as u32 },
format: wgpu::TextureFormat::R32Uint,
}
);
let block_texture = device.create_texture(
&wgpu::TextureDescriptor {
mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D3,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, label: None,
size: wgpu::Extent3d{ width: BLOCK_SIZE as u32, height: (BLOCK_TEX_SIZE * BLOCK_SIZE) as u32, depth: (BLOCK_TEX_SIZE * BLOCK_SIZE) as u32 },
format: wgpu::TextureFormat::R8Uint,
}
);
// Bind layout
let sampler_entry = wgpu::BindGroupLayoutEntry {
binding: 0,visibility: wgpu::ShaderStage::FRAGMENT, count: None,
ty: wgpu::BindingType::Sampler { comparison: false, filtering: false },
};
let texture_entry = wgpu::BindGroupLayoutEntry {
binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, count: None,
ty: wgpu::BindingType::Texture { multisampled: false, view_dimension: wgpu::TextureViewDimension::D3, sample_type: wgpu::TextureSampleType::Uint },
};
let bind_layout = device.create_bind_group_layout(
&wgpu::BindGroupLayoutDescriptor {
label: None, entries: &[
wgpu::BindGroupLayoutEntry { binding: 0, ..texture_entry },
wgpu::BindGroupLayoutEntry { binding: 1, ..texture_entry },
wgpu::BindGroupLayoutEntry { binding: 2, ..sampler_entry },
wgpu::BindGroupLayoutEntry { binding: 3, ..sampler_entry },
],
}
);
// Bind group
let bind_group = device.create_bind_group(
&wgpu::BindGroupDescriptor {
label: None, layout: &bind_layout,
entries: &[
wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::TextureView(&node_texture.create_view(&wgpu::TextureViewDescriptor::default())) },
wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::TextureView(&block_texture.create_view(&wgpu::TextureViewDescriptor::default())) },
wgpu::BindGroupEntry { binding: 2, resource: wgpu::BindingResource::Sampler(&device.create_sampler(&Default::default())) },
wgpu::BindGroupEntry { binding: 3, resource: wgpu::BindingResource::Sampler(&device.create_sampler(&Default::default())) }
],
}
);
// Done
let block_freeidx = 0;
Self { node_buffer, node_texture, block_freeidx, block_texture, bind_layout, bind_group }
}
#[allow(unused)]
pub fn write(&mut self, queue: &wgpu::Queue, block_pos: &Point3<u32>, 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 mut value = self.node_buffer[index] as usize;
// Allocate new block
if value == 0 {
value = self.block_freeidx;
self.node_buffer[index] = value as u32;
self.block_freeidx += 1;
}
// Calculate position in block texture
let y = (value % BLOCK_TEX_SIZE * BLOCK_SIZE) as u32;
let z = (value / BLOCK_TEX_SIZE * BLOCK_SIZE) as u32;
let block_origin = wgpu::Origin3d{ x:0, y, z };
let block_size = wgpu::Extent3d{ width: BLOCK_SIZE as u32, height: BLOCK_SIZE as u32, depth: BLOCK_SIZE as u32 };
let block_bytes : [u8;BLOCK_SIZE*BLOCK_SIZE*BLOCK_SIZE] = block.materials.try_into().unwrap();
// Write block
queue.write_texture(
wgpu::TextureCopyView { texture: &self.block_texture, mip_level: 0, origin: block_origin }, &block_bytes,
wgpu::TextureDataLayout { offset: 0, bytes_per_row: block_size.width, rows_per_image: block_size.height }, block_size
);
// Convert u32 node buffer to u8
let node_size = wgpu::Extent3d { width: NODE_TEX_SIZE as u32, height: NODE_TEX_SIZE as u32, depth: NODE_TEX_SIZE as u32 };
let mut node_bytes = [0_u8; NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE*4];
LittleEndian::write_u32_into(&self.node_buffer, &mut node_bytes);
// Write nodes (TODO: do it max once per frame, and only if smth changed)
queue.write_texture(
wgpu::TextureCopyView { texture: &self.node_texture, mip_level: 0, origin: wgpu::Origin3d::ZERO }, &node_bytes,
wgpu::TextureDataLayout { offset: 0, bytes_per_row: 4*node_size.width, rows_per_image: node_size.height }, node_size
);
}
}
+10 -35
View File
@@ -1,50 +1,25 @@
// Consts
pub const BLOCK_SIZE : usize = 32; // 32x32x32 block size
pub const BLOCK_TEX_SIZE : usize = 64; // 64x64 blocks in texture
pub const NODE_TEX_SIZE: usize = 48; // 32x32x32 nodes in texture
pub const NODE_TEX_LEN: usize = NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE; // Number of u32 in node texture
pub const BLOCK_LEN : usize = BLOCK_SIZE*BLOCK_SIZE*BLOCK_SIZE; // Number of u8 in one block
pub const BLOCK_ARR_LEN: usize = BLOCK_TEX_SIZE*BLOCK_TEX_SIZE; // Number of blocks in texture
pub const BLOCK_TEX_LEN: usize = BLOCK_TEX_SIZE*BLOCK_TEX_SIZE * BLOCK_LEN; // Number of u8 in block texture
// Import names
mod nodes;
pub use nodes::Nodes;
mod blocks;
pub use blocks::Blocks;
pub use blocks::RenderBlock;
mod uniform; mod uniform;
pub use uniform::Uniform; pub use uniform::Uniform;
pub use uniform::UniformValues; pub use uniform::UniformValues;
mod content;
pub use content::Content;
mod materials; mod materials;
pub use materials::Materials; pub use materials::Materials;
// Create buffers
pub struct Buffers { pub struct Buffers {
pub uniform_buffer: Uniform, pub uniforms: Uniform,
pub node_buffer: Nodes, pub content: Content,
pub brick_buffer: Blocks, pub materials: Materials
pub material_buffer: Materials
} }
impl Buffers { impl Buffers {
pub fn new(device: &wgpu::Device) -> Self { pub fn new(device: &wgpu::Device) -> Self {
let uniform_buffer = Uniform::new(device); Self {
let node_buffer = Nodes::new(device); uniforms: Uniform::new(device),
let brick_buffer = Blocks::new(device); content: Content::new(device),
let material_buffer = Materials::new(device); materials: Materials::new(device)
Self { uniform_buffer, node_buffer, brick_buffer, material_buffer } }
} }
} }
-91
View File
@@ -1,91 +0,0 @@
use byteorder::{ByteOrder, LittleEndian};
use crate::renderer::buffers::{NODE_TEX_SIZE, NODE_TEX_LEN};
pub struct Nodes {
pub nodes: Box<[u32]>,
texture: wgpu::Texture,
size: wgpu::Extent3d,
pub bind_layout: wgpu::BindGroupLayout,
pub bind_group: wgpu::BindGroup
}
impl Nodes {
pub fn new(device: &wgpu::Device) -> Self {
// Create texture
let size = wgpu::Extent3d { width: NODE_TEX_SIZE as u32, height: NODE_TEX_SIZE as u32, depth: NODE_TEX_SIZE as u32 };
let texture = device.create_texture(
&wgpu::TextureDescriptor {
size: size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D3,
format: wgpu::TextureFormat::R32Uint,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, // STORAGE?
label: Some("Node texture"),
}
);
// Bind layout
let bind_layout = device.create_bind_group_layout(
&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture { multisampled: false, view_dimension: wgpu::TextureViewDimension::D3, sample_type: wgpu::TextureSampleType::Uint },
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: false, filtering: false },
count: None,
},
],
label: Some("Node texture layout"),
}
);
// Bind group
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Nearest, min_filter: wgpu::FilterMode::Nearest, mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
let bind_group = device.create_bind_group(
&wgpu::BindGroupDescriptor {
layout: &bind_layout,
entries: &[
wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::TextureView(&view) },
wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::Sampler(&sampler) }
],
label: Some("Node texture group"),
}
);
// Data
let nodes = vec![0_u32; NODE_TEX_LEN].into_boxed_slice();
println!("Nodes size: {} MB", (nodes.len() as f32 * 4.0 / 1024.0 / 1024.0 * 100.0).round() / 100.0);
// Done
Self { nodes, texture, size, bind_layout, bind_group }
}
pub fn write(&mut self, queue: &wgpu::Queue) {
// Convert 32 bit values to 8 bit
let mut bytes = [0_u8; NODE_TEX_LEN*4];
LittleEndian::write_u32_into(&self.nodes, &mut bytes);
// Write
queue.write_texture(
wgpu::TextureCopyView { texture: &self.texture, mip_level: 0, origin: wgpu::Origin3d::ZERO },
&bytes,
wgpu::TextureDataLayout { offset: 0, bytes_per_row: 4*self.size.width, rows_per_image: self.size.height },
self.size
);
}
}
+3 -26
View File
@@ -1,17 +1,11 @@
use winit::{window::Window, dpi::PhysicalSize}; use winit::{window::Window, dpi::PhysicalSize};
pub mod buffers; pub mod buffers;
use buffers::Buffers; use buffers::Buffers;
mod passes; mod passes;
use passes::{RaytracePass, PostprocessPass}; use passes::{RaytracePass, PostprocessPass};
pub mod camera; pub mod camera;
use camera::Camera; use camera::Camera;
pub mod renderspace;
pub use renderspace::RenderSpace;
pub struct Renderer { pub struct Renderer {
surface: wgpu::Surface, surface: wgpu::Surface,
device: wgpu::Device, device: wgpu::Device,
@@ -27,7 +21,6 @@ pub struct Renderer {
// Other // Other
pub camera: Camera, pub camera: Camera,
start: std::time::Instant, start: std::time::Instant,
changed_bricks: Vec<usize>,
} }
impl Renderer { impl Renderer {
@@ -84,10 +77,9 @@ impl Renderer {
// Other // Other
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let changed_bricks: Vec<usize> = Vec::new();
println!("Initialized"); println!("Initialized");
Self { surface, device, queue, swapchain_desc, swapchain, texture, raytrace_pass, postprocess_pass, buffers, camera, start, changed_bricks } Self { surface, device, queue, swapchain_desc, swapchain, texture, raytrace_pass, postprocess_pass, buffers, camera, start }
} }
/* /*
@@ -113,23 +105,8 @@ impl Renderer {
pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> { pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> {
// Update uniform buffer // Update uniform buffer
self.buffers.uniform_buffer.values.update(&self.camera, self.start.elapsed().as_secs_f32()); self.buffers.uniforms.values.update(&self.camera, self.start.elapsed().as_secs_f32());
self.queue.write_buffer(&self.buffers.uniform_buffer.buffer, 0, bytemuck::cast_slice(&[self.buffers.uniform_buffer.values])); self.queue.write_buffer(&self.buffers.uniforms.buffer, 0, bytemuck::cast_slice(&[self.buffers.uniforms.values]));
// Update changed nodes
if self.changed_bricks.len() > 0 {
self.buffers.node_buffer.write(&self.queue);
for block_id in &self.changed_bricks {
self.buffers.brick_buffer.write(&self.queue, *block_id);
}
// let used = self.buffers.brick_buffer.next_block(false);
// let total = buffers::BLOCK_TEX_SIZE * buffers::BLOCK_TEX_SIZE;
// let changed = self.changed_bricks.len();
// println!("Used: {}/{} Changed: {}", used, total, changed);
self.changed_bricks.clear();
}
// Get next frame to render to // Get next frame to render to
let frame = self.swapchain.get_current_frame()?.output; let frame = self.swapchain.get_current_frame()?.output;
+6 -8
View File
@@ -28,10 +28,9 @@ impl RaytracePass {
// Bind group layouts // Bind group layouts
let bind_group_layouts = [ let bind_group_layouts = [
&buffers.uniform_buffer.bind_layout, &buffers.uniforms.bind_layout,
&buffers.node_buffer.bind_layout, &buffers.content.bind_layout,
&buffers.brick_buffer.bind_layout, &buffers.materials.bind_layout
&buffers.material_buffer.bind_layout
]; ];
// Pipeline layout // Pipeline layout
@@ -81,10 +80,9 @@ impl RaytracePass {
render_pass.set_pipeline(&self.pipeline); render_pass.set_pipeline(&self.pipeline);
// Bind groups // Bind groups
render_pass.set_bind_group(0, &buffers.uniform_buffer.bind_group, &[]); render_pass.set_bind_group(0, &buffers.uniforms.bind_group, &[]);
render_pass.set_bind_group(1, &buffers.node_buffer.bind_group, &[]); render_pass.set_bind_group(1, &buffers.content.bind_group, &[]);
render_pass.set_bind_group(2, &buffers.brick_buffer.bind_group, &[]); render_pass.set_bind_group(2, &buffers.materials.bind_group, &[]);
render_pass.set_bind_group(3, &buffers.material_buffer.bind_group, &[]);
// Draw 2 triangles // Draw 2 triangles
render_pass.draw(0..6, 0..1); render_pass.draw(0..6, 0..1);
-44
View File
@@ -1,44 +0,0 @@
use cgmath::Point3;
use crate::renderer::{Renderer, buffers};
pub trait RenderSpace {
fn block_get(&mut self, block_pos: Point3<usize>) -> &mut buffers::RenderBlock;
fn block_dirty(&mut self, id: usize);
}
impl RenderSpace for Renderer {
/*
* Grabs existing or allocates new block for given position
*
* block_pos: Position of the block in world, in block space
* block_id: Block identifier, equal to Block.id
*/
fn block_get(&mut self, block_pos: Point3<usize>) -> &mut buffers::RenderBlock {
// Get node
let node_idx = block_pos.x + buffers::NODE_TEX_SIZE * (block_pos.y + buffers::NODE_TEX_SIZE * block_pos.z);
let node_value = self.buffers.node_buffer.nodes[node_idx];
// Allocate new block
if node_value == 0 {
let block = self.buffers.brick_buffer.alloc();
self.buffers.node_buffer.nodes[node_idx] = (block.id+1) as u32;
return block;
}
// Return existing block
self.buffers.brick_buffer.get((node_value-1) as usize)
}
/*
* Marks block as dirty, will be sent to gpu at the next frame
*
* block_id: Block identifier, equal to Block.id
*/
fn block_dirty(&mut self, block_id: usize) {
if !self.changed_bricks.contains(&block_id) {
self.changed_bricks.push(block_id);
}
}
}