new loading api

This commit is contained in:
2024-02-14 23:45:16 -08:00
parent f3174cd191
commit a2eac57282
7 changed files with 637 additions and 60 deletions

@ -8,6 +8,7 @@ mod roblox;
mod source;
pub mod texture;
pub mod valve_mesh;
#[cfg(feature="legacy")]
pub fn roblox_legacy()->roblox_legacy::Loader{

@ -1,7 +1,7 @@
use std::io::Read;
use std::collections::HashMap;
use crate::texture::{Texture,Textures};
use strafesnet_common::model::TextureId;
use crate::texture::{Texture,RenderConfigs};
use strafesnet_common::model::{TextureId,RenderConfigId,RenderConfig};
#[derive(Hash,Eq,PartialEq)]
struct RobloxAssetId(u64);
@ -29,30 +29,65 @@ impl std::fmt::Display for RobloxAssetIdParseErr{
impl std::error::Error for RobloxAssetIdParseErr{}
pub struct Loader{
texture_names:HashMap<RobloxAssetId,TextureId>,
texture_count:u32,
render_configs:Vec<RenderConfig>,
render_config_id_from_asset_id:HashMap<Option<RobloxAssetId>,RenderConfigId>,
}
impl Loader{
pub fn new()->Self{
Self{
texture_names:HashMap::new(),
texture_count:0,
render_configs:Vec::new(),
render_config_id_from_asset_id:HashMap::new(),
}
}
}
impl Loader{
pub fn acquire_texture_id(&mut self,name:&str)->Result<TextureId,RobloxAssetIdParseErr>{
let texture_id=TextureId::new(self.texture_names.len() as u32);
Ok(*self.texture_names.entry(name.parse::<RobloxAssetId>()?).or_insert(texture_id))
pub fn acquire_render_config_id(&mut self,name:Option<&str>)->RenderConfigId{
let render_id=RenderConfigId::new(self.render_config_id_from_asset_id.len() as u32);
let index=name.and_then(|name|{
match name.parse::<RobloxAssetId>(){
Ok(asset_id)=>Some(asset_id),
Err(e)=>{
println!("Failed to parse AssetId: {e}");
None
},
}
});
*self.render_config_id_from_asset_id.entry(index).or_insert_with(||{
//create the render config.
let render_config=if name.is_some(){
let render_config=RenderConfig::texture(TextureId::new(self.texture_count));
self.texture_count+=1;
render_config
}else{
RenderConfig::default()
};
self.render_configs.push(render_config);
render_id
})
}
pub fn load_textures(&self)->Result<Textures,std::io::Error>{
let mut texture_data=vec![Vec::<u8>::new();self.texture_names.len()];
for (texture_name,texture_id) in &self.texture_names{
let path=std::path::PathBuf::from(format!("textures/{}.dds",texture_name.0));
if let Ok(mut file)=std::fs::File::open(path){
//TODO: parallel
file.read_to_end(texture_data.get_mut(texture_id.get() as usize).unwrap())?;
pub fn into_render_configs(mut self)->Result<RenderConfigs,std::io::Error>{
let mut sorted_textures=vec![None;self.texture_count as usize];
for (asset_id,render_config_id) in self.render_config_id_from_asset_id{
let render_config=self.render_configs.get_mut(render_config_id.get() as usize).unwrap();
if let (Some(asset_id),Some(texture_id))=(asset_id,render_config.texture){
let path=std::path::PathBuf::from(format!("textures/{}.dds",asset_id.0));
if let Ok(mut file)=std::fs::File::open(path){
//TODO: parallel
let mut data=Vec::<u8>::new();
file.read_to_end(&mut data)?;
sorted_textures[texture_id.get() as usize]=Some(Texture::ImageDDS(data));
}else{
//texture failed to load
render_config.texture=None;
}
}
}
Ok(Textures::new(texture_data.into_iter().map(Texture::ImageDDS).collect()))
Ok(RenderConfigs::new(
sorted_textures,
self.render_configs,
))
}
}

@ -1,15 +1,29 @@
use std::io::Read;
use std::collections::HashMap;
use crate::texture::{Texture,Textures};
use strafesnet_common::model::{MeshId,TextureId};
use crate::valve_mesh;
use crate::texture::{Texture,RenderConfigs};
use strafesnet_common::model::{MeshId,TextureId,RenderConfig,RenderConfigId};
pub struct TextureLoader{
texture_paths:HashMap<Box<str>,TextureId>,
pub struct RenderConfigLoader{
texture_count:u32,
render_configs:Vec<RenderConfig>,
texture_paths:HashMap<Option<Box<str>>,RenderConfigId>,
}
impl TextureLoader{
pub fn acquire_texture_id(&mut self,name:&str)->TextureId{
let texture_id=TextureId::new(self.texture_paths.len() as u32);
*self.texture_paths.entry(name.into()).or_insert(texture_id)
impl RenderConfigLoader{
pub fn acquire_render_config_id(&mut self,name:Option<&str>)->RenderConfigId{
let render_id=RenderConfigId::new(self.texture_paths.len() as u32);
*self.texture_paths.entry(name.map(Into::into)).or_insert_with(||{
//create the render config.
let render_config=if name.is_some(){
let render_config=RenderConfig::texture(TextureId::new(self.texture_count));
self.texture_count+=1;
render_config
}else{
RenderConfig::default()
};
self.render_configs.push(render_config);
render_id
})
}
}
pub struct MeshLoader{
@ -17,42 +31,79 @@ pub struct MeshLoader{
}
impl MeshLoader{
pub fn acquire_mesh_id(&mut self,name:&str)->MeshId{
let texture_id=MeshId::new(self.mesh_paths.len() as u32);
*self.mesh_paths.entry(name.into()).or_insert(texture_id)
let mesh_id=MeshId::new(self.mesh_paths.len() as u32);
*self.mesh_paths.entry(name.into()).or_insert(mesh_id)
}
//load_meshes should look like load_textures
pub fn load_meshes(&mut self,bsp:&vbsp::Bsp)->valve_mesh::Meshes{
let mut mesh_data=vec![None;self.mesh_paths.len()];
for (mesh_path,mesh_id) in &self.mesh_paths{
let mesh_path_lower=mesh_path.to_lowercase();
//.mdl, .vvd, .dx90.vtx
let mut path=std::path::PathBuf::from(mesh_path_lower.as_str());
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(mesh_path_lower.as_str()),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)))=>{
mesh_data[mesh_id.get() as usize]=Some(valve_mesh::ModelData{
mdl:valve_mesh::MdlData::new(mdl_file),
vtx:valve_mesh::VtxData::new(vtx_file),
vvd:valve_mesh::VvdData::new(vvd_file),
});
},
_=>println!("no model name={}",mesh_path),
}
}
valve_mesh::Meshes::new(mesh_data)
}
}
pub struct Loader{
texture_loader:TextureLoader,
render_config_loader:RenderConfigLoader,
mesh_loader:MeshLoader,
}
impl Loader{
pub fn new()->Self{
Self{
texture_loader:TextureLoader{texture_paths:HashMap::new()},
render_config_loader:RenderConfigLoader{
texture_count:0,
texture_paths:HashMap::new(),
render_configs:Vec::new(),
},
mesh_loader:MeshLoader{mesh_paths:HashMap::new()},
}
}
pub fn get_inner_mut(&mut self)->(&mut TextureLoader,&mut MeshLoader){
(&mut self.texture_loader,&mut self.mesh_loader)
pub fn get_inner_mut(&mut self)->(&mut RenderConfigLoader,&mut MeshLoader){
(&mut self.render_config_loader,&mut self.mesh_loader)
}
}
impl Loader{
pub fn load_textures(&self)->Result<Textures,std::io::Error>{
let mut texture_data=vec![Vec::<u8>::new();self.texture_loader.texture_paths.len()];
for (texture_path,texture_id) in &self.texture_loader.texture_paths{
let path=std::path::PathBuf::from(format!("textures/{}.dds",texture_path));
if let Ok(mut file)=std::fs::File::open(path){
//TODO: parallel
file.read_to_end(texture_data.get_mut(texture_id.get() as usize).unwrap())?;
pub fn into_render_configs(mut self)->Result<RenderConfigs,std::io::Error>{
let mut sorted_textures=vec![None;self.render_config_loader.texture_count as usize];
for (texture_path,render_config_id) in self.render_config_loader.texture_paths{
let render_config=self.render_config_loader.render_configs.get_mut(render_config_id.get() as usize).unwrap();
if let (Some(texture_path),Some(texture_id))=(texture_path,render_config.texture){
let path=std::path::PathBuf::from(format!("textures/{}.dds",texture_path));
if let Ok(mut file)=std::fs::File::open(path){
//TODO: parallel
let mut data=Vec::<u8>::new();
file.read_to_end(&mut data)?;
sorted_textures[texture_id.get() as usize]=Some(Texture::ImageDDS(data));
}else{
//texture failed to load
render_config.texture=None;
}
}
}
Ok(Textures::new(texture_data.into_iter().map(Texture::ImageDDS).collect()))
Ok(RenderConfigs::new(
sorted_textures,
self.render_config_loader.render_configs,
))
}
//load_meshes should look like load_textures
/*
pub fn load_meshes(&mut self)->Result<Meshes,std::io::Error>{
}
*/
}

@ -1,5 +1,6 @@
use strafesnet_common::model::TextureId;
use strafesnet_common::model::{TextureId,RenderConfigId,RenderConfig};
#[derive(Clone)]
pub enum Texture{
ImageDDS(Vec<u8>),
}
@ -11,19 +12,28 @@ impl AsRef<[u8]> for Texture{
}
}
pub struct Textures{
textures:Vec<Texture>,
pub struct RenderConfigs{
textures:Vec<Option<Texture>>,
render_configs:Vec<RenderConfig>,
}
impl Textures{
pub(crate) const fn new(textures:Vec<Texture>)->Self{
impl RenderConfigs{
pub(crate) const fn new(textures:Vec<Option<Texture>>,render_configs:Vec<RenderConfig>)->Self{
Self{
textures,
render_configs,
}
}
pub fn get_texture(&self,texture_id:TextureId)->Option<&Texture>{
self.textures.get(texture_id.get() as usize)
pub fn consume(self)->(
impl Iterator<Item=(TextureId,Texture)>,
impl Iterator<Item=(RenderConfigId,RenderConfig)>
){
(
self.textures.into_iter().enumerate().filter_map(|(texture_id,maybe_texture)|
maybe_texture.map(|texture|(TextureId::new(texture_id as u32),texture))
),
self.render_configs.into_iter().enumerate().map(|(render_id,render)|
(RenderConfigId::new(render_id as u32),render)
),
)
}
pub fn into_iter(self)->impl Iterator<Item=(TextureId,Texture)>{
self.textures.into_iter().enumerate().map(|(texture_id,texture)|(TextureId::new(texture_id as u32),texture))
}
}
}

60
src/valve_mesh.rs Normal file

@ -0,0 +1,60 @@
use strafesnet_common::model::MeshId;
//duplicate this code for now
#[derive(Clone)]
pub struct MdlData(Vec<u8>);
impl MdlData{
pub const fn new(value:Vec<u8>)->Self{
Self(value)
}
pub fn get(self)->Vec<u8>{
self.0
}
}
#[derive(Clone)]
pub struct VtxData(Vec<u8>);
impl VtxData{
pub const fn new(value:Vec<u8>)->Self{
Self(value)
}
pub fn get(self)->Vec<u8>{
self.0
}
}
#[derive(Clone)]
pub struct VvdData(Vec<u8>);
impl VvdData{
pub const fn new(value:Vec<u8>)->Self{
Self(value)
}
pub fn get(self)->Vec<u8>{
self.0
}
}
#[derive(Clone)]
pub struct ModelData{
pub mdl:MdlData,
pub vtx:VtxData,
pub vvd:VvdData,
}
//meshes is more prone to failure
pub struct Meshes{
meshes:Vec<Option<ModelData>>,
}
impl Meshes{
pub(crate) const fn new(meshes:Vec<Option<ModelData>>)->Self{
Self{
meshes,
}
}
pub fn get_texture(&self,texture_id:MeshId)->Option<&ModelData>{
self.meshes.get(texture_id.get() as usize)?.as_ref()
}
pub fn into_iter(self)->impl Iterator<Item=(MeshId,ModelData)>{
self.meshes.into_iter().enumerate().filter_map(|(mesh_id,maybe_mesh)|
maybe_mesh.map(|mesh|(MeshId::new(mesh_id as u32),mesh))
)
}
}