Skip to content

Commit 11db717

Browse files
authored
Refactor bevy_gltf (#15994)
# Objective Refactor `bevy_gltf`, the criteria for the split is kind of arbitrary but at least it is not a 2.6k line file. ## Solution Move methods and structs found in `bevy_gltf/loader.rs` into multiple new modules. ## Testing `cargo run -p ci`
1 parent 831ecf0 commit 11db717

File tree

13 files changed

+1376
-1228
lines changed

13 files changed

+1376
-1228
lines changed

crates/bevy_gltf/src/assets.rs

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
//! Representation of assets present in a glTF file
2+
3+
#[cfg(feature = "bevy_animation")]
4+
use bevy_animation::AnimationClip;
5+
use bevy_asset::{Asset, Handle};
6+
use bevy_ecs::{component::Component, reflect::ReflectComponent};
7+
use bevy_pbr::StandardMaterial;
8+
use bevy_platform_support::collections::HashMap;
9+
use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};
10+
use bevy_render::mesh::{skinning::SkinnedMeshInverseBindposes, Mesh};
11+
use bevy_scene::Scene;
12+
13+
use crate::GltfAssetLabel;
14+
15+
/// Representation of a loaded glTF file.
16+
#[derive(Asset, Debug, TypePath)]
17+
pub struct Gltf {
18+
/// All scenes loaded from the glTF file.
19+
pub scenes: Vec<Handle<Scene>>,
20+
/// Named scenes loaded from the glTF file.
21+
pub named_scenes: HashMap<Box<str>, Handle<Scene>>,
22+
/// All meshes loaded from the glTF file.
23+
pub meshes: Vec<Handle<GltfMesh>>,
24+
/// Named meshes loaded from the glTF file.
25+
pub named_meshes: HashMap<Box<str>, Handle<GltfMesh>>,
26+
/// All materials loaded from the glTF file.
27+
pub materials: Vec<Handle<StandardMaterial>>,
28+
/// Named materials loaded from the glTF file.
29+
pub named_materials: HashMap<Box<str>, Handle<StandardMaterial>>,
30+
/// All nodes loaded from the glTF file.
31+
pub nodes: Vec<Handle<GltfNode>>,
32+
/// Named nodes loaded from the glTF file.
33+
pub named_nodes: HashMap<Box<str>, Handle<GltfNode>>,
34+
/// All skins loaded from the glTF file.
35+
pub skins: Vec<Handle<GltfSkin>>,
36+
/// Named skins loaded from the glTF file.
37+
pub named_skins: HashMap<Box<str>, Handle<GltfSkin>>,
38+
/// Default scene to be displayed.
39+
pub default_scene: Option<Handle<Scene>>,
40+
/// All animations loaded from the glTF file.
41+
#[cfg(feature = "bevy_animation")]
42+
pub animations: Vec<Handle<AnimationClip>>,
43+
/// Named animations loaded from the glTF file.
44+
#[cfg(feature = "bevy_animation")]
45+
pub named_animations: HashMap<Box<str>, Handle<AnimationClip>>,
46+
/// The gltf root of the gltf asset, see <https://docs.rs/gltf/latest/gltf/struct.Gltf.html>. Only has a value when `GltfLoaderSettings::include_source` is true.
47+
pub source: Option<gltf::Gltf>,
48+
}
49+
50+
/// A glTF mesh, which may consist of multiple [`GltfPrimitives`](GltfPrimitive)
51+
/// and an optional [`GltfExtras`].
52+
///
53+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh).
54+
#[derive(Asset, Debug, Clone, TypePath)]
55+
pub struct GltfMesh {
56+
/// Index of the mesh inside the scene
57+
pub index: usize,
58+
/// Computed name for a mesh - either a user defined mesh name from gLTF or a generated name from index
59+
pub name: String,
60+
/// Primitives of the glTF mesh.
61+
pub primitives: Vec<GltfPrimitive>,
62+
/// Additional data.
63+
pub extras: Option<GltfExtras>,
64+
}
65+
66+
impl GltfMesh {
67+
/// Create a mesh extracting name and index from glTF def
68+
pub fn new(
69+
mesh: &gltf::Mesh,
70+
primitives: Vec<GltfPrimitive>,
71+
extras: Option<GltfExtras>,
72+
) -> Self {
73+
Self {
74+
index: mesh.index(),
75+
name: if let Some(name) = mesh.name() {
76+
name.to_string()
77+
} else {
78+
format!("GltfMesh{}", mesh.index())
79+
},
80+
primitives,
81+
extras,
82+
}
83+
}
84+
85+
/// Subasset label for this mesh within the gLTF parent asset.
86+
pub fn asset_label(&self) -> GltfAssetLabel {
87+
GltfAssetLabel::Mesh(self.index)
88+
}
89+
}
90+
91+
/// A glTF node with all of its child nodes, its [`GltfMesh`],
92+
/// [`Transform`](bevy_transform::prelude::Transform), its optional [`GltfSkin`]
93+
/// and an optional [`GltfExtras`].
94+
///
95+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-node).
96+
#[derive(Asset, Debug, Clone, TypePath)]
97+
pub struct GltfNode {
98+
/// Index of the node inside the scene
99+
pub index: usize,
100+
/// Computed name for a node - either a user defined node name from gLTF or a generated name from index
101+
pub name: String,
102+
/// Direct children of the node.
103+
pub children: Vec<Handle<GltfNode>>,
104+
/// Mesh of the node.
105+
pub mesh: Option<Handle<GltfMesh>>,
106+
/// Skin of the node.
107+
pub skin: Option<Handle<GltfSkin>>,
108+
/// Local transform.
109+
pub transform: bevy_transform::prelude::Transform,
110+
/// Is this node used as an animation root
111+
#[cfg(feature = "bevy_animation")]
112+
pub is_animation_root: bool,
113+
/// Additional data.
114+
pub extras: Option<GltfExtras>,
115+
}
116+
117+
impl GltfNode {
118+
/// Create a node extracting name and index from glTF def
119+
pub fn new(
120+
node: &gltf::Node,
121+
children: Vec<Handle<GltfNode>>,
122+
mesh: Option<Handle<GltfMesh>>,
123+
transform: bevy_transform::prelude::Transform,
124+
skin: Option<Handle<GltfSkin>>,
125+
extras: Option<GltfExtras>,
126+
) -> Self {
127+
Self {
128+
index: node.index(),
129+
name: if let Some(name) = node.name() {
130+
name.to_string()
131+
} else {
132+
format!("GltfNode{}", node.index())
133+
},
134+
children,
135+
mesh,
136+
transform,
137+
skin,
138+
#[cfg(feature = "bevy_animation")]
139+
is_animation_root: false,
140+
extras,
141+
}
142+
}
143+
144+
/// Create a node with animation root mark
145+
#[cfg(feature = "bevy_animation")]
146+
pub fn with_animation_root(self, is_animation_root: bool) -> Self {
147+
Self {
148+
is_animation_root,
149+
..self
150+
}
151+
}
152+
153+
/// Subasset label for this node within the gLTF parent asset.
154+
pub fn asset_label(&self) -> GltfAssetLabel {
155+
GltfAssetLabel::Node(self.index)
156+
}
157+
}
158+
159+
/// Part of a [`GltfMesh`] that consists of a [`Mesh`], an optional [`StandardMaterial`] and [`GltfExtras`].
160+
///
161+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh-primitive).
162+
#[derive(Asset, Debug, Clone, TypePath)]
163+
pub struct GltfPrimitive {
164+
/// Index of the primitive inside the mesh
165+
pub index: usize,
166+
/// Index of the parent [`GltfMesh`] of this primitive
167+
pub parent_mesh_index: usize,
168+
/// Computed name for a primitive - either a user defined primitive name from gLTF or a generated name from index
169+
pub name: String,
170+
/// Topology to be rendered.
171+
pub mesh: Handle<Mesh>,
172+
/// Material to apply to the `mesh`.
173+
pub material: Option<Handle<StandardMaterial>>,
174+
/// Additional data.
175+
pub extras: Option<GltfExtras>,
176+
/// Additional data of the `material`.
177+
pub material_extras: Option<GltfExtras>,
178+
}
179+
180+
impl GltfPrimitive {
181+
/// Create a primitive extracting name and index from glTF def
182+
pub fn new(
183+
gltf_mesh: &gltf::Mesh,
184+
gltf_primitive: &gltf::Primitive,
185+
mesh: Handle<Mesh>,
186+
material: Option<Handle<StandardMaterial>>,
187+
extras: Option<GltfExtras>,
188+
material_extras: Option<GltfExtras>,
189+
) -> Self {
190+
GltfPrimitive {
191+
index: gltf_primitive.index(),
192+
parent_mesh_index: gltf_mesh.index(),
193+
name: {
194+
let mesh_name = gltf_mesh.name().unwrap_or("Mesh");
195+
if gltf_mesh.primitives().len() > 1 {
196+
format!("{}.{}", mesh_name, gltf_primitive.index())
197+
} else {
198+
mesh_name.to_string()
199+
}
200+
},
201+
mesh,
202+
material,
203+
extras,
204+
material_extras,
205+
}
206+
}
207+
208+
/// Subasset label for this primitive within its parent [`GltfMesh`] within the gLTF parent asset.
209+
pub fn asset_label(&self) -> GltfAssetLabel {
210+
GltfAssetLabel::Primitive {
211+
mesh: self.parent_mesh_index,
212+
primitive: self.index,
213+
}
214+
}
215+
}
216+
217+
/// A glTF skin with all of its joint nodes, [`SkinnedMeshInversiveBindposes`](bevy_render::mesh::skinning::SkinnedMeshInverseBindposes)
218+
/// and an optional [`GltfExtras`].
219+
///
220+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-skin).
221+
#[derive(Asset, Debug, Clone, TypePath)]
222+
pub struct GltfSkin {
223+
/// Index of the skin inside the scene
224+
pub index: usize,
225+
/// Computed name for a skin - either a user defined skin name from gLTF or a generated name from index
226+
pub name: String,
227+
/// All the nodes that form this skin.
228+
pub joints: Vec<Handle<GltfNode>>,
229+
/// Inverse-bind matrices of this skin.
230+
pub inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,
231+
/// Additional data.
232+
pub extras: Option<GltfExtras>,
233+
}
234+
235+
impl GltfSkin {
236+
/// Create a skin extracting name and index from glTF def
237+
pub fn new(
238+
skin: &gltf::Skin,
239+
joints: Vec<Handle<GltfNode>>,
240+
inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,
241+
extras: Option<GltfExtras>,
242+
) -> Self {
243+
Self {
244+
index: skin.index(),
245+
name: if let Some(name) = skin.name() {
246+
name.to_string()
247+
} else {
248+
format!("GltfSkin{}", skin.index())
249+
},
250+
joints,
251+
inverse_bind_matrices,
252+
extras,
253+
}
254+
}
255+
256+
/// Subasset label for this skin within the gLTF parent asset.
257+
pub fn asset_label(&self) -> GltfAssetLabel {
258+
GltfAssetLabel::Skin(self.index)
259+
}
260+
}
261+
262+
/// Additional untyped data that can be present on most glTF types at the primitive level.
263+
///
264+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
265+
#[derive(Clone, Debug, Reflect, Default, Component)]
266+
#[reflect(Component, Default, Debug)]
267+
pub struct GltfExtras {
268+
/// Content of the extra data.
269+
pub value: String,
270+
}
271+
272+
impl From<&serde_json::value::RawValue> for GltfExtras {
273+
fn from(value: &serde_json::value::RawValue) -> Self {
274+
GltfExtras {
275+
value: value.get().to_string(),
276+
}
277+
}
278+
}
279+
280+
/// Additional untyped data that can be present on most glTF types at the scene level.
281+
///
282+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
283+
#[derive(Clone, Debug, Reflect, Default, Component)]
284+
#[reflect(Component, Default, Debug)]
285+
pub struct GltfSceneExtras {
286+
/// Content of the extra data.
287+
pub value: String,
288+
}
289+
290+
/// Additional untyped data that can be present on most glTF types at the mesh level.
291+
///
292+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
293+
#[derive(Clone, Debug, Reflect, Default, Component)]
294+
#[reflect(Component, Default, Debug)]
295+
pub struct GltfMeshExtras {
296+
/// Content of the extra data.
297+
pub value: String,
298+
}
299+
300+
/// Additional untyped data that can be present on most glTF types at the material level.
301+
///
302+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
303+
#[derive(Clone, Debug, Reflect, Default, Component)]
304+
#[reflect(Component, Default, Debug)]
305+
pub struct GltfMaterialExtras {
306+
/// Content of the extra data.
307+
pub value: String,
308+
}
309+
310+
/// The material name of a glTF primitive.
311+
///
312+
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-material).
313+
#[derive(Clone, Debug, Reflect, Default, Component)]
314+
#[reflect(Component)]
315+
pub struct GltfMaterialName(pub String);

0 commit comments

Comments
 (0)