//! 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_platform::collections::HashMap;10use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};11use bevy_scene::Scene;1213use crate::{GltfAssetLabel, GltfMaterial};1415/// Representation of a loaded glTF file.16#[derive(Asset, Debug, TypePath)]17pub struct Gltf {18/// All scenes loaded from the glTF file.19pub scenes: Vec<Handle<Scene>>,20/// Named scenes loaded from the glTF file.21pub named_scenes: HashMap<Box<str>, Handle<Scene>>,22/// All meshes loaded from the glTF file.23pub meshes: Vec<Handle<GltfMesh>>,24/// Named meshes loaded from the glTF file.25pub named_meshes: HashMap<Box<str>, Handle<GltfMesh>>,26/// All materials loaded from the glTF file.27pub materials: Vec<Handle<GltfMaterial>>,28/// Named materials loaded from the glTF file.29pub named_materials: HashMap<Box<str>, Handle<GltfMaterial>>,30/// All nodes loaded from the glTF file.31pub nodes: Vec<Handle<GltfNode>>,32/// Named nodes loaded from the glTF file.33pub named_nodes: HashMap<Box<str>, Handle<GltfNode>>,34/// All skins loaded from the glTF file.35pub skins: Vec<Handle<GltfSkin>>,36/// Named skins loaded from the glTF file.37pub named_skins: HashMap<Box<str>, Handle<GltfSkin>>,38/// Default scene to be displayed.39pub default_scene: Option<Handle<Scene>>,40/// All animations loaded from the glTF file.41#[cfg(feature = "bevy_animation")]42pub animations: Vec<Handle<AnimationClip>>,43/// Named animations loaded from the glTF file.44#[cfg(feature = "bevy_animation")]45pub 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.47pub source: Option<gltf::Gltf>,48}4950/// 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)]55pub struct GltfMesh {56/// Index of the mesh inside the scene57pub index: usize,58/// Computed name for a mesh - either a user defined mesh name from gLTF or a generated name from index59pub name: String,60/// Primitives of the glTF mesh.61pub primitives: Vec<GltfPrimitive>,62/// Additional data.63pub extras: Option<GltfExtras>,64}6566impl GltfMesh {67/// Create a mesh extracting name and index from glTF def68pub fn new(69mesh: &gltf::Mesh,70primitives: Vec<GltfPrimitive>,71extras: Option<GltfExtras>,72) -> Self {73Self {74index: mesh.index(),75name: if let Some(name) = mesh.name() {76name.to_string()77} else {78format!("GltfMesh{}", mesh.index())79},80primitives,81extras,82}83}8485/// Subasset label for this mesh within the gLTF parent asset.86pub fn asset_label(&self) -> GltfAssetLabel {87GltfAssetLabel::Mesh(self.index)88}89}9091/// 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)]97pub struct GltfNode {98/// Index of the node inside the scene99pub index: usize,100/// Computed name for a node - either a user defined node name from gLTF or a generated name from index101pub name: String,102/// Direct children of the node.103pub children: Vec<Handle<GltfNode>>,104/// Mesh of the node.105pub mesh: Option<Handle<GltfMesh>>,106/// Skin of the node.107pub skin: Option<Handle<GltfSkin>>,108/// Local transform.109pub transform: bevy_transform::prelude::Transform,110/// Is this node used as an animation root111#[cfg(feature = "bevy_animation")]112pub is_animation_root: bool,113/// Additional data.114pub extras: Option<GltfExtras>,115}116117impl GltfNode {118/// Create a node extracting name and index from glTF def119pub fn new(120node: &gltf::Node,121children: Vec<Handle<GltfNode>>,122mesh: Option<Handle<GltfMesh>>,123transform: bevy_transform::prelude::Transform,124skin: Option<Handle<GltfSkin>>,125extras: Option<GltfExtras>,126) -> Self {127Self {128index: node.index(),129name: if let Some(name) = node.name() {130name.to_string()131} else {132format!("GltfNode{}", node.index())133},134children,135mesh,136transform,137skin,138#[cfg(feature = "bevy_animation")]139is_animation_root: false,140extras,141}142}143144/// Create a node with animation root mark145#[cfg(feature = "bevy_animation")]146pub fn with_animation_root(self, is_animation_root: bool) -> Self {147Self {148is_animation_root,149..self150}151}152153/// Subasset label for this node within the gLTF parent asset.154pub fn asset_label(&self) -> GltfAssetLabel {155GltfAssetLabel::Node(self.index)156}157}158159/// Part of a [`GltfMesh`] that consists of a [`Mesh`], an optional [`GltfMaterial`] 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)]163pub struct GltfPrimitive {164/// Index of the primitive inside the mesh165pub index: usize,166/// Index of the parent [`GltfMesh`] of this primitive167pub parent_mesh_index: usize,168/// Computed name for a primitive - either a user defined primitive name from gLTF or a generated name from index169pub name: String,170/// Topology to be rendered.171pub mesh: Handle<Mesh>,172/// Material to apply to the `mesh`.173pub material: Option<Handle<GltfMaterial>>,174/// Additional data.175pub extras: Option<GltfExtras>,176/// Additional data of the `material`.177pub material_extras: Option<GltfExtras>,178}179180impl GltfPrimitive {181/// Create a primitive extracting name and index from glTF def182pub fn new(183gltf_mesh: &gltf::Mesh,184gltf_primitive: &gltf::Primitive,185mesh: Handle<Mesh>,186material: Option<Handle<GltfMaterial>>,187extras: Option<GltfExtras>,188material_extras: Option<GltfExtras>,189) -> Self {190GltfPrimitive {191index: gltf_primitive.index(),192parent_mesh_index: gltf_mesh.index(),193name: {194let mesh_name = gltf_mesh.name().unwrap_or("Mesh");195if gltf_mesh.primitives().len() > 1 {196format!("{}.{}", mesh_name, gltf_primitive.index())197} else {198mesh_name.to_string()199}200},201mesh,202material,203extras,204material_extras,205}206}207208/// Subasset label for this primitive within its parent [`GltfMesh`] within the gLTF parent asset.209pub fn asset_label(&self) -> GltfAssetLabel {210GltfAssetLabel::Primitive {211mesh: self.parent_mesh_index,212primitive: self.index,213}214}215}216217/// A glTF skin with all of its joint nodes, [`SkinnedMeshInversiveBindposes`](bevy_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)]222pub struct GltfSkin {223/// Index of the skin inside the scene224pub index: usize,225/// Computed name for a skin - either a user defined skin name from gLTF or a generated name from index226pub name: String,227/// All the nodes that form this skin.228pub joints: Vec<Handle<GltfNode>>,229/// Inverse-bind matrices of this skin.230pub inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,231/// Additional data.232pub extras: Option<GltfExtras>,233}234235impl GltfSkin {236/// Create a skin extracting name and index from glTF def237pub fn new(238skin: &gltf::Skin,239joints: Vec<Handle<GltfNode>>,240inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,241extras: Option<GltfExtras>,242) -> Self {243Self {244index: skin.index(),245name: if let Some(name) = skin.name() {246name.to_string()247} else {248format!("GltfSkin{}", skin.index())249},250joints,251inverse_bind_matrices,252extras,253}254}255256/// Subasset label for this skin within the gLTF parent asset.257pub fn asset_label(&self) -> GltfAssetLabel {258GltfAssetLabel::Skin(self.index)259}260}261262/// 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, Clone, Default, Debug)]267pub struct GltfExtras {268/// Content of the extra data.269pub value: String,270}271272impl From<&serde_json::value::RawValue> for GltfExtras {273fn from(value: &serde_json::value::RawValue) -> Self {274GltfExtras {275value: value.get().to_string(),276}277}278}279280/// 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, Clone, Default, Debug)]285pub struct GltfSceneExtras {286/// Content of the extra data.287pub value: String,288}289290/// The name of a glTF scene.291///292/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-scene).293#[derive(Clone, Debug, Reflect, Default, Component)]294#[reflect(Component, Clone)]295pub struct GltfSceneName(pub String);296297impl Deref for GltfSceneName {298type Target = str;299300fn deref(&self) -> &Self::Target {301self.0.as_ref()302}303}304305/// Additional untyped data that can be present on most glTF types at the mesh level.306///307/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).308#[derive(Clone, Debug, Reflect, Default, Component)]309#[reflect(Component, Clone, Default, Debug)]310pub struct GltfMeshExtras {311/// Content of the extra data.312pub value: String,313}314315/// The mesh name of a glTF primitive.316///317/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh).318#[derive(Clone, Debug, Reflect, Default, Component)]319#[reflect(Component, Clone)]320pub struct GltfMeshName(pub String);321322impl Deref for GltfMeshName {323type Target = str;324325fn deref(&self) -> &Self::Target {326self.0.as_ref()327}328}329330/// Additional untyped data that can be present on most glTF types at the material level.331///332/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).333#[derive(Clone, Debug, Reflect, Default, Component)]334#[reflect(Component, Clone, Default, Debug)]335pub struct GltfMaterialExtras {336/// Content of the extra data.337pub value: String,338}339340/// The material name of a glTF primitive.341///342/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-material).343#[derive(Clone, Debug, Reflect, Default, Component)]344#[reflect(Component, Clone)]345pub struct GltfMaterialName(pub String);346347impl Deref for GltfMaterialName {348type Target = str;349350fn deref(&self) -> &Self::Target {351self.0.as_ref()352}353}354355356