From 28139fe8d2a5c69cedd2e4710f0e0adb3a152337 Mon Sep 17 00:00:00 2001 From: Mikhail Novikov Date: Tue, 28 May 2024 17:25:00 +0200 Subject: [PATCH 1/8] Add labels to Gltf Node and Mesh assets --- crates/bevy_gltf/src/lib.rs | 4 ++ crates/bevy_gltf/src/loader.rs | 112 +++++++++++++++++---------------- 2 files changed, 61 insertions(+), 55 deletions(-) diff --git a/crates/bevy_gltf/src/lib.rs b/crates/bevy_gltf/src/lib.rs index b95064af9a20b..66f19e44cff68 100644 --- a/crates/bevy_gltf/src/lib.rs +++ b/crates/bevy_gltf/src/lib.rs @@ -111,6 +111,8 @@ pub struct Gltf { /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-node). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfNode { + /// Label of the node, either user defined in GLTF or Node{index}. + pub label: String, /// Direct children of the node. pub children: Vec, /// Mesh of the node. @@ -127,6 +129,8 @@ pub struct GltfNode { /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfMesh { + /// Label of the mesh, either user defined in GLTF or Mesh{index}. + pub label: String, /// Primitives of the glTF mesh. pub primitives: Vec, /// Additional data. diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index bfdec7aaacdc8..368b7e61b9499 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -552,9 +552,11 @@ async fn load_gltf<'a, 'b, 'c>( }); } + let label = mesh_label(&gltf_mesh); let handle = load_context.add_labeled_asset( mesh_label(&gltf_mesh), super::GltfMesh { + label, primitives, extras: get_gltf_extras(gltf_mesh.extras()), }, @@ -570,8 +572,8 @@ async fn load_gltf<'a, 'b, 'c>( for node in gltf.nodes() { let node_label = node_label(&node); nodes_intermediate.push(( - node_label, GltfNode { + label: node_label, children: vec![], mesh: node .mesh() @@ -590,7 +592,7 @@ async fn load_gltf<'a, 'b, 'c>( } let nodes = resolve_node_hierarchy(nodes_intermediate, load_context.path()) .into_iter() - .map(|(label, node)| load_context.add_labeled_asset(label, node)) + .map(|node| load_context.add_labeled_asset(node.label.clone(), node)) .collect::>>(); let named_nodes = named_nodes_intermediate .into_iter() @@ -1630,16 +1632,16 @@ async fn load_buffers( } fn resolve_node_hierarchy( - nodes_intermediate: Vec<(String, GltfNode, Vec)>, + nodes_intermediate: Vec<(GltfNode, Vec)>, asset_path: &Path, -) -> Vec<(String, GltfNode)> { +) -> Vec { let mut has_errored = false; let mut empty_children = VecDeque::new(); let mut parents = vec![None; nodes_intermediate.len()]; let mut unprocessed_nodes = nodes_intermediate .into_iter() .enumerate() - .map(|(i, (label, node, children))| { + .map(|(i, (node, children))| { for child in &children { if let Some(parent) = parents.get_mut(*child) { *parent = Some(i); @@ -1652,20 +1654,19 @@ fn resolve_node_hierarchy( if children.is_empty() { empty_children.push_back(i); } - (i, (label, node, children)) + (i, (node, children)) }) .collect::>(); - let mut nodes = std::collections::HashMap::::new(); + let mut nodes = std::collections::HashMap::::new(); while let Some(index) = empty_children.pop_front() { - let (label, node, children) = unprocessed_nodes.remove(&index).unwrap(); + let (node, children) = unprocessed_nodes.remove(&index).unwrap(); assert!(children.is_empty()); - nodes.insert(index, (label, node)); + nodes.insert(index, node); if let Some(parent_index) = parents[index] { - let (_, parent_node, parent_children) = - unprocessed_nodes.get_mut(&parent_index).unwrap(); + let (parent_node, parent_children) = unprocessed_nodes.get_mut(&parent_index).unwrap(); assert!(parent_children.remove(&index)); - if let Some((_, child_node)) = nodes.get(&index) { + if let Some(child_node) = nodes.get(&index) { parent_node.children.push(child_node.clone()); } if parent_children.is_empty() { @@ -1923,8 +1924,9 @@ mod test { use crate::GltfNode; impl GltfNode { - fn empty() -> Self { + fn with_label(label: String) -> Self { GltfNode { + label, children: vec![], mesh: None, transform: bevy_transform::prelude::Transform::IDENTITY, @@ -1935,87 +1937,87 @@ mod test { #[test] fn node_hierarchy_single_node() { let result = resolve_node_hierarchy( - vec![("l1".to_string(), GltfNode::empty(), vec![])], + vec![(GltfNode::with_label("l1".to_string()), vec![])], PathBuf::new().as_path(), ); assert_eq!(result.len(), 1); - assert_eq!(result[0].0, "l1"); - assert_eq!(result[0].1.children.len(), 0); + assert_eq!(result[0].label, "l1"); + assert_eq!(result[0].children.len(), 0); } #[test] fn node_hierarchy_no_hierarchy() { let result = resolve_node_hierarchy( vec![ - ("l1".to_string(), GltfNode::empty(), vec![]), - ("l2".to_string(), GltfNode::empty(), vec![]), + (GltfNode::with_label("l1".to_string()), vec![]), + (GltfNode::with_label("l2".to_string()), vec![]), ], PathBuf::new().as_path(), ); assert_eq!(result.len(), 2); - assert_eq!(result[0].0, "l1"); - assert_eq!(result[0].1.children.len(), 0); - assert_eq!(result[1].0, "l2"); - assert_eq!(result[1].1.children.len(), 0); + assert_eq!(result[0].label, "l1"); + assert_eq!(result[0].children.len(), 0); + assert_eq!(result[1].label, "l2"); + assert_eq!(result[1].children.len(), 0); } #[test] fn node_hierarchy_simple_hierarchy() { let result = resolve_node_hierarchy( vec![ - ("l1".to_string(), GltfNode::empty(), vec![1]), - ("l2".to_string(), GltfNode::empty(), vec![]), + (GltfNode::with_label("l1".to_string()), vec![1]), + (GltfNode::with_label("l2".to_string()), vec![]), ], PathBuf::new().as_path(), ); assert_eq!(result.len(), 2); - assert_eq!(result[0].0, "l1"); - assert_eq!(result[0].1.children.len(), 1); - assert_eq!(result[1].0, "l2"); - assert_eq!(result[1].1.children.len(), 0); + assert_eq!(result[0].label, "l1"); + assert_eq!(result[0].children.len(), 1); + assert_eq!(result[1].label, "l2"); + assert_eq!(result[1].children.len(), 0); } #[test] fn node_hierarchy_hierarchy() { let result = resolve_node_hierarchy( vec![ - ("l1".to_string(), GltfNode::empty(), vec![1]), - ("l2".to_string(), GltfNode::empty(), vec![2]), - ("l3".to_string(), GltfNode::empty(), vec![3, 4, 5]), - ("l4".to_string(), GltfNode::empty(), vec![6]), - ("l5".to_string(), GltfNode::empty(), vec![]), - ("l6".to_string(), GltfNode::empty(), vec![]), - ("l7".to_string(), GltfNode::empty(), vec![]), + (GltfNode::with_label("l1".to_string()), vec![1]), + (GltfNode::with_label("l2".to_string()), vec![2]), + (GltfNode::with_label("l3".to_string()), vec![3, 4, 5]), + (GltfNode::with_label("l4".to_string()), vec![6]), + (GltfNode::with_label("l5".to_string()), vec![]), + (GltfNode::with_label("l6".to_string()), vec![]), + (GltfNode::with_label("l7".to_string()), vec![]), ], PathBuf::new().as_path(), ); assert_eq!(result.len(), 7); - assert_eq!(result[0].0, "l1"); - assert_eq!(result[0].1.children.len(), 1); - assert_eq!(result[1].0, "l2"); - assert_eq!(result[1].1.children.len(), 1); - assert_eq!(result[2].0, "l3"); - assert_eq!(result[2].1.children.len(), 3); - assert_eq!(result[3].0, "l4"); - assert_eq!(result[3].1.children.len(), 1); - assert_eq!(result[4].0, "l5"); - assert_eq!(result[4].1.children.len(), 0); - assert_eq!(result[5].0, "l6"); - assert_eq!(result[5].1.children.len(), 0); - assert_eq!(result[6].0, "l7"); - assert_eq!(result[6].1.children.len(), 0); + assert_eq!(result[0].label, "l1"); + assert_eq!(result[0].children.len(), 1); + assert_eq!(result[1].label, "l2"); + assert_eq!(result[1].children.len(), 1); + assert_eq!(result[2].label, "l3"); + assert_eq!(result[2].children.len(), 3); + assert_eq!(result[3].label, "l4"); + assert_eq!(result[3].children.len(), 1); + assert_eq!(result[4].label, "l5"); + assert_eq!(result[4].children.len(), 0); + assert_eq!(result[5].label, "l6"); + assert_eq!(result[5].children.len(), 0); + assert_eq!(result[6].label, "l7"); + assert_eq!(result[6].children.len(), 0); } #[test] fn node_hierarchy_cyclic() { let result = resolve_node_hierarchy( vec![ - ("l1".to_string(), GltfNode::empty(), vec![1]), - ("l2".to_string(), GltfNode::empty(), vec![0]), + (GltfNode::with_label("l1".to_string()), vec![1]), + (GltfNode::with_label("l2".to_string()), vec![0]), ], PathBuf::new().as_path(), ); @@ -2027,14 +2029,14 @@ mod test { fn node_hierarchy_missing_node() { let result = resolve_node_hierarchy( vec![ - ("l1".to_string(), GltfNode::empty(), vec![2]), - ("l2".to_string(), GltfNode::empty(), vec![]), + (GltfNode::with_label("l1".to_string()), vec![2]), + (GltfNode::with_label("l2".to_string()), vec![]), ], PathBuf::new().as_path(), ); assert_eq!(result.len(), 1); - assert_eq!(result[0].0, "l2"); - assert_eq!(result[0].1.children.len(), 0); + assert_eq!(result[0].label, "l2"); + assert_eq!(result[0].children.len(), 0); } } From 98bf1e6699b3c800525de0862446cc1faca56a6d Mon Sep 17 00:00:00 2001 From: Mikhail Novikov Date: Wed, 29 May 2024 11:40:28 +0200 Subject: [PATCH 2/8] Fix labeling logic --- crates/bevy_gltf/src/lib.rs | 76 +++++++++++++++++++++-- crates/bevy_gltf/src/loader.rs | 106 ++++++++++++++------------------- 2 files changed, 117 insertions(+), 65 deletions(-) diff --git a/crates/bevy_gltf/src/lib.rs b/crates/bevy_gltf/src/lib.rs index 66f19e44cff68..03ebb0bf3e19d 100644 --- a/crates/bevy_gltf/src/lib.rs +++ b/crates/bevy_gltf/src/lib.rs @@ -111,8 +111,10 @@ pub struct Gltf { /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-node). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfNode { - /// Label of the node, either user defined in GLTF or Node{index}. - pub label: String, + /// A user defined node name from GLTF + pub name: Option, + /// Index of the node inside the scene + pub index: usize, /// Direct children of the node. pub children: Vec, /// Mesh of the node. @@ -123,20 +125,86 @@ pub struct GltfNode { pub extras: Option, } +impl GltfNode { + /// Create a node extracting name and index from gltf def + pub fn new( + node: &gltf::Node, + children: Vec, + mesh: Option>, + transform: bevy_transform::prelude::Transform, + extras: Option, + ) -> Self { + Self { + index: node.index(), + name: node.name().map(|s| s.to_string()), + children, + mesh, + transform, + extras, + } + } + + /// Computed name for a node - either a user defined name or a generated name from index + pub fn name(&self) -> String { + if let Some(name) = &self.name { + name.clone() + } else { + format!("GltfNode{}", self.index) + } + } + + /// Computed asset label for node based on its index in the scene + pub fn label(&self) -> String { + format!("Node{}", self.index) + } +} + /// A glTF mesh, which may consist of multiple [`GltfPrimitives`](GltfPrimitive) /// and an optional [`GltfExtras`]. /// /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfMesh { - /// Label of the mesh, either user defined in GLTF or Mesh{index}. - pub label: String, + /// A user defined mesh name from GLTF + pub name: Option, + /// Index of the mesh inside the scene + pub index: usize, /// Primitives of the glTF mesh. pub primitives: Vec, /// Additional data. pub extras: Option, } +impl GltfMesh { + /// Create a mesh extracting name and index from gltf def + pub fn new( + mesh: &gltf::Mesh, + primitives: Vec, + extras: Option, + ) -> Self { + Self { + index: mesh.index(), + name: mesh.name().map(|s| s.to_string()), + primitives, + extras, + } + } + + /// Computed name for a mesh - either a user defined name or a generated name from index + pub fn name(&self) -> String { + if let Some(name) = &self.name { + name.clone() + } else { + format!("GltfMesh{}", self.index) + } + } + + /// Computed asset label for mesh based on its index in the scene + pub fn label(&self) -> String { + format!("Mesh{}", self.index) + } +} + /// Part of a [`GltfMesh`] that consists of a [`Mesh`], an optional [`StandardMaterial`] and [`GltfExtras`]. /// /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh-primitive). diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 368b7e61b9499..31f7c43c6ab97 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -552,15 +552,10 @@ async fn load_gltf<'a, 'b, 'c>( }); } - let label = mesh_label(&gltf_mesh); - let handle = load_context.add_labeled_asset( - mesh_label(&gltf_mesh), - super::GltfMesh { - label, - primitives, - extras: get_gltf_extras(gltf_mesh.extras()), - }, - ); + let mesh = + super::GltfMesh::new(&gltf_mesh, primitives, get_gltf_extras(gltf_mesh.extras())); + + let handle = load_context.add_labeled_asset(mesh.label(), mesh); if let Some(name) = gltf_mesh.name() { named_meshes.insert(name.into(), handle.clone()); } @@ -570,18 +565,16 @@ async fn load_gltf<'a, 'b, 'c>( let mut nodes_intermediate = vec![]; let mut named_nodes_intermediate = HashMap::default(); for node in gltf.nodes() { - let node_label = node_label(&node); nodes_intermediate.push(( - GltfNode { - label: node_label, - children: vec![], - mesh: node - .mesh() + GltfNode::new( + &node, + vec![], + node.mesh() .map(|mesh| mesh.index()) - .and_then(|i| meshes.get(i).cloned()), - transform: node_transform(&node), - extras: get_gltf_extras(node.extras()), - }, + .and_then(|i: usize| meshes.get(i).cloned()), + node_transform(&node), + get_gltf_extras(node.extras()), + ), node.children() .map(|child| child.index()) .collect::>(), @@ -592,7 +585,7 @@ async fn load_gltf<'a, 'b, 'c>( } let nodes = resolve_node_hierarchy(nodes_intermediate, load_context.path()) .into_iter() - .map(|node| load_context.add_labeled_asset(node.label.clone(), node)) + .map(|node| load_context.add_labeled_asset(node.label(), node)) .collect::>>(); let named_nodes = named_nodes_intermediate .into_iter() @@ -1415,11 +1408,6 @@ fn load_node( } } -/// Returns the label for the `mesh`. -fn mesh_label(mesh: &gltf::Mesh) -> String { - format!("Mesh{}", mesh.index()) -} - /// Returns the label for the `mesh` and `primitive`. fn primitive_label(mesh: &gltf::Mesh, primitive: &Primitive) -> String { format!("Mesh{}/Primitive{}", mesh.index(), primitive.index()) @@ -1501,11 +1489,6 @@ fn texture_handle_from_info( texture_handle(load_context, &texture) } -/// Returns the label for the `node`. -fn node_label(node: &Node) -> String { - format!("Node{}", node.index()) -} - /// Returns the label for the `scene`. fn scene_label(scene: &gltf::Scene) -> String { format!("Scene{}", scene.index()) @@ -1924,9 +1907,10 @@ mod test { use crate::GltfNode; impl GltfNode { - fn with_label(label: String) -> Self { + fn with_generated_name(index: usize) -> Self { GltfNode { - label, + index, + name: Some(format!("l{}", index)), children: vec![], mesh: None, transform: bevy_transform::prelude::Transform::IDENTITY, @@ -1937,12 +1921,12 @@ mod test { #[test] fn node_hierarchy_single_node() { let result = resolve_node_hierarchy( - vec![(GltfNode::with_label("l1".to_string()), vec![])], + vec![(GltfNode::with_generated_name(1), vec![])], PathBuf::new().as_path(), ); assert_eq!(result.len(), 1); - assert_eq!(result[0].label, "l1"); + assert_eq!(result[0].name(), "l1"); assert_eq!(result[0].children.len(), 0); } @@ -1950,16 +1934,16 @@ mod test { fn node_hierarchy_no_hierarchy() { let result = resolve_node_hierarchy( vec![ - (GltfNode::with_label("l1".to_string()), vec![]), - (GltfNode::with_label("l2".to_string()), vec![]), + (GltfNode::with_generated_name(1), vec![]), + (GltfNode::with_generated_name(2), vec![]), ], PathBuf::new().as_path(), ); assert_eq!(result.len(), 2); - assert_eq!(result[0].label, "l1"); + assert_eq!(result[0].name(), "l1"); assert_eq!(result[0].children.len(), 0); - assert_eq!(result[1].label, "l2"); + assert_eq!(result[1].name(), "l2"); assert_eq!(result[1].children.len(), 0); } @@ -1967,16 +1951,16 @@ mod test { fn node_hierarchy_simple_hierarchy() { let result = resolve_node_hierarchy( vec![ - (GltfNode::with_label("l1".to_string()), vec![1]), - (GltfNode::with_label("l2".to_string()), vec![]), + (GltfNode::with_generated_name(1), vec![1]), + (GltfNode::with_generated_name(2), vec![]), ], PathBuf::new().as_path(), ); assert_eq!(result.len(), 2); - assert_eq!(result[0].label, "l1"); + assert_eq!(result[0].name(), "l1"); assert_eq!(result[0].children.len(), 1); - assert_eq!(result[1].label, "l2"); + assert_eq!(result[1].name(), "l2"); assert_eq!(result[1].children.len(), 0); } @@ -1984,31 +1968,31 @@ mod test { fn node_hierarchy_hierarchy() { let result = resolve_node_hierarchy( vec![ - (GltfNode::with_label("l1".to_string()), vec![1]), - (GltfNode::with_label("l2".to_string()), vec![2]), - (GltfNode::with_label("l3".to_string()), vec![3, 4, 5]), - (GltfNode::with_label("l4".to_string()), vec![6]), - (GltfNode::with_label("l5".to_string()), vec![]), - (GltfNode::with_label("l6".to_string()), vec![]), - (GltfNode::with_label("l7".to_string()), vec![]), + (GltfNode::with_generated_name(1), vec![1]), + (GltfNode::with_generated_name(2), vec![2]), + (GltfNode::with_generated_name(3), vec![3, 4, 5]), + (GltfNode::with_generated_name(4), vec![6]), + (GltfNode::with_generated_name(5), vec![]), + (GltfNode::with_generated_name(6), vec![]), + (GltfNode::with_generated_name(7), vec![]), ], PathBuf::new().as_path(), ); assert_eq!(result.len(), 7); - assert_eq!(result[0].label, "l1"); + assert_eq!(result[0].name(), "l1"); assert_eq!(result[0].children.len(), 1); - assert_eq!(result[1].label, "l2"); + assert_eq!(result[1].name(), "l2"); assert_eq!(result[1].children.len(), 1); - assert_eq!(result[2].label, "l3"); + assert_eq!(result[2].name(), "l3"); assert_eq!(result[2].children.len(), 3); - assert_eq!(result[3].label, "l4"); + assert_eq!(result[3].name(), "l4"); assert_eq!(result[3].children.len(), 1); - assert_eq!(result[4].label, "l5"); + assert_eq!(result[4].name(), "l5"); assert_eq!(result[4].children.len(), 0); - assert_eq!(result[5].label, "l6"); + assert_eq!(result[5].name(), "l6"); assert_eq!(result[5].children.len(), 0); - assert_eq!(result[6].label, "l7"); + assert_eq!(result[6].name(), "l7"); assert_eq!(result[6].children.len(), 0); } @@ -2016,8 +2000,8 @@ mod test { fn node_hierarchy_cyclic() { let result = resolve_node_hierarchy( vec![ - (GltfNode::with_label("l1".to_string()), vec![1]), - (GltfNode::with_label("l2".to_string()), vec![0]), + (GltfNode::with_generated_name(1), vec![1]), + (GltfNode::with_generated_name(2), vec![0]), ], PathBuf::new().as_path(), ); @@ -2029,14 +2013,14 @@ mod test { fn node_hierarchy_missing_node() { let result = resolve_node_hierarchy( vec![ - (GltfNode::with_label("l1".to_string()), vec![2]), - (GltfNode::with_label("l2".to_string()), vec![]), + (GltfNode::with_generated_name(1), vec![2]), + (GltfNode::with_generated_name(2), vec![]), ], PathBuf::new().as_path(), ); assert_eq!(result.len(), 1); - assert_eq!(result[0].label, "l2"); + assert_eq!(result[0].name(), "l2"); assert_eq!(result[0].children.len(), 0); } } From c72bd9753600f4fa7fd0af7e823114675f11ba96 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 29 May 2024 18:39:00 -0400 Subject: [PATCH 3/8] glTF nit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François Mockers --- crates/bevy_gltf/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_gltf/src/lib.rs b/crates/bevy_gltf/src/lib.rs index 03ebb0bf3e19d..57617861d4c59 100644 --- a/crates/bevy_gltf/src/lib.rs +++ b/crates/bevy_gltf/src/lib.rs @@ -111,7 +111,7 @@ pub struct Gltf { /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-node). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfNode { - /// A user defined node name from GLTF + /// A user defined node name from glTF pub name: Option, /// Index of the node inside the scene pub index: usize, @@ -126,7 +126,7 @@ pub struct GltfNode { } impl GltfNode { - /// Create a node extracting name and index from gltf def + /// Create a node extracting name and index from glTF def pub fn new( node: &gltf::Node, children: Vec, @@ -165,7 +165,7 @@ impl GltfNode { /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfMesh { - /// A user defined mesh name from GLTF + /// A user defined mesh name from glTF pub name: Option, /// Index of the mesh inside the scene pub index: usize, @@ -176,7 +176,7 @@ pub struct GltfMesh { } impl GltfMesh { - /// Create a mesh extracting name and index from gltf def + /// Create a mesh extracting name and index from glTF def pub fn new( mesh: &gltf::Mesh, primitives: Vec, From abd80d6fe085b292b0aa064e8ce03df5010b0e93 Mon Sep 17 00:00:00 2001 From: Mikhail Novikov Date: Tue, 4 Jun 2024 17:12:08 +0200 Subject: [PATCH 4/8] Store generated label and node inside gltf objects --- crates/bevy_gltf/src/lib.rs | 62 +++++++++++++++------------------- crates/bevy_gltf/src/loader.rs | 31 +++++++++-------- 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/crates/bevy_gltf/src/lib.rs b/crates/bevy_gltf/src/lib.rs index 03ebb0bf3e19d..369576bcd0b32 100644 --- a/crates/bevy_gltf/src/lib.rs +++ b/crates/bevy_gltf/src/lib.rs @@ -111,10 +111,16 @@ pub struct Gltf { /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-node). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfNode { - /// A user defined node name from GLTF - pub name: Option, /// Index of the node inside the scene pub index: usize, + /// Computed name for a node - either a user defined name or a generated name from index + pub name: String, + /// Subasset label for this node within the GLTF parent asset. + /// + /// ``` + /// asset_server.load(format!("my_glft.glft#{}", node.asset_label()); + /// ``` + pub asset_label: String, /// Direct children of the node. pub children: Vec, /// Mesh of the node. @@ -136,27 +142,18 @@ impl GltfNode { ) -> Self { Self { index: node.index(), - name: node.name().map(|s| s.to_string()), + asset_label: format!("Node{}", node.index()), + name: if let Some(name) = node.name() { + name.to_string() + } else { + format!("GltfNode{}", node.index()) + }, children, mesh, transform, extras, } } - - /// Computed name for a node - either a user defined name or a generated name from index - pub fn name(&self) -> String { - if let Some(name) = &self.name { - name.clone() - } else { - format!("GltfNode{}", self.index) - } - } - - /// Computed asset label for node based on its index in the scene - pub fn label(&self) -> String { - format!("Node{}", self.index) - } } /// A glTF mesh, which may consist of multiple [`GltfPrimitives`](GltfPrimitive) @@ -165,10 +162,16 @@ impl GltfNode { /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfMesh { - /// A user defined mesh name from GLTF - pub name: Option, /// Index of the mesh inside the scene pub index: usize, + /// Computed name for a mesh - either a user defined name or a generated name from index + pub name: String, + /// Subasset label for this mesh within the GLTF parent asset. + /// + /// ``` + /// asset_server.load(format!("my_glft.glft#{}", mesh.asset_label()); + /// ``` + pub asset_label: String, /// Primitives of the glTF mesh. pub primitives: Vec, /// Additional data. @@ -184,25 +187,16 @@ impl GltfMesh { ) -> Self { Self { index: mesh.index(), - name: mesh.name().map(|s| s.to_string()), + asset_label: format!("Mesh{}", mesh.index()), + name: if let Some(name) = mesh.name() { + name.to_string() + } else { + format!("GltfMesh{}", mesh.index()) + }, primitives, extras, } } - - /// Computed name for a mesh - either a user defined name or a generated name from index - pub fn name(&self) -> String { - if let Some(name) = &self.name { - name.clone() - } else { - format!("GltfMesh{}", self.index) - } - } - - /// Computed asset label for mesh based on its index in the scene - pub fn label(&self) -> String { - format!("Mesh{}", self.index) - } } /// Part of a [`GltfMesh`] that consists of a [`Mesh`], an optional [`StandardMaterial`] and [`GltfExtras`]. diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 31f7c43c6ab97..94b4095867347 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -555,7 +555,7 @@ async fn load_gltf<'a, 'b, 'c>( let mesh = super::GltfMesh::new(&gltf_mesh, primitives, get_gltf_extras(gltf_mesh.extras())); - let handle = load_context.add_labeled_asset(mesh.label(), mesh); + let handle = load_context.add_labeled_asset(mesh.asset_label.clone(), mesh); if let Some(name) = gltf_mesh.name() { named_meshes.insert(name.into(), handle.clone()); } @@ -1910,7 +1910,8 @@ mod test { fn with_generated_name(index: usize) -> Self { GltfNode { index, - name: Some(format!("l{}", index)), + asset_label: format!("Node{}", index), + name: format!("l{}", index), children: vec![], mesh: None, transform: bevy_transform::prelude::Transform::IDENTITY, @@ -1926,7 +1927,7 @@ mod test { ); assert_eq!(result.len(), 1); - assert_eq!(result[0].name(), "l1"); + assert_eq!(result[0].name, "l1"); assert_eq!(result[0].children.len(), 0); } @@ -1941,9 +1942,9 @@ mod test { ); assert_eq!(result.len(), 2); - assert_eq!(result[0].name(), "l1"); + assert_eq!(result[0].name, "l1"); assert_eq!(result[0].children.len(), 0); - assert_eq!(result[1].name(), "l2"); + assert_eq!(result[1].name, "l2"); assert_eq!(result[1].children.len(), 0); } @@ -1958,9 +1959,9 @@ mod test { ); assert_eq!(result.len(), 2); - assert_eq!(result[0].name(), "l1"); + assert_eq!(result[0].name, "l1"); assert_eq!(result[0].children.len(), 1); - assert_eq!(result[1].name(), "l2"); + assert_eq!(result[1].name, "l2"); assert_eq!(result[1].children.len(), 0); } @@ -1980,19 +1981,19 @@ mod test { ); assert_eq!(result.len(), 7); - assert_eq!(result[0].name(), "l1"); + assert_eq!(result[0].name, "l1"); assert_eq!(result[0].children.len(), 1); - assert_eq!(result[1].name(), "l2"); + assert_eq!(result[1].name, "l2"); assert_eq!(result[1].children.len(), 1); - assert_eq!(result[2].name(), "l3"); + assert_eq!(result[2].name, "l3"); assert_eq!(result[2].children.len(), 3); - assert_eq!(result[3].name(), "l4"); + assert_eq!(result[3].name, "l4"); assert_eq!(result[3].children.len(), 1); - assert_eq!(result[4].name(), "l5"); + assert_eq!(result[4].name, "l5"); assert_eq!(result[4].children.len(), 0); - assert_eq!(result[5].name(), "l6"); + assert_eq!(result[5].name, "l6"); assert_eq!(result[5].children.len(), 0); - assert_eq!(result[6].name(), "l7"); + assert_eq!(result[6].name, "l7"); assert_eq!(result[6].children.len(), 0); } @@ -2020,7 +2021,7 @@ mod test { ); assert_eq!(result.len(), 1); - assert_eq!(result[0].name(), "l2"); + assert_eq!(result[0].name, "l2"); assert_eq!(result[0].children.len(), 0); } } From 508733726cb215935dc8d3e8f20a55f1c3d4667a Mon Sep 17 00:00:00 2001 From: Mikhail Novikov Date: Wed, 5 Jun 2024 10:38:58 +0200 Subject: [PATCH 5/8] Fix lib --- crates/bevy_gltf/src/lib.rs | 50 ++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/crates/bevy_gltf/src/lib.rs b/crates/bevy_gltf/src/lib.rs index cb8e171a41cfe..720e2652fd2f0 100644 --- a/crates/bevy_gltf/src/lib.rs +++ b/crates/bevy_gltf/src/lib.rs @@ -214,7 +214,7 @@ pub struct GltfNode { /// ``` /// asset_server.load(format!("my_glft.glft#{}", node.asset_label()); /// ``` - pub asset_label: String, + pub asset_label: GltfAssetLabel, /// Direct children of the node. pub children: Vec, /// Mesh of the node. @@ -236,7 +236,7 @@ impl GltfNode { ) -> Self { Self { index: node.index(), - asset_label: format!("Node{}", node.index()), + asset_label: GltfAssetLabel::Node(node.index()), name: if let Some(name) = node.name() { name.to_string() } else { @@ -265,7 +265,7 @@ pub struct GltfMesh { /// ``` /// asset_server.load(format!("my_glft.glft#{}", mesh.asset_label()); /// ``` - pub asset_label: String, + pub asset_label: GltfAssetLabel, /// Primitives of the glTF mesh. pub primitives: Vec, /// Additional data. @@ -281,7 +281,7 @@ impl GltfMesh { ) -> Self { Self { index: mesh.index(), - asset_label: format!("Mesh{}", mesh.index()), + asset_label: GltfAssetLabel::Mesh(mesh.index()), name: if let Some(name) = mesh.name() { name.to_string() } else { @@ -298,6 +298,16 @@ impl GltfMesh { /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh-primitive). #[derive(Asset, Debug, Clone, TypePath)] pub struct GltfPrimitive { + /// Index of the primitive inside the mesh + pub index: usize, + /// Computed name for a primitive - either a user defined primitive name from gLTF or a generated name from index + pub name: String, + /// Subasset label for this mesh within the gLTF parent asset. + /// + /// ``` + /// asset_server.load(format!("my_glft.glft#{}", primitive.asset_label()); + /// ``` + pub asset_label: GltfAssetLabel, /// Topology to be rendered. pub mesh: Handle, /// Material to apply to the `mesh`. @@ -308,6 +318,38 @@ pub struct GltfPrimitive { pub material_extras: Option, } +impl GltfPrimitive { + /// Create a primitive extracting name and index from glTF def + pub fn new( + gltf_mesh: &gltf::Mesh, + gltf_primitive: &gltf::Primitive, + mesh: Handle, + material: Option>, + extras: Option, + material_extras: Option, + ) -> Self { + GltfPrimitive { + index: gltf_primitive.index(), + name: { + let mesh_name = gltf_mesh.name().unwrap_or("Mesh"); + if gltf_mesh.primitives().len() > 1 { + format!("{}.{}", mesh_name, gltf_primitive.index()) + } else { + mesh_name.to_string() + } + }, + asset_label: GltfAssetLabel::Primitive { + mesh: gltf_mesh.index(), + primitive: gltf_primitive.index(), + }, + mesh, + material, + extras, + material_extras, + } + } +} + /// Additional untyped data that can be present on most glTF types at the primitive level. /// /// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras). From 4c0a613ae9c95be96dd2feee436cd289c567edf0 Mon Sep 17 00:00:00 2001 From: Mikhail Novikov Date: Wed, 5 Jun 2024 11:09:21 +0200 Subject: [PATCH 6/8] Fix label in test --- crates/bevy_gltf/src/loader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 1c7564eefe74e..c4426026c92de 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -1990,7 +1990,7 @@ mod test { fn with_generated_name(index: usize) -> Self { GltfNode { index, - asset_label: format!("Node{}", index), + asset_label: crate::GltfAssetLabel::Node(index), name: format!("l{}", index), children: vec![], mesh: None, From 14ad9f9df419ecd0ce9432c7d3a267f97368b19d Mon Sep 17 00:00:00 2001 From: Mikhail Novikov Date: Wed, 5 Jun 2024 11:48:00 +0200 Subject: [PATCH 7/8] Doctest fix? --- crates/bevy_gltf/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bevy_gltf/src/lib.rs b/crates/bevy_gltf/src/lib.rs index 720e2652fd2f0..3e28a5bba08ad 100644 --- a/crates/bevy_gltf/src/lib.rs +++ b/crates/bevy_gltf/src/lib.rs @@ -211,8 +211,8 @@ pub struct GltfNode { pub name: String, /// Subasset label for this node within the gLTF parent asset. /// - /// ``` - /// asset_server.load(format!("my_glft.glft#{}", node.asset_label()); + /// ```no_run + /// asset_server.load(format!("my_glft.glft#{}", node.asset_label())); /// ``` pub asset_label: GltfAssetLabel, /// Direct children of the node. @@ -262,8 +262,8 @@ pub struct GltfMesh { pub name: String, /// Subasset label for this mesh within the gLTF parent asset. /// - /// ``` - /// asset_server.load(format!("my_glft.glft#{}", mesh.asset_label()); + /// ```no_run + /// asset_server.load(format!("my_glft.glft#{}", mesh.asset_label())); /// ``` pub asset_label: GltfAssetLabel, /// Primitives of the glTF mesh. @@ -304,8 +304,8 @@ pub struct GltfPrimitive { pub name: String, /// Subasset label for this mesh within the gLTF parent asset. /// - /// ``` - /// asset_server.load(format!("my_glft.glft#{}", primitive.asset_label()); + /// ```no_run + /// asset_server.load(format!("my_glft.glft#{}", primitive.asset_label())); /// ``` pub asset_label: GltfAssetLabel, /// Topology to be rendered. From d408b74f684af81ffa256b076b476417a3961b17 Mon Sep 17 00:00:00 2001 From: Mikhail Novikov Date: Wed, 5 Jun 2024 11:50:53 +0200 Subject: [PATCH 8/8] Remove redundant doctests --- crates/bevy_gltf/src/lib.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/crates/bevy_gltf/src/lib.rs b/crates/bevy_gltf/src/lib.rs index 3e28a5bba08ad..faf25e58a7231 100644 --- a/crates/bevy_gltf/src/lib.rs +++ b/crates/bevy_gltf/src/lib.rs @@ -210,10 +210,6 @@ pub struct GltfNode { /// Computed name for a node - either a user defined node name from gLTF or a generated name from index pub name: String, /// Subasset label for this node within the gLTF parent asset. - /// - /// ```no_run - /// asset_server.load(format!("my_glft.glft#{}", node.asset_label())); - /// ``` pub asset_label: GltfAssetLabel, /// Direct children of the node. pub children: Vec, @@ -261,10 +257,6 @@ pub struct GltfMesh { /// Computed name for a mesh - either a user defined mesh name from gLTF or a generated name from index pub name: String, /// Subasset label for this mesh within the gLTF parent asset. - /// - /// ```no_run - /// asset_server.load(format!("my_glft.glft#{}", mesh.asset_label())); - /// ``` pub asset_label: GltfAssetLabel, /// Primitives of the glTF mesh. pub primitives: Vec, @@ -303,10 +295,6 @@ pub struct GltfPrimitive { /// Computed name for a primitive - either a user defined primitive name from gLTF or a generated name from index pub name: String, /// Subasset label for this mesh within the gLTF parent asset. - /// - /// ```no_run - /// asset_server.load(format!("my_glft.glft#{}", primitive.asset_label())); - /// ``` pub asset_label: GltfAssetLabel, /// Topology to be rendered. pub mesh: Handle,