Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gltf/src/loader/gltf_ext/scene.rs
9451 views
1
use bevy_ecs::name::Name;
2
use bevy_math::{Mat4, Vec3};
3
use bevy_transform::components::Transform;
4
5
use gltf::scene::Node;
6
7
use fixedbitset::FixedBitSet;
8
use itertools::Itertools;
9
10
#[cfg(feature = "bevy_animation")]
11
use bevy_platform::collections::{HashMap, HashSet};
12
13
use crate::GltfError;
14
15
pub(crate) fn node_name(node: &Node) -> Name {
16
let name = node
17
.name()
18
.map(ToString::to_string)
19
.unwrap_or_else(|| format!("GltfNode{}", node.index()));
20
Name::new(name)
21
}
22
23
/// Calculate the transform of gLTF [`Node`].
24
///
25
/// This should be used instead of calling [`gltf::scene::Transform::matrix()`]
26
/// on [`Node::transform()`](gltf::Node::transform) directly because it uses optimized glam types and
27
/// if `libm` feature of `bevy_math` crate is enabled also handles cross
28
/// platform determinism properly.
29
pub(crate) fn node_transform(node: &Node) -> Transform {
30
match node.transform() {
31
gltf::scene::Transform::Matrix { matrix } => {
32
Transform::from_matrix(Mat4::from_cols_array_2d(&matrix))
33
}
34
gltf::scene::Transform::Decomposed {
35
translation,
36
rotation,
37
scale,
38
} => Transform {
39
translation: Vec3::from(translation),
40
rotation: bevy_math::Quat::from_array(rotation),
41
scale: Vec3::from(scale),
42
},
43
}
44
}
45
46
#[cfg_attr(
47
not(target_arch = "wasm32"),
48
expect(
49
clippy::result_large_err,
50
reason = "need to be signature compatible with `load_gltf`"
51
)
52
)]
53
/// Check if [`Node`] is part of cycle
54
pub(crate) fn check_is_part_of_cycle(
55
node: &Node,
56
visited: &mut FixedBitSet,
57
) -> Result<(), GltfError> {
58
// Do we have a cycle?
59
if visited.contains(node.index()) {
60
return Err(GltfError::CircularChildren(format!(
61
"glTF nodes form a cycle: {} -> {}",
62
visited.ones().map(|bit| bit.to_string()).join(" -> "),
63
node.index()
64
)));
65
}
66
67
// Recurse.
68
visited.insert(node.index());
69
for kid in node.children() {
70
check_is_part_of_cycle(&kid, visited)?;
71
}
72
visited.remove(node.index());
73
74
Ok(())
75
}
76
77
#[cfg(feature = "bevy_animation")]
78
pub(crate) fn collect_path(
79
node: &Node,
80
current_path: &[Name],
81
paths: &mut HashMap<usize, (usize, Vec<Name>)>,
82
root_index: usize,
83
visited: &mut HashSet<usize>,
84
) {
85
let mut path = current_path.to_owned();
86
path.push(node_name(node));
87
visited.insert(node.index());
88
for child in node.children() {
89
if !visited.contains(&child.index()) {
90
collect_path(&child, &path, paths, root_index, visited);
91
}
92
}
93
paths.insert(node.index(), (root_index, path));
94
}
95
96