From c1b5ca768f9b827f908230188f0e521eaf8b3abe Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Fri, 8 Mar 2024 00:20:29 -0500 Subject: [PATCH] resource: Create Gltf object, expand GltfScene to collect all node transforms, other qol changes --- lyra-resource/src/gltf/loader.rs | 31 +++++++++++-------- lyra-resource/src/gltf/mesh.rs | 6 ++-- lyra-resource/src/gltf/mod.rs | 23 ++++++++++++-- lyra-resource/src/gltf/scene.rs | 43 +++++++++++++++++++++++---- lyra-resource/src/loader/image.rs | 5 ++++ lyra-resource/src/resource.rs | 18 ++++------- lyra-resource/src/resource_manager.rs | 6 ++-- 7 files changed, 93 insertions(+), 39 deletions(-) diff --git a/lyra-resource/src/gltf/loader.rs b/lyra-resource/src/gltf/loader.rs index 20ff5ad..4298756 100644 --- a/lyra-resource/src/gltf/loader.rs +++ b/lyra-resource/src/gltf/loader.rs @@ -64,7 +64,7 @@ impl ModelLoader { } } */ - fn process_node(ctx: &mut GltfLoadContext, materials: &Vec, gnode: gltf::Node<'_>) -> GltfNode { + fn process_node(ctx: &mut GltfLoadContext, materials: &Vec>, gnode: gltf::Node<'_>) -> GltfNode { let mut node = GltfNode::default(); node.transform = { @@ -131,7 +131,7 @@ impl ModelLoader { } for child in gnode.children() { - let mut cmesh = ModelLoader::process_node(ctx, materials, child); + let cmesh = ModelLoader::process_node(ctx, materials, child); node.children.push(cmesh); } @@ -184,13 +184,13 @@ impl ResourceLoader for ModelLoader { }; let start_inst = Instant::now(); - let materials: Vec = gltf.materials() - .map(|mat| Material::from_gltf(&mut context, mat)) + let materials: Vec> = gltf.materials() + .map(|mat| ResHandle::with_data("", Material::from_gltf(&mut context, mat))) .collect(); let mat_time = Instant::now() - start_inst; debug!("Loaded {} materials in {}s", materials.len(), mat_time.as_secs_f32()); - for scene in gltf.scenes() { + for (idx, scene) in gltf.scenes().enumerate() { let start_inst = Instant::now(); let nodes: Vec = scene.nodes() .map(|node| ModelLoader::process_node(&mut context, &materials, node)) @@ -199,14 +199,20 @@ impl ResourceLoader for ModelLoader { debug!("Loaded {} nodes in the scene in {}s", nodes.len(), node_time.as_secs_f32()); - /* debug!("Loaded {} nodes (in {}s), and {} materials (in {}s) from '{}'", nodes.len(), - node_time.as_secs_f32(), materials.len(), mat_time.as_secs_f32(), path); */ - + for mesh in nodes.iter().map(|n| &n.mesh) { + if let Some(mesh) = mesh { + gltf_out.meshes.push(mesh.clone()); + } + } + let scene = GltfScene { nodes, }; + let scene = ResHandle::with_data(&format!("{}:Scene{}", path, idx), scene); gltf_out.scenes.push(scene); } + + gltf_out.materials = materials; Ok(Arc::new(ResHandle::with_data(path, gltf_out))) } @@ -236,10 +242,11 @@ mod tests { let loader = ModelLoader::default(); let gltf = loader.load(&mut manager, &path).unwrap(); let gltf = Arc::downcast::>(gltf.as_arc_any()).unwrap(); - let gltf = gltf.data_ref(); + let gltf = gltf.data_ref().unwrap(); assert_eq!(gltf.scenes.len(), 1); - let scene = &gltf.scenes[0]; + let scene = &gltf.scenes[0] + .data_ref().unwrap(); assert_eq!(scene.nodes.len(), 1); let mnode = &scene.nodes[0]; @@ -249,11 +256,11 @@ mod tests { assert_eq!(mnode.children.len(), 0); let mesh = mnode.mesh.as_ref().unwrap(); - let mesh = mesh.data_ref(); + let mesh = mesh.data_ref().unwrap(); assert!(mesh.position().unwrap().len() > 0); assert!(mesh.normals().unwrap().len() > 0); assert!(mesh.tex_coords().unwrap().len() > 0); assert!(mesh.indices.clone().unwrap().len() > 0); - assert!(mesh.material.as_ref().unwrap().base_color_texture.is_some()); + assert!(mesh.material.as_ref().unwrap().data_ref().unwrap().base_color_texture.is_some()); } } \ No newline at end of file diff --git a/lyra-resource/src/gltf/mesh.rs b/lyra-resource/src/gltf/mesh.rs index 7121e9c..49c559f 100644 --- a/lyra-resource/src/gltf/mesh.rs +++ b/lyra-resource/src/gltf/mesh.rs @@ -1,8 +1,6 @@ use std::collections::HashMap; -use lyra_math::Transform; - -use crate::lyra_engine; +use crate::{lyra_engine, ResHandle}; use super::Material; @@ -89,7 +87,7 @@ pub enum MeshVertexAttribute { pub struct Mesh { pub attributes: HashMap, pub indices: Option, - pub material: Option, + pub material: Option>, } impl Mesh { diff --git a/lyra-resource/src/gltf/mod.rs b/lyra-resource/src/gltf/mod.rs index 0f7c8ac..862acdf 100644 --- a/lyra-resource/src/gltf/mod.rs +++ b/lyra-resource/src/gltf/mod.rs @@ -2,6 +2,7 @@ pub mod loader; pub use loader::*; pub mod material; +use lyra_math::Transform; pub use material::*; pub mod mesh; @@ -10,9 +11,27 @@ pub use mesh::*; pub mod scene; pub use scene::*; +use crate::ResHandle; + /// A loaded Gltf file #[derive(Clone, Default)] pub struct Gltf { - pub scenes: Vec, - pub materials: Vec, + pub scenes: Vec>, + pub materials: Vec>, + pub meshes: Vec>, +} + +impl Gltf { + /// Collects all Gltf meshes and gets their world Transform. + pub fn collect_world_meshes(&self) -> Vec<(ResHandle, Transform)> { + let mut v = vec![]; + + for scene in self.scenes.iter() { + let mut tmp = scene.data_ref() + .unwrap().collect_world_meshes(); + v.append(&mut tmp); + } + + v + } } \ No newline at end of file diff --git a/lyra-resource/src/gltf/scene.rs b/lyra-resource/src/gltf/scene.rs index 8b14456..39f1d12 100644 --- a/lyra-resource/src/gltf/scene.rs +++ b/lyra-resource/src/gltf/scene.rs @@ -1,10 +1,7 @@ -use std::collections::HashMap; - -use lyra_ecs::Component; use lyra_math::Transform; -use super::{Material, Mesh}; -use crate::{lyra_engine, ResHandle}; +use super::Mesh; +use crate::ResHandle; /// A Node in the Gltf file #[derive(Clone, Default)] @@ -19,4 +16,40 @@ pub struct GltfNode { #[derive(Clone)] pub struct GltfScene { pub nodes: Vec, +} + +impl GltfScene { + fn collect_node(&self, parent_node: &GltfNode, node: &GltfNode) -> Vec<(ResHandle, Transform)> { + let mut v = vec![]; + + if let Some(mesh) = &node.mesh { + v.push((mesh.clone(), parent_node.transform + node.transform)); + } + + for child in node.children.iter() { + let mut tmp = self.collect_node(node, child); + v.append(&mut tmp); + } + + v + } + + /// Collects all Gltf meshes and gets their world Transform. + pub fn collect_world_meshes(&self) -> Vec<(ResHandle, Transform)> { + let mut v = vec![]; + + // process the root nodes in the scene + for parent_node in self.nodes.iter() { + if let Some(mesh) = &parent_node.mesh { + v.push((mesh.clone(), parent_node.transform)); + } + + for child in parent_node.children.iter() { + let mut tmp = self.collect_node(parent_node, child); + v.append(&mut tmp); + } + } + + v + } } \ No newline at end of file diff --git a/lyra-resource/src/loader/image.rs b/lyra-resource/src/loader/image.rs index d7c3df7..4a020ac 100644 --- a/lyra-resource/src/loader/image.rs +++ b/lyra-resource/src/loader/image.rs @@ -1,6 +1,7 @@ use std::{fs::File, sync::Arc, io::Read}; use image::ImageError; +use tracing::{debug, trace}; use crate::{resource_manager::ResourceStorage, texture::Texture, resource::ResHandle, ResourceManager}; @@ -68,6 +69,8 @@ impl ResourceLoader for ImageLoader { } fn load_bytes(&self, _resource_manager: &mut ResourceManager, bytes: Vec, offset: usize, length: usize) -> Result, LoaderError> { + trace!("Loading {} bytes as an image", length); + let image = image::load_from_memory(&bytes[offset..(length-offset)]) .map_err(|e| match e { ImageError::IoError(e) => LoaderError::IoError(e), @@ -78,6 +81,8 @@ impl ResourceLoader for ImageLoader { }; let res = ResHandle::with_data(&uuid::Uuid::new_v4().to_string(), texture); + debug!("Finished loading image of {} bytes", length); + Ok(Arc::new(res)) } } diff --git a/lyra-resource/src/resource.rs b/lyra-resource/src/resource.rs index 1423de2..3b7610b 100644 --- a/lyra-resource/src/resource.rs +++ b/lyra-resource/src/resource.rs @@ -1,5 +1,7 @@ use std::{any::Any, sync::{Arc, RwLock}}; +use lyra_ecs::Component; +use crate::lyra_engine; use uuid::Uuid; use crate::ResourceStorage; @@ -38,7 +40,8 @@ pub struct Resource { /// This struct has an inner [`RwLock`] to the resource data, so most methods may be blocking. /// However, the only times it will be blocking is if another thread is reloading the resource /// and has a write lock on the data. This means that most of the time, it is not blocking. -pub struct ResHandle { +#[derive(Component)] +pub struct ResHandle { pub(crate) data: Arc>>, } @@ -103,18 +106,7 @@ impl ResHandle { } /// Get a reference to the data in the resource - /// - /// # Panics - /// Panics if the resource was not loaded yet. - pub fn data_ref<'a>(&'a self) -> ResourceDataRef<'a, T> { - let d = self.data.read().expect("Resource mutex was poisoned!"); - ResourceDataRef { - guard: d - } - } - - /// Attempt to get a borrow to the resource data. Returns `None` if the resource is not loaded. - pub fn try_data_ref<'a>(&'a self) -> Option> { + pub fn data_ref<'a>(&'a self) -> Option> { if self.is_loaded() { let d = self.data.read().expect("Resource mutex was poisoned!"); Some(ResourceDataRef { diff --git a/lyra-resource/src/resource_manager.rs b/lyra-resource/src/resource_manager.rs index 970c629..2069b5e 100644 --- a/lyra-resource/src/resource_manager.rs +++ b/lyra-resource/src/resource_manager.rs @@ -329,7 +329,7 @@ mod tests { let mut man = ResourceManager::new(); let res = man.request::(&get_image("squiggles.png")).unwrap(); assert_eq!(res.state(), ResourceState::Ready); - let img = res.try_data_ref(); + let img = res.data_ref(); img.unwrap(); } @@ -365,7 +365,7 @@ mod tests { let mut man = ResourceManager::new(); let res = man.request::(&get_image("squiggles.png")).unwrap(); assert_eq!(res.state(), ResourceState::Ready); - let img = res.try_data_ref(); + let img = res.data_ref(); img.unwrap(); println!("Path = {}", res.path()); @@ -385,7 +385,7 @@ mod tests { let mut man = ResourceManager::new(); let res = man.request::(&image_path).unwrap(); assert_eq!(res.state(), ResourceState::Ready); - let img = res.try_data_ref(); + let img = res.data_ref(); img.unwrap(); let recv = man.watch(&image_path, false).unwrap();