gltf-reader 0.1.0

A simple glTF 2.0 reader using `serde` and `serde_json`
Documentation
use alloc::borrow::Cow;
use alloc::vec::Vec;
use ownable::IntoOwned;
use serde::Deserialize;

use crate::accessor::Accessor;
use crate::node::Node;
use crate::{Extensions, Extras, Idx};

/// glTF known interpolation algorithms.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InterpolationEnum {
    Linear,
    Step,
    CubicSpline,
}

/// Interpolation algorithm.
#[derive(Clone, PartialEq, Eq, Deserialize, IntoOwned)]
#[serde(transparent)]
pub struct Interpolation<'a>(#[serde(borrow)] pub Cow<'a, str>);

impl Default for Interpolation<'_> {
    fn default() -> Self {
        Self::LINEAR
    }
}

impl core::fmt::Debug for Interpolation<'_> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        if let Some(e) = self.to_enum() {
            e.fmt(f)
        } else {
            self.0.fmt(f)
        }
    }
}

impl Interpolation<'_> {
    pub const LINEAR: Self = Self(Cow::Borrowed("LINEAR"));
    pub const STEP: Self = Self(Cow::Borrowed("STEP"));
    pub const CUBICSPLINE: Self = Self(Cow::Borrowed("CUBICSPLINE"));

    pub fn to_enum(&self) -> Option<InterpolationEnum> {
        if *self == Self::LINEAR {
            return Some(InterpolationEnum::Linear);
        } else if *self == Self::STEP {
            return Some(InterpolationEnum::Step);
        } else if *self == Self::CUBICSPLINE {
            return Some(InterpolationEnum::CubicSpline);
        }

        None
    }
}

/// An animation sampler combines timestamps with a sequence of output values and defines an
/// interpolation algorithm.
#[derive(Debug, Clone, Deserialize, IntoOwned)]
pub struct AnimationSampler<'a> {
    /// The index of an accessor containing keyframe timestamps.
    pub input: Idx<Accessor<'static>>,
    /// The index of an accessor containing keyframe output values.
    pub output: Idx<Accessor<'static>>,
    /// Interpolation algorithm.
    #[serde(default, borrow)]
    pub interpolation: Interpolation<'a>,

    #[serde(borrow)]
    pub extensions: Option<Extensions<'a>>,
    #[serde(borrow)]
    pub extras: Option<Extras<'a>>,
}

/// glTF known animation properties.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PropertyEnum {
    Translation,
    Rotation,
    Scale,
    Weights,
}

/// The name of a node's TRS property to animate, or the `weights` of the Morph Targets it
/// instantiates.
#[derive(Clone, PartialEq, Eq, Deserialize, IntoOwned)]
#[serde(transparent)]
pub struct Property<'a>(#[serde(borrow)] pub Cow<'a, str>);

impl core::fmt::Debug for Property<'_> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        if let Some(e) = self.to_enum() {
            e.fmt(f)
        } else {
            self.0.fmt(f)
        }
    }
}

impl Property<'_> {
    pub const TRANSLATION: Self = Self(Cow::Borrowed("translation"));
    pub const ROTATION: Self = Self(Cow::Borrowed("rotation"));
    pub const SCALE: Self = Self(Cow::Borrowed("scale"));
    pub const WEIGHTS: Self = Self(Cow::Borrowed("weights"));

    pub fn to_enum(&self) -> Option<PropertyEnum> {
        if *self == Self::TRANSLATION {
            return Some(PropertyEnum::Translation);
        } else if *self == Self::ROTATION {
            return Some(PropertyEnum::Rotation);
        } else if *self == Self::SCALE {
            return Some(PropertyEnum::Scale);
        } else if *self == Self::WEIGHTS {
            return Some(PropertyEnum::Weights);
        }

        None
    }
}

/// The descriptor of an animated property.
#[derive(Debug, Clone, Deserialize, IntoOwned)]
pub struct ChannelTarget<'a> {
    /// The index of the node to animate.
    pub node: Option<Idx<Node<'static>>>,
    /// The name of the node's TRS property to animate, or the `weights` of the Morph Targets it
    /// instantiates.
    #[serde(borrow)]
    pub path: Property<'a>,

    #[serde(borrow)]
    pub extensions: Option<Extensions<'a>>,
    #[serde(borrow)]
    pub extras: Option<Extras<'a>>,
}

/// An animation channel combines an animation sampler with a target property being animated.
#[derive(Debug, Clone, Deserialize, IntoOwned)]
pub struct Channel<'a> {
    /// The index of a sampler in an animation used to compute the value for the target.
    pub sampler: Idx<AnimationSampler<'static>>,
    /// The descriptor of the animated property.
    #[serde(borrow)]
    pub target: ChannelTarget<'a>,

    #[serde(borrow)]
    pub extensions: Option<Extensions<'a>>,
    #[serde(borrow)]
    pub extras: Option<Extras<'a>>,
}

/// A keyframe animation.
#[derive(Debug, Clone, Deserialize, IntoOwned)]
pub struct Animation<'a> {
    /// The user-defined name of this object.
    #[serde(borrow)]
    pub name: Option<Cow<'a, str>>,

    /// An array of animation samplers.
    #[serde(borrow)]
    pub samplers: Vec<AnimationSampler<'a>>,
    /// An array of animation channels.
    #[serde(borrow)]
    pub channels: Vec<Channel<'a>>,

    #[serde(borrow)]
    pub extensions: Option<Extensions<'a>>,
    #[serde(borrow)]
    pub extras: Option<Extras<'a>>,
}