From 306f2cf2c41886edaf9860038b9041a8c82c4b5b Mon Sep 17 00:00:00 2001 From: Lizzy Fleckenstein Date: Mon, 15 May 2023 21:55:22 +0200 Subject: Defer block mesh building for 100ms or until all neighbors are present Avoid excessive rebuilds --- src/gfx/map.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 9 deletions(-) (limited to 'src/gfx/map.rs') diff --git a/src/gfx/map.rs b/src/gfx/map.rs index 42fff6c..8b300dd 100644 --- a/src/gfx/map.rs +++ b/src/gfx/map.rs @@ -9,9 +9,10 @@ use mesh::{create_mesh, MeshData}; use mt_net::{MapBlock, NodeDef}; use serde::{Deserialize, Serialize}; use std::{ - collections::HashMap, + collections::hash_map::{Entry, HashMap}, ops::{Deref, DerefMut}, sync::{Arc, Mutex, RwLock}, + time::Instant, }; use wgpu::util::DeviceExt; @@ -51,11 +52,20 @@ struct MeshgenInfo { type MeshQueue = HashMap, MeshData>; +// to avoid excessive block mesh rebuilds, only build a mesh once all 6 neighbors are present +// or a timeout of 100ms has elapsed +struct DeferredBlock { + count: u8, + mask: [bool; 6], + time: Instant, +} + pub struct MapRender { pipeline: wgpu::RenderPipeline, atlas: wgpu::BindGroup, model: wgpu::BindGroupLayout, blocks: Arc, Arc>>>, + blocks_defer: HashMap, DeferredBlock>, block_models: HashMap, BlockModel>, meshgen_info: Arc, meshgen_threads: Vec>, @@ -145,7 +155,7 @@ impl MapRender { continue; } - let fpos = block_float_pos(Point3::from(pos)); + let fpos = block_float_pos(pos); let one = Vector3::new(1.0, 1.0, 1.0); let aabb = Aabb3::new(fpos - one * 0.5, fpos + one * 15.5).transform(&state.view); @@ -182,13 +192,21 @@ impl MapRender { } pub fn update(&mut self, state: &mut State) { + for (pos, _) in self + .blocks_defer + .drain_filter(|_, v| v.time.elapsed().as_millis() > 100) + { + self.meshgen_channel.send(pos).ok(); + } + std::mem::swap( self.queue_produce.lock().unwrap().deref_mut(), &mut self.queue_consume, ); + for (pos, data) in self.queue_consume.drain() { self.block_models.insert( - pos.into(), + pos, BlockModel { mesh: BlockMesh::new(state, &data.vertices), mesh_blend: BlockMesh::new(state, &data.vertices_blend), @@ -204,15 +222,58 @@ impl MapRender { } } - // TODO: move this to a map thread - pub fn add_block(&self, pos: Point3, block: Box) { + pub fn add_block(&mut self, pos: Point3, block: Box) { self.blocks.write().unwrap().insert(pos, Arc::new(*block)); - self.meshgen_channel.send(pos).ok(); + let blocks = self.blocks.read().unwrap(); + + let mut count = 6; + let mut mask = [false; 6]; + + for (f, off) in FACE_DIR.iter().enumerate() { + let npos = pos + Vector3::from(*off); + + if let Entry::Occupied(mut nbor) = self.blocks_defer.entry(npos) { + let inner = nbor.get_mut(); + + let rf = f ^ 1; + + if !inner.mask[rf] { + inner.mask[rf] = true; + inner.count -= 1; - // TODO: make this smarter (less rebuilds pls) - for off in FACE_DIR { - self.meshgen_channel.send(pos + Vector3::from(off)).ok(); + if inner.count == 0 { + self.meshgen_channel.send(npos).ok(); + nbor.remove(); + } + } + } else if blocks.get(&npos).is_some() { + self.meshgen_channel.send(npos).ok(); + } else { + continue; + } + + mask[f] = true; + count -= 1; + } + + if count == 0 { + self.meshgen_channel.send(pos).ok(); + } else { + match self.blocks_defer.entry(pos) { + Entry::Occupied(mut x) => { + let x = x.get_mut(); + x.mask = mask; + x.count = count; + } + Entry::Vacant(x) => { + x.insert(DeferredBlock { + mask, + count, + time: Instant::now(), + }); + } + } } } @@ -429,6 +490,7 @@ impl MapRender { atlas: atlas_bind_group, model: model_bind_group_layout, blocks, + blocks_defer: HashMap::new(), block_models: HashMap::new(), meshgen_info, meshgen_threads, -- cgit v1.2.3