use core::ops::Deref;
#[cfg(feature = "bevy_animation")]
use bevy_animation::AnimationClip;
use bevy_asset::{Asset, Handle};
use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_mesh::{skinning::SkinnedMeshInverseBindposes, Mesh};
use bevy_platform::collections::HashMap;
use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};
use bevy_world_serialization::WorldAsset;
use crate::{GltfAssetLabel, GltfMaterial};
#[derive(Asset, Debug, TypePath)]
pub struct Gltf {
pub scenes: Vec<Handle<WorldAsset>>,
pub named_scenes: HashMap<Box<str>, Handle<WorldAsset>>,
pub meshes: Vec<Handle<GltfMesh>>,
pub named_meshes: HashMap<Box<str>, Handle<GltfMesh>>,
pub materials: Vec<Handle<GltfMaterial>>,
pub named_materials: HashMap<Box<str>, Handle<GltfMaterial>>,
pub nodes: Vec<Handle<GltfNode>>,
pub named_nodes: HashMap<Box<str>, Handle<GltfNode>>,
pub skins: Vec<Handle<GltfSkin>>,
pub named_skins: HashMap<Box<str>, Handle<GltfSkin>>,
pub default_scene: Option<Handle<WorldAsset>>,
#[cfg(feature = "bevy_animation")]
pub animations: Vec<Handle<AnimationClip>>,
#[cfg(feature = "bevy_animation")]
pub named_animations: HashMap<Box<str>, Handle<AnimationClip>>,
pub source: Option<gltf::Gltf>,
}
#[derive(Asset, Debug, Clone, TypePath)]
pub struct GltfMesh {
pub index: usize,
pub name: String,
pub primitives: Vec<GltfPrimitive>,
pub extras: Option<GltfExtras>,
}
impl GltfMesh {
pub fn new(
mesh: &gltf::Mesh,
primitives: Vec<GltfPrimitive>,
extras: Option<GltfExtras>,
) -> Self {
Self {
index: mesh.index(),
name: if let Some(name) = mesh.name() {
name.to_string()
} else {
format!("GltfMesh{}", mesh.index())
},
primitives,
extras,
}
}
pub fn asset_label(&self) -> GltfAssetLabel {
GltfAssetLabel::Mesh(self.index)
}
}
#[derive(Asset, Debug, Clone, TypePath)]
pub struct GltfNode {
pub index: usize,
pub name: String,
pub children: Vec<Handle<GltfNode>>,
pub mesh: Option<Handle<GltfMesh>>,
pub skin: Option<Handle<GltfSkin>>,
pub transform: bevy_transform::prelude::Transform,
#[cfg(feature = "bevy_animation")]
pub is_animation_root: bool,
pub extras: Option<GltfExtras>,
}
impl GltfNode {
pub fn new(
node: &gltf::Node,
children: Vec<Handle<GltfNode>>,
mesh: Option<Handle<GltfMesh>>,
transform: bevy_transform::prelude::Transform,
skin: Option<Handle<GltfSkin>>,
extras: Option<GltfExtras>,
) -> Self {
Self {
index: node.index(),
name: if let Some(name) = node.name() {
name.to_string()
} else {
format!("GltfNode{}", node.index())
},
children,
mesh,
transform,
skin,
#[cfg(feature = "bevy_animation")]
is_animation_root: false,
extras,
}
}
#[cfg(feature = "bevy_animation")]
pub fn with_animation_root(self, is_animation_root: bool) -> Self {
Self {
is_animation_root,
..self
}
}
pub fn asset_label(&self) -> GltfAssetLabel {
GltfAssetLabel::Node(self.index)
}
}
#[derive(Asset, Debug, Clone, TypePath)]
pub struct GltfPrimitive {
pub index: usize,
pub parent_mesh_index: usize,
pub name: String,
pub mesh: Handle<Mesh>,
pub material: Option<Handle<GltfMaterial>>,
pub extras: Option<GltfExtras>,
pub material_extras: Option<GltfExtras>,
}
impl GltfPrimitive {
pub fn new(
gltf_mesh: &gltf::Mesh,
gltf_primitive: &gltf::Primitive,
mesh: Handle<Mesh>,
material: Option<Handle<GltfMaterial>>,
extras: Option<GltfExtras>,
material_extras: Option<GltfExtras>,
) -> Self {
GltfPrimitive {
index: gltf_primitive.index(),
parent_mesh_index: gltf_mesh.index(),
name: {
let mesh_name = gltf_mesh.name().unwrap_or("Mesh");
if gltf_mesh.primitives().len() > 1 {
format!("{}.{}", mesh_name, gltf_primitive.index())
} else {
mesh_name.to_string()
}
},
mesh,
material,
extras,
material_extras,
}
}
pub fn asset_label(&self) -> GltfAssetLabel {
GltfAssetLabel::Primitive {
mesh: self.parent_mesh_index,
primitive: self.index,
}
}
}
#[derive(Asset, Debug, Clone, TypePath)]
pub struct GltfSkin {
pub index: usize,
pub name: String,
pub joints: Vec<Handle<GltfNode>>,
pub inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,
pub extras: Option<GltfExtras>,
}
impl GltfSkin {
pub fn new(
skin: &gltf::Skin,
joints: Vec<Handle<GltfNode>>,
inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,
extras: Option<GltfExtras>,
) -> Self {
Self {
index: skin.index(),
name: if let Some(name) = skin.name() {
name.to_string()
} else {
format!("GltfSkin{}", skin.index())
},
joints,
inverse_bind_matrices,
extras,
}
}
pub fn asset_label(&self) -> GltfAssetLabel {
GltfAssetLabel::Skin(self.index)
}
}
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component, Clone, Default, Debug)]
pub struct GltfExtras {
pub value: String,
}
impl From<&serde_json::value::RawValue> for GltfExtras {
fn from(value: &serde_json::value::RawValue) -> Self {
GltfExtras {
value: value.get().to_string(),
}
}
}
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component, Clone, Default, Debug)]
pub struct GltfSceneExtras {
pub value: String,
}
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component, Clone)]
pub struct GltfSceneName(pub String);
impl Deref for GltfSceneName {
type Target = str;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component, Clone, Default, Debug)]
pub struct GltfMeshExtras {
pub value: String,
}
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component, Clone)]
pub struct GltfMeshName(pub String);
impl Deref for GltfMeshName {
type Target = str;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component, Clone, Default, Debug)]
pub struct GltfMaterialExtras {
pub value: String,
}
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component, Clone)]
pub struct GltfMaterialName(pub String);
impl Deref for GltfMaterialName {
type Target = str;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}