mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-03 16:44:11 +02:00
extract loader into crate
This commit is contained in:
parent
585a485031
commit
d330108905
7 changed files with 28 additions and 135 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
|
@ -2581,6 +2581,18 @@ version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tf-asset-loader"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d19874714b7454f34d6142f9a2e2521b6e48ff4b3929cbac7acc72f161baf7bf"
|
||||||
|
dependencies = [
|
||||||
|
"steamlocate",
|
||||||
|
"thiserror",
|
||||||
|
"tracing",
|
||||||
|
"vpk",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.50"
|
version = "1.0.50"
|
||||||
|
|
@ -2878,13 +2890,12 @@ dependencies = [
|
||||||
"main_error",
|
"main_error",
|
||||||
"miette",
|
"miette",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"steamlocate",
|
"tf-asset-loader",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"three-d",
|
"three-d",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"vmt-parser",
|
"vmt-parser",
|
||||||
"vpk",
|
|
||||||
"vtf",
|
"vtf",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,7 @@ three-d = { version = "0.14.0", features = ["egui-gui"] }
|
||||||
miette = { version = "5.5.0", features = ["fancy"] }
|
miette = { version = "5.5.0", features = ["fancy"] }
|
||||||
criterion = "0.4.0"
|
criterion = "0.4.0"
|
||||||
iai = "0.1"
|
iai = "0.1"
|
||||||
steamlocate = "2.0.0-alpha.0"
|
|
||||||
vtf = "0.1.6"
|
vtf = "0.1.6"
|
||||||
vpk = "0.2.0"
|
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = "0.3.18"
|
tracing-subscriber = "0.3.18"
|
||||||
gltf-json = "1.3.0"
|
gltf-json = "1.3.0"
|
||||||
|
|
@ -30,6 +28,7 @@ image = "0.23.14"
|
||||||
clap = { version = "4.4.11", features = ["derive"] }
|
clap = { version = "4.4.11", features = ["derive"] }
|
||||||
main_error = "0.1.2"
|
main_error = "0.1.2"
|
||||||
vmt-parser = { version = "0.1", git = "https://github.com/icewind1991/vmt-parser" }
|
vmt-parser = { version = "0.1", git = "https://github.com/icewind1991/vmt-parser" }
|
||||||
|
tf-asset-loader = "0.1"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "parse"
|
name = "parse"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::loader::LoadError;
|
|
||||||
use miette::Diagnostic;
|
use miette::Diagnostic;
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
use tf_asset_loader::LoaderError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vmt_parser::VdfError;
|
use vmt_parser::VdfError;
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
IO(#[from] std::io::Error),
|
IO(#[from] std::io::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Loader(#[from] LoadError),
|
Loader(#[from] LoaderError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Vtf(#[from] vtf::Error),
|
Vtf(#[from] vtf::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
use std::fmt::{Debug, Formatter};
|
|
||||||
use std::fs;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use steamlocate::SteamDir;
|
|
||||||
use thiserror::Error;
|
|
||||||
use tracing::{debug, error, info};
|
|
||||||
use vpk::VPK;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum LoadError {
|
|
||||||
#[error("{0}")]
|
|
||||||
Other(&'static str),
|
|
||||||
#[error(transparent)]
|
|
||||||
IO(#[from] std::io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&'static str> for LoadError {
|
|
||||||
fn from(e: &'static str) -> Self {
|
|
||||||
LoadError::Other(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Loader {
|
|
||||||
tf_dir: PathBuf,
|
|
||||||
download: PathBuf,
|
|
||||||
vpks: Vec<VPK>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Loader {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_struct("Loader")
|
|
||||||
.field("tf_dir", &self.tf_dir)
|
|
||||||
.finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Loader {
|
|
||||||
pub fn new() -> Result<Self, LoadError> {
|
|
||||||
let tf_dir = SteamDir::locate()
|
|
||||||
.ok_or("Can't find steam directory")?
|
|
||||||
.app(&440)
|
|
||||||
.ok_or("Can't find tf2 directory")?
|
|
||||||
.path
|
|
||||||
.join("tf");
|
|
||||||
let download = tf_dir.join("download");
|
|
||||||
let vpks = tf_dir
|
|
||||||
.read_dir()?
|
|
||||||
.filter_map(|item| item.ok())
|
|
||||||
.filter_map(|item| Some(item.path().to_str()?.to_string()))
|
|
||||||
.filter(|path| path.ends_with("dir.vpk"))
|
|
||||||
.map(|path| vpk::from_path(&path))
|
|
||||||
.filter_map(|res| res.ok())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(Loader {
|
|
||||||
tf_dir,
|
|
||||||
download,
|
|
||||||
vpks,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub fn exists(&self, name: &str) -> bool {
|
|
||||||
debug!("loading {}", name);
|
|
||||||
if name.ends_with("bsp") {
|
|
||||||
let path = self.tf_dir.join(name);
|
|
||||||
if path.exists() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
let path = self.download.join(name);
|
|
||||||
if path.exists() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for vpk in self.vpks.iter() {
|
|
||||||
if vpk.tree.contains_key(name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub fn load(&self, name: &str) -> Result<Vec<u8>, LoadError> {
|
|
||||||
debug!("loading {}", name);
|
|
||||||
if name.ends_with("bsp") {
|
|
||||||
let path = self.tf_dir.join(name);
|
|
||||||
if path.exists() {
|
|
||||||
debug!("found in tf2 dir");
|
|
||||||
return Ok(fs::read(path)?);
|
|
||||||
}
|
|
||||||
let path = self.download.join(name);
|
|
||||||
if path.exists() {
|
|
||||||
debug!("found in download dir");
|
|
||||||
return Ok(fs::read(path)?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for vpk in self.vpks.iter() {
|
|
||||||
if let Some(entry) = vpk.tree.get(name) {
|
|
||||||
let data = entry.get()?.into_owned();
|
|
||||||
debug!("got {} bytes from vpk", data.len());
|
|
||||||
return Ok(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info!("Failed to find {} in vpk", name);
|
|
||||||
Err(LoadError::Other("Can't find file in vpks"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_in_paths(&self, name: &str, paths: &[String]) -> Option<String> {
|
|
||||||
for path in paths {
|
|
||||||
let full_path = format!("{}{}", path, name);
|
|
||||||
if self.exists(&full_path) {
|
|
||||||
return Some(full_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::loader::{LoadError, Loader};
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
|
use tf_asset_loader::Loader;
|
||||||
use tracing::{error, instrument};
|
use tracing::{error, instrument};
|
||||||
use vmt_parser::from_str;
|
use vmt_parser::from_str;
|
||||||
use vtf::vtf::VTF;
|
use vtf::vtf::VTF;
|
||||||
|
|
@ -54,8 +54,8 @@ pub fn load_material(
|
||||||
let path = format!("{}.vmt", name.to_ascii_lowercase().trim_end_matches(".vmt"));
|
let path = format!("{}.vmt", name.to_ascii_lowercase().trim_end_matches(".vmt"));
|
||||||
let path = loader
|
let path = loader
|
||||||
.find_in_paths(&path, &dirs)
|
.find_in_paths(&path, &dirs)
|
||||||
.ok_or(LoadError::Other("Can't find file in vpks"))?;
|
.ok_or(Error::Other(format!("Can't find file {}", path)))?;
|
||||||
let raw = loader.load(&path)?;
|
let raw = loader.load(&path)?.expect("didn't find foudn path?");
|
||||||
let vdf = String::from_utf8(raw)?;
|
let vdf = String::from_utf8(raw)?;
|
||||||
|
|
||||||
let material = from_str(&vdf).map_err(|e| {
|
let material = from_str(&vdf).map_err(|e| {
|
||||||
|
|
@ -64,7 +64,9 @@ pub fn load_material(
|
||||||
Error::Other(format!("Failed to load material {}", path))
|
Error::Other(format!("Failed to load material {}", path))
|
||||||
})?;
|
})?;
|
||||||
let material = material.resolve(|path| {
|
let material = material.resolve(|path| {
|
||||||
let data = loader.load(path)?;
|
let data = loader
|
||||||
|
.load(path)?
|
||||||
|
.ok_or(Error::Other(format!("Can't find file {}", path)))?;
|
||||||
let vdf = String::from_utf8(data)?;
|
let vdf = String::from_utf8(data)?;
|
||||||
Ok::<_, Error>(vdf)
|
Ok::<_, Error>(vdf)
|
||||||
})?;
|
})?;
|
||||||
|
|
@ -102,7 +104,9 @@ fn load_texture(name: &str, loader: &Loader) -> Result<DynamicImage, Error> {
|
||||||
"materials/{}.vtf",
|
"materials/{}.vtf",
|
||||||
name.trim_end_matches(".vtf").trim_start_matches('/')
|
name.trim_end_matches(".vtf").trim_start_matches('/')
|
||||||
);
|
);
|
||||||
let mut raw = loader.load(&path)?;
|
let mut raw = loader
|
||||||
|
.load(&path)?
|
||||||
|
.ok_or(Error::Other(format!("Can't find file {}", path)))?;
|
||||||
let vtf = VTF::read(&mut raw)?;
|
let vtf = VTF::read(&mut raw)?;
|
||||||
let image = vtf.highres_image.decode(0)?;
|
let image = vtf.highres_image.decode(0)?;
|
||||||
Ok(image)
|
Ok(image)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
mod convert;
|
mod convert;
|
||||||
#[path = "../common/error.rs"]
|
#[path = "../common/error.rs"]
|
||||||
mod error;
|
mod error;
|
||||||
#[path = "../common/loader.rs"]
|
|
||||||
mod loader;
|
|
||||||
#[path = "../common/materials.rs"]
|
#[path = "../common/materials.rs"]
|
||||||
mod material;
|
mod material;
|
||||||
|
|
||||||
|
|
@ -11,7 +9,6 @@ use gltf_json as json;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use crate::convert::{push_material, push_model};
|
use crate::convert::{push_material, push_model};
|
||||||
use crate::loader::Loader;
|
|
||||||
use crate::material::load_material_fallback;
|
use crate::material::load_material_fallback;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
|
@ -20,6 +17,7 @@ use main_error::MainResult;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use tf_asset_loader::Loader;
|
||||||
use vmdl::Model;
|
use vmdl::Model;
|
||||||
|
|
||||||
fn align_to_multiple_of_four(n: &mut u32) {
|
fn align_to_multiple_of_four(n: &mut u32) {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
#[path = "../common/error.rs"]
|
#[path = "../common/error.rs"]
|
||||||
mod error;
|
mod error;
|
||||||
#[path = "../common/loader.rs"]
|
|
||||||
mod loader;
|
|
||||||
#[path = "../common/materials.rs"]
|
#[path = "../common/materials.rs"]
|
||||||
mod material;
|
mod material;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::loader::Loader;
|
|
||||||
use crate::material::{load_material_fallback, MaterialData};
|
use crate::material::{load_material_fallback, MaterialData};
|
||||||
use image::GenericImageView;
|
use image::GenericImageView;
|
||||||
use std::env::args_os;
|
use std::env::args_os;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use tf_asset_loader::Loader;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use three_d::*;
|
use three_d::*;
|
||||||
use vmdl::{Model, Vector};
|
use vmdl::{Model, Vector};
|
||||||
|
|
@ -59,6 +57,7 @@ fn main() -> Result<(), Error> {
|
||||||
let mut gui = three_d::GUI::new(&context);
|
let mut gui = three_d::GUI::new(&context);
|
||||||
|
|
||||||
let loader = Loader::new().expect("loader");
|
let loader = Loader::new().expect("loader");
|
||||||
|
dbg!(&loader);
|
||||||
let skin_count = source_model.skin_tables().count();
|
let skin_count = source_model.skin_tables().count();
|
||||||
|
|
||||||
let cpu_models = (0..skin_count).map(|skin| model_to_model(&source_model, &loader, skin));
|
let cpu_models = (0..skin_count).map(|skin| model_to_model(&source_model, &loader, skin));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue