impl deferred_loader::Loader for bsp_loader
This commit is contained in:
parent
a594f77453
commit
85480cb13e
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2329,6 +2329,7 @@ version = "0.2.2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"glam",
|
"glam",
|
||||||
"strafesnet_common",
|
"strafesnet_common",
|
||||||
|
"strafesnet_deferred_loader",
|
||||||
"vbsp",
|
"vbsp",
|
||||||
"vmdl",
|
"vmdl",
|
||||||
]
|
]
|
||||||
|
@ -12,5 +12,6 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
glam = "0.29.0"
|
glam = "0.29.0"
|
||||||
strafesnet_common = { path = "../common", registry = "strafesnet" }
|
strafesnet_common = { path = "../common", registry = "strafesnet" }
|
||||||
|
strafesnet_deferred_loader = { version = "0.5.0", path = "../deferred_loader" }
|
||||||
vbsp = "0.6.0"
|
vbsp = "0.6.0"
|
||||||
vmdl = "0.2.0"
|
vmdl = "0.2.0"
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
use strafesnet_common::{map,model,integer,gameplay_attributes};
|
use std::borrow::Cow;
|
||||||
|
|
||||||
const VALVE_SCALE:f32=1.0/16.0;
|
use strafesnet_common::{map,model,integer,gameplay_attributes};
|
||||||
fn valve_transform([x,y,z]:[f32;3])->integer::Planar64Vec3{
|
use strafesnet_deferred_loader::deferred_loader::{MeshDeferredLoader,RenderConfigDeferredLoader};
|
||||||
integer::vec3::try_from_f32_array([x*VALVE_SCALE,z*VALVE_SCALE,-y*VALVE_SCALE]).unwrap()
|
use strafesnet_deferred_loader::mesh::Meshes;
|
||||||
}
|
use strafesnet_deferred_loader::texture::{RenderConfigs,Texture};
|
||||||
pub fn convert_bsp<AcquireRenderConfigId,AcquireMeshId>(
|
|
||||||
bsp:&vbsp::Bsp,
|
use crate::valve_transform;
|
||||||
mut acquire_render_config_id:AcquireRenderConfigId,
|
|
||||||
mut acquire_mesh_id:AcquireMeshId
|
pub fn convert<'a>(
|
||||||
)->PartialMap1
|
bsp:&'a crate::Bsp,
|
||||||
where
|
render_config_deferred_loader:&mut RenderConfigDeferredLoader<Cow<'a,str>>,
|
||||||
AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId,
|
mesh_deferred_loader:&mut MeshDeferredLoader<&'a str>,
|
||||||
AcquireMeshId:FnMut(&str)->model::MeshId,
|
)->PartialMap1{
|
||||||
{
|
let bsp=bsp.as_ref();
|
||||||
//figure out real attributes later
|
//figure out real attributes later
|
||||||
let mut unique_attributes=Vec::new();
|
let mut unique_attributes=Vec::new();
|
||||||
unique_attributes.push(gameplay_attributes::CollisionAttributes::Decoration);
|
unique_attributes.push(gameplay_attributes::CollisionAttributes::Decoration);
|
||||||
@ -22,7 +22,7 @@ where
|
|||||||
//declare all prop models to Loader
|
//declare all prop models to Loader
|
||||||
let prop_models=bsp.static_props().map(|prop|{
|
let prop_models=bsp.static_props().map(|prop|{
|
||||||
//get or create mesh_id
|
//get or create mesh_id
|
||||||
let mesh_id=acquire_mesh_id(prop.model());
|
let mesh_id=mesh_deferred_loader.acquire_mesh_id(prop.model());
|
||||||
//not the most failsafe code but this is just for the map tool lmao
|
//not the most failsafe code but this is just for the map tool lmao
|
||||||
if prop_mesh_count==mesh_id.get(){
|
if prop_mesh_count==mesh_id.get(){
|
||||||
prop_mesh_count+=1;
|
prop_mesh_count+=1;
|
||||||
@ -65,7 +65,7 @@ where
|
|||||||
|
|
||||||
//this automatically figures out what the texture is trying to do and creates
|
//this automatically figures out what the texture is trying to do and creates
|
||||||
//a render config for it, and then returns the id to that render config
|
//a render config for it, and then returns the id to that render config
|
||||||
let render_id=acquire_render_config_id(Some(face_texture_data.name()));
|
let render_id=render_config_deferred_loader.acquire_render_config_id(Some(Cow::Borrowed(face_texture_data.name())));
|
||||||
|
|
||||||
//normal
|
//normal
|
||||||
let normal=face.normal();
|
let normal=face.normal();
|
||||||
@ -176,26 +176,13 @@ pub struct PartialMap1{
|
|||||||
modes:strafesnet_common::gameplay_modes::Modes,
|
modes:strafesnet_common::gameplay_modes::Modes,
|
||||||
}
|
}
|
||||||
impl PartialMap1{
|
impl PartialMap1{
|
||||||
pub fn add_prop_meshes<AcquireRenderConfigId>(
|
pub fn add_prop_meshes<'a>(
|
||||||
self,
|
self,
|
||||||
prop_meshes:impl IntoIterator<Item=(model::MeshId,crate::data::ModelData)>,
|
prop_meshes:Meshes,
|
||||||
mut acquire_render_config_id:AcquireRenderConfigId,
|
)->PartialMap2{
|
||||||
)->PartialMap2
|
|
||||||
where
|
|
||||||
AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId,
|
|
||||||
{
|
|
||||||
PartialMap2{
|
PartialMap2{
|
||||||
attributes:self.attributes,
|
attributes:self.attributes,
|
||||||
prop_meshes:prop_meshes.into_iter().filter_map(|(mesh_id,model_data)|
|
prop_meshes:prop_meshes.consume().collect(),
|
||||||
//this will generate new render ids and texture ids
|
|
||||||
match convert_mesh(model_data,&mut acquire_render_config_id){
|
|
||||||
Ok(mesh)=>Some((mesh_id,mesh)),
|
|
||||||
Err(e)=>{
|
|
||||||
println!("error converting mesh: {e}");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).collect(),
|
|
||||||
prop_models:self.prop_models,
|
prop_models:self.prop_models,
|
||||||
world_meshes:self.world_meshes,
|
world_meshes:self.world_meshes,
|
||||||
world_models:self.world_models,
|
world_models:self.world_models,
|
||||||
@ -214,8 +201,7 @@ pub struct PartialMap2{
|
|||||||
impl PartialMap2{
|
impl PartialMap2{
|
||||||
pub fn add_render_configs_and_textures(
|
pub fn add_render_configs_and_textures(
|
||||||
mut self,
|
mut self,
|
||||||
render_configs:impl IntoIterator<Item=(model::RenderConfigId,model::RenderConfig)>,
|
render_configs:RenderConfigs,
|
||||||
textures:impl IntoIterator<Item=(model::TextureId,Vec<u8>)>,
|
|
||||||
)->map::CompleteMap{
|
)->map::CompleteMap{
|
||||||
//merge mesh and model lists, flatten and remap all ids
|
//merge mesh and model lists, flatten and remap all ids
|
||||||
let mesh_id_offset=self.world_meshes.len();
|
let mesh_id_offset=self.world_meshes.len();
|
||||||
@ -234,10 +220,11 @@ impl PartialMap2{
|
|||||||
})
|
})
|
||||||
));
|
));
|
||||||
//let mut models=Vec::new();
|
//let mut models=Vec::new();
|
||||||
|
let (textures,render_configs)=render_configs.consume();
|
||||||
let (textures,texture_id_map):(Vec<Vec<u8>>,std::collections::HashMap<model::TextureId,model::TextureId>)
|
let (textures,texture_id_map):(Vec<Vec<u8>>,std::collections::HashMap<model::TextureId,model::TextureId>)
|
||||||
=textures.into_iter()
|
=textures.into_iter()
|
||||||
//.filter_map(f) cull unused textures
|
//.filter_map(f) cull unused textures
|
||||||
.enumerate().map(|(new_texture_id,(old_texture_id,texture))|{
|
.enumerate().map(|(new_texture_id,(old_texture_id,Texture::ImageDDS(texture)))|{
|
||||||
(texture,(old_texture_id,model::TextureId::new(new_texture_id as u32)))
|
(texture,(old_texture_id,model::TextureId::new(new_texture_id as u32)))
|
||||||
}).unzip();
|
}).unzip();
|
||||||
let render_configs=render_configs.into_iter().map(|(_render_config_id,mut render_config)|{
|
let render_configs=render_configs.into_iter().map(|(_render_config_id,mut render_config)|{
|
||||||
@ -257,77 +244,3 @@ impl PartialMap2{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_mesh<AcquireRenderConfigId>(
|
|
||||||
model_data:crate::data::ModelData,
|
|
||||||
acquire_render_config_id:&mut AcquireRenderConfigId,
|
|
||||||
)->Result<model::Mesh,vmdl::ModelError>
|
|
||||||
where
|
|
||||||
AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId,
|
|
||||||
{
|
|
||||||
let model=model_data.read_model()?;
|
|
||||||
let texture_paths=model.texture_directories();
|
|
||||||
if texture_paths.len()!=1{
|
|
||||||
println!("WARNING: multiple texture paths");
|
|
||||||
}
|
|
||||||
let skin=model.skin_tables().nth(0).unwrap();
|
|
||||||
|
|
||||||
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(vertex.position.into()));
|
|
||||||
spam_normal.push(valve_transform(vertex.normal.into()));
|
|
||||||
spam_tex.push(glam::Vec2::from_array(vertex.texture_coordinates));
|
|
||||||
spam_vertices.push(model::IndexedVertex{
|
|
||||||
pos:model::PositionId::new(i as u32),
|
|
||||||
tex:model::TextureCoordinateId::new(i as u32),
|
|
||||||
normal:model::NormalId::new(i as u32),
|
|
||||||
color:model::ColorId::new(0),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let mut graphics_groups=Vec::new();
|
|
||||||
let mut physics_groups=Vec::new();
|
|
||||||
let polygon_groups=model.meshes().enumerate().map(|(polygon_group_id,mesh)|{
|
|
||||||
let polygon_group_id=model::PolygonGroupId::new(polygon_group_id as u32);
|
|
||||||
|
|
||||||
let render_id=if let (Some(texture_path),Some(texture_name))=(texture_paths.get(0),skin.texture(mesh.material_index())){
|
|
||||||
let mut path=std::path::PathBuf::from(texture_path.as_str());
|
|
||||||
path.push(texture_name);
|
|
||||||
acquire_render_config_id(path.as_os_str().to_str())
|
|
||||||
}else{
|
|
||||||
acquire_render_config_id(None)
|
|
||||||
};
|
|
||||||
|
|
||||||
graphics_groups.push(model::IndexedGraphicsGroup{
|
|
||||||
render:render_id,
|
|
||||||
groups:vec![polygon_group_id],
|
|
||||||
});
|
|
||||||
physics_groups.push(model::IndexedPhysicsGroup{
|
|
||||||
groups:vec![polygon_group_id],
|
|
||||||
});
|
|
||||||
model::PolygonGroup::PolygonList(model::PolygonList::new(
|
|
||||||
//looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function
|
|
||||||
mesh.vertex_strip_indices().flat_map(|mut strip|
|
|
||||||
std::iter::from_fn(move||{
|
|
||||||
match (strip.next(),strip.next(),strip.next()){
|
|
||||||
(Some(v1),Some(v2),Some(v3))=>Some([v1,v2,v3].map(|vertex_id|model::VertexId::new(vertex_id as u32)).to_vec()),
|
|
||||||
//ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate
|
|
||||||
_=>None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
).collect()
|
|
||||||
))
|
|
||||||
}).collect();
|
|
||||||
Ok(model::Mesh{
|
|
||||||
unique_pos:spam_pos,
|
|
||||||
unique_normal:spam_normal,
|
|
||||||
unique_tex:spam_tex,
|
|
||||||
unique_color:vec![glam::Vec4::ONE],
|
|
||||||
unique_vertices:spam_vertices,
|
|
||||||
polygon_groups,
|
|
||||||
graphics_groups,
|
|
||||||
physics_groups,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
pub struct Bsp(vbsp::Bsp);
|
|
||||||
impl Bsp{
|
|
||||||
pub const fn new(value:vbsp::Bsp)->Self{
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl AsRef<vbsp::Bsp> for Bsp{
|
|
||||||
fn as_ref(&self)->&vbsp::Bsp{
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MdlData(Vec<u8>);
|
|
||||||
impl MdlData{
|
|
||||||
pub const fn new(value:Vec<u8>)->Self{
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl AsRef<[u8]> for MdlData{
|
|
||||||
fn as_ref(&self)->&[u8]{
|
|
||||||
self.0.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct VtxData(Vec<u8>);
|
|
||||||
impl VtxData{
|
|
||||||
pub const fn new(value:Vec<u8>)->Self{
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl AsRef<[u8]> for VtxData{
|
|
||||||
fn as_ref(&self)->&[u8]{
|
|
||||||
self.0.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct VvdData(Vec<u8>);
|
|
||||||
impl VvdData{
|
|
||||||
pub const fn new(value:Vec<u8>)->Self{
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl AsRef<[u8]> for VvdData{
|
|
||||||
fn as_ref(&self)->&[u8]{
|
|
||||||
self.0.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ModelData{
|
|
||||||
pub mdl:MdlData,
|
|
||||||
pub vtx:VtxData,
|
|
||||||
pub vvd:VvdData,
|
|
||||||
}
|
|
||||||
impl ModelData{
|
|
||||||
pub fn read_model(&self)->Result<vmdl::Model,vmdl::ModelError>{
|
|
||||||
Ok(vmdl::Model::from_parts(
|
|
||||||
vmdl::mdl::Mdl::read(self.mdl.as_ref())?,
|
|
||||||
vmdl::vtx::Vtx::read(self.vtx.as_ref())?,
|
|
||||||
vmdl::vvd::Vvd::read(self.vvd.as_ref())?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,23 @@
|
|||||||
mod bsp;
|
mod bsp;
|
||||||
pub mod data;
|
mod mesh;
|
||||||
|
pub mod loader;
|
||||||
|
|
||||||
pub use data::Bsp;
|
pub struct Bsp(vbsp::Bsp);
|
||||||
|
impl Bsp{
|
||||||
|
pub const fn new(value:vbsp::Bsp)->Self{
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AsRef<vbsp::Bsp> for Bsp{
|
||||||
|
fn as_ref(&self)->&vbsp::Bsp{
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VALVE_SCALE:f32=1.0/16.0;
|
||||||
|
pub(crate) fn valve_transform([x,y,z]:[f32;3])->strafesnet_common::integer::Planar64Vec3{
|
||||||
|
strafesnet_common::integer::vec3::try_from_f32_array([x*VALVE_SCALE,z*VALVE_SCALE,-y*VALVE_SCALE]).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ReadError{
|
pub enum ReadError{
|
||||||
@ -24,14 +40,4 @@ pub fn read<R:std::io::Read>(mut input:R)->Result<Bsp,ReadError>{
|
|||||||
vbsp::Bsp::read(s.as_slice()).map(Bsp::new).map_err(ReadError::Bsp)
|
vbsp::Bsp::read(s.as_slice()).map(Bsp::new).map_err(ReadError::Bsp)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert<AcquireRenderConfigId,AcquireMeshId>(
|
pub use bsp::convert;
|
||||||
bsp:&Bsp,
|
|
||||||
acquire_render_config_id:AcquireRenderConfigId,
|
|
||||||
acquire_mesh_id:AcquireMeshId
|
|
||||||
)->bsp::PartialMap1
|
|
||||||
where
|
|
||||||
AcquireRenderConfigId:FnMut(Option<&str>)->strafesnet_common::model::RenderConfigId,
|
|
||||||
AcquireMeshId:FnMut(&str)->strafesnet_common::model::MeshId,
|
|
||||||
{
|
|
||||||
bsp::convert_bsp(bsp.as_ref(),acquire_render_config_id,acquire_mesh_id)
|
|
||||||
}
|
|
||||||
|
112
lib/bsp_loader/src/loader.rs
Normal file
112
lib/bsp_loader/src/loader.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use std::{borrow::Cow, io::Read};
|
||||||
|
|
||||||
|
use strafesnet_common::model::Mesh;
|
||||||
|
use strafesnet_deferred_loader::{loader::Loader,texture::Texture};
|
||||||
|
|
||||||
|
use crate::{mesh::ModelData, Bsp};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TextureError{
|
||||||
|
Io(std::io::Error),
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for TextureError{
|
||||||
|
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||||
|
write!(f,"{self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::error::Error for TextureError{}
|
||||||
|
impl From<std::io::Error> for TextureError{
|
||||||
|
fn from(value:std::io::Error)->Self{
|
||||||
|
Self::Io(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TextureLoader<'a>(std::marker::PhantomData<&'a ()>);
|
||||||
|
impl TextureLoader<'_>{
|
||||||
|
pub fn new()->Self{
|
||||||
|
Self(std::marker::PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> Loader for TextureLoader<'a>{
|
||||||
|
type Error=TextureError;
|
||||||
|
type Index=Cow<'a,str>;
|
||||||
|
type Resource=Texture;
|
||||||
|
fn load(&mut self,index:Self::Index)->Result<Self::Resource,Self::Error>{
|
||||||
|
let file_name=format!("textures/{}.dds",index);
|
||||||
|
let mut file=std::fs::File::open(file_name)?;
|
||||||
|
let mut data=Vec::new();
|
||||||
|
file.read_to_end(&mut data)?;
|
||||||
|
Ok(Texture::ImageDDS(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MeshError{
|
||||||
|
Io(std::io::Error),
|
||||||
|
VMDL(vmdl::ModelError),
|
||||||
|
VBSP(vbsp::BspError),
|
||||||
|
MissingMdl,
|
||||||
|
MissingVtx,
|
||||||
|
MissingVvd,
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for MeshError{
|
||||||
|
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||||
|
write!(f,"{self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::error::Error for MeshError{}
|
||||||
|
impl From<std::io::Error> for MeshError{
|
||||||
|
fn from(value:std::io::Error)->Self{
|
||||||
|
Self::Io(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<vmdl::ModelError> for MeshError{
|
||||||
|
fn from(value:vmdl::ModelError)->Self{
|
||||||
|
Self::VMDL(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<vbsp::BspError> for MeshError{
|
||||||
|
fn from(value:vbsp::BspError)->Self{
|
||||||
|
Self::VBSP(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MeshLoader<'a,'b>{
|
||||||
|
bsp:&'a Bsp,
|
||||||
|
deferred_loader:&'b mut strafesnet_deferred_loader::deferred_loader::RenderConfigDeferredLoader<Cow<'a,str>>,
|
||||||
|
}
|
||||||
|
impl MeshLoader<'_,'_>{
|
||||||
|
pub fn new<'a,'b>(
|
||||||
|
bsp:&'a Bsp,
|
||||||
|
deferred_loader:&'b mut strafesnet_deferred_loader::deferred_loader::RenderConfigDeferredLoader<Cow<'a,str>>,
|
||||||
|
)->MeshLoader<'a,'b>{
|
||||||
|
MeshLoader{
|
||||||
|
bsp,
|
||||||
|
deferred_loader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> Loader for MeshLoader<'a,'_>{
|
||||||
|
type Error=MeshError;
|
||||||
|
type Index=&'a str;
|
||||||
|
type Resource=Mesh;
|
||||||
|
fn load(&mut self,index:Self::Index)->Result<Self::Resource,Self::Error>{
|
||||||
|
let mdl_path_lower=index.to_lowercase();
|
||||||
|
//.mdl, .vvd, .dx90.vtx
|
||||||
|
let path=std::path::PathBuf::from(mdl_path_lower.as_str());
|
||||||
|
let mut vvd_path=path.clone();
|
||||||
|
let mut vtx_path=path;
|
||||||
|
vvd_path.set_extension("vvd");
|
||||||
|
vtx_path.set_extension("dx90.vtx");
|
||||||
|
// TODO: search more packs, possibly using an index of multiple packs
|
||||||
|
let bsp=self.bsp.as_ref();
|
||||||
|
let mdl=bsp.pack.get(mdl_path_lower.as_str())?.ok_or(MeshError::MissingMdl)?;
|
||||||
|
let vtx=bsp.pack.get(vtx_path.as_os_str().to_str().unwrap())?.ok_or(MeshError::MissingVtx)?;
|
||||||
|
let vvd=bsp.pack.get(vvd_path.as_os_str().to_str().unwrap())?.ok_or(MeshError::MissingVvd)?;
|
||||||
|
let model=ModelData{mdl,vtx,vvd};
|
||||||
|
let mesh=model.convert_mesh(&mut self.deferred_loader)?;
|
||||||
|
Ok(mesh)
|
||||||
|
}
|
||||||
|
}
|
89
lib/bsp_loader/src/mesh.rs
Normal file
89
lib/bsp_loader/src/mesh.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use strafesnet_common::model;
|
||||||
|
use strafesnet_deferred_loader::deferred_loader::RenderConfigDeferredLoader;
|
||||||
|
|
||||||
|
use crate::valve_transform;
|
||||||
|
|
||||||
|
pub struct ModelData{
|
||||||
|
pub mdl:Vec<u8>,
|
||||||
|
pub vtx:Vec<u8>,
|
||||||
|
pub vvd:Vec<u8>,
|
||||||
|
}
|
||||||
|
impl ModelData{
|
||||||
|
fn read_model(&self)->Result<vmdl::Model,vmdl::ModelError>{
|
||||||
|
Ok(vmdl::Model::from_parts(
|
||||||
|
vmdl::mdl::Mdl::read(self.mdl.as_ref())?,
|
||||||
|
vmdl::vtx::Vtx::read(self.vtx.as_ref())?,
|
||||||
|
vmdl::vvd::Vvd::read(self.vvd.as_ref())?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
pub fn convert_mesh<'a>(self,deferred_loader:&mut RenderConfigDeferredLoader<Cow<'a,str>>)->Result<model::Mesh,vmdl::ModelError>{
|
||||||
|
let model=self.read_model()?;
|
||||||
|
let texture_paths=model.texture_directories();
|
||||||
|
if texture_paths.len()!=1{
|
||||||
|
println!("WARNING: multiple texture paths");
|
||||||
|
}
|
||||||
|
let skin=model.skin_tables().nth(0).unwrap();
|
||||||
|
|
||||||
|
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(vertex.position.into()));
|
||||||
|
spam_normal.push(valve_transform(vertex.normal.into()));
|
||||||
|
spam_tex.push(glam::Vec2::from_array(vertex.texture_coordinates));
|
||||||
|
spam_vertices.push(model::IndexedVertex{
|
||||||
|
pos:model::PositionId::new(i as u32),
|
||||||
|
tex:model::TextureCoordinateId::new(i as u32),
|
||||||
|
normal:model::NormalId::new(i as u32),
|
||||||
|
color:model::ColorId::new(0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let mut graphics_groups=Vec::new();
|
||||||
|
let mut physics_groups=Vec::new();
|
||||||
|
let polygon_groups=model.meshes().enumerate().map(|(polygon_group_id,mesh)|{
|
||||||
|
let polygon_group_id=model::PolygonGroupId::new(polygon_group_id as u32);
|
||||||
|
|
||||||
|
let render_id=if let (Some(texture_path),Some(texture_name))=(texture_paths.get(0),skin.texture(mesh.material_index())){
|
||||||
|
let mut path=std::path::PathBuf::from(texture_path.as_str());
|
||||||
|
path.push(texture_name);
|
||||||
|
let index=path.as_os_str().to_str().map(|s|Cow::Owned(s.to_owned()));
|
||||||
|
deferred_loader.acquire_render_config_id(index)
|
||||||
|
}else{
|
||||||
|
deferred_loader.acquire_render_config_id(None)
|
||||||
|
};
|
||||||
|
|
||||||
|
graphics_groups.push(model::IndexedGraphicsGroup{
|
||||||
|
render:render_id,
|
||||||
|
groups:vec![polygon_group_id],
|
||||||
|
});
|
||||||
|
physics_groups.push(model::IndexedPhysicsGroup{
|
||||||
|
groups:vec![polygon_group_id],
|
||||||
|
});
|
||||||
|
model::PolygonGroup::PolygonList(model::PolygonList::new(
|
||||||
|
//looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function
|
||||||
|
mesh.vertex_strip_indices().flat_map(|mut strip|
|
||||||
|
std::iter::from_fn(move||{
|
||||||
|
match (strip.next(),strip.next(),strip.next()){
|
||||||
|
(Some(v1),Some(v2),Some(v3))=>Some([v1,v2,v3].map(|vertex_id|model::VertexId::new(vertex_id as u32)).to_vec()),
|
||||||
|
//ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate
|
||||||
|
_=>None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
).collect()
|
||||||
|
))
|
||||||
|
}).collect();
|
||||||
|
Ok(model::Mesh{
|
||||||
|
unique_pos:spam_pos,
|
||||||
|
unique_normal:spam_normal,
|
||||||
|
unique_tex:spam_tex,
|
||||||
|
unique_color:vec![glam::Vec4::ONE],
|
||||||
|
unique_vertices:spam_vertices,
|
||||||
|
polygon_groups,
|
||||||
|
graphics_groups,
|
||||||
|
physics_groups,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user