Files
first-voxels/src/renderer/buffers/blocks.rs
T

119 lines
4.6 KiB
Rust

use std::convert::TryInto;
use crate::renderer::buffers::{BLOCK_SIZE, BLOCK_TEX_SIZE, BLOCK_TEX_LEN, BLOCK_LEN};
pub struct Blocks {
pub blocks: Box<[u8]>,
pub 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![0_u8; BLOCK_TEX_LEN].into_boxed_slice();
blocks[0] = 1;
println!("block buffer size: {} MB", BLOCK_TEX_LEN as f32 / 1024.0 / 1024.0);
// Done
Self { blocks, texture, bind_layout, bind_group, free_block: 0 }
}
/*
Write block data to gpu, should be called to apply changes
offset: block index to copy
*/
pub fn write(&mut self, queue: &wgpu::Queue, block: usize) {
// Get first block
let block_offset = block*BLOCK_LEN;
let block_bytes : [u8;BLOCK_LEN] = self.blocks[block_offset..block_offset+BLOCK_LEN].try_into().unwrap();
let block_size = wgpu::Extent3d{ width: BLOCK_SIZE as u32, height: BLOCK_SIZE as u32, depth: BLOCK_SIZE as u32 };
let y = (block%BLOCK_TEX_SIZE * BLOCK_SIZE) as u32;
let z = (block/BLOCK_TEX_SIZE * BLOCK_SIZE) as u32;
let block_origin = wgpu::Origin3d{ x:0, y, z };
// Write
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
);
}
/*
* Get id of next free block
* Later: reusing old blocks
*/
pub fn next_block(&mut self, consume: bool) -> usize {
if self.free_block >= self.blocks.len() {
panic!("No more free blocks! we should consider reusing blocks...");
}
let next = self.free_block + 1;
if consume { self.free_block = next; }
next
}
}