gltf_v1_json/
mesh.rs

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}