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();
|
let mut node = GltfNode::default();
|
||||||
|
|
||||||
node.transform = {
|
node.transform = {
|
||||||
|
@ -131,7 +131,7 @@ impl ModelLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
for child in gnode.children() {
|
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);
|
node.children.push(cmesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,13 +184,13 @@ impl ResourceLoader for ModelLoader {
|
||||||
};
|
};
|
||||||
|
|
||||||
let start_inst = Instant::now();
|
let start_inst = Instant::now();
|
||||||
let materials: Vec<Material> = gltf.materials()
|
let materials: Vec<ResHandle<Material>> = gltf.materials()
|
||||||
.map(|mat| Material::from_gltf(&mut context, mat))
|
.map(|mat| ResHandle::with_data("", Material::from_gltf(&mut context, mat)))
|
||||||
.collect();
|
.collect();
|
||||||
let mat_time = Instant::now() - start_inst;
|
let mat_time = Instant::now() - start_inst;
|
||||||
debug!("Loaded {} materials in {}s", materials.len(), mat_time.as_secs_f32());
|
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 start_inst = Instant::now();
|
||||||
let nodes: Vec<GltfNode> = scene.nodes()
|
let nodes: Vec<GltfNode> = scene.nodes()
|
||||||
.map(|node| ModelLoader::process_node(&mut context, &materials, node))
|
.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 the scene in {}s", nodes.len(), node_time.as_secs_f32());
|
||||||
|
|
||||||
/* debug!("Loaded {} nodes (in {}s), and {} materials (in {}s) from '{}'", nodes.len(),
|
for mesh in nodes.iter().map(|n| &n.mesh) {
|
||||||
node_time.as_secs_f32(), materials.len(), mat_time.as_secs_f32(), path); */
|
if let Some(mesh) = mesh {
|
||||||
|
gltf_out.meshes.push(mesh.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let scene = GltfScene {
|
let scene = GltfScene {
|
||||||
nodes,
|
nodes,
|
||||||
};
|
};
|
||||||
|
let scene = ResHandle::with_data(&format!("{}:Scene{}", path, idx), scene);
|
||||||
gltf_out.scenes.push(scene);
|
gltf_out.scenes.push(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gltf_out.materials = materials;
|
||||||
|
|
||||||
Ok(Arc::new(ResHandle::with_data(path, gltf_out)))
|
Ok(Arc::new(ResHandle::with_data(path, gltf_out)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,10 +242,11 @@ mod tests {
|
||||||
let loader = ModelLoader::default();
|
let loader = ModelLoader::default();
|
||||||
let gltf = loader.load(&mut manager, &path).unwrap();
|
let gltf = loader.load(&mut manager, &path).unwrap();
|
||||||
let gltf = Arc::downcast::<ResHandle<Gltf>>(gltf.as_arc_any()).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);
|
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);
|
assert_eq!(scene.nodes.len(), 1);
|
||||||
let mnode = &scene.nodes[0];
|
let mnode = &scene.nodes[0];
|
||||||
|
@ -249,11 +256,11 @@ mod tests {
|
||||||
assert_eq!(mnode.children.len(), 0);
|
assert_eq!(mnode.children.len(), 0);
|
||||||
|
|
||||||
let mesh = mnode.mesh.as_ref().unwrap();
|
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.position().unwrap().len() > 0);
|
||||||
assert!(mesh.normals().unwrap().len() > 0);
|
assert!(mesh.normals().unwrap().len() > 0);
|
||||||
assert!(mesh.tex_coords().unwrap().len() > 0);
|
assert!(mesh.tex_coords().unwrap().len() > 0);
|
||||||
assert!(mesh.indices.clone().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 std::collections::HashMap;
|
||||||
|
|
||||||
use lyra_math::Transform;
|
use crate::{lyra_engine, ResHandle};
|
||||||
|
|
||||||
use crate::lyra_engine;
|
|
||||||
|
|
||||||
use super::Material;
|
use super::Material;
|
||||||
|
|
||||||
|
@ -89,7 +87,7 @@ pub enum MeshVertexAttribute {
|
||||||
pub struct Mesh {
|
pub struct Mesh {
|
||||||
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
|
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
|
||||||
pub indices: Option<MeshIndices>,
|
pub indices: Option<MeshIndices>,
|
||||||
pub material: Option<Material>,
|
pub material: Option<ResHandle<Material>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mesh {
|
impl Mesh {
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub mod loader;
|
||||||
pub use loader::*;
|
pub use loader::*;
|
||||||
|
|
||||||
pub mod material;
|
pub mod material;
|
||||||
|
use lyra_math::Transform;
|
||||||
pub use material::*;
|
pub use material::*;
|
||||||
|
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
|
@ -10,9 +11,27 @@ pub use mesh::*;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
pub use scene::*;
|
pub use scene::*;
|
||||||
|
|
||||||
|
use crate::ResHandle;
|
||||||
|
|
||||||
/// A loaded Gltf file
|
/// A loaded Gltf file
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Gltf {
|
pub struct Gltf {
|
||||||
pub scenes: Vec<GltfScene>,
|
pub scenes: Vec<ResHandle<GltfScene>>,
|
||||||
pub materials: Vec<Material>,
|
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 lyra_math::Transform;
|
||||||
|
|
||||||
use super::{Material, Mesh};
|
use super::Mesh;
|
||||||
use crate::{lyra_engine, ResHandle};
|
use crate::ResHandle;
|
||||||
|
|
||||||
/// A Node in the Gltf file
|
/// A Node in the Gltf file
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
@ -20,3 +17,39 @@ pub struct GltfNode {
|
||||||
pub struct GltfScene {
|
pub struct GltfScene {
|
||||||
pub nodes: Vec<GltfNode>,
|
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 std::{fs::File, sync::Arc, io::Read};
|
||||||
|
|
||||||
use image::ImageError;
|
use image::ImageError;
|
||||||
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
use crate::{resource_manager::ResourceStorage, texture::Texture, resource::ResHandle, ResourceManager};
|
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> {
|
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)])
|
let image = image::load_from_memory(&bytes[offset..(length-offset)])
|
||||||
.map_err(|e| match e {
|
.map_err(|e| match e {
|
||||||
ImageError::IoError(e) => LoaderError::IoError(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);
|
let res = ResHandle::with_data(&uuid::Uuid::new_v4().to_string(), texture);
|
||||||
|
|
||||||
|
debug!("Finished loading image of {} bytes", length);
|
||||||
|
|
||||||
Ok(Arc::new(res))
|
Ok(Arc::new(res))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::{any::Any, sync::{Arc, RwLock}};
|
use std::{any::Any, sync::{Arc, RwLock}};
|
||||||
|
|
||||||
|
use lyra_ecs::Component;
|
||||||
|
use crate::lyra_engine;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::ResourceStorage;
|
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.
|
/// 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
|
/// 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.
|
/// 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>>>,
|
pub(crate) data: Arc<RwLock<Resource<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,18 +106,7 @@ impl<T> ResHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the data in the resource
|
/// Get a reference to the data in the resource
|
||||||
///
|
pub fn data_ref<'a>(&'a self) -> Option<ResourceDataRef<'a, T>> {
|
||||||
/// # 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>> {
|
|
||||||
if self.is_loaded() {
|
if self.is_loaded() {
|
||||||
let d = self.data.read().expect("Resource mutex was poisoned!");
|
let d = self.data.read().expect("Resource mutex was poisoned!");
|
||||||
Some(ResourceDataRef {
|
Some(ResourceDataRef {
|
||||||
|
|
|
@ -329,7 +329,7 @@ mod tests {
|
||||||
let mut man = ResourceManager::new();
|
let mut man = ResourceManager::new();
|
||||||
let res = man.request::<Texture>(&get_image("squiggles.png")).unwrap();
|
let res = man.request::<Texture>(&get_image("squiggles.png")).unwrap();
|
||||||
assert_eq!(res.state(), ResourceState::Ready);
|
assert_eq!(res.state(), ResourceState::Ready);
|
||||||
let img = res.try_data_ref();
|
let img = res.data_ref();
|
||||||
img.unwrap();
|
img.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ mod tests {
|
||||||
let mut man = ResourceManager::new();
|
let mut man = ResourceManager::new();
|
||||||
let res = man.request::<Texture>(&get_image("squiggles.png")).unwrap();
|
let res = man.request::<Texture>(&get_image("squiggles.png")).unwrap();
|
||||||
assert_eq!(res.state(), ResourceState::Ready);
|
assert_eq!(res.state(), ResourceState::Ready);
|
||||||
let img = res.try_data_ref();
|
let img = res.data_ref();
|
||||||
img.unwrap();
|
img.unwrap();
|
||||||
|
|
||||||
println!("Path = {}", res.path());
|
println!("Path = {}", res.path());
|
||||||
|
@ -385,7 +385,7 @@ mod tests {
|
||||||
let mut man = ResourceManager::new();
|
let mut man = ResourceManager::new();
|
||||||
let res = man.request::<Texture>(&image_path).unwrap();
|
let res = man.request::<Texture>(&image_path).unwrap();
|
||||||
assert_eq!(res.state(), ResourceState::Ready);
|
assert_eq!(res.state(), ResourceState::Ready);
|
||||||
let img = res.try_data_ref();
|
let img = res.data_ref();
|
||||||
img.unwrap();
|
img.unwrap();
|
||||||
|
|
||||||
let recv = man.watch(&image_path, false).unwrap();
|
let recv = man.watch(&image_path, false).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue