Some gltf improvements #4
|
@ -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,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::<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());
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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<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
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue