diff --git a/src/main.rs b/src/main.rs index df1cf2e..f4ee1d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::io::{Read, Seek}; + use clap::{Args, Parser, Subcommand}; mod error; @@ -20,6 +22,7 @@ struct Cli { enum Commands { Download(MapList), DownloadTextures(PathBufList), + ConvertTextures, Upload, Scan, Extract(PathBufList), @@ -291,6 +294,81 @@ fn download_textures(paths: Vec) -> BoxResult<()>{ Ok(()) } +fn convert(file_thing:std::fs::DirEntry) -> BoxResult<()>{ + let mut input = std::io::BufReader::new(std::fs::File::open(file_thing.path())?); + let mut fourcc=[0u8;4]; + input.read_exact(&mut fourcc)?; + input.rewind()?; + + let mut extracted_input=None; + let image=if&fourcc==b"\x89PNG"{ + image::load(input,image::ImageFormat::Png)?.to_rgba8() + }else if &fourcc[0..2]==b"\x1f\x8b"{ + //gzip + let mut extracted:Vec=Vec::new(); + flate2::read::GzDecoder::new(input).read_to_end(&mut extracted)?; + extracted_input=Some(extracted.clone()); + image::load(std::io::Cursor::new(extracted),image::ImageFormat::Png)?.to_rgba8() + }else{ + Err(error::Error::new("Unknown texture format"))? + }; + + let dds = image_dds::dds_from_image( + &image, + image_dds::ImageFormat::BC7Unorm, + image_dds::Quality::Slow, + image_dds::Mipmaps::GeneratedAutomatic, + )?; + + //write dds + let mut dest=std::path::PathBuf::from("textures/dds"); + dest.push(file_thing.file_name()); + dest.set_extension("dds"); + let mut writer = std::io::BufWriter::new(std::fs::File::create(dest)?); + dds.write(&mut writer)?; + + if let Some(mut extracted)=extracted_input{ + //write extracted to processed + let mut dest=std::path::PathBuf::from("textures/processed"); + dest.push(file_thing.file_name()); + std::fs::write(dest, &mut extracted)?; + //delete ugly gzip file + std::fs::remove_file(file_thing.path())?; + }else{ + //move file to processed + let mut dest=std::path::PathBuf::from("textures/processed"); + dest.push(file_thing.file_name()); + std::fs::rename(file_thing.path(), dest)?; + } + Ok(()) +} +fn convert_textures() -> BoxResult<()>{ + let start = std::time::Instant::now(); + let mut threads=Vec::new(); + for entry in std::fs::read_dir("textures/unprocessed")? { + let file_thing=entry?; + threads.push(std::thread::spawn(move ||{ + let file_name=file_thing.file_name(); + let result=convert(file_thing); + if let Err(e)=result{ + println!("error processing file:{:?} error message:{:?}",file_name,e); + } + })); + } + let mut i=0; + let n_threads=threads.len(); + for thread in threads{ + i+=1; + if let Err(e)=thread.join(){ + println!("thread error: {:?}",e); + }else{ + println!("{}/{}",i,n_threads); + } + } + println!("{:?}", start.elapsed()); + Ok(()) +} + enum Scan{ Passed, Blocked, @@ -748,6 +826,7 @@ fn main() -> BoxResult<()> { match cli.command { Commands::Download(map_list)=>download(map_list.maps), Commands::DownloadTextures(pathlist)=>download_textures(pathlist.paths), + Commands::ConvertTextures=>convert_textures(), Commands::Upload=>upload(), Commands::Scan=>scan(), Commands::Replace=>replace(),