write map
This commit is contained in:
parent
4abeefa7e8
commit
e1cdddc892
137
src/map.rs
137
src/map.rs
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use crate::newtypes;
|
use crate::newtypes;
|
||||||
use crate::file::BlockId;
|
use crate::file::BlockId;
|
||||||
use binrw::{binrw,BinReaderExt};
|
use binrw::{binrw,BinReaderExt,BinWriterExt};
|
||||||
use strafesnet_common::model;
|
use strafesnet_common::model;
|
||||||
use strafesnet_common::aabb::Aabb;
|
use strafesnet_common::aabb::Aabb;
|
||||||
use strafesnet_common::bvh::BvhNode;
|
use strafesnet_common::bvh::BvhNode;
|
||||||
@ -135,15 +135,12 @@ struct ResourceExternalHeader{
|
|||||||
#[binrw]
|
#[binrw]
|
||||||
#[brw(little)]
|
#[brw(little)]
|
||||||
struct MapHeader{
|
struct MapHeader{
|
||||||
num_nodes:u32,
|
|
||||||
num_spacial_blocks:u32,
|
num_spacial_blocks:u32,
|
||||||
num_resource_blocks:u32,
|
num_resource_blocks:u32,
|
||||||
num_resources_external:u32,
|
num_resources_external:u32,
|
||||||
num_modes:u32,
|
num_modes:u32,
|
||||||
num_attributes:u32,
|
num_attributes:u32,
|
||||||
num_render_configs:u32,
|
num_render_configs:u32,
|
||||||
#[br(count=num_nodes)]
|
|
||||||
nodes:Vec<u32>,
|
|
||||||
#[br(count=num_spacial_blocks)]
|
#[br(count=num_spacial_blocks)]
|
||||||
spacial_blocks:Vec<SpacialBlockHeader>,
|
spacial_blocks:Vec<SpacialBlockHeader>,
|
||||||
#[br(count=num_resource_blocks)]
|
#[br(count=num_resource_blocks)]
|
||||||
@ -244,7 +241,7 @@ impl<R:BinReaderExt> StreamableMap<R>{
|
|||||||
}
|
}
|
||||||
pub fn get_intersecting_region_block_ids(&self,aabb:&Aabb)->Vec<BlockId>{
|
pub fn get_intersecting_region_block_ids(&self,aabb:&Aabb)->Vec<BlockId>{
|
||||||
let mut block_ids=Vec::new();
|
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
|
block_ids
|
||||||
}
|
}
|
||||||
pub fn load_region(&mut self,block_id:BlockId)->Result<Vec<model::Model>,Error>{
|
pub fn load_region(&mut self,block_id:BlockId)->Result<Vec<model::Model>,Error>{
|
||||||
@ -284,3 +281,133 @@ impl<R:BinReaderExt> StreamableMap<R>{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,newtypes::model::Model>
|
||||||
|
)->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()<BVH_NODE_MAX_WEIGHT{
|
||||||
|
let mut models=Vec::new();
|
||||||
|
let mut model_count=0;
|
||||||
|
let extents=bvh_node.aabb().clone().into();
|
||||||
|
bvh_node.into_visitor(&mut |model|{
|
||||||
|
model_count+=1;
|
||||||
|
models.push(model);
|
||||||
|
});
|
||||||
|
let id=BlockId::new(block_headers.len() as u32);
|
||||||
|
block_headers.push(SpacialBlockHeader{
|
||||||
|
id,
|
||||||
|
extents,
|
||||||
|
});
|
||||||
|
let region=Region{
|
||||||
|
model_count,
|
||||||
|
models,
|
||||||
|
};
|
||||||
|
binrw::BinWrite::write_le(®ion,sequential_block_data).map_err(Error::InvalidData)?;
|
||||||
|
block_location.push(sequential_block_data.position());
|
||||||
|
}else{
|
||||||
|
match bvh_node.into_content(){
|
||||||
|
strafesnet_common::bvh::RecursiveContent::Branch(bvh_node_list)=>{
|
||||||
|
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<W:BinWriterExt>(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::<Result<Vec<_>,_>>()?;
|
||||||
|
let bvh=strafesnet_common::bvh::generate_bvh(boxen).weigh_contents(&|_|std::mem::size_of::<newtypes::model::Model>());
|
||||||
|
//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(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user