recursive vmt loader

This commit is contained in:
Quaternions 2024-01-10 15:13:59 -08:00
parent 0e1b9494c2
commit 894584f855

View File

@ -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<String>)->Self{
match opt{
Some(s)=>Self::VTF(s),
None=>Self::Unresolved,
}
}
}
fn get_some_texture(material:vmt_parser::material::Material)->AResult<VMTContent>{
//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_vmt<F:Fn(String)->AResult<Option<Vec<u8>>>>(find_stuff:&F,search_name:String)->AResult<Option<vmt_parser::material::Material>>{
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_loader<F:Fn(String)->AResult<Option<Vec<u8>>>>(find_stuff:&F,material:vmt_parser::material::Material)->AResult<Option<Vec<u8>>>{
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<std::path::PathBuf>,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<std::path::PathBuf>,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<std::path::PathBuf>,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<std::path::PathBuf>,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::<Option<Vec<u8>>,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,
})
};
if let Some(stuff)=find_stuff(texture_file_name.as_os_str().to_str().unwrap())?{
found_texture=true;
let texture_name=texture_name.clone();
thread_handles.push(s.spawn(move||write_image(stuff,texture_name)));
match pack.get(search_file_name.as_str()){
Ok(file)=>return Ok(file),
_=>(),
}
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")),
//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::<Option<Vec<u8>>,anyhow::Error>(None)
};
if let Some(search_texture_name)=some_texture{
println!("searching for some random texture: {}",search_texture_name);
let loader=|texture_name:String|{
let mut texture_file_name=std::path::PathBuf::from("materials");
texture_file_name.push(search_texture_name);
//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");
if let Some(stuff)=find_stuff(texture_file_name.as_os_str().to_str().unwrap())?{
println!("got it! writing to {:?}",texture_name);
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 !found_texture{
println!("no data");
}