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 } }