strafe-project/src/load_bsp.rs

223 lines
8.2 KiB
Rust
Raw Normal View History

2024-01-08 18:29:57 -08:00
const VALVE_SCALE:f32=1.0/16.0;
fn valve_transform(v:[f32;3])->crate::integer::Planar64Vec3{
crate::integer::Planar64Vec3::try_from([v[0]*VALVE_SCALE,v[2]*VALVE_SCALE,v[1]*VALVE_SCALE]).unwrap()
}
2024-01-08 17:31:51 -08:00
pub fn generate_indexed_models<R:std::io::Read+std::io::Seek>(input:&mut R)->Result<crate::model::IndexedModelInstances,vbsp::BspError>{
2023-10-09 21:37:07 -07:00
let mut s=Vec::new();
match input.read_to_end(&mut s){
2024-01-08 17:31:51 -08:00
Ok(_)=>(),
Err(e)=>println!("load_bsp::generate_indexed_models read_to_end failed: {:?}",e),
2023-10-09 21:37:07 -07:00
}
match vbsp::Bsp::read(s.as_slice()){
2024-01-08 17:31:51 -08:00
Ok(bsp)=>{
let mut spawn_point=crate::integer::Planar64Vec3::ZERO;
2023-10-02 15:28:57 -07:00
2024-01-08 18:06:18 -08:00
let vertices: Vec<_> = bsp
.vertices
.iter()
.map(|vertex|<[f32;3]>::from(vertex.position))
2024-01-08 18:06:18 -08:00
.collect();
2024-01-08 20:53:59 -08:00
let mut name_from_texture_id=Vec::new();
let mut texture_id_from_name=std::collections::HashMap::new();
2024-01-08 18:06:18 -08:00
2024-01-09 14:11:15 -08:00
let mut models=bsp.models().map(|world_model|{
//non-deduplicated
let mut spam_pos=Vec::new();
let mut spam_tex=Vec::new();
2024-01-08 19:54:29 -08:00
let mut spam_normal=Vec::new();
let mut spam_vertices=Vec::new();
let groups=world_model.faces()
.filter(|face| face.is_visible())//TODO: look at this
.map(|face|{
let face_texture=face.texture();
let face_texture_data=face_texture.texture_data();
let (texture_u,texture_v)=(glam::Vec3A::from_slice(&face_texture.texture_transforms_u[0..3]),glam::Vec3A::from_slice(&face_texture.texture_transforms_v[0..3]));
let texture_offset=glam::vec2(face_texture.texture_transforms_u[3],face_texture.texture_transforms_v[3]);
let texture_size=glam::vec2(face_texture_data.width as f32,face_texture_data.height as f32);
2024-01-08 19:54:29 -08:00
2024-01-08 20:53:59 -08:00
//texture
let texture_id=if let Some(&texture_id)=texture_id_from_name.get(face_texture_data.name()){
texture_id
}else{
let texture_id=name_from_texture_id.len() as u32;
2024-01-09 16:48:55 -08:00
texture_id_from_name.insert(face_texture_data.name().to_string(),texture_id);
2024-01-08 20:53:59 -08:00
name_from_texture_id.push(face_texture_data.name().to_string());
texture_id
};
2024-01-08 19:54:29 -08:00
//normal
let normal=face.normal();
let normal_idx=spam_normal.len() as u32;
spam_normal.push(valve_transform(<[f32;3]>::from(normal)));
crate::model::IndexedGroup{
2024-01-08 20:53:59 -08:00
texture:Some(texture_id),
polys:vec![crate::model::IndexedPolygon{vertices:face.vertex_indexes().map(|vertex_index|{
let pos=glam::Vec3A::from_array(vertices[vertex_index as usize]);
let pos_idx=spam_pos.len();
spam_pos.push(valve_transform(vertices[vertex_index as usize]));
//calculate texture coordinates
let tex=(glam::vec2(pos.dot(texture_u),pos.dot(texture_v))+texture_offset)/texture_size;
let tex_idx=spam_tex.len() as u32;
spam_tex.push(tex);
let i=spam_vertices.len() as u32;
spam_vertices.push(crate::model::IndexedVertex{
pos: pos_idx as u32,
tex: tex_idx as u32,
2024-01-08 19:54:29 -08:00
normal: normal_idx,
color: 0,
});
i
}).collect()}],
}
}).collect();
crate::model::IndexedModel{
2024-01-08 20:53:45 -08:00
unique_pos:spam_pos,
unique_tex:spam_tex,
2024-01-08 19:54:29 -08:00
unique_normal:spam_normal,
unique_color:vec![glam::Vec4::ONE],
unique_vertices:spam_vertices,
groups,
instances:vec![crate::model::ModelInstance{
attributes:crate::model::CollisionAttributes::Decoration,
2024-01-09 14:10:43 -08:00
transform:crate::integer::Planar64Affine3::new(
crate::integer::Planar64Mat3::default(),
valve_transform(<[f32;3]>::from(world_model.origin))
),
..Default::default()
2024-01-08 18:06:18 -08:00
}],
2024-01-08 18:29:57 -08:00
}
}).collect();
2024-01-08 18:06:18 -08:00
2024-01-09 14:11:15 -08:00
//dedupe prop models
let mut model_dedupe=std::collections::HashSet::new();
for prop in bsp.static_props(){
model_dedupe.insert(prop.model());
}
//generate unique meshes
let mut model_map=std::collections::HashMap::with_capacity(model_dedupe.len());
let mut prop_models=Vec::new();
for model_name in model_dedupe{
//.mdl, .vvd, .dx90.vtx
let mut path=std::path::PathBuf::from(model_name);
let file_name=std::path::PathBuf::from(path.file_stem().unwrap());
path.pop();
path.push(file_name);
let mut vvd_path=path.clone();
let mut vtx_path=path.clone();
vvd_path.set_extension("vvd");
vtx_path.set_extension("dx90.vtx");
match (bsp.pack.get(model_name),bsp.pack.get(vvd_path.as_os_str().to_str().unwrap()),bsp.pack.get(vtx_path.as_os_str().to_str().unwrap())){
(Ok(Some(mdl_file)),Ok(Some(vvd_file)),Ok(Some(vtx_file)))=>{
match (vmdl::mdl::Mdl::read(mdl_file.as_ref()),vmdl::vvd::Vvd::read(vvd_file.as_ref()),vmdl::vtx::Vtx::read(vtx_file.as_ref())){
(Ok(mdl),Ok(vvd),Ok(vtx))=>{
let model=vmdl::Model::from_parts(mdl,vtx,vvd);
2024-01-09 16:48:55 -08:00
let skin=model.skin_tables().nth(0).unwrap();
2024-01-09 14:11:15 -08:00
let mut spam_pos=Vec::with_capacity(model.vertices().len());
let mut spam_normal=Vec::with_capacity(model.vertices().len());
let mut spam_tex=Vec::with_capacity(model.vertices().len());
let mut spam_vertices=Vec::with_capacity(model.vertices().len());
for (i,vertex) in model.vertices().iter().enumerate(){
spam_pos.push(valve_transform(<[f32;3]>::from(vertex.position)));
spam_normal.push(valve_transform(<[f32;3]>::from(vertex.normal)));
spam_tex.push(glam::Vec2::from_array(vertex.texture_coordinates));
spam_vertices.push(crate::model::IndexedVertex{
pos:i as u32,
tex:i as u32,
normal:i as u32,
color:0,
});
}
let model_id=prop_models.len();
model_map.insert(model_name,model_id);
prop_models.push(crate::model::IndexedModel{
unique_pos:spam_pos,
unique_normal:spam_normal,
unique_tex:spam_tex,
unique_color:vec![glam::Vec4::ONE],
unique_vertices:spam_vertices,
groups:model.meshes().map(|mesh|{
2024-01-09 16:48:55 -08:00
let texture=match skin.texture(mesh.material_index()){
Some(texture_name)=>Some(if let Some(&texture_id)=texture_id_from_name.get(texture_name){
texture_id
}else{
//println!("texture! {}",texture_name);
let texture_id=name_from_texture_id.len() as u32;
texture_id_from_name.insert(texture_name.to_string(),texture_id);
name_from_texture_id.push(texture_name.to_string());
texture_id
}),
None=>None,
};
2024-01-09 14:11:15 -08:00
crate::model::IndexedGroup{
2024-01-09 16:48:55 -08:00
texture,
2024-01-09 16:49:29 -08:00
polys:{
//looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function
mesh.vertex_strip_indices().map(|strip|{
strip.collect::<Vec<usize>>().chunks(3).map(|tri|{
//tris are ccw, probably because of the quaternion
crate::model::IndexedPolygon{vertices:vec![tri[1] as u32,tri[0] as u32,tri[2] as u32]}
}).collect::<Vec<crate::model::IndexedPolygon>>()
}).flatten().collect()
},
2024-01-09 14:11:15 -08:00
}
}).collect(),
instances:Vec::new(),
});
},
_=>print!("model_name={} error",model_name),
}
},
_=>print!("no model name={}",model_name),
}
}
//generate model instances
for prop in bsp.static_props(){
let placement=prop.as_prop_placement();
2024-01-09 16:49:08 -08:00
if let Some(&model_index)=model_map.get(placement.model){
prop_models[model_index].instances.push(crate::model::ModelInstance{
transform:crate::integer::Planar64Affine3::new(
crate::integer::Planar64Mat3::try_from(
glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale))
*glam::Mat3A::from_quat(
//TODO: does rotation need valve transform?
glam::Quat::from_xyzw(placement.rotation.v.x,placement.rotation.v.y,placement.rotation.v.z,placement.rotation.s),
)
).unwrap(),
valve_transform(<[f32;3]>::from(placement.origin)),
),
attributes:crate::model::CollisionAttributes::Decoration,
..Default::default()
});
}else{
println!("model not found {}",placement.model);
}
2024-01-09 14:11:15 -08:00
}
//actually add the prop models
prop_models.append(&mut models);
2024-01-08 17:31:51 -08:00
Ok(crate::model::IndexedModelInstances{
2024-01-08 20:53:59 -08:00
textures:name_from_texture_id,
2024-01-09 14:11:15 -08:00
models:prop_models,
2024-01-08 17:31:51 -08:00
spawn_point,
modes:Vec::new(),
})
},
Err(e)=>{
println!("rotten {:?}",e);
Err(e)
},
2023-10-02 15:28:57 -07:00
}
}