Compare commits
10 Commits
23ea18c3de
...
956fdd180f
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 956fdd180f | |
Jarrod Doyle | 511e4b9233 | |
Jarrod Doyle | 77b3e5172b | |
Jarrod Doyle | c26f3c8ffb | |
Jarrod Doyle | 03a74d1b02 | |
Jarrod Doyle | 5acea1192c | |
Jarrod Doyle | e6d73686b4 | |
Jarrod Doyle | 60381c6a58 | |
Jarrod Doyle | 8e08506e6c | |
Jarrod Doyle | 66f44c5461 |
|
@ -78,6 +78,7 @@ pub fn tri_lerp_block(p: &[f32], dims: &[u32], vals: &mut [f32]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps a 3d index to a 1d index
|
/// Maps a 3d index to a 1d index
|
||||||
|
// TODO: Handle out of range!!
|
||||||
pub fn to_1d_index(p: glam::UVec3, dim: glam::UVec3) -> usize {
|
pub fn to_1d_index(p: glam::UVec3, dim: glam::UVec3) -> usize {
|
||||||
(p.x + p.y * dim.x + p.z * dim.x * dim.y) as usize
|
(p.x + p.y * dim.x + p.z * dim.x * dim.y) as usize
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
gfx::{BulkBufferBuilder, Context},
|
||||||
|
math,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum BrickgridFlag {
|
||||||
|
Empty = 0,
|
||||||
|
Unloaded = 1,
|
||||||
|
Loading = 2,
|
||||||
|
Loaded = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for BrickgridFlag {
|
||||||
|
fn from(value: u32) -> Self {
|
||||||
|
match value {
|
||||||
|
x if x == Self::Unloaded as u32 => Self::Unloaded,
|
||||||
|
x if x == Self::Loading as u32 => Self::Loading,
|
||||||
|
x if x == Self::Loaded as u32 => Self::Loaded,
|
||||||
|
_ => Self::Empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
pub struct BrickgridElement(pub u32);
|
||||||
|
|
||||||
|
impl BrickgridElement {
|
||||||
|
pub fn new(brickmap_cache_idx: usize, flag: BrickgridFlag) -> Self {
|
||||||
|
Self(((brickmap_cache_idx as u32) << 8) + flag as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pointer(&self) -> usize {
|
||||||
|
(self.0 >> 8) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_flag(&self) -> BrickgridFlag {
|
||||||
|
BrickgridFlag::from(self.0 & 0xF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Brickgrid {
|
||||||
|
dimensions: glam::UVec3,
|
||||||
|
data: Vec<BrickgridElement>,
|
||||||
|
staged: HashSet<usize>,
|
||||||
|
max_upload_count: usize,
|
||||||
|
buffer: wgpu::Buffer,
|
||||||
|
upload_buffer: wgpu::Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Brickgrid {
|
||||||
|
pub fn new(context: &Context, dimensions: glam::UVec3, max_upload_count: usize) -> Self {
|
||||||
|
let element_count = (dimensions.x * dimensions.y * dimensions.z) as usize;
|
||||||
|
let data = vec![BrickgridElement::new(0, BrickgridFlag::Unloaded); element_count];
|
||||||
|
|
||||||
|
// TODO: change type of upload data. Will need some messyness with bytemucking probably
|
||||||
|
// but should lead to clearer data definitions
|
||||||
|
let mut upload_data = vec![0u32; 4 + 4 * max_upload_count];
|
||||||
|
upload_data[0] = max_upload_count as u32;
|
||||||
|
|
||||||
|
let mut buffers = BulkBufferBuilder::new()
|
||||||
|
.set_usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
|
||||||
|
.with_init_buffer_bm("Brickgrid", &data)
|
||||||
|
.with_init_buffer_bm("Brickgrid Upload", &upload_data)
|
||||||
|
.build(context);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
dimensions,
|
||||||
|
data,
|
||||||
|
staged: HashSet::new(),
|
||||||
|
max_upload_count,
|
||||||
|
buffer: buffers.remove(0),
|
||||||
|
upload_buffer: buffers.remove(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Panics if position maps to out of range index
|
||||||
|
// pub fn set(&mut self, pos: glam::UVec3, value: BrickgridElement) -> BrickgridElement {
|
||||||
|
// let index = math::to_1d_index(pos, self.dimensions);
|
||||||
|
pub fn set(&mut self, index: usize, value: BrickgridElement) -> BrickgridElement {
|
||||||
|
let current = self.data[index];
|
||||||
|
self.data[index] = value;
|
||||||
|
self.staged.insert(index);
|
||||||
|
current
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Panics if position maps to out of range index
|
||||||
|
// pub fn get(&mut self, pos: glam::UVec3) -> BrickgridElement {
|
||||||
|
// let index = math::to_1d_index(pos, self.dimensions);
|
||||||
|
pub fn get(&mut self, index: usize) -> BrickgridElement {
|
||||||
|
self.data[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn upload(&mut self, context: &Context) {
|
||||||
|
let mut upload_data = Vec::new();
|
||||||
|
let mut idx = 0;
|
||||||
|
self.staged.retain(|e| {
|
||||||
|
// We have a limit of how many elements to upload each frame. So we need
|
||||||
|
// to keep any excess
|
||||||
|
if idx >= self.max_upload_count {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index of the brickgrid element, and the value of it
|
||||||
|
upload_data.push(*e as u32);
|
||||||
|
upload_data.push(self.data[*e].0);
|
||||||
|
|
||||||
|
idx += 1;
|
||||||
|
false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Upload buffer is {max_count, count, pad, pad, bricks[]}. So we need to add
|
||||||
|
// the count and pads, and upload at an offset to skip max_count
|
||||||
|
let data = [&[upload_data.len() as u32, 0, 0], &upload_data[..]].concat();
|
||||||
|
context
|
||||||
|
.queue
|
||||||
|
.write_buffer(&self.upload_buffer, 4, bytemuck::cast_slice(&data));
|
||||||
|
|
||||||
|
if idx != 0 {
|
||||||
|
log::info!(
|
||||||
|
"Uploading {} brickgrid entries. ({} remaining)",
|
||||||
|
idx,
|
||||||
|
self.staged.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_buffer(&self) -> &wgpu::Buffer {
|
||||||
|
&self.buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_upload_buffer(&self) -> &wgpu::Buffer {
|
||||||
|
&self.upload_buffer
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +1,14 @@
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
gfx::{self, BufferExt},
|
gfx::{self, BufferExt},
|
||||||
math,
|
math,
|
||||||
voxel::world::{Voxel, WorldManager},
|
voxel::world::WorldManager,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::shading_table::ShadingTableAllocator;
|
use super::{
|
||||||
|
brickgrid::{Brickgrid, BrickgridElement, BrickgridFlag},
|
||||||
#[repr(C)]
|
brickmap_cache::{BrickmapCache, BrickmapCacheEntry},
|
||||||
#[derive(Debug, Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
shading_table::ShadingTableAllocator,
|
||||||
struct Brickmap {
|
};
|
||||||
pub bitmask: [u32; 16],
|
|
||||||
pub shading_table_offset: u32,
|
|
||||||
pub lod_color: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Debug, Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
@ -23,46 +17,17 @@ struct WorldState {
|
||||||
_pad: u32,
|
_pad: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
|
||||||
struct BrickmapCacheEntry {
|
|
||||||
grid_idx: usize,
|
|
||||||
shading_table_offset: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
|
||||||
struct BrickmapUnpackElement {
|
|
||||||
cache_idx: u32,
|
|
||||||
brickmap: Brickmap,
|
|
||||||
shading_element_count: u32,
|
|
||||||
shading_elements: [u32; 512],
|
|
||||||
}
|
|
||||||
|
|
||||||
enum BrickgridFlag {
|
|
||||||
_Empty = 0,
|
|
||||||
_Unloaded = 1,
|
|
||||||
_Loading = 2,
|
|
||||||
Loaded = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BrickmapManager {
|
pub struct BrickmapManager {
|
||||||
state_uniform: WorldState,
|
state_uniform: WorldState,
|
||||||
state_buffer: wgpu::Buffer,
|
state_buffer: wgpu::Buffer,
|
||||||
brickgrid: Vec<u32>,
|
brickgrid: Brickgrid,
|
||||||
brickgrid_buffer: wgpu::Buffer,
|
brickmap_cache: BrickmapCache,
|
||||||
brickmap_cache_map: Vec<Option<BrickmapCacheEntry>>,
|
|
||||||
brickmap_cache_idx: usize,
|
|
||||||
brickmap_buffer: wgpu::Buffer,
|
|
||||||
shading_table_buffer: wgpu::Buffer,
|
shading_table_buffer: wgpu::Buffer,
|
||||||
shading_table_allocator: ShadingTableAllocator,
|
shading_table_allocator: ShadingTableAllocator,
|
||||||
feedback_buffer: wgpu::Buffer,
|
feedback_buffer: wgpu::Buffer,
|
||||||
feedback_result_buffer: wgpu::Buffer,
|
feedback_result_buffer: wgpu::Buffer,
|
||||||
unpack_max_count: usize,
|
unpack_max_count: usize,
|
||||||
brickgrid_staged: HashSet<usize>,
|
|
||||||
brickgrid_unpack_buffer: wgpu::Buffer,
|
|
||||||
brickmap_staged: Vec<BrickmapUnpackElement>,
|
|
||||||
brickmap_unpack_buffer: wgpu::Buffer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
|
@ -81,11 +46,12 @@ impl BrickmapManager {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let brickgrid =
|
let brickgrid = Brickgrid::new(context, brickgrid_dims, max_uploaded_brickmaps as usize);
|
||||||
vec![1u32; (brickgrid_dims.x * brickgrid_dims.y * brickgrid_dims.z) as usize];
|
let brickmap_cache = BrickmapCache::new(
|
||||||
|
context,
|
||||||
let brickmap_cache = vec![Brickmap::default(); brickmap_cache_size];
|
brickmap_cache_size,
|
||||||
let brickmap_cache_map = vec![None; brickmap_cache.capacity()];
|
max_uploaded_brickmaps as usize,
|
||||||
|
);
|
||||||
|
|
||||||
let shading_table_allocator = ShadingTableAllocator::new(4, shading_table_bucket_size);
|
let shading_table_allocator = ShadingTableAllocator::new(4, shading_table_bucket_size);
|
||||||
let shading_table = vec![0u32; shading_table_allocator.total_elements as usize];
|
let shading_table = vec![0u32; shading_table_allocator.total_elements as usize];
|
||||||
|
@ -94,22 +60,13 @@ impl BrickmapManager {
|
||||||
feedback_data[0] = max_requested_brickmaps;
|
feedback_data[0] = max_requested_brickmaps;
|
||||||
let feedback_data_u8 = bytemuck::cast_slice(&feedback_data);
|
let feedback_data_u8 = bytemuck::cast_slice(&feedback_data);
|
||||||
|
|
||||||
let mut brickgrid_upload_data = vec![0u32; 4 + 4 * max_uploaded_brickmaps as usize];
|
|
||||||
brickgrid_upload_data[0] = max_uploaded_brickmaps;
|
|
||||||
let brickgrid_staged = HashSet::new();
|
|
||||||
|
|
||||||
let mut brickmap_upload_data = vec![0u32; 4 + 532 * max_uploaded_brickmaps as usize];
|
let mut brickmap_upload_data = vec![0u32; 4 + 532 * max_uploaded_brickmaps as usize];
|
||||||
brickmap_upload_data[0] = max_uploaded_brickmaps;
|
brickmap_upload_data[0] = max_uploaded_brickmaps;
|
||||||
let brickmap_staged = Vec::new();
|
|
||||||
|
|
||||||
let mut buffers = gfx::BulkBufferBuilder::new()
|
let mut buffers = gfx::BulkBufferBuilder::new()
|
||||||
.with_init_buffer_bm("Brick World State", &[state_uniform])
|
.with_init_buffer_bm("Brick World State", &[state_uniform])
|
||||||
.set_usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
|
.set_usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
|
||||||
.with_init_buffer_bm("Brickgrid", &brickgrid)
|
|
||||||
.with_init_buffer_bm("Brickmap Cache", &brickmap_cache)
|
|
||||||
.with_init_buffer_bm("Shading Table", &shading_table)
|
.with_init_buffer_bm("Shading Table", &shading_table)
|
||||||
.with_init_buffer_bm("Brickgrid Unpack", &brickgrid_upload_data)
|
|
||||||
.with_init_buffer_bm("Brickmap Unpack", &brickmap_upload_data)
|
|
||||||
.set_usage(
|
.set_usage(
|
||||||
wgpu::BufferUsages::STORAGE
|
wgpu::BufferUsages::STORAGE
|
||||||
| wgpu::BufferUsages::COPY_DST
|
| wgpu::BufferUsages::COPY_DST
|
||||||
|
@ -123,26 +80,19 @@ impl BrickmapManager {
|
||||||
Self {
|
Self {
|
||||||
state_uniform,
|
state_uniform,
|
||||||
brickgrid,
|
brickgrid,
|
||||||
brickmap_cache_map,
|
brickmap_cache,
|
||||||
brickmap_cache_idx: 0,
|
|
||||||
shading_table_allocator,
|
shading_table_allocator,
|
||||||
unpack_max_count: max_uploaded_brickmaps as usize,
|
unpack_max_count: max_uploaded_brickmaps as usize,
|
||||||
brickgrid_staged,
|
|
||||||
brickmap_staged,
|
|
||||||
|
|
||||||
state_buffer: buffers.remove(0),
|
state_buffer: buffers.remove(0),
|
||||||
brickgrid_buffer: buffers.remove(0),
|
|
||||||
brickmap_buffer: buffers.remove(0),
|
|
||||||
shading_table_buffer: buffers.remove(0),
|
shading_table_buffer: buffers.remove(0),
|
||||||
brickgrid_unpack_buffer: buffers.remove(0),
|
|
||||||
brickmap_unpack_buffer: buffers.remove(0),
|
|
||||||
feedback_buffer: buffers.remove(0),
|
feedback_buffer: buffers.remove(0),
|
||||||
feedback_result_buffer: buffers.remove(0),
|
feedback_result_buffer: buffers.remove(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brickgrid_buffer(&self) -> &wgpu::Buffer {
|
pub fn get_brickgrid_buffer(&self) -> &wgpu::Buffer {
|
||||||
&self.brickgrid_buffer
|
self.brickgrid.get_buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_worldstate_buffer(&self) -> &wgpu::Buffer {
|
pub fn get_worldstate_buffer(&self) -> &wgpu::Buffer {
|
||||||
|
@ -150,7 +100,7 @@ impl BrickmapManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brickmap_buffer(&self) -> &wgpu::Buffer {
|
pub fn get_brickmap_buffer(&self) -> &wgpu::Buffer {
|
||||||
&self.brickmap_buffer
|
self.brickmap_cache.get_buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_shading_buffer(&self) -> &wgpu::Buffer {
|
pub fn get_shading_buffer(&self) -> &wgpu::Buffer {
|
||||||
|
@ -166,11 +116,11 @@ impl BrickmapManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brickmap_unpack_buffer(&self) -> &wgpu::Buffer {
|
pub fn get_brickmap_unpack_buffer(&self) -> &wgpu::Buffer {
|
||||||
&self.brickmap_unpack_buffer
|
self.brickmap_cache.get_upload_buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brickgrid_unpack_buffer(&self) -> &wgpu::Buffer {
|
pub fn get_brickgrid_unpack_buffer(&self) -> &wgpu::Buffer {
|
||||||
&self.brickgrid_unpack_buffer
|
self.brickgrid.get_upload_buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_unpack_max_count(&self) -> usize {
|
pub fn get_unpack_max_count(&self) -> usize {
|
||||||
|
@ -198,8 +148,7 @@ impl BrickmapManager {
|
||||||
// TODO: Why do we call this here rather than doing it outside of here?
|
// TODO: Why do we call this here rather than doing it outside of here?
|
||||||
self.upload_unpack_buffers(context);
|
self.upload_unpack_buffers(context);
|
||||||
|
|
||||||
// TODO: This is inaccurate if we've looped
|
log::info!("Num loaded brickmaps: {}", self.brickmap_cache.num_loaded);
|
||||||
log::info!("Num loaded brickmaps: {}", self.brickmap_cache_idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_request(&mut self, world: &mut WorldManager, data: &[u32]) {
|
fn handle_request(&mut self, world: &mut WorldManager, data: &[u32]) {
|
||||||
|
@ -215,264 +164,73 @@ impl BrickmapManager {
|
||||||
// We only want to upload voxels that are on the surface, so we cull anything
|
// We only want to upload voxels that are on the surface, so we cull anything
|
||||||
// that is surrounded by solid voxels
|
// that is surrounded by solid voxels
|
||||||
let grid_pos = grid_pos.as_ivec3();
|
let grid_pos = grid_pos.as_ivec3();
|
||||||
let (bitmask_data, albedo_data) = Self::cull_interior_voxels(world, grid_pos);
|
let (bitmask_data, albedo_data) = super::util::cull_interior_voxels(world, grid_pos);
|
||||||
|
|
||||||
// If there's no voxel colour data post-culling it means the brickmap is
|
// If there's no voxel colour data post-culling it means the brickmap is
|
||||||
// empty. We don't need to upload it, just mark the relevant brickgrid entry.
|
// empty. We don't need to upload it, just mark the relevant brickgrid entry.
|
||||||
if albedo_data.is_empty() {
|
if albedo_data.is_empty() {
|
||||||
self.update_brickgrid_element(grid_idx, 0);
|
if let Some(entry) = self.update_brickgrid_element(grid_idx, 0) {
|
||||||
|
// TODO: We need to actually remove the cache entry lmao
|
||||||
|
// The brickgrid element had a brickmap entry so we need to unload it's
|
||||||
|
// shading data
|
||||||
|
if let Err(e) = self
|
||||||
|
.shading_table_allocator
|
||||||
|
.try_dealloc(entry.shading_table_offset)
|
||||||
|
{
|
||||||
|
log::warn!("{}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the brickgrid index
|
|
||||||
self.update_brickgrid_element(
|
|
||||||
grid_idx,
|
|
||||||
Self::to_brickgrid_element(self.brickmap_cache_idx as u32, BrickgridFlag::Loaded),
|
|
||||||
);
|
|
||||||
|
|
||||||
// If there's already something in the cache spot we want to write to, we
|
|
||||||
// need to unload it.
|
|
||||||
if self.brickmap_cache_map[self.brickmap_cache_idx].is_some() {
|
|
||||||
let entry = self.brickmap_cache_map[self.brickmap_cache_idx].unwrap();
|
|
||||||
self.update_brickgrid_element(entry.grid_idx, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the shading table
|
// Update the shading table
|
||||||
let shading_idx = self
|
let shading_idx = self
|
||||||
.shading_table_allocator
|
.shading_table_allocator
|
||||||
.try_alloc(albedo_data.len() as u32)
|
.try_alloc(albedo_data.len() as u32)
|
||||||
.unwrap() as usize;
|
.unwrap() as usize;
|
||||||
|
|
||||||
// We're all good to overwrite the cache map entry now :)
|
if let Some(entry) =
|
||||||
self.brickmap_cache_map[self.brickmap_cache_idx] = Some(BrickmapCacheEntry {
|
self.brickmap_cache
|
||||||
|
.add_entry(grid_idx, shading_idx as u32, bitmask_data, albedo_data)
|
||||||
|
{
|
||||||
|
self.update_brickgrid_element(entry.grid_idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the brickgrid index
|
||||||
|
if let Some(old_entry) = self.update_brickgrid_element(
|
||||||
grid_idx,
|
grid_idx,
|
||||||
shading_table_offset: shading_idx as u32,
|
super::util::to_brickgrid_element(
|
||||||
});
|
self.brickmap_cache.index as u32,
|
||||||
|
BrickgridFlag::Loaded,
|
||||||
// Update the brickmap
|
),
|
||||||
let brickmap = Brickmap {
|
) {
|
||||||
bitmask: bitmask_data,
|
// TODO: We need to actually remove the cache entry lmao
|
||||||
shading_table_offset: shading_idx as u32,
|
// The brickgrid element had a brickmap entry so we need to unload it's
|
||||||
lod_color: 0,
|
// shading data
|
||||||
};
|
if let Err(e) = self
|
||||||
|
.shading_table_allocator
|
||||||
let shading_element_count = albedo_data.len();
|
.try_dealloc(old_entry.shading_table_offset)
|
||||||
let mut shading_elements = [0u32; 512];
|
{
|
||||||
shading_elements[..shading_element_count].copy_from_slice(&albedo_data);
|
log::warn!("{}", e)
|
||||||
|
}
|
||||||
let staged_brickmap = BrickmapUnpackElement {
|
}
|
||||||
cache_idx: self.brickmap_cache_idx as u32,
|
|
||||||
brickmap,
|
|
||||||
shading_element_count: shading_element_count as u32,
|
|
||||||
shading_elements,
|
|
||||||
};
|
|
||||||
self.brickmap_staged.push(staged_brickmap);
|
|
||||||
self.brickmap_cache_idx = (self.brickmap_cache_idx + 1) % self.brickmap_cache_map.len();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_brickgrid_element(&mut self, index: usize, data: u32) {
|
fn update_brickgrid_element(&mut self, index: usize, data: u32) -> Option<BrickmapCacheEntry> {
|
||||||
// If we're updating a brickgrid element, we need to make sure to deallocate anything
|
let mut brickmap_cache_entry = None;
|
||||||
// that's already there. The shading table gets deallocated, and the brickmap cache entry
|
let current = self.brickgrid.get(index);
|
||||||
// is marked as None.
|
if current.get_flag() == BrickgridFlag::Loaded {
|
||||||
if (self.brickgrid[index] & 0xF) == 4 {
|
let cache_index = current.get_pointer();
|
||||||
let brickmap_idx = (self.brickgrid[index] >> 8) as usize;
|
brickmap_cache_entry = self.brickmap_cache.get_entry(cache_index);
|
||||||
let cache_map_entry = self.brickmap_cache_map[brickmap_idx];
|
|
||||||
match cache_map_entry {
|
|
||||||
Some(entry) => {
|
|
||||||
match self
|
|
||||||
.shading_table_allocator
|
|
||||||
.try_dealloc(entry.shading_table_offset)
|
|
||||||
{
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => log::warn!("{}", e),
|
|
||||||
}
|
|
||||||
self.brickmap_cache_map[brickmap_idx] = None;
|
|
||||||
}
|
|
||||||
None => log::warn!("Expected brickmap cache entry, found None!"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're safe to overwrite the CPU brickgrid and mark for GPU upload now
|
// We're safe to overwrite the CPU brickgrid and mark for GPU upload now
|
||||||
self.brickgrid[index] = data;
|
self.brickgrid.set(index, BrickgridElement(data));
|
||||||
self.brickgrid_staged.insert(index);
|
brickmap_cache_entry
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_unpack_buffers(&mut self, context: &gfx::Context) {
|
fn upload_unpack_buffers(&mut self, context: &gfx::Context) {
|
||||||
// Brickgrid
|
self.brickgrid.upload(context);
|
||||||
let mut data = Vec::new();
|
self.brickmap_cache.upload(context);
|
||||||
let mut iter = self.brickgrid_staged.iter();
|
|
||||||
let mut to_remove = Vec::new();
|
|
||||||
for _ in 0..self.unpack_max_count {
|
|
||||||
let el = iter.next();
|
|
||||||
if el.is_none() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let val = el.unwrap();
|
|
||||||
to_remove.push(*val as u32);
|
|
||||||
data.push(*val as u32);
|
|
||||||
data.push(self.brickgrid[*val]);
|
|
||||||
}
|
|
||||||
for val in &to_remove {
|
|
||||||
self.brickgrid_staged.remove(&(*val as usize));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !data.is_empty() {
|
|
||||||
log::info!(
|
|
||||||
"Uploading {} brickgrid entries. ({} remaining)",
|
|
||||||
to_remove.len(),
|
|
||||||
self.brickgrid_staged.len()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.queue.write_buffer(
|
|
||||||
&self.brickgrid_unpack_buffer,
|
|
||||||
4,
|
|
||||||
bytemuck::cast_slice(&[data.len()]),
|
|
||||||
);
|
|
||||||
context.queue.write_buffer(
|
|
||||||
&self.brickgrid_unpack_buffer,
|
|
||||||
16,
|
|
||||||
bytemuck::cast_slice(&data),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Brickmap
|
|
||||||
let end = self.unpack_max_count.min(self.brickmap_staged.len());
|
|
||||||
let iter = self.brickmap_staged.drain(0..end);
|
|
||||||
let data = iter.as_slice();
|
|
||||||
context.queue.write_buffer(
|
|
||||||
&self.brickmap_unpack_buffer,
|
|
||||||
4,
|
|
||||||
bytemuck::cast_slice(&[end]),
|
|
||||||
);
|
|
||||||
context
|
|
||||||
.queue
|
|
||||||
.write_buffer(&self.brickmap_unpack_buffer, 16, bytemuck::cast_slice(data));
|
|
||||||
drop(iter);
|
|
||||||
|
|
||||||
if end > 0 {
|
|
||||||
log::info!(
|
|
||||||
"Uploading {} brickmap entries. ({} remaining)",
|
|
||||||
end,
|
|
||||||
self.brickmap_staged.len()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cull_interior_voxels(
|
|
||||||
world: &mut WorldManager,
|
|
||||||
grid_pos: glam::IVec3,
|
|
||||||
) -> ([u32; 16], Vec<u32>) {
|
|
||||||
// This is the data we want to return
|
|
||||||
let mut bitmask_data = [0xFFFFFFFF_u32; 16];
|
|
||||||
let mut albedo_data = Vec::<u32>::new();
|
|
||||||
|
|
||||||
// Calculate world chunk and block positions for each that may be accessed
|
|
||||||
let center_pos = Self::grid_pos_to_world_pos(world, grid_pos);
|
|
||||||
let forward_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(1, 0, 0));
|
|
||||||
let backward_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(-1, 0, 0));
|
|
||||||
let left_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 0, -1));
|
|
||||||
let right_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 0, 1));
|
|
||||||
let up_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 1, 0));
|
|
||||||
let down_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, -1, 0));
|
|
||||||
|
|
||||||
// Fetch those blocks
|
|
||||||
let center_block = world.get_block(center_pos.0, center_pos.1);
|
|
||||||
let forward_block = world.get_block(forward_pos.0, forward_pos.1);
|
|
||||||
let backward_block = world.get_block(backward_pos.0, backward_pos.1);
|
|
||||||
let left_block = world.get_block(left_pos.0, left_pos.1);
|
|
||||||
let right_block = world.get_block(right_pos.0, right_pos.1);
|
|
||||||
let up_block = world.get_block(up_pos.0, up_pos.1);
|
|
||||||
let down_block = world.get_block(down_pos.0, down_pos.1);
|
|
||||||
|
|
||||||
// Reusable array of whether cardinal neighbours are empty
|
|
||||||
let mut neighbours = [false; 6];
|
|
||||||
for z in 0..8 {
|
|
||||||
// Each z level contains two bitmask segments of voxels
|
|
||||||
let mut entry = 0u64;
|
|
||||||
for y in 0..8 {
|
|
||||||
for x in 0..8 {
|
|
||||||
// Ignore non-solids
|
|
||||||
let idx = x + y * 8 + z * 8 * 8;
|
|
||||||
let empty_voxel = Voxel::Empty;
|
|
||||||
|
|
||||||
match center_block[idx] {
|
|
||||||
Voxel::Empty => continue,
|
|
||||||
Voxel::Color(r, g, b) => {
|
|
||||||
// A voxel is on the surface if at least one of it's
|
|
||||||
// cardinal neighbours is non-solid.
|
|
||||||
neighbours[0] = if x == 7 {
|
|
||||||
forward_block[idx - 7] == empty_voxel
|
|
||||||
} else {
|
|
||||||
center_block[idx + 1] == empty_voxel
|
|
||||||
};
|
|
||||||
|
|
||||||
neighbours[1] = if x == 0 {
|
|
||||||
backward_block[idx + 7] == empty_voxel
|
|
||||||
} else {
|
|
||||||
center_block[idx - 1] == empty_voxel
|
|
||||||
};
|
|
||||||
|
|
||||||
neighbours[2] = if z == 7 {
|
|
||||||
right_block[idx - 448] == empty_voxel
|
|
||||||
} else {
|
|
||||||
center_block[idx + 64] == empty_voxel
|
|
||||||
};
|
|
||||||
|
|
||||||
neighbours[3] = if z == 0 {
|
|
||||||
left_block[idx + 448] == empty_voxel
|
|
||||||
} else {
|
|
||||||
center_block[idx - 64] == empty_voxel
|
|
||||||
};
|
|
||||||
|
|
||||||
neighbours[4] = if y == 7 {
|
|
||||||
up_block[idx - 56] == empty_voxel
|
|
||||||
} else {
|
|
||||||
center_block[idx + 8] == empty_voxel
|
|
||||||
};
|
|
||||||
|
|
||||||
neighbours[5] = if y == 0 {
|
|
||||||
down_block[idx + 56] == empty_voxel
|
|
||||||
} else {
|
|
||||||
center_block[idx - 8] == empty_voxel
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the appropriate bit in the z entry and add the
|
|
||||||
// shading data
|
|
||||||
let surface_voxel = neighbours.iter().any(|v| *v);
|
|
||||||
if surface_voxel {
|
|
||||||
entry += 1 << (x + y * 8);
|
|
||||||
let albedo = ((r as u32) << 24)
|
|
||||||
+ ((g as u32) << 16)
|
|
||||||
+ ((b as u32) << 8)
|
|
||||||
+ 255u32;
|
|
||||||
albedo_data.push(albedo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let offset = 2 * z;
|
|
||||||
bitmask_data[offset] = (entry & 0xFFFFFFFF).try_into().unwrap();
|
|
||||||
bitmask_data[offset + 1] = ((entry >> 32) & 0xFFFFFFFF).try_into().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
(bitmask_data, albedo_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_brickgrid_element(brickmap_cache_idx: u32, flags: BrickgridFlag) -> u32 {
|
|
||||||
(brickmap_cache_idx << 8) + flags as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn grid_pos_to_world_pos(
|
|
||||||
world: &mut WorldManager,
|
|
||||||
grid_pos: glam::IVec3,
|
|
||||||
) -> (glam::IVec3, glam::UVec3) {
|
|
||||||
// We deal with dvecs here because we want a negative grid_pos to have floored
|
|
||||||
// chunk_pos
|
|
||||||
let chunk_dims = world.get_chunk_dims().as_dvec3();
|
|
||||||
let chunk_pos = (grid_pos.as_dvec3() / chunk_dims).floor();
|
|
||||||
let block_pos = grid_pos - (chunk_pos * chunk_dims).as_ivec3();
|
|
||||||
(chunk_pos.as_ivec3(), block_pos.as_uvec3())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
use crate::gfx::{BulkBufferBuilder, Context};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
pub struct Brickmap {
|
||||||
|
pub bitmask: [u32; 16],
|
||||||
|
pub shading_table_offset: u32,
|
||||||
|
pub lod_color: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct BrickmapCacheEntry {
|
||||||
|
pub grid_idx: usize,
|
||||||
|
pub shading_table_offset: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
// TODO: Rename struct
|
||||||
|
struct BrickmapUnpackElement {
|
||||||
|
cache_idx: u32, // TODO: Change to usize?
|
||||||
|
brickmap: Brickmap,
|
||||||
|
shading_element_count: u32,
|
||||||
|
shading_elements: [u32; 512], // TODO: Replace u32 with custom type?
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BrickmapCache {
|
||||||
|
cache: Vec<Option<BrickmapCacheEntry>>,
|
||||||
|
pub index: usize,
|
||||||
|
pub num_loaded: u32,
|
||||||
|
staged: Vec<BrickmapUnpackElement>,
|
||||||
|
max_upload_count: usize,
|
||||||
|
buffer: wgpu::Buffer,
|
||||||
|
upload_buffer: wgpu::Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrickmapCache {
|
||||||
|
pub fn new(context: &Context, size: usize, max_upload_count: usize) -> Self {
|
||||||
|
let data = vec![Brickmap::default(); size];
|
||||||
|
|
||||||
|
// TODO: change type of upload data. Will need some messyness with bytemucking probably
|
||||||
|
// but should lead to clearer data definitions
|
||||||
|
let mut upload_data = vec![0u32; 4 + 532 * max_upload_count];
|
||||||
|
upload_data[0] = max_upload_count as u32;
|
||||||
|
|
||||||
|
let mut buffers = BulkBufferBuilder::new()
|
||||||
|
.set_usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
|
||||||
|
.with_init_buffer_bm("Brickmap Cache", &data)
|
||||||
|
.with_init_buffer_bm("Brickmap Unpack", &upload_data)
|
||||||
|
.build(context);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cache: vec![None; size],
|
||||||
|
index: 0,
|
||||||
|
num_loaded: 0,
|
||||||
|
staged: vec![],
|
||||||
|
max_upload_count,
|
||||||
|
buffer: buffers.remove(0),
|
||||||
|
upload_buffer: buffers.remove(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_buffer(&self) -> &wgpu::Buffer {
|
||||||
|
&self.buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_upload_buffer(&self) -> &wgpu::Buffer {
|
||||||
|
&self.upload_buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a brickmap entry and returns the entry that was overwritten.
|
||||||
|
pub fn add_entry(
|
||||||
|
&mut self,
|
||||||
|
grid_idx: usize,
|
||||||
|
shading_table_offset: u32,
|
||||||
|
bitmask: [u32; 16],
|
||||||
|
albedo_data: Vec<u32>,
|
||||||
|
) -> Option<BrickmapCacheEntry> {
|
||||||
|
// We do this first because we want this to be the index of the most recently added entry
|
||||||
|
// This has the side effect of meaning that on the first loop through the cache the first
|
||||||
|
// entry is empty, but it's fine.
|
||||||
|
self.index = (self.index + 1) % self.cache.len();
|
||||||
|
|
||||||
|
let existing_entry = self.cache[self.index];
|
||||||
|
if existing_entry.is_none() {
|
||||||
|
self.num_loaded += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cache[self.index] = Some(BrickmapCacheEntry {
|
||||||
|
grid_idx,
|
||||||
|
shading_table_offset,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Need to stage this entry
|
||||||
|
let brickmap = Brickmap {
|
||||||
|
bitmask,
|
||||||
|
shading_table_offset,
|
||||||
|
lod_color: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let shading_element_count = albedo_data.len();
|
||||||
|
let mut shading_elements = [0u32; 512];
|
||||||
|
shading_elements[..shading_element_count].copy_from_slice(&albedo_data);
|
||||||
|
|
||||||
|
let staged_brickmap = BrickmapUnpackElement {
|
||||||
|
cache_idx: self.index as u32,
|
||||||
|
brickmap,
|
||||||
|
shading_element_count: shading_element_count as u32,
|
||||||
|
shading_elements,
|
||||||
|
};
|
||||||
|
self.staged.push(staged_brickmap);
|
||||||
|
|
||||||
|
existing_entry
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove an entry from the cache and return it
|
||||||
|
pub fn remove_entry(&mut self, index: usize) -> Option<BrickmapCacheEntry> {
|
||||||
|
let entry = self.cache[index];
|
||||||
|
if entry.is_some() {
|
||||||
|
self.cache[index] = None;
|
||||||
|
self.num_loaded -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_entry(&self, index: usize) -> Option<BrickmapCacheEntry> {
|
||||||
|
self.cache[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn upload(&mut self, context: &Context) {
|
||||||
|
// Takes up to max_upload_count upload elements
|
||||||
|
let count = usize::min(self.max_upload_count, self.staged.len());
|
||||||
|
let iter = self.staged.drain(0..count);
|
||||||
|
let upload_data = iter.as_slice();
|
||||||
|
|
||||||
|
// Upload buffer is {max_count, count, pad, pad, maps[]}. So we need to add
|
||||||
|
// the count and pads, and upload at an offset to skip max_count
|
||||||
|
let data: Vec<u8> = [
|
||||||
|
bytemuck::cast_slice(&[count as u32, 0, 0]),
|
||||||
|
bytemuck::cast_slice(upload_data),
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
context.queue.write_buffer(&self.upload_buffer, 4, &data);
|
||||||
|
drop(iter);
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
log::info!(
|
||||||
|
"Uploading {} brickmap entries. ({} remaining)",
|
||||||
|
count,
|
||||||
|
self.staged.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
|
mod brickgrid;
|
||||||
mod brickmap;
|
mod brickmap;
|
||||||
|
mod brickmap_cache;
|
||||||
mod shading_table;
|
mod shading_table;
|
||||||
|
mod util;
|
||||||
|
|
||||||
pub use brickmap::BrickmapManager;
|
pub use brickmap::BrickmapManager;
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
use crate::voxel::world::{Voxel, WorldManager};
|
||||||
|
|
||||||
|
use super::brickgrid::BrickgridFlag;
|
||||||
|
|
||||||
|
pub fn cull_interior_voxels(
|
||||||
|
world: &mut WorldManager,
|
||||||
|
grid_pos: glam::IVec3,
|
||||||
|
) -> ([u32; 16], Vec<u32>) {
|
||||||
|
// This is the data we want to return
|
||||||
|
let mut bitmask_data = [0xFFFFFFFF_u32; 16];
|
||||||
|
let mut albedo_data = Vec::<u32>::new();
|
||||||
|
|
||||||
|
// Calculate world chunk and block positions for each that may be accessed
|
||||||
|
let center_pos = grid_pos_to_world_pos(world, grid_pos);
|
||||||
|
let forward_pos = grid_pos_to_world_pos(world, grid_pos + glam::ivec3(1, 0, 0));
|
||||||
|
let backward_pos = grid_pos_to_world_pos(world, grid_pos + glam::ivec3(-1, 0, 0));
|
||||||
|
let left_pos = grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 0, -1));
|
||||||
|
let right_pos = grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 0, 1));
|
||||||
|
let up_pos = grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 1, 0));
|
||||||
|
let down_pos = grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, -1, 0));
|
||||||
|
|
||||||
|
// Fetch those blocks
|
||||||
|
let center_block = world.get_block(center_pos.0, center_pos.1);
|
||||||
|
let forward_block = world.get_block(forward_pos.0, forward_pos.1);
|
||||||
|
let backward_block = world.get_block(backward_pos.0, backward_pos.1);
|
||||||
|
let left_block = world.get_block(left_pos.0, left_pos.1);
|
||||||
|
let right_block = world.get_block(right_pos.0, right_pos.1);
|
||||||
|
let up_block = world.get_block(up_pos.0, up_pos.1);
|
||||||
|
let down_block = world.get_block(down_pos.0, down_pos.1);
|
||||||
|
|
||||||
|
// Reusable array of whether cardinal neighbours are empty
|
||||||
|
let mut neighbours = [false; 6];
|
||||||
|
for z in 0..8 {
|
||||||
|
// Each z level contains two bitmask segments of voxels
|
||||||
|
let mut entry = 0u64;
|
||||||
|
for y in 0..8 {
|
||||||
|
for x in 0..8 {
|
||||||
|
// Ignore non-solids
|
||||||
|
let idx = x + y * 8 + z * 8 * 8;
|
||||||
|
let empty_voxel = Voxel::Empty;
|
||||||
|
|
||||||
|
match center_block[idx] {
|
||||||
|
Voxel::Empty => continue,
|
||||||
|
Voxel::Color(r, g, b) => {
|
||||||
|
// A voxel is on the surface if at least one of it's
|
||||||
|
// cardinal neighbours is non-solid.
|
||||||
|
neighbours[0] = if x == 7 {
|
||||||
|
forward_block[idx - 7] == empty_voxel
|
||||||
|
} else {
|
||||||
|
center_block[idx + 1] == empty_voxel
|
||||||
|
};
|
||||||
|
|
||||||
|
neighbours[1] = if x == 0 {
|
||||||
|
backward_block[idx + 7] == empty_voxel
|
||||||
|
} else {
|
||||||
|
center_block[idx - 1] == empty_voxel
|
||||||
|
};
|
||||||
|
|
||||||
|
neighbours[2] = if z == 7 {
|
||||||
|
right_block[idx - 448] == empty_voxel
|
||||||
|
} else {
|
||||||
|
center_block[idx + 64] == empty_voxel
|
||||||
|
};
|
||||||
|
|
||||||
|
neighbours[3] = if z == 0 {
|
||||||
|
left_block[idx + 448] == empty_voxel
|
||||||
|
} else {
|
||||||
|
center_block[idx - 64] == empty_voxel
|
||||||
|
};
|
||||||
|
|
||||||
|
neighbours[4] = if y == 7 {
|
||||||
|
up_block[idx - 56] == empty_voxel
|
||||||
|
} else {
|
||||||
|
center_block[idx + 8] == empty_voxel
|
||||||
|
};
|
||||||
|
|
||||||
|
neighbours[5] = if y == 0 {
|
||||||
|
down_block[idx + 56] == empty_voxel
|
||||||
|
} else {
|
||||||
|
center_block[idx - 8] == empty_voxel
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the appropriate bit in the z entry and add the
|
||||||
|
// shading data
|
||||||
|
let surface_voxel = neighbours.iter().any(|v| *v);
|
||||||
|
if surface_voxel {
|
||||||
|
entry += 1 << (x + y * 8);
|
||||||
|
let albedo = ((r as u32) << 24)
|
||||||
|
+ ((g as u32) << 16)
|
||||||
|
+ ((b as u32) << 8)
|
||||||
|
+ 255u32;
|
||||||
|
albedo_data.push(albedo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let offset = 2 * z;
|
||||||
|
bitmask_data[offset] = (entry & 0xFFFFFFFF).try_into().unwrap();
|
||||||
|
bitmask_data[offset + 1] = ((entry >> 32) & 0xFFFFFFFF).try_into().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
(bitmask_data, albedo_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_brickgrid_element(brickmap_cache_idx: u32, flags: BrickgridFlag) -> u32 {
|
||||||
|
(brickmap_cache_idx << 8) + flags as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grid_pos_to_world_pos(
|
||||||
|
world: &mut WorldManager,
|
||||||
|
grid_pos: glam::IVec3,
|
||||||
|
) -> (glam::IVec3, glam::UVec3) {
|
||||||
|
// We deal with dvecs here because we want a negative grid_pos to have floored
|
||||||
|
// chunk_pos
|
||||||
|
let chunk_dims = world.get_chunk_dims().as_dvec3();
|
||||||
|
let chunk_pos = (grid_pos.as_dvec3() / chunk_dims).floor();
|
||||||
|
let block_pos = grid_pos - (chunk_pos * chunk_dims).as_ivec3();
|
||||||
|
(chunk_pos.as_ivec3(), block_pos.as_uvec3())
|
||||||
|
}
|
|
@ -177,6 +177,15 @@ impl VoxelRenderer {
|
||||||
unpack_bind_group,
|
unpack_bind_group,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_brickmap(
|
||||||
|
&mut self,
|
||||||
|
context: &gfx::Context,
|
||||||
|
world: &mut super::world::WorldManager,
|
||||||
|
) {
|
||||||
|
self.brickmap_manager
|
||||||
|
.process_feedback_buffer(context, world);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl gfx::Renderer for VoxelRenderer {
|
impl gfx::Renderer for VoxelRenderer {
|
||||||
|
@ -240,14 +249,3 @@ impl gfx::Renderer for VoxelRenderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VoxelRenderer {
|
|
||||||
pub fn update_brickmap(
|
|
||||||
&mut self,
|
|
||||||
context: &gfx::Context,
|
|
||||||
world: &mut super::world::WorldManager,
|
|
||||||
) {
|
|
||||||
self.brickmap_manager
|
|
||||||
.process_feedback_buffer(context, world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue