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#[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#[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#[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#[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#[derive(Debug, Clone, Deserialize, IntoOwned)]
151pub struct Primitive<'a> {
152 #[serde(borrow = "'a")]
155 pub attributes: BTreeMap<Attribute<'a>, Idx<Accessor<'static>>>,
156 pub indices: Option<Idx<Accessor<'static>>>,
158 pub material: Option<Idx<Material<'static>>>,
160 #[serde(default)]
162 pub mode: Mode,
163 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#[derive(Debug, Clone, Deserialize, IntoOwned)]
174pub struct Mesh<'a> {
175 #[serde(borrow)]
177 pub name: Option<Cow<'a, str>>,
178
179 #[serde(borrow)]
181 pub primitives: Vec<Primitive<'a>>,
182 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}