Files
first-voxels/src/renderer/buffers/content.rs
T
2021-05-06 15:38:51 +02:00

126 lines
5.9 KiB
Rust

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 + 1;
self.node_buffer[index] = value as u32;
self.block_freeidx = value;
//println!("Alloc: {}", value);
}
//println!("Index: {} Value: {}", index, value);
// Calculate position in block texture
let y = ((value-1) % BLOCK_TEX_SIZE * BLOCK_SIZE) as u32;
let z = ((value-1) / 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();
//println!("Y: {} Z: {}", y, z);
// 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
);
}
}