mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-03 16:44:11 +02:00
gltf: args and loader
This commit is contained in:
parent
92449728fb
commit
471b4d7644
5 changed files with 183 additions and 54 deletions
118
Cargo.lock
generated
118
Cargo.lock
generated
|
|
@ -67,6 +67,54 @@ version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "approx"
|
name = "approx"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
@ -324,11 +372,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
|
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"clap_lex",
|
"clap_lex 0.2.4",
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
"textwrap 0.16.0",
|
"textwrap 0.16.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.4.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.4.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex 0.6.0",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.40",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
|
|
@ -338,6 +420,12 @@ dependencies = [
|
||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cmake"
|
name = "cmake"
|
||||||
version = "0.1.50"
|
version = "0.1.50"
|
||||||
|
|
@ -399,6 +487,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
@ -492,7 +586,7 @@ dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"cast",
|
"cast",
|
||||||
"ciborium",
|
"ciborium",
|
||||||
"clap",
|
"clap 3.2.25",
|
||||||
"criterion-plot",
|
"criterion-plot",
|
||||||
"itertools 0.10.5",
|
"itertools 0.10.5",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
|
@ -1086,6 +1180,12 @@ version = "0.14.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
|
|
@ -1358,6 +1458,12 @@ version = "0.4.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "main_error"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
|
|
@ -2687,6 +2793,12 @@ version = "2.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -2713,12 +2825,14 @@ dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cgmath",
|
"cgmath",
|
||||||
|
"clap 4.4.11",
|
||||||
"criterion",
|
"criterion",
|
||||||
"gltf",
|
"gltf",
|
||||||
"gltf-json",
|
"gltf-json",
|
||||||
"iai",
|
"iai",
|
||||||
"image 0.23.14",
|
"image 0.23.14",
|
||||||
"itertools 0.12.0",
|
"itertools 0.12.0",
|
||||||
|
"main_error",
|
||||||
"miette",
|
"miette",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"steamlocate",
|
"steamlocate",
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ steamy-vdf = { version = "0.3.0", git = "https://github.com/icewind1991/steamy",
|
||||||
gltf-json = "1.3.0"
|
gltf-json = "1.3.0"
|
||||||
gltf = "1.3.0"
|
gltf = "1.3.0"
|
||||||
image = "0.23.14"
|
image = "0.23.14"
|
||||||
|
clap = { version = "4.4.11", features = ["derive"] }
|
||||||
|
main_error = "0.1.2"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "parse"
|
name = "parse"
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,6 @@ pub enum Error {
|
||||||
Vtf(#[from] vtf::Error),
|
Vtf(#[from] vtf::Error),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Other(&'static str),
|
Other(&'static str),
|
||||||
|
#[error("Skin index out of bounds: {0}, model only has {1} skins")]
|
||||||
|
SkinOutOfBounds(u16, u16),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,27 @@ impl Loader {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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]
|
#[tracing::instrument]
|
||||||
pub fn load(&self, name: &str) -> Result<Vec<u8>, LoadError> {
|
pub fn load(&self, name: &str) -> Result<Vec<u8>, LoadError> {
|
||||||
debug!("loading {}", name);
|
debug!("loading {}", name);
|
||||||
|
|
@ -87,8 +108,8 @@ impl Loader {
|
||||||
|
|
||||||
pub fn load_from_paths(&self, name: &str, paths: &[String]) -> Result<Vec<u8>, LoadError> {
|
pub fn load_from_paths(&self, name: &str, paths: &[String]) -> Result<Vec<u8>, LoadError> {
|
||||||
for path in paths {
|
for path in paths {
|
||||||
if let Ok(data) = self.load(&format!("{}{}", path, name)) {
|
if self.exists(&format!("{}{}", path, name)) {
|
||||||
return Ok(data);
|
return self.load(&format!("{}{}", path, name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error!("Failed to find {} in vpk paths: {}", name, paths.join(", "));
|
error!("Failed to find {} in vpk paths: {}", name, paths.join(", "));
|
||||||
|
|
|
||||||
|
|
@ -10,23 +10,14 @@ use std::fs;
|
||||||
use crate::convert::{push_material, push_model};
|
use crate::convert::{push_material, push_model};
|
||||||
use crate::loader::Loader;
|
use crate::loader::Loader;
|
||||||
use crate::material::load_material_fallback;
|
use crate::material::load_material_fallback;
|
||||||
|
use clap::Parser;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
use gltf_json::Index;
|
use gltf_json::Index;
|
||||||
|
use main_error::MainResult;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::env::args_os;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use vmdl::Model;
|
use vmdl::Model;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
|
||||||
enum Output {
|
|
||||||
/// Output standard glTF.
|
|
||||||
Standard,
|
|
||||||
|
|
||||||
/// Output binary glTF.
|
|
||||||
Binary,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn align_to_multiple_of_four(n: &mut u32) {
|
fn align_to_multiple_of_four(n: &mut u32) {
|
||||||
*n = (*n + 3) & !3;
|
*n = (*n + 3) & !3;
|
||||||
}
|
}
|
||||||
|
|
@ -38,13 +29,17 @@ fn pad_byte_vector(mut vec: Vec<u8>) -> Vec<u8> {
|
||||||
vec
|
vec
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export(model: Model, output: Output) -> Result<(), Error> {
|
fn export(model: Model, skin: u16, target: PathBuf) -> Result<(), Error> {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
let mut views = Vec::new();
|
let mut views = Vec::new();
|
||||||
let mut accessors = Vec::new();
|
let mut accessors = Vec::new();
|
||||||
let mut textures = Vec::new();
|
let mut textures = Vec::new();
|
||||||
let mut images = Vec::new();
|
let mut images = Vec::new();
|
||||||
let skin = model.skin_tables().next().unwrap();
|
|
||||||
|
let skin = model
|
||||||
|
.skin_tables()
|
||||||
|
.nth(skin as usize)
|
||||||
|
.ok_or_else(|| Error::SkinOutOfBounds(skin, model.skin_tables().count() as u16))?;
|
||||||
|
|
||||||
let loader = Loader::new()?;
|
let loader = Loader::new()?;
|
||||||
|
|
||||||
|
|
@ -85,11 +80,7 @@ fn export(model: Model, output: Output) -> Result<(), Error> {
|
||||||
extensions: Default::default(),
|
extensions: Default::default(),
|
||||||
extras: Default::default(),
|
extras: Default::default(),
|
||||||
name: None,
|
name: None,
|
||||||
uri: if output == Output::Standard {
|
uri: None,
|
||||||
Some("buffer0.bin".into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let root = json::Root {
|
let root = json::Root {
|
||||||
|
|
@ -110,18 +101,6 @@ fn export(model: Model, output: Output) -> Result<(), Error> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
match output {
|
|
||||||
Output::Standard => {
|
|
||||||
let _ = fs::create_dir("triangle");
|
|
||||||
|
|
||||||
let writer = fs::File::create("triangle/triangle.gltf").expect("I/O error");
|
|
||||||
json::serialize::to_writer_pretty(writer, &root).expect("Serialization error");
|
|
||||||
|
|
||||||
let bin = pad_byte_vector(buffer);
|
|
||||||
let mut writer = fs::File::create("triangle/buffer0.bin").expect("I/O error");
|
|
||||||
writer.write_all(&bin).expect("I/O error");
|
|
||||||
}
|
|
||||||
Output::Binary => {
|
|
||||||
let json_string = json::serialize::to_string(&root).expect("Serialization error");
|
let json_string = json::serialize::to_string(&root).expect("Serialization error");
|
||||||
let mut json_offset = json_string.len() as u32;
|
let mut json_offset = json_string.len() as u32;
|
||||||
align_to_multiple_of_four(&mut json_offset);
|
align_to_multiple_of_four(&mut json_offset);
|
||||||
|
|
@ -134,17 +113,28 @@ fn export(model: Model, output: Output) -> Result<(), Error> {
|
||||||
bin: Some(Cow::Owned(pad_byte_vector(buffer))),
|
bin: Some(Cow::Owned(pad_byte_vector(buffer))),
|
||||||
json: Cow::Owned(json_string.into_bytes()),
|
json: Cow::Owned(json_string.into_bytes()),
|
||||||
};
|
};
|
||||||
let writer = std::fs::File::create("output.glb").expect("I/O error");
|
let writer = fs::File::create(target).expect("I/O error");
|
||||||
glb.to_writer(writer).expect("glTF binary output error");
|
glb.to_writer(writer).expect("glTF binary output error");
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
#[derive(Parser, Debug)]
|
||||||
let path = PathBuf::from(args_os().nth(1).expect("No model file provided"));
|
#[command(author, version, about, long_about = None)]
|
||||||
let source_model = Model::from_path(&path)?;
|
struct Args {
|
||||||
|
source: PathBuf,
|
||||||
|
target: PathBuf,
|
||||||
|
|
||||||
export(source_model, Output::Binary)?;
|
#[arg(short, long, default_value_t = 0)]
|
||||||
|
skin: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> MainResult {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
let source_model = Model::from_path(&args.source)?;
|
||||||
|
|
||||||
|
export(source_model, args.skin, args.target)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue