summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gfx.rs2
-rw-r--r--src/gfx/map.rs80
-rw-r--r--src/main.rs2
3 files changed, 74 insertions, 10 deletions
diff --git a/src/gfx.rs b/src/gfx.rs
index f765a9b..ce7ae2e 100644
--- a/src/gfx.rs
+++ b/src/gfx.rs
@@ -122,7 +122,7 @@ pub async fn run(
Close => *flow = ExitWithCode(0),
NodeDefs(defs) => nodedefs = Some(defs),
MapBlock(pos, blk) => {
- if let Some(map) = &map {
+ if let Some(map) = &mut map {
map.add_block(pos, blk);
}
}
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<Point3<i16>, 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<RwLock<HashMap<Point3<i16>, Arc<MapBlock>>>>,
+ blocks_defer: HashMap<Point3<i16>, DeferredBlock>,
block_models: HashMap<Point3<i16>, BlockModel>,
meshgen_info: Arc<MeshgenInfo>,
meshgen_threads: Vec<std::thread::JoinHandle<()>>,
@@ -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<i16>, block: Box<MapBlock>) {
+ pub fn add_block(&mut self, pos: Point3<i16>, block: Box<MapBlock>) {
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,
diff --git a/src/main.rs b/src/main.rs
index 04e8a91..759a5bf 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,5 @@
+#![feature(hash_drain_filter)]
+
mod gfx;
mod net;