gltf-reader 0.1.0

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

use crate::texture::Texture;
use crate::{Extensions, Extras, Idx};

fn default_base_color_factor() -> [f32; 4] {
    [1.0; 4]
}

fn one_f32() -> f32 {
    1.0
}

fn half_f32() -> f32 {
    0.5
}

/// Reference to a texture.
#[derive(Debug, Clone, Deserialize, IntoOwned)]
pub struct TextureInfo<'a> {
    /// The index of the texture.
    pub index: Idx<Texture<'static>>,
    /// The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
    #[serde(rename = "texCoord")]
    #[serde(default)]
    pub texcoord: u64,

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

/// Reference to a normal texture.
#[derive(Debug, Clone, Deserialize, IntoOwned)]
pub struct NormalTextureInfo<'a> {
    #[serde(flatten, borrow)]
    pub inner: TextureInfo<'a>,
    /// The scalar parameter applied to each normal vector of the normal texture.
    #[serde(default = "one_f32")]
    pub scale: f32,
}

/// Reference to an occlusion texture.
#[derive(Debug, Clone, Deserialize, IntoOwned)]
pub struct OcclusionTextureInfo<'a> {
    #[serde(flatten, borrow)]
    pub inner: TextureInfo<'a>,
    /// A scalar multiplier controlling the amount of occlusion applied.
    #[serde(default = "one_f32")]
    pub strength: f32,
}

/// A set of parameter values that are used to define the metallic-roughness material model from
/// Physically-Based Rendering (PBR) methodology.
#[derive(Debug, Clone, Deserialize, IntoOwned)]
pub struct PbrMetallicRoughness<'a> {
    /// The base color texture.
    #[serde(rename = "baseColorTexture")]
    #[serde(borrow)]
    pub base_color_texture: Option<TextureInfo<'a>>,
    #[serde(rename = "metallicRoughnessTexture")]
    #[serde(borrow)]
    pub metallic_roughness_texture: Option<TextureInfo<'a>>,

    /// The factors for the base color of the material.
    #[serde(rename = "baseColorFactor")]
    #[serde(default = "default_base_color_factor")]
    pub base_color_factor: [f32; 4],
    /// The factor for the metalness of the material.
    #[serde(rename = "metallicFactor")]
    #[serde(default = "one_f32")]
    pub metallic_factor: f32,
    /// The factor for the roughness of the material,
    #[serde(rename = "roughnessFactor")]
    #[serde(default = "one_f32")]
    pub roughness_factor: f32,

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

/// glTF known alpha modes.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AlphaModeEnum {
    Opaque,
    Mask,
    Blend,
}

/// The alpha rendering mode of a material.
#[derive(Clone, PartialEq, Eq, Deserialize, IntoOwned)]
#[serde(transparent)]
pub struct AlphaMode<'a>(#[serde(borrow)] pub Cow<'a, str>);

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

impl core::fmt::Debug for AlphaMode<'_> {
    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 AlphaMode<'_> {
    pub const OPAQUE: Self = Self(Cow::Borrowed("OPAQUE"));
    pub const MASK: Self = Self(Cow::Borrowed("MASK"));
    pub const BLEND: Self = Self(Cow::Borrowed("BLEND"));

    pub fn to_enum(&self) -> Option<AlphaModeEnum> {
        if *self == Self::OPAQUE {
            return Some(AlphaModeEnum::Opaque);
        } else if *self == Self::MASK {
            return Some(AlphaModeEnum::Mask);
        } else if *self == Self::BLEND {
            return Some(AlphaModeEnum::Blend);
        }

        None
    }
}

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

    /// A set of parameter values that are used to define the metallic-roughness material model from
    /// Physically Based Rendering (PBR) methodology.
    #[serde(rename = "pbrMetallicRoughness")]
    #[serde(borrow)]
    pub pbr_metallic_roughness: Option<PbrMetallicRoughness<'a>>,
    /// The tangent space normal texture.
    #[serde(rename = "normalTexture")]
    #[serde(borrow)]
    pub normal_texture: Option<NormalTextureInfo<'a>>,
    /// The occlusion texture.
    #[serde(rename = "occlusionTexture")]
    #[serde(borrow)]
    pub occlusion_texture: Option<OcclusionTextureInfo<'a>>,
    /// The emissive texture.
    #[serde(rename = "emissiveTexture")]
    #[serde(borrow)]
    pub emissive_texture: Option<TextureInfo<'a>>,
    /// The factors for the emissive color of the material.
    #[serde(rename = "emissiveFactor")]
    #[serde(default)]
    pub emissive_factor: [f32; 3],
    /// The alpha rendering mode of the material.
    #[serde(rename = "alphaMode")]
    #[serde(default)]
    pub alpha_mode: AlphaMode<'a>,
    /// The alpha cutoff value of the material.
    #[serde(rename = "alphaCutoff")]
    #[serde(default = "half_f32")]
    pub alpha_cutoff: f32,
    /// Specifies whether the material is double sided.
    #[serde(rename = "doubleSided")]
    #[serde(default)]
    pub double_sided: bool,

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