From 504f63be549008a546b4d9f68ec45ca3bee406de 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 13:19:29 +0000 Subject: [PATCH] Add support for split .gltf and .bin files (#3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.eirexe.moe/EIREXE/shinespark/pulls/3 Co-authored-by: Álex Román Núñez --- src/fighter/baked_animation.rs | 56 ++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/src/fighter/baked_animation.rs b/src/fighter/baked_animation.rs index 887db06..8c4e2c0 100644 --- a/src/fighter/baked_animation.rs +++ b/src/fighter/baked_animation.rs @@ -3,6 +3,7 @@ use std::{ collections::{HashMap, HashSet}, io, + path::Path, }; use bevy::{ @@ -517,6 +518,7 @@ struct FighterBakeDeclaration { #[derive(Asset, TypePath)] struct FighterBakeSource { model_bytes: Vec, + buffers: Vec>, animations: HashMap, } @@ -550,8 +552,31 @@ impl AssetLoader for FighterBakeSourceLoader { .read_asset_bytes(&manifest.model_path) .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(AssetPath::from_path_buf( + Path::new(&manifest.model_path) + .parent() + .unwrap_or_else(|| Path::new("")) + .join(uri), + )) + .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 +625,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 +681,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(