diff --git a/lib/common/src/bvh.rs b/lib/common/src/bvh.rs index 66d0b2e..05b7cf3 100644 --- a/lib/common/src/bvh.rs +++ b/lib/common/src/bvh.rs @@ -31,11 +31,6 @@ impl<T> Default for BvhNode<T>{ } } } -pub struct BvhWeightNode<W,T>{ - content:RecursiveContent<BvhWeightNode<W,T>,T>, - weight:W, - aabb:Aabb, -} impl<T> BvhNode<T>{ pub fn the_tester<F:FnMut(&T)>(&self,aabb:&Aabb,f:&mut F){ @@ -52,44 +47,8 @@ impl<T> BvhNode<T>{ }, } } - pub fn into_visitor<F:FnMut(T)>(self,f:&mut F){ - match self.content{ - RecursiveContent::Leaf(model)=>f(model), - RecursiveContent::Branch(children)=>for child in children{ - child.into_visitor(f) - }, - } - } - pub fn weigh_contents<W:Copy+std::iter::Sum<W>,F:Fn(&T)->W>(self,f:&F)->BvhWeightNode<W,T>{ - match self.content{ - RecursiveContent::Leaf(model)=>BvhWeightNode{ - weight:f(&model), - content:RecursiveContent::Leaf(model), - aabb:self.aabb, - }, - RecursiveContent::Branch(children)=>{ - let branch:Vec<BvhWeightNode<W,T>>=children.into_iter().map(|child| - child.weigh_contents(f) - ).collect(); - BvhWeightNode{ - weight:branch.iter().map(|node|node.weight).sum(), - content:RecursiveContent::Branch(branch), - aabb:self.aabb, - } - }, - } - } -} - -impl <W,T> BvhWeightNode<W,T>{ - pub const fn weight(&self)->&W{ - &self.weight - } - pub const fn aabb(&self)->&Aabb{ - &self.aabb - } - pub fn into_content(self)->RecursiveContent<BvhWeightNode<W,T>,T>{ - self.content + pub fn into_inner(self)->(RecursiveContent<BvhNode<T>,T>,Aabb){ + (self.content,self.aabb) } pub fn into_visitor<F:FnMut(T)>(self,f:&mut F){ match self.content{ diff --git a/lib/snf/src/map.rs b/lib/snf/src/map.rs index c822795..0d91209 100644 --- a/lib/snf/src/map.rs +++ b/lib/snf/src/map.rs @@ -6,7 +6,7 @@ use crate::file::BlockId; use binrw::{binrw,BinReaderExt,BinWriterExt}; use strafesnet_common::model; use strafesnet_common::aabb::Aabb; -use strafesnet_common::bvh::BvhNode; +use strafesnet_common::bvh::{BvhNode,RecursiveContent}; use strafesnet_common::gameplay_modes; #[derive(Debug)] @@ -287,12 +287,60 @@ impl<R:BinReaderExt> StreamableMap<R>{ } } +// silly redefinition of Bvh for determining the size of subnodes +// without duplicating work by running weight calculation recursion top down on every node +pub struct BvhWeightNode<W,T>{ + content:RecursiveContent<BvhWeightNode<W,T>,T>, + weight:W, + aabb:Aabb, +} +impl <W,T> BvhWeightNode<W,T>{ + pub const fn weight(&self)->&W{ + &self.weight + } + pub const fn aabb(&self)->&Aabb{ + &self.aabb + } + pub fn into_content(self)->RecursiveContent<BvhWeightNode<W,T>,T>{ + self.content + } + pub fn into_visitor<F:FnMut(T)>(self,f:&mut F){ + match self.content{ + RecursiveContent::Leaf(model)=>f(model), + RecursiveContent::Branch(children)=>for child in children{ + child.into_visitor(f) + }, + } + } +} + +pub fn weigh_contents<T,W:Copy+std::iter::Sum<W>,F:Fn(&T)->W>(node:BvhNode<T>,f:&F)->BvhWeightNode<W,T>{ + let (content,aabb)=node.into_inner(); + match content{ + RecursiveContent::Leaf(model)=>BvhWeightNode{ + weight:f(&model), + content:RecursiveContent::Leaf(model), + aabb, + }, + RecursiveContent::Branch(children)=>{ + let branch:Vec<BvhWeightNode<W,T>>=children.into_iter().map(|child| + weigh_contents(child,f) + ).collect(); + BvhWeightNode{ + weight:branch.iter().map(|node|node.weight).sum(), + content:RecursiveContent::Branch(branch), + aabb, + } + }, + } +} + const BVH_NODE_MAX_WEIGHT:usize=64*1024;//64 kB fn collect_spacial_blocks( block_location:&mut Vec<u64>, block_headers:&mut Vec<SpacialBlockHeader>, sequential_block_data:&mut std::io::Cursor<&mut Vec<u8>>, - bvh_node:strafesnet_common::bvh::BvhWeightNode<usize,(model::ModelId,newtypes::model::Model)> + bvh_node:BvhWeightNode<usize,(model::ModelId,newtypes::model::Model)> )->Result<(),Error>{ //inspect the node weights top-down. //When a node weighs less than the limit, @@ -342,7 +390,7 @@ pub fn write_map<W:BinWriterExt>(mut writer:W,map:strafesnet_common::map::Comple } Ok(((model::ModelId::new(model_id as u32),model.into()),aabb)) }).collect::<Result<Vec<_>,_>>()?; - let bvh=strafesnet_common::bvh::generate_bvh(boxen).weigh_contents(&|_|std::mem::size_of::<newtypes::model::Model>()); + let bvh=weigh_contents(strafesnet_common::bvh::generate_bvh(boxen),&|_|std::mem::size_of::<newtypes::model::Model>()); //build blocks //block location is initialized with two values //the first value represents the location of the first byte after the file header