Combined node and block buffer into one struct: content.
This commit is contained in:
+3
-3
@@ -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,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]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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();
|
||||||
|
|||||||
@@ -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]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
@@ -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 }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user