//! Representation of assets present in a glTF file12use core::ops::Deref;34#[cfg(feature = "bevy_animation")]5use bevy_animation::AnimationClip;6use bevy_asset::{Asset, Handle};7use bevy_ecs::{component::Component, reflect::ReflectComponent};8use bevy_mesh::{skinning::SkinnedMeshInverseBindposes, Mesh};9use bevy_pbr::StandardMaterial;10use bevy_platform::collections::HashMap;11use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};12use bevy_scene::Scene;1314use crate::GltfAssetLabel;1516/// Representation of a loaded glTF file.17#[derive(Asset, Debug, TypePath)]18pub struct Gltf {19/// All scenes loaded from the glTF file.20pub scenes: Vec<Handle<Scene>>,21/// Named scenes loaded from the glTF file.22pub named_scenes: HashMap<Box<str>, Handle<Scene>>,23/// All meshes loaded from the glTF file.24pub meshes: Vec<Handle<GltfMesh>>,25/// Named meshes loaded from the glTF file.26pub named_meshes: HashMap<Box<str>, Handle<GltfMesh>>,27/// All materials loaded from the glTF file.28pub materials: Vec<Handle<StandardMaterial>>,29/// Named materials loaded from the glTF file.30pub named_materials: HashMap<Box<str>, Handle<StandardMaterial>>,31/// All nodes loaded from the glTF file.32pub nodes: Vec<Handle<GltfNode>>,33/// Named nodes loaded from the glTF file.34pub named_nodes: HashMap<Box<str>, Handle<GltfNode>>,35/// All skins loaded from the glTF file.36pub skins: Vec<Handle<GltfSkin>>,37/// Named skins loaded from the glTF file.38pub named_skins: HashMap<Box<str>, Handle<GltfSkin>>,39/// Default scene to be displayed.40pub default_scene: Option<Handle<Scene>>,41/// All animations loaded from the glTF file.42#[cfg(feature = "bevy_animation")]43pub animations: Vec<Handle<AnimationClip>>,44/// Named animations loaded from the glTF file.45#[cfg(feature = "bevy_animation")]46pub named_animations: HashMap<Box<str>, Handle<AnimationClip>>,47/// 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.48pub source: Option<gltf::Gltf>,49}5051/// A glTF mesh, which may consist of multiple [`GltfPrimitives`](GltfPrimitive)52/// and an optional [`GltfExtras`].53///54/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh).55#[derive(Asset, Debug, Clone, TypePath)]56pub struct GltfMesh {57/// Index of the mesh inside the scene58pub index: usize,59/// Computed name for a mesh - either a user defined mesh name from gLTF or a generated name from index60pub name: String,61/// Primitives of the glTF mesh.62pub primitives: Vec<GltfPrimitive>,63/// Additional data.64pub extras: Option<GltfExtras>,65}6667impl GltfMesh {68/// Create a mesh extracting name and index from glTF def69pub fn new(70mesh: &gltf::Mesh,71primitives: Vec<GltfPrimitive>,72extras: Option<GltfExtras>,73) -> Self {74Self {75index: mesh.index(),76name: if let Some(name) = mesh.name() {77name.to_string()78} else {79format!("GltfMesh{}", mesh.index())80},81primitives,82extras,83}84}8586/// Subasset label for this mesh within the gLTF parent asset.87pub fn asset_label(&self) -> GltfAssetLabel {88GltfAssetLabel::Mesh(self.index)89}90}9192/// A glTF node with all of its child nodes, its [`GltfMesh`],93/// [`Transform`](bevy_transform::prelude::Transform), its optional [`GltfSkin`]94/// and an optional [`GltfExtras`].95///96/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-node).97#[derive(Asset, Debug, Clone, TypePath)]98pub struct GltfNode {99/// Index of the node inside the scene100pub index: usize,101/// Computed name for a node - either a user defined node name from gLTF or a generated name from index102pub name: String,103/// Direct children of the node.104pub children: Vec<Handle<GltfNode>>,105/// Mesh of the node.106pub mesh: Option<Handle<GltfMesh>>,107/// Skin of the node.108pub skin: Option<Handle<GltfSkin>>,109/// Local transform.110pub transform: bevy_transform::prelude::Transform,111/// Is this node used as an animation root112#[cfg(feature = "bevy_animation")]113pub is_animation_root: bool,114/// Additional data.115pub extras: Option<GltfExtras>,116}117118impl GltfNode {119/// Create a node extracting name and index from glTF def120pub fn new(121node: &gltf::Node,122children: Vec<Handle<GltfNode>>,123mesh: Option<Handle<GltfMesh>>,124transform: bevy_transform::prelude::Transform,125skin: Option<Handle<GltfSkin>>,126extras: Option<GltfExtras>,127) -> Self {128Self {129index: node.index(),130name: if let Some(name) = node.name() {131name.to_string()132} else {133format!("GltfNode{}", node.index())134},135children,136mesh,137transform,138skin,139#[cfg(feature = "bevy_animation")]140is_animation_root: false,141extras,142}143}144145/// Create a node with animation root mark146#[cfg(feature = "bevy_animation")]147pub fn with_animation_root(self, is_animation_root: bool) -> Self {148Self {149is_animation_root,150..self151}152}153154/// Subasset label for this node within the gLTF parent asset.155pub fn asset_label(&self) -> GltfAssetLabel {156GltfAssetLabel::Node(self.index)157}158}159160/// Part of a [`GltfMesh`] that consists of a [`Mesh`], an optional [`StandardMaterial`] and [`GltfExtras`].161///162/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh-primitive).163#[derive(Asset, Debug, Clone, TypePath)]164pub struct GltfPrimitive {165/// Index of the primitive inside the mesh166pub index: usize,167/// Index of the parent [`GltfMesh`] of this primitive168pub parent_mesh_index: usize,169/// Computed name for a primitive - either a user defined primitive name from gLTF or a generated name from index170pub name: String,171/// Topology to be rendered.172pub mesh: Handle<Mesh>,173/// Material to apply to the `mesh`.174pub material: Option<Handle<StandardMaterial>>,175/// Additional data.176pub extras: Option<GltfExtras>,177/// Additional data of the `material`.178pub material_extras: Option<GltfExtras>,179}180181impl GltfPrimitive {182/// Create a primitive extracting name and index from glTF def183pub fn new(184gltf_mesh: &gltf::Mesh,185gltf_primitive: &gltf::Primitive,186mesh: Handle<Mesh>,187material: Option<Handle<StandardMaterial>>,188extras: Option<GltfExtras>,189material_extras: Option<GltfExtras>,190) -> Self {191GltfPrimitive {192index: gltf_primitive.index(),193parent_mesh_index: gltf_mesh.index(),194name: {195let mesh_name = gltf_mesh.name().unwrap_or("Mesh");196if gltf_mesh.primitives().len() > 1 {197format!("{}.{}", mesh_name, gltf_primitive.index())198} else {199mesh_name.to_string()200}201},202mesh,203material,204extras,205material_extras,206}207}208209/// Subasset label for this primitive within its parent [`GltfMesh`] within the gLTF parent asset.210pub fn asset_label(&self) -> GltfAssetLabel {211GltfAssetLabel::Primitive {212mesh: self.parent_mesh_index,213primitive: self.index,214}215}216}217218/// A glTF skin with all of its joint nodes, [`SkinnedMeshInversiveBindposes`](bevy_mesh::skinning::SkinnedMeshInverseBindposes)219/// and an optional [`GltfExtras`].220///221/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-skin).222#[derive(Asset, Debug, Clone, TypePath)]223pub struct GltfSkin {224/// Index of the skin inside the scene225pub index: usize,226/// Computed name for a skin - either a user defined skin name from gLTF or a generated name from index227pub name: String,228/// All the nodes that form this skin.229pub joints: Vec<Handle<GltfNode>>,230/// Inverse-bind matrices of this skin.231pub inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,232/// Additional data.233pub extras: Option<GltfExtras>,234}235236impl GltfSkin {237/// Create a skin extracting name and index from glTF def238pub fn new(239skin: &gltf::Skin,240joints: Vec<Handle<GltfNode>>,241inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,242extras: Option<GltfExtras>,243) -> Self {244Self {245index: skin.index(),246name: if let Some(name) = skin.name() {247name.to_string()248} else {249format!("GltfSkin{}", skin.index())250},251joints,252inverse_bind_matrices,253extras,254}255}256257/// Subasset label for this skin within the gLTF parent asset.258pub fn asset_label(&self) -> GltfAssetLabel {259GltfAssetLabel::Skin(self.index)260}261}262263/// Additional untyped data that can be present on most glTF types at the primitive level.264///265/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).266#[derive(Clone, Debug, Reflect, Default, Component)]267#[reflect(Component, Clone, Default, Debug)]268pub struct GltfExtras {269/// Content of the extra data.270pub value: String,271}272273impl From<&serde_json::value::RawValue> for GltfExtras {274fn from(value: &serde_json::value::RawValue) -> Self {275GltfExtras {276value: value.get().to_string(),277}278}279}280281/// Additional untyped data that can be present on most glTF types at the scene level.282///283/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).284#[derive(Clone, Debug, Reflect, Default, Component)]285#[reflect(Component, Clone, Default, Debug)]286pub struct GltfSceneExtras {287/// Content of the extra data.288pub value: String,289}290291/// Additional untyped data that can be present on most glTF types at the mesh level.292///293/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).294#[derive(Clone, Debug, Reflect, Default, Component)]295#[reflect(Component, Clone, Default, Debug)]296pub struct GltfMeshExtras {297/// Content of the extra data.298pub value: String,299}300301/// The mesh name of a glTF primitive.302///303/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh).304#[derive(Clone, Debug, Reflect, Default, Component)]305#[reflect(Component, Clone)]306pub struct GltfMeshName(pub String);307308impl Deref for GltfMeshName {309type Target = str;310311fn deref(&self) -> &Self::Target {312self.0.as_ref()313}314}315316/// Additional untyped data that can be present on most glTF types at the material level.317///318/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).319#[derive(Clone, Debug, Reflect, Default, Component)]320#[reflect(Component, Clone, Default, Debug)]321pub struct GltfMaterialExtras {322/// Content of the extra data.323pub value: String,324}325326/// The material name of a glTF primitive.327///328/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-material).329#[derive(Clone, Debug, Reflect, Default, Component)]330#[reflect(Component, Clone)]331pub struct GltfMaterialName(pub String);332333impl Deref for GltfMaterialName {334type Target = str;335336fn deref(&self) -> &Self::Target {337self.0.as_ref()338}339}340341342