resource: Create Gltf object, expand GltfScene to collect all node transforms, other qol changes

This commit is contained in:
SeanOMik 2024-03-08 00:20:29 -05:00 committed by SeanOMik
parent c3de9e77db
commit c1b5ca768f
7 changed files with 93 additions and 39 deletions

View File

@ -64,7 +64,7 @@ impl ModelLoader {
}
} */
fn process_node(ctx: &mut GltfLoadContext, materials: &Vec<Material>, gnode: gltf::Node<'_>) -> GltfNode {
fn process_node(ctx: &mut GltfLoadContext, materials: &Vec<ResHandle<Material>>, 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<Material> = gltf.materials()
.map(|mat| Material::from_gltf(&mut context, mat))
let materials: Vec<ResHandle<Material>> = 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<GltfNode> = scene.nodes()
.map(|node| ModelLoader::process_node(&mut context, &materials, node))
@ -199,15 +199,21 @@ 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::<ResHandle<Gltf>>(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());
}
}

View File

@ -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<MeshVertexAttribute, VertexAttributeData>,
pub indices: Option<MeshIndices>,
pub material: Option<Material>,
pub material: Option<ResHandle<Material>>,
}
impl Mesh {

View File

@ -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<GltfScene>,
pub materials: Vec<Material>,
pub scenes: Vec<ResHandle<GltfScene>>,
pub materials: Vec<ResHandle<Material>>,
pub meshes: Vec<ResHandle<Mesh>>,
}
impl Gltf {
/// Collects all Gltf meshes and gets their world Transform.
pub fn collect_world_meshes(&self) -> Vec<(ResHandle<Mesh>, 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
}
}

View File

@ -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)]
@ -20,3 +17,39 @@ pub struct GltfNode {
pub struct GltfScene {
pub nodes: Vec<GltfNode>,
}
impl GltfScene {
fn collect_node(&self, parent_node: &GltfNode, node: &GltfNode) -> Vec<(ResHandle<Mesh>, 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<Mesh>, 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
}
}

View File

@ -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<u8>, offset: usize, length: usize) -> Result<Arc<dyn ResourceStorage>, 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))
}
}

View File

@ -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<T> {
/// 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<T> {
#[derive(Component)]
pub struct ResHandle<T: 'static> {
pub(crate) data: Arc<RwLock<Resource<T>>>,
}
@ -103,18 +106,7 @@ impl<T> ResHandle<T> {
}
/// 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<ResourceDataRef<'a, T>> {
pub fn data_ref<'a>(&'a self) -> Option<ResourceDataRef<'a, T>> {
if self.is_loaded() {
let d = self.data.read().expect("Resource mutex was poisoned!");
Some(ResourceDataRef {

View File

@ -329,7 +329,7 @@ mod tests {
let mut man = ResourceManager::new();
let res = man.request::<Texture>(&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::<Texture>(&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::<Texture>(&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();