Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add labels to Gltf Node and Mesh assets #13558

Merged
4 changes: 4 additions & 0 deletions crates/bevy_gltf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<GltfNode>,
/// Mesh of the node.
Expand All @@ -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<GltfPrimitive>,
/// Additional data.
Expand Down
112 changes: 57 additions & 55 deletions crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
},
Expand All @@ -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()
Expand All @@ -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::<Vec<Handle<GltfNode>>>();
let named_nodes = named_nodes_intermediate
.into_iter()
Expand Down Expand Up @@ -1630,16 +1632,16 @@ async fn load_buffers(
}

fn resolve_node_hierarchy(
nodes_intermediate: Vec<(String, GltfNode, Vec<usize>)>,
nodes_intermediate: Vec<(GltfNode, Vec<usize>)>,
asset_path: &Path,
) -> Vec<(String, GltfNode)> {
) -> Vec<GltfNode> {
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);
Expand All @@ -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::<HashMap<_, _>>();
let mut nodes = std::collections::HashMap::<usize, (String, GltfNode)>::new();
let mut nodes = std::collections::HashMap::<usize, GltfNode>::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() {
Expand Down Expand Up @@ -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,
Expand All @@ -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(),
);
Expand All @@ -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);
}
}