From 445f249153f6f899e3a949e42013aafdc3db325d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Rom=C3=A1n=20N=C3=BA=C3=B1ez?= Date: Mon, 14 Sep 2026 14:48:10 +0200 Subject: [PATCH] Add support for split .gltf and .bin files --- src/fighter/baked_animation.rs | 60 +++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/src/fighter/baked_animation.rs b/src/fighter/baked_animation.rs index 887db06..50916c0 100644 --- a/src/fighter/baked_animation.rs +++ b/src/fighter/baked_animation.rs @@ -517,6 +517,7 @@ struct FighterBakeDeclaration { #[derive(Asset, TypePath)] struct FighterBakeSource { model_bytes: Vec, + buffers: Vec>, animations: HashMap, } @@ -546,12 +547,38 @@ impl AssetLoader for FighterBakeSourceLoader { let manifest: FighterManifest = ron::de::from_bytes(&manifest_bytes) .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?; + let model_path = load_context + .path() + .resolve_embed_str(&manifest.model_path) + .map_err(|error| io::Error::other(error.to_string()))?; let model_bytes = load_context - .read_asset_bytes(&manifest.model_path) + .read_asset_bytes(model_path.clone_owned()) .await .map_err(|error| io::Error::other(error.to_string()))?; + + let gltf = gltf::Gltf::from_slice(&model_bytes) + .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?; + let mut buffers = Vec::with_capacity(gltf.buffers().len()); + for buffer in gltf.buffers() { + let bytes = match buffer.source() { + gltf::buffer::Source::Uri(uri) => load_context + .read_asset_bytes( + model_path + .resolve_embed_str(uri) + .map_err(|error| io::Error::other(error.to_string()))?, + ) + .await + .map_err(|error| io::Error::other(error.to_string()))?, + gltf::buffer::Source::Bin => gltf.blob.clone().ok_or_else(|| { + io::Error::new(io::ErrorKind::InvalidData, "missing glTF binary blob") + })?, + }; + buffers.push(bytes); + } + Ok(FighterBakeSource { model_bytes, + buffers, animations: manifest.animations, }) } @@ -600,7 +627,7 @@ impl AssetTransformer for FighterBakeTransformer { source: TransformedAsset, _: &'a Self::Settings, ) -> Result, Self::Error> { - let baked = bake_gltf(&source.model_bytes, &source.animations)?; + let baked = bake_gltf(&source.model_bytes, &source.buffers, &source.animations)?; Ok(source.replace_asset(baked)) } } @@ -656,11 +683,36 @@ impl Plugin for BakedAnimationPlugin { fn bake_gltf( bytes: &[u8], + buffer_bytes: &[Vec], animations: &HashMap, ) -> io::Result { - let (document, buffers, _) = gltf::import_slice(bytes) + let gltf = gltf::Gltf::from_slice(bytes) .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?; - bake_gltf_document(document, buffers, animations) + let buffers = gltf + .buffers() + .zip(buffer_bytes) + .map(|(buffer, bytes)| { + if bytes.len() < buffer.length() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!( + "glTF buffer {} is too short: expected {}, got {}", + buffer.index(), + buffer.length(), + bytes.len() + ), + )); + } + Ok(gltf::buffer::Data(bytes.clone())) + }) + .collect::>>()?; + if buffers.len() != gltf.buffers().len() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "glTF buffer data is incomplete", + )); + } + bake_gltf_document(gltf.document, buffers, animations) } fn bake_gltf_document(