1use core::ops::Deref;
4
5#[cfg(feature = "bevy_animation")]
6use bevy_animation::AnimationClip;
7use bevy_asset::{Asset, Handle};
8use bevy_ecs::{component::Component, reflect::ReflectComponent};
9use bevy_mesh::{skinning::SkinnedMeshInverseBindposes, Mesh};
10use bevy_pbr::StandardMaterial;
11use bevy_platform::collections::HashMap;
12use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};
13use bevy_scene::Scene;
14
15use crate::GltfAssetLabel;
16
17#[derive(Asset, Debug, TypePath)]
19pub struct Gltf {
20 pub scenes: Vec<Handle<Scene>>,
22 pub named_scenes: HashMap<Box<str>, Handle<Scene>>,
24 pub meshes: Vec<Handle<GltfMesh>>,
26 pub named_meshes: HashMap<Box<str>, Handle<GltfMesh>>,
28 pub materials: Vec<Handle<StandardMaterial>>,
30 pub named_materials: HashMap<Box<str>, Handle<StandardMaterial>>,
32 pub nodes: Vec<Handle<GltfNode>>,
34 pub named_nodes: HashMap<Box<str>, Handle<GltfNode>>,
36 pub skins: Vec<Handle<GltfSkin>>,
38 pub named_skins: HashMap<Box<str>, Handle<GltfSkin>>,
40 pub default_scene: Option<Handle<Scene>>,
42 #[cfg(feature = "bevy_animation")]
44 pub animations: Vec<Handle<AnimationClip>>,
45 #[cfg(feature = "bevy_animation")]
47 pub named_animations: HashMap<Box<str>, Handle<AnimationClip>>,
48 pub source: Option<gltf::Gltf>,
50}
51
52#[derive(Asset, Debug, Clone, TypePath)]
57pub struct GltfMesh {
58 pub index: usize,
60 pub name: String,
62 pub primitives: Vec<GltfPrimitive>,
64 pub extras: Option<GltfExtras>,
66}
67
68impl GltfMesh {
69 pub fn new(
71 mesh: &gltf::Mesh,
72 primitives: Vec<GltfPrimitive>,
73 extras: Option<GltfExtras>,
74 ) -> Self {
75 Self {
76 index: mesh.index(),
77 name: if let Some(name) = mesh.name() {
78 name.to_string()
79 } else {
80 format!("GltfMesh{}", mesh.index())
81 },
82 primitives,
83 extras,
84 }
85 }
86
87 pub fn asset_label(&self) -> GltfAssetLabel {
89 GltfAssetLabel::Mesh(self.index)
90 }
91}
92
93#[derive(Asset, Debug, Clone, TypePath)]
99pub struct GltfNode {
100 pub index: usize,
102 pub name: String,
104 pub children: Vec<Handle<GltfNode>>,
106 pub mesh: Option<Handle<GltfMesh>>,
108 pub skin: Option<Handle<GltfSkin>>,
110 pub transform: bevy_transform::prelude::Transform,
112 #[cfg(feature = "bevy_animation")]
114 pub is_animation_root: bool,
115 pub extras: Option<GltfExtras>,
117}
118
119impl GltfNode {
120 pub fn new(
122 node: &gltf::Node,
123 children: Vec<Handle<GltfNode>>,
124 mesh: Option<Handle<GltfMesh>>,
125 transform: bevy_transform::prelude::Transform,
126 skin: Option<Handle<GltfSkin>>,
127 extras: Option<GltfExtras>,
128 ) -> Self {
129 Self {
130 index: node.index(),
131 name: if let Some(name) = node.name() {
132 name.to_string()
133 } else {
134 format!("GltfNode{}", node.index())
135 },
136 children,
137 mesh,
138 transform,
139 skin,
140 #[cfg(feature = "bevy_animation")]
141 is_animation_root: false,
142 extras,
143 }
144 }
145
146 #[cfg(feature = "bevy_animation")]
148 pub fn with_animation_root(self, is_animation_root: bool) -> Self {
149 Self {
150 is_animation_root,
151 ..self
152 }
153 }
154
155 pub fn asset_label(&self) -> GltfAssetLabel {
157 GltfAssetLabel::Node(self.index)
158 }
159}
160
161#[derive(Asset, Debug, Clone, TypePath)]
165pub struct GltfPrimitive {
166 pub index: usize,
168 pub parent_mesh_index: usize,
170 pub name: String,
172 pub mesh: Handle<Mesh>,
174 pub material: Option<Handle<StandardMaterial>>,
176 pub extras: Option<GltfExtras>,
178 pub material_extras: Option<GltfExtras>,
180}
181
182impl GltfPrimitive {
183 pub fn new(
185 gltf_mesh: &gltf::Mesh,
186 gltf_primitive: &gltf::Primitive,
187 mesh: Handle<Mesh>,
188 material: Option<Handle<StandardMaterial>>,
189 extras: Option<GltfExtras>,
190 material_extras: Option<GltfExtras>,
191 ) -> Self {
192 GltfPrimitive {
193 index: gltf_primitive.index(),
194 parent_mesh_index: gltf_mesh.index(),
195 name: {
196 let mesh_name = gltf_mesh.name().unwrap_or("Mesh");
197 if gltf_mesh.primitives().len() > 1 {
198 format!("{}.{}", mesh_name, gltf_primitive.index())
199 } else {
200 mesh_name.to_string()
201 }
202 },
203 mesh,
204 material,
205 extras,
206 material_extras,
207 }
208 }
209
210 pub fn asset_label(&self) -> GltfAssetLabel {
212 GltfAssetLabel::Primitive {
213 mesh: self.parent_mesh_index,
214 primitive: self.index,
215 }
216 }
217}
218
219#[derive(Asset, Debug, Clone, TypePath)]
224pub struct GltfSkin {
225 pub index: usize,
227 pub name: String,
229 pub joints: Vec<Handle<GltfNode>>,
231 pub inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,
233 pub extras: Option<GltfExtras>,
235}
236
237impl GltfSkin {
238 pub fn new(
240 skin: &gltf::Skin,
241 joints: Vec<Handle<GltfNode>>,
242 inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,
243 extras: Option<GltfExtras>,
244 ) -> Self {
245 Self {
246 index: skin.index(),
247 name: if let Some(name) = skin.name() {
248 name.to_string()
249 } else {
250 format!("GltfSkin{}", skin.index())
251 },
252 joints,
253 inverse_bind_matrices,
254 extras,
255 }
256 }
257
258 pub fn asset_label(&self) -> GltfAssetLabel {
260 GltfAssetLabel::Skin(self.index)
261 }
262}
263
264#[derive(Clone, Debug, Reflect, Default, Component)]
268#[reflect(Component, Clone, Default, Debug)]
269pub struct GltfExtras {
270 pub value: String,
272}
273
274impl From<&serde_json::value::RawValue> for GltfExtras {
275 fn from(value: &serde_json::value::RawValue) -> Self {
276 GltfExtras {
277 value: value.get().to_string(),
278 }
279 }
280}
281
282#[derive(Clone, Debug, Reflect, Default, Component)]
286#[reflect(Component, Clone, Default, Debug)]
287pub struct GltfSceneExtras {
288 pub value: String,
290}
291
292#[derive(Clone, Debug, Reflect, Default, Component)]
296#[reflect(Component, Clone, Default, Debug)]
297pub struct GltfMeshExtras {
298 pub value: String,
300}
301
302#[derive(Clone, Debug, Reflect, Default, Component)]
306#[reflect(Component, Clone)]
307pub struct GltfMeshName(pub String);
308
309impl Deref for GltfMeshName {
310 type Target = str;
311
312 fn deref(&self) -> &Self::Target {
313 self.0.as_ref()
314 }
315}
316
317#[derive(Clone, Debug, Reflect, Default, Component)]
321#[reflect(Component, Clone, Default, Debug)]
322pub struct GltfMaterialExtras {
323 pub value: String,
325}
326
327#[derive(Clone, Debug, Reflect, Default, Component)]
331#[reflect(Component, Clone)]
332pub struct GltfMaterialName(pub String);
333
334impl Deref for GltfMaterialName {
335 type Target = str;
336
337 fn deref(&self) -> &Self::Target {
338 self.0.as_ref()
339 }
340}