Skip to main content

gltf_reader/
mesh.rs

1use alloc::collections::BTreeMap;
2use alloc::format;
3use alloc::vec::Vec;
4
5use alloc::borrow::Cow;
6use ownable::IntoOwned;
7use serde::Deserialize;
8
9use crate::accessor::Accessor;
10use crate::material::Material;
11use crate::{Extensions, Extras, Idx};
12
13/// glTF known attribute semantics.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum AttributeEnum {
16    Position,
17    Normal,
18    Tangent,
19    Texcoord(u16),
20    Color(u16),
21    Joints(u16),
22    Weights(u16),
23}
24
25/// A vertex attribute semantic.
26#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, IntoOwned)]
27#[serde(transparent)]
28pub struct Attribute<'a>(#[serde(borrow)] pub Cow<'a, str>);
29
30impl core::fmt::Debug for Attribute<'_> {
31    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32        if let Some(e) = self.to_enum() {
33            e.fmt(f)
34        } else {
35            self.0.fmt(f)
36        }
37    }
38}
39
40impl Attribute<'_> {
41    pub const POSITION: Self = Self(Cow::Borrowed("POSITION"));
42    pub const NORMAL: Self = Self(Cow::Borrowed("NORMAL"));
43    pub const TANGENT: Self = Self(Cow::Borrowed("TANGENT"));
44
45    const PREFIX_TEXCOORD: &'static str = "TEXCOORD";
46    const PREFIX_COLOR: &'static str = "COLOR";
47    const PREFIX_JOINTS: &'static str = "JOINTS";
48    const PREFIX_WEIGHTS: &'static str = "WEIGHTS";
49
50    pub fn to_enum(&self) -> Option<AttributeEnum> {
51        if *self == Self::POSITION {
52            return Some(AttributeEnum::Position);
53        } else if *self == Self::NORMAL {
54            return Some(AttributeEnum::Normal);
55        } else if *self == Self::TANGENT {
56            return Some(AttributeEnum::Tangent);
57        }
58
59        if let Some((prefix, n)) = self.0.rsplit_once('_') {
60            let Ok(n) = n.parse::<u16>() else {
61                return None;
62            };
63
64            match prefix {
65                Self::PREFIX_TEXCOORD => return Some(AttributeEnum::Texcoord(n)),
66                Self::PREFIX_COLOR => return Some(AttributeEnum::Color(n)),
67                Self::PREFIX_JOINTS => return Some(AttributeEnum::Joints(n)),
68                Self::PREFIX_WEIGHTS => return Some(AttributeEnum::Weights(n)),
69                _ => (),
70            }
71        }
72
73        None
74    }
75
76    pub fn texcoord(n: u16) -> Self {
77        Self(Cow::Owned(format!("{}{n}", Self::PREFIX_TEXCOORD)))
78    }
79
80    pub fn color(n: u16) -> Self {
81        Self(Cow::Owned(format!("{}{n}", Self::PREFIX_COLOR)))
82    }
83
84    pub fn joints(n: u16) -> Self {
85        Self(Cow::Owned(format!("{}{n}", Self::PREFIX_JOINTS)))
86    }
87
88    pub fn weights(n: u16) -> Self {
89        Self(Cow::Owned(format!("{}{n}", Self::PREFIX_WEIGHTS)))
90    }
91}
92
93/// glTF known primitive topologies.
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum ModeEnum {
96    Points,
97    Lines,
98    LineLoop,
99    LineStrip,
100    Triangles,
101    TriangleStrip,
102    TriangleFan,
103}
104
105/// The topology type of a set primitives to render.
106#[derive(Clone, Copy, PartialEq, Eq, Deserialize, IntoOwned)]
107#[serde(transparent)]
108pub struct Mode(pub u64);
109
110impl Default for Mode {
111    fn default() -> Self {
112        Self::TRIANGLES
113    }
114}
115
116impl core::fmt::Debug for Mode {
117    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118        if let Some(e) = self.to_enum() {
119            e.fmt(f)
120        } else {
121            self.0.fmt(f)
122        }
123    }
124}
125
126impl Mode {
127    pub const POINTS: Self = Self(0);
128    pub const LINES: Self = Self(1);
129    pub const LINE_LOOP: Self = Self(2);
130    pub const LINE_STRIP: Self = Self(3);
131    pub const TRIANGLES: Self = Self(4);
132    pub const TRIANGLE_STRIP: Self = Self(5);
133    pub const TRIANGLE_FAN: Self = Self(6);
134
135    pub fn to_enum(self) -> Option<ModeEnum> {
136        Some(match self {
137            Self::POINTS => ModeEnum::Points,
138            Self::LINES => ModeEnum::Lines,
139            Self::LINE_LOOP => ModeEnum::LineLoop,
140            Self::LINE_STRIP => ModeEnum::LineStrip,
141            Self::TRIANGLES => ModeEnum::Triangles,
142            Self::TRIANGLE_STRIP => ModeEnum::TriangleStrip,
143            Self::TRIANGLE_FAN => ModeEnum::TriangleFan,
144            _ => return None,
145        })
146    }
147}
148
149/// A set of primitives to be rendered.
150#[derive(Debug, Clone, Deserialize, IntoOwned)]
151pub struct Primitive<'a> {
152    /// A map where each key corresponds to a mesh attribute semantic and each value is the index of
153    /// the accessor containing the attribute's data.
154    #[serde(borrow = "'a")]
155    pub attributes: BTreeMap<Attribute<'a>, Idx<Accessor<'static>>>,
156    /// The index of the accessor that contains the vertex indices.
157    pub indices: Option<Idx<Accessor<'static>>>,
158    /// The index of the material to apply to this primitive when rendering.
159    pub material: Option<Idx<Material<'static>>>,
160    /// The topology type of primitives to render.
161    #[serde(default)]
162    pub mode: Mode,
163    /// An array of morph targets.
164    pub targets: Option<Vec<BTreeMap<Cow<'a, str>, Idx<Accessor<'static>>>>>,
165
166    #[serde(borrow)]
167    pub extensions: Option<Extensions<'a>>,
168    #[serde(borrow)]
169    pub extras: Option<Extras<'a>>,
170}
171
172/// A set of primitives to be rendered.
173#[derive(Debug, Clone, Deserialize, IntoOwned)]
174pub struct Mesh<'a> {
175    /// The user-defined name of this object.
176    #[serde(borrow)]
177    pub name: Option<Cow<'a, str>>,
178
179    /// An array of primitives, each defining geometry to be rendered.
180    #[serde(borrow)]
181    pub primitives: Vec<Primitive<'a>>,
182    /// Array of weights to be applied to the morph targets.
183    pub weights: Option<Vec<f32>>,
184
185    #[serde(borrow)]
186    pub extensions: Option<Extensions<'a>>,
187    #[serde(borrow)]
188    pub extras: Option<Extras<'a>>,
189}