From e1cdddc89285cbe170057ab495f1ecb4ab4c97c9 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 25 Jul 2024 15:35:54 -0700 Subject: [PATCH] write map --- src/map.rs | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 5 deletions(-) diff --git a/src/map.rs b/src/map.rs index ffea77b..12fd577 100644 --- a/src/map.rs +++ b/src/map.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use crate::newtypes; use crate::file::BlockId; -use binrw::{binrw,BinReaderExt}; +use binrw::{binrw,BinReaderExt,BinWriterExt}; use strafesnet_common::model; use strafesnet_common::aabb::Aabb; use strafesnet_common::bvh::BvhNode; @@ -135,15 +135,12 @@ struct ResourceExternalHeader{ #[binrw] #[brw(little)] struct MapHeader{ - num_nodes:u32, num_spacial_blocks:u32, num_resource_blocks:u32, num_resources_external:u32, num_modes:u32, num_attributes:u32, num_render_configs:u32, - #[br(count=num_nodes)] - nodes:Vec, #[br(count=num_spacial_blocks)] spacial_blocks:Vec, #[br(count=num_resource_blocks)] @@ -244,7 +241,7 @@ impl StreamableMap{ } pub fn get_intersecting_region_block_ids(&self,aabb:&Aabb)->Vec{ let mut block_ids=Vec::new(); - self.bvh.the_tester(aabb,&mut |block_id|block_ids.push(block_id)); + self.bvh.the_tester(aabb,&mut |&block_id|block_ids.push(block_id)); block_ids } pub fn load_region(&mut self,block_id:BlockId)->Result,Error>{ @@ -284,3 +281,133 @@ impl StreamableMap{ }) } } + +const BVH_NODE_MAX_WEIGHT:usize=64*1024;//64 kB +fn collect_spacial_blocks( + block_location:&mut Vec, + block_headers:&mut Vec, + sequential_block_data:&mut std::io::Cursor<&mut Vec>, + bvh_node:strafesnet_common::bvh::BvhWeightNode +)->Result<(),Error>{ + //inspect the node weights top-down. + //When a node weighs less than the limit, + //serialize its entire contents into a region block + if *bvh_node.weight(){ + for bvh_node in bvh_node_list{ + collect_spacial_blocks(block_location,block_headers,sequential_block_data,bvh_node)?; + } + }, + strafesnet_common::bvh::RecursiveContent::Leaf(_)=>panic!(),//bvh branches are 20 leaves minimum + } + } + Ok(()) +} + +/// TODO: Optionally provide a bot that describes the path through the map +/// otherwise sort by distance to start zone +pub fn write_map(mut writer:W,map:strafesnet_common::map::CompleteMap)->Result<(),Error>{ + //serialize models and make a bvh that knows the file size of the branch + let boxen=map.models.into_iter().map(|model|{ + //grow your own aabb + let mesh=map.meshes.get(model.mesh.get() as usize).ok_or(Error::InvalidMeshId(model.mesh))?; + let mut aabb=strafesnet_common::aabb::Aabb::default(); + for &pos in &mesh.unique_pos{ + aabb.grow(model.transform.transform_point3(pos)); + } + Ok((model.into(),aabb)) + }).collect::,_>>()?; + let bvh=strafesnet_common::bvh::generate_bvh(boxen).weigh_contents(&|_|std::mem::size_of::()); + //build blocks + let mut block_location=vec![0];//for file header + let mut spacial_blocks=Vec::new();//for map header + let mut sequential_block_data=Vec::new(); + let mut cursor_to_data=std::io::Cursor::new(&mut sequential_block_data); + collect_spacial_blocks(&mut block_location,&mut spacial_blocks,&mut cursor_to_data,bvh)?; + let mut block_count=spacial_blocks.len() as u32;//continue block id + let mut resource_blocks=Vec::new();//for map header + //meshes + for mesh in map.meshes.into_iter(){ + resource_blocks.push(ResourceBlockHeader{ + resource:ResourceType::Mesh, + id:BlockId::new(block_count), + }); + block_count+=1; + let serializable_mesh:newtypes::model::Mesh=mesh.into(); + binrw::BinWrite::write_le(&serializable_mesh,&mut cursor_to_data).map_err(Error::InvalidData)?; + block_location.push(cursor_to_data.position()); + } + //textures + for mut texture in map.textures.into_iter(){ + resource_blocks.push(ResourceBlockHeader{ + resource:ResourceType::Texture, + id:BlockId::new(block_count), + }); + block_count+=1; + sequential_block_data.append(&mut texture); + block_location.push(sequential_block_data.len() as u64); + } + //build header + let map_header=MapHeader{ + num_spacial_blocks:spacial_blocks.len() as u32, + num_resource_blocks:resource_blocks.len() as u32, + num_resources_external:0, + num_modes:map.modes.modes.len() as u32, + num_attributes:map.attributes.len() as u32, + num_render_configs:map.render_configs.len() as u32, + spacial_blocks, + resource_blocks, + external_resources:Vec::new(), + modes:map.modes.modes.into_iter().map(Into::into).collect(), + attributes:map.attributes.into_iter().map(Into::into).collect(), + render_configs:map.render_configs.into_iter().map(Into::into).collect(), + }; + let mut file_header=crate::file::Header{ + fourcc:crate::file::FourCC::Map, + version:0, + priming:0,//TODO + resource:0, + block_count, + block_location, + }; + //probe header lengths + let mut file_header_data=Vec::new(); + binrw::BinWrite::write_le(&file_header,&mut std::io::Cursor::new(&mut file_header_data)).map_err(Error::InvalidData)?; + let mut map_header_data=Vec::new(); + binrw::BinWrite::write_le(&map_header,&mut std::io::Cursor::new(&mut map_header_data)).map_err(Error::InvalidData)?; + + //update file header according to probe data + let offset=file_header_data.len() as u64+map_header_data.len() as u64; + file_header.priming=offset; + for position in &mut file_header.block_location{ + *position+=offset; + } + + //write file header + writer.write_le(&file_header).map_err(Error::InvalidData)?; + //write map header + writer.write(&map_header_data).map_err(Error::IO)?; + //write blocks + writer.write(&sequential_block_data).map_err(Error::IO)?; + Ok(()) +}