From 894584f855a41726df2730d0e8e1527acdfc731d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 10 Jan 2024 15:13:59 -0800 Subject: [PATCH] recursive vmt loader --- src/main.rs | 175 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 66 deletions(-) diff --git a/src/main.rs b/src/main.rs index 51e86dc..fc08d2f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1045,6 +1045,79 @@ fn write_attributes() -> AResult<()>{ Ok(()) } +enum VMTContent{ + VMT(String), + VTF(String), + Patch(vmt_parser::material::PatchMaterial), + Unsupported,//don't want to deal with whatever vmt variant + Unresolved,//could not locate a texture because of vmt content +} +impl VMTContent{ + fn vtf(opt:Option)->Self{ + match opt{ + Some(s)=>Self::VTF(s), + None=>Self::Unresolved, + } + } +} + +fn get_some_texture(material:vmt_parser::material::Material)->AResult{ + //just grab some texture from somewhere for now + Ok(match material{ + vmt_parser::material::Material::LightMappedGeneric(mat)=>VMTContent::vtf(Some(mat.base_texture)), + vmt_parser::material::Material::VertexLitGeneric(mat)=>VMTContent::vtf(mat.base_texture.or(mat.decal_texture)),//this just dies if there is none + vmt_parser::material::Material::VertexLitGenericDx6(mat)=>VMTContent::vtf(mat.base_texture.or(mat.decal_texture)), + vmt_parser::material::Material::UnlitGeneric(mat)=>VMTContent::vtf(mat.base_texture), + vmt_parser::material::Material::UnlitTwoTexture(mat)=>VMTContent::vtf(mat.base_texture), + vmt_parser::material::Material::Water(mat)=>VMTContent::vtf(mat.base_texture), + vmt_parser::material::Material::WorldVertexTransition(mat)=>VMTContent::vtf(Some(mat.base_texture)), + vmt_parser::material::Material::EyeRefract(mat)=>VMTContent::vtf(Some(mat.cornea_texture)), + vmt_parser::material::Material::SubRect(mat)=>VMTContent::VMT(mat.material),//recursive + vmt_parser::material::Material::Sprite(mat)=>VMTContent::vtf(Some(mat.base_texture)), + vmt_parser::material::Material::SpriteCard(mat)=>VMTContent::vtf(mat.base_texture), + vmt_parser::material::Material::Cable(mat)=>VMTContent::vtf(Some(mat.base_texture)), + vmt_parser::material::Material::Refract(mat)=>VMTContent::vtf(mat.base_texture), + vmt_parser::material::Material::Modulate(mat)=>VMTContent::vtf(Some(mat.base_texture)), + vmt_parser::material::Material::DecalModulate(mat)=>VMTContent::vtf(Some(mat.base_texture)), + vmt_parser::material::Material::Sky(mat)=>VMTContent::vtf(Some(mat.base_texture)), + vmt_parser::material::Material::Replacements(_mat)=>VMTContent::Unsupported, + vmt_parser::material::Material::Patch(mat)=>VMTContent::Patch(mat), + _=>return Err(anyhow::Error::msg("vmt failed to parse")), + }) +} + +fn get_vmtAResult>>>(find_stuff:&F,search_name:String)->AResult>{ + if let Some(stuff)=find_stuff(search_name)?{ + //println!("woahh its a vmt {:?}",search_name); + //decode vmt and then write + let stuff=String::from_utf8(stuff)?; + let material=vmt_parser::from_str(stuff.as_str())?; + println!("vmt material={:?}",material); + return Ok(Some(material)); + } + Ok(None) +} + +fn recursive_vmt_loaderAResult>>>(find_stuff:&F,material:vmt_parser::material::Material)->AResult>>{ + match get_some_texture(material)?{ + VMTContent::VMT(s)=>match get_vmt(find_stuff,s)?{ + Some(mat)=>recursive_vmt_loader(find_stuff,mat), + None=>Ok(None), + }, + VMTContent::VTF(s)=>find_stuff(s), + VMTContent::Patch(mat)=>recursive_vmt_loader(find_stuff, + mat.resolve(|search_name| + match find_stuff(search_name.to_string())?{ + Some(bytes)=>Ok(String::from_utf8(bytes)?), + None=>Err(anyhow::Error::msg("could not find vmt")), + } + )? + ), + VMTContent::Unsupported=>Ok(None), + VMTContent::Unresolved=>Ok(None), + } +} + fn extract_textures(paths:Vec,vpk_path:std::path::PathBuf)->AResult<()>{ let vpk_index=vpk::VPK::read(&vpk_path)?; for path in paths{ @@ -1077,6 +1150,7 @@ fn extract_textures(paths:Vec,vpk_path:std::path::PathBuf)-> let model=vmdl::Model::from_parts(mdl,vtx,vvd); for texture in model.textures(){ println!("prop texture={}",texture.name.as_str()); + println!("search paths={:?}",texture.search_paths); deduplicate.insert(std::path::PathBuf::from(texture.name.as_str())); } }, @@ -1087,23 +1161,11 @@ fn extract_textures(paths:Vec,vpk_path:std::path::PathBuf)-> } } - let mut zippyt=bsp.pack.into_zip().into_inner().unwrap(); + let pack=&bsp.pack; let tree=&vpk_index.tree; std::thread::scope(move|s|{ let mut thread_handles=Vec::new(); for texture_name in deduplicate{ - let mut texture_file_name=std::path::PathBuf::from("materials"); - //lower case - let texture_file_name_lowercase=texture_name.to_string_lossy().to_lowercase(); - texture_file_name.push(texture_file_name_lowercase.clone()); - //remove stem and search for both vtf and vmt files - let stem=std::path::PathBuf::from(texture_file_name.file_stem().unwrap()); - texture_file_name.pop(); - texture_file_name.push(stem); - //somehow search for both files - let mut texture_file_name2=texture_file_name.clone(); - texture_file_name.set_extension("vtf"); - texture_file_name2.set_extension("vmt"); let mut found_texture=false; //LMAO imagine having to write type names let write_image=|mut stuff,write_file_name|{ @@ -1131,65 +1193,46 @@ fn extract_textures(paths:Vec,vpk_path:std::path::PathBuf)-> dds.write(&mut writer)?; Ok::<(),anyhow::Error>(()) }; - let mut find_stuff=|search_file_name|{ + let find_stuff=|search_file_name:String|{ //println!("search_file_name={}",search_file_name); - Ok::>,anyhow::Error>(match (zippyt.by_name(search_file_name),tree.get(search_file_name)){ - (Ok(mut zip_file),None)=>{ - let mut buf=Vec::new(); - zip_file.read_to_end(&mut buf)?; - Some(buf) - }, - (_,Some(vpk_entry))=>Some(vpk_entry.get()?.to_vec()), - _=>None, - }) + match pack.get(search_file_name.as_str()){ + Ok(file)=>return Ok(file), + _=>(), + } + //search pak list + for tree in [tree]{ + if let Some(vpk_entry)=tree.get(search_file_name.as_str()){ + return Ok(Some(vpk_entry.get()?.to_vec())); + } + } + Ok::>,anyhow::Error>(None) }; - if let Some(stuff)=find_stuff(texture_file_name.as_os_str().to_str().unwrap())?{ + let loader=|texture_name:String|{ + let mut texture_file_name=std::path::PathBuf::from("materials"); + //lower case + let texture_file_name_lowercase=texture_name.to_lowercase(); + texture_file_name.push(texture_file_name_lowercase.clone()); + //remove stem and search for both vtf and vmt files + let stem=std::path::PathBuf::from(texture_file_name.file_stem().unwrap()); + texture_file_name.pop(); + texture_file_name.push(stem); + //somehow search for both files + let mut texture_file_name2=texture_file_name.clone(); + texture_file_name.set_extension("vtf"); + texture_file_name2.set_extension("vmt"); + if let Some(stuff)=find_stuff(texture_file_name.to_string_lossy().to_string())?{ + return Ok(Some(stuff)) + } + if let Some(mat)=get_vmt(&find_stuff,texture_file_name2.to_string_lossy().to_string())?{ + return recursive_vmt_loader(&find_stuff,mat); + } + Ok(None) + }; + if let Some(stuff)=loader(texture_name.to_string_lossy().to_string())?{ found_texture=true; let texture_name=texture_name.clone(); thread_handles.push(s.spawn(move||write_image(stuff,texture_name))); } - if let Some(stuff)=find_stuff(texture_file_name2.as_os_str().to_str().unwrap())?{ - println!("woahh its a vmt {:?}",texture_file_name2); - //decode vmt and then write - let stuff=String::from_utf8(stuff)?; - - //just grab some texture from somewhere for now - let vmt=vmt_parser::from_str(stuff.as_str())?; - println!("le vmt {:?}",vmt); - let some_texture=match vmt{ - vmt_parser::material::Material::LightMappedGeneric(mat)=>Some(mat.base_texture), - vmt_parser::material::Material::VertexLitGeneric(mat)=>mat.base_texture.or(mat.decal_texture),//this just dies if there is none - vmt_parser::material::Material::VertexLitGenericDx6(mat)=>mat.base_texture.or(mat.decal_texture), - vmt_parser::material::Material::UnlitGeneric(mat)=>mat.base_texture, - vmt_parser::material::Material::UnlitTwoTexture(mat)=>mat.base_texture, - vmt_parser::material::Material::Water(mat)=>mat.base_texture, - vmt_parser::material::Material::WorldVertexTransition(mat)=>Some(mat.base_texture), - vmt_parser::material::Material::EyeRefract(mat)=>Some(mat.cornea_texture), - vmt_parser::material::Material::SubRect(_mat)=>None,//recursive - vmt_parser::material::Material::Sprite(mat)=>Some(mat.base_texture), - vmt_parser::material::Material::SpriteCard(mat)=>mat.base_texture, - vmt_parser::material::Material::Cable(mat)=>Some(mat.base_texture), - vmt_parser::material::Material::Refract(mat)=>mat.base_texture, - vmt_parser::material::Material::Modulate(mat)=>Some(mat.base_texture), - vmt_parser::material::Material::DecalModulate(mat)=>Some(mat.base_texture), - vmt_parser::material::Material::Sky(mat)=>Some(mat.base_texture), - vmt_parser::material::Material::Replacements(_mat)=>None, - vmt_parser::material::Material::Patch(_mat)=>None,//recursive - _=>return Err(anyhow::Error::msg("vmt failed to parse")), - }; - if let Some(search_texture_name)=some_texture{ - println!("searching for some random texture: {}",search_texture_name); - let mut texture_file_name=std::path::PathBuf::from("materials"); - texture_file_name.push(search_texture_name); - texture_file_name.set_extension("vtf"); - if let Some(stuff)=find_stuff(texture_file_name.as_os_str().to_str().unwrap())?{ - println!("got it! writing to {:?}",texture_name); - found_texture=true; - let texture_name=texture_name.clone(); - thread_handles.push(s.spawn(move||write_image(stuff,texture_name))); - } - } - } if !found_texture{ println!("no data"); }