1use std::fmt::{self, Display};
2
3use gltf_v1_derive::Validate;
4use indexmap::IndexMap;
5use serde::{de, ser};
6use serde_derive::{Deserialize, Serialize};
7
8use super::{accessor::Accessor, common::StringIndex, material::Material, validation::Checked};
9
10pub const POSITION: &str = "POSITION";
11pub const NORMAL: &str = "NORMAL";
12pub const COLOR: &str = "COLOR_";
13pub const TEXCOORD: &str = "TEXCOORD_";
14pub const JOINT: &str = "JOINT_";
15pub const WEIGHT: &str = "WEIGHT_";
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
18pub enum Semantic {
19 Positions,
20 Normals,
21 Colors(u32),
22 TexCoords(u32),
23 Joints(u32),
24 Weights(u32),
25}
26
27impl Semantic {
28 pub const VALID_SEMANTICS: &[&str] = &[POSITION, NORMAL, COLOR, TEXCOORD, JOINT, WEIGHT];
29}
30
31impl Display for Semantic {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 let str: String = (*self).into();
34 f.write_str(&str)
35 }
36}
37
38impl From<Semantic> for String {
39 fn from(value: Semantic) -> Self {
40 match value {
41 Semantic::Positions => POSITION.into(),
42 Semantic::Normals => NORMAL.into(),
43 Semantic::Colors(c) => format!("{}{}", COLOR, c),
44 Semantic::TexCoords(c) => format!("{}{}", TEXCOORD, c),
45 Semantic::Joints(c) => format!("{}{}", JOINT, c),
46 Semantic::Weights(c) => format!("{}{}", WEIGHT, c),
47 }
48 }
49}
50
51impl TryFrom<&str> for Semantic {
52 type Error = ();
53
54 fn try_from(s: &str) -> Result<Self, Self::Error> {
55 match s {
56 NORMAL => Ok(Semantic::Normals),
57 POSITION => Ok(Semantic::Positions),
58 _ if s.starts_with(COLOR) => match s[COLOR.len()..].parse() {
59 Ok(set) => Ok(Semantic::Colors(set)),
60 Err(_) => Err(()),
61 },
62 _ if s.starts_with(TEXCOORD) => match s[TEXCOORD.len()..].parse() {
63 Ok(set) => Ok(Semantic::TexCoords(set)),
64 Err(_) => Err(()),
65 },
66 _ if s.starts_with(JOINT) => match s[JOINT.len()..].parse() {
67 Ok(set) => Ok(Semantic::Joints(set)),
68 Err(_) => Err(()),
69 },
70 _ if s.starts_with(WEIGHT) => match s[WEIGHT.len()..].parse() {
71 Ok(set) => Ok(Semantic::Weights(set)),
72 Err(_) => Err(()),
73 },
74 _ => Err(()),
75 }
76 }
77}
78
79impl ser::Serialize for Semantic {
80 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
81 where
82 S: ser::Serializer,
83 {
84 serializer.serialize_str(&self.to_string())
85 }
86}
87
88impl<'de> de::Deserialize<'de> for Checked<Semantic> {
89 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
90 where
91 D: de::Deserializer<'de>,
92 {
93 struct Visitor;
94 impl de::Visitor<'_> for Visitor {
95 type Value = Checked<Semantic>;
96
97 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 write!(f, "any of: {:?}", Semantic::VALID_SEMANTICS)
99 }
100
101 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
102 where
103 E: de::Error,
104 {
105 Ok(value
106 .try_into()
107 .map(Checked::Valid)
108 .unwrap_or(Checked::Invalid))
109 }
110 }
111 deserializer.deserialize_str(Visitor)
112 }
113}
114pub const POINTS: u32 = 0;
115pub const LINES: u32 = 1;
116pub const LINE_LOOP: u32 = 2;
117pub const LINE_STRIP: u32 = 3;
118pub const TRIANGLES: u32 = 4;
119pub const TRIANGLE_STRIP: u32 = 5;
120pub const TRIANGLE_FAN: u32 = 6;
121
122#[repr(u8)]
123#[derive(Clone, Copy, Debug, Eq, PartialEq)]
124pub enum PrimitiveMode {
125 Points,
126 Lines,
127 LineLoop,
128 LineStrip,
129 Triangles,
130 TriangleStrip,
131 TriangleFan,
132}
133
134impl PrimitiveMode {
135 pub const VALID_PRIMITIVE_MODES: &[u32] = &[
136 POINTS,
137 LINES,
138 LINE_LOOP,
139 LINE_STRIP,
140 TRIANGLES,
141 TRIANGLE_STRIP,
142 TRIANGLE_FAN,
143 ];
144}
145
146impl From<PrimitiveMode> for u32 {
147 fn from(value: PrimitiveMode) -> Self {
148 match value {
149 PrimitiveMode::Points => POINTS,
150 PrimitiveMode::Lines => LINES,
151 PrimitiveMode::LineLoop => LINE_LOOP,
152 PrimitiveMode::LineStrip => LINE_STRIP,
153 PrimitiveMode::Triangles => TRIANGLES,
154 PrimitiveMode::TriangleStrip => TRIANGLE_STRIP,
155 PrimitiveMode::TriangleFan => TRIANGLE_FAN,
156 }
157 }
158}
159
160impl TryFrom<u32> for PrimitiveMode {
161 type Error = ();
162
163 fn try_from(value: u32) -> Result<Self, Self::Error> {
164 match value {
165 POINTS => Ok(PrimitiveMode::Points),
166 LINES => Ok(PrimitiveMode::Lines),
167 LINE_LOOP => Ok(PrimitiveMode::LineLoop),
168 LINE_STRIP => Ok(PrimitiveMode::LineStrip),
169 TRIANGLES => Ok(PrimitiveMode::Triangles),
170 TRIANGLE_STRIP => Ok(PrimitiveMode::TriangleStrip),
171 TRIANGLE_FAN => Ok(PrimitiveMode::TriangleFan),
172 _ => Err(()),
173 }
174 }
175}
176
177impl ser::Serialize for PrimitiveMode {
178 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
179 where
180 S: ser::Serializer,
181 {
182 serializer.serialize_u32((*self).into())
183 }
184}
185
186impl<'de> de::Deserialize<'de> for Checked<PrimitiveMode> {
187 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
188 where
189 D: de::Deserializer<'de>,
190 {
191 struct Visitor;
192 impl de::Visitor<'_> for Visitor {
193 type Value = Checked<PrimitiveMode>;
194
195 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 write!(f, "any of: {:?}", PrimitiveMode::VALID_PRIMITIVE_MODES)
197 }
198
199 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
200 where
201 E: de::Error,
202 {
203 Ok((value as u32)
204 .try_into()
205 .map(Checked::Valid)
206 .unwrap_or(Checked::Invalid))
207 }
208 }
209 deserializer.deserialize_u64(Visitor)
210 }
211}
212
213#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
214pub struct Primitive {
215 #[serde(skip_serializing_if = "IndexMap::is_empty")]
216 pub attributes: IndexMap<Checked<Semantic>, StringIndex<Accessor>>,
217 #[serde(skip_serializing_if = "Option::is_none")]
218 pub indices: Option<StringIndex<Accessor>>,
219 pub material: StringIndex<Material>,
220 #[serde(default = "default_primitive_mode")]
221 pub mode: Checked<PrimitiveMode>,
222}
223
224impl Primitive {
225 pub fn new(material: StringIndex<Material>) -> Self {
226 Self {
227 attributes: IndexMap::new(),
228 indices: None,
229 material,
230 mode: Checked::Valid(PrimitiveMode::Triangles),
231 }
232 }
233}
234
235fn default_primitive_mode() -> Checked<PrimitiveMode> {
236 Checked::Valid(PrimitiveMode::Triangles)
237}
238
239#[derive(Clone, Debug, Deserialize, Serialize, Validate, Default)]
240pub struct Mesh {
241 #[serde(default)]
242 #[serde(skip_serializing_if = "Vec::is_empty")]
243 pub primitives: Vec<Primitive>,
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub name: Option<String>,
246}
247
248#[test]
249fn test_mesh_deserialize() {
250 let data = r#"{
251 "name": "user-defined name of mesh",
252 "primitives": [
253 {
254 "attributes": {
255 "NORMAL": "accessor_id0",
256 "POSITION": "accessor_id1",
257 "TEXCOORD_0": "accessor_id2"
258 },
259 "indices": "accessor_id3",
260 "material": "material_id",
261 "mode": 4,
262 "extensions" : {
263 "extension_name" : {
264 "extension specific" : "value"
265 }
266 },
267 "extras" : {
268 "Application specific" : "The extra object can contain any properties."
269 }
270 }
271 ],
272 "extensions" : {
273 "extension_name" : {
274 "extension specific" : "value"
275 }
276 },
277 "extras" : {
278 "Application specific" : "The extra object can contain any properties."
279 }
280 }"#;
281 let mesh: Result<Mesh, _> = serde_json::from_str(data);
282 let mesh_unwrap = mesh.unwrap();
283 println!("{}", serde_json::to_string(&mesh_unwrap).unwrap());
284 assert_eq!(
285 Some("user-defined name of mesh".to_string()),
286 mesh_unwrap.name
287 );
288}