shine_gltf/
mesh.rs

1use crate::validation::{Checked, Error, Validate};
2use crate::{accessor, extensions, material, Index};
3use serde::{de, ser};
4use serde_derive::{Deserialize, Serialize};
5use serde_json::from_value;
6use shine_gltf_macro::Validate;
7use std::collections::HashMap;
8use std::fmt;
9
10/// Corresponds to `GL_POINTS`.
11pub const POINTS: u32 = 0;
12
13/// Corresponds to `GL_LINES`.
14pub const LINES: u32 = 1;
15
16/// Corresponds to `GL_LINE_LOOP`.
17pub const LINE_LOOP: u32 = 2;
18
19/// Corresponds to `GL_LINE_STRIP`.
20pub const LINE_STRIP: u32 = 3;
21
22/// Corresponds to `GL_TRIANGLES`.
23pub const TRIANGLES: u32 = 4;
24
25/// Corresponds to `GL_TRIANGLE_STRIP`.
26pub const TRIANGLE_STRIP: u32 = 5;
27
28/// Corresponds to `GL_TRIANGLE_FAN`.
29pub const TRIANGLE_FAN: u32 = 6;
30
31/// All valid primitive rendering modes.
32pub const VALID_MODES: &[u32] = &[POINTS, LINES, LINE_LOOP, LINE_STRIP, TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN];
33
34/// All valid semantic names for Morph targets.
35pub const VALID_MORPH_TARGETS: &[&str] = &["POSITION", "NORMAL", "TANGENT"];
36
37/// The type of primitives to render.
38#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
39pub enum Mode {
40    /// Corresponds to `GL_POINTS`.
41    Points = 1,
42
43    /// Corresponds to `GL_LINES`.
44    Lines,
45
46    /// Corresponds to `GL_LINE_LOOP`.
47    LineLoop,
48
49    /// Corresponds to `GL_LINE_STRIP`.
50    LineStrip,
51
52    /// Corresponds to `GL_TRIANGLES`.
53    Triangles,
54
55    /// Corresponds to `GL_TRIANGLE_STRIP`.
56    TriangleStrip,
57
58    /// Corresponds to `GL_TRIANGLE_FAN`.
59    TriangleFan,
60}
61
62/// A set of primitives to be rendered.
63///
64/// A node can contain one or more meshes and its transform places the meshes in
65/// the scene.
66#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
67pub struct Mesh {
68    /// Extension specific data.
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub extensions: Option<extensions::mesh::Mesh>,
71
72    /// Defines the geometry to be renderered with a material.
73    #[serde(skip_serializing_if = "Vec::is_empty")]
74    pub primitives: Vec<Primitive>,
75
76    /// Defines the weights to be applied to the morph targets.
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub weights: Option<Vec<f32>>,
79}
80
81/// Geometry to be rendered with the given material.
82#[derive(Clone, Debug, Default, Deserialize, Serialize)]
83pub struct Primitive {
84    /// Maps attribute semantic names to the `Accessor`s containing the
85    /// corresponding attribute data.
86    pub attributes: HashMap<Checked<Semantic>, Index<accessor::Accessor>>,
87
88    /// Extension specific data.
89    #[serde(default, skip_serializing_if = "Option::is_none")]
90    pub extensions: Option<extensions::mesh::Primitive>,
91
92    /// The index of the accessor that contains the indices.
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub indices: Option<Index<accessor::Accessor>>,
95
96    /// The index of the material to apply to this primitive when rendering
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub material: Option<Index<material::Material>>,
99
100    /// The type of primitives to render.
101    #[serde(default, skip_serializing_if = "is_primitive_mode_default")]
102    pub mode: Checked<Mode>,
103
104    /// An array of Morph Targets, each  Morph Target is a dictionary mapping
105    /// attributes (only `POSITION`, `NORMAL`, and `TANGENT` supported) to their
106    /// deviations in the Morph Target.
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub targets: Option<Vec<MorphTarget>>,
109}
110
111// Help serde avoid serializing this glTF 2.0 default value.
112#[allow(clippy::trivially_copy_pass_by_ref)]
113fn is_primitive_mode_default(mode: &Checked<Mode>) -> bool {
114    *mode == Checked::Valid(Mode::Triangles)
115}
116
117impl Validate for Primitive {
118    fn validate_minimally<P, R>(&self, root: &crate::Root, path: P, report: &mut R)
119    where
120        P: Fn() -> crate::Path,
121        R: FnMut(&dyn Fn() -> crate::Path, crate::validation::Error),
122    {
123        // Generated part
124        self.attributes
125            .validate_minimally(root, || path().field("attributes"), report);
126        self.extensions
127            .validate_minimally(root, || path().field("extensions"), report);
128        self.indices.validate_minimally(root, || path().field("indices"), report);
129        self.material.validate_minimally(root, || path().field("material"), report);
130        self.mode.validate_minimally(root, || path().field("mode"), report);
131        self.targets.validate_minimally(root, || path().field("targets"), report);
132
133        // Custom part
134        let position_path = &|| path().field("attributes").key("POSITION");
135        if let Some(pos_accessor_index) = self.attributes.get(&Checked::Valid(Semantic::Positions)) {
136            // spec: POSITION accessor **must** have `min` and `max` properties defined.
137            let pos_accessor = &root.accessors[pos_accessor_index.value()];
138
139            let min_path = &|| position_path().field("min");
140            if let Some(ref min) = pos_accessor.min {
141                if from_value::<[f32; 3]>(min.clone()).is_err() {
142                    report(min_path, Error::Invalid);
143                }
144            } else {
145                report(min_path, Error::Missing);
146            }
147
148            let max_path = &|| position_path().field("max");
149            if let Some(ref max) = pos_accessor.max {
150                if from_value::<[f32; 3]>(max.clone()).is_err() {
151                    report(max_path, Error::Invalid);
152                }
153            } else {
154                report(max_path, Error::Missing);
155            }
156        } else {
157            report(position_path, Error::Missing);
158        }
159    }
160}
161
162/// A dictionary mapping attributes to their deviations in the Morph Target.
163#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
164pub struct MorphTarget {
165    /// XYZ vertex position displacements of type `[f32; 3]`.
166    #[serde(rename = "POSITION")]
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub positions: Option<Index<accessor::Accessor>>,
169
170    /// XYZ vertex normal displacements of type `[f32; 3]`.
171    #[serde(rename = "NORMAL")]
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub normals: Option<Index<accessor::Accessor>>,
174
175    /// XYZ vertex tangent displacements of type `[f32; 3]`.
176    #[serde(rename = "TANGENT")]
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub tangents: Option<Index<accessor::Accessor>>,
179}
180
181/// Vertex attribute semantic name.
182#[derive(Clone, Debug, Eq, Hash, PartialEq)]
183pub enum Semantic {
184    /// XYZ vertex positions.
185    Positions,
186
187    /// XYZ vertex normals.
188    Normals,
189
190    /// XYZW vertex tangents where the `w` component is a sign value indicating the
191    /// handedness of the tangent basis.
192    Tangents,
193
194    /// RGB or RGBA vertex color.
195    Colors(u32),
196
197    /// UV texture co-ordinates.
198    TexCoords(u32),
199
200    /// Joint indices.
201    Joints(u32),
202
203    /// Joint weights.
204    Weights(u32),
205}
206
207impl Default for Mode {
208    fn default() -> Mode {
209        Mode::Triangles
210    }
211}
212
213impl Mode {
214    /// Returns the equivalent `GLenum`.
215    pub fn as_gl_enum(self) -> u32 {
216        match self {
217            Mode::Points => POINTS,
218            Mode::Lines => LINES,
219            Mode::LineLoop => LINE_LOOP,
220            Mode::LineStrip => LINE_STRIP,
221            Mode::Triangles => TRIANGLES,
222            Mode::TriangleStrip => TRIANGLE_STRIP,
223            Mode::TriangleFan => TRIANGLE_FAN,
224        }
225    }
226}
227
228impl<'de> de::Deserialize<'de> for Checked<Mode> {
229    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
230    where
231        D: de::Deserializer<'de>,
232    {
233        struct Visitor;
234        impl<'de> de::Visitor<'de> for Visitor {
235            type Value = Checked<Mode>;
236
237            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238                write!(f, "any of: {:?}", VALID_MODES)
239            }
240
241            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
242            where
243                E: de::Error,
244            {
245                use self::Mode::*;
246                use crate::validation::Checked::*;
247                Ok(match value as u32 {
248                    POINTS => Valid(Points),
249                    LINES => Valid(Lines),
250                    LINE_LOOP => Valid(LineLoop),
251                    LINE_STRIP => Valid(LineStrip),
252                    TRIANGLES => Valid(Triangles),
253                    TRIANGLE_STRIP => Valid(TriangleStrip),
254                    TRIANGLE_FAN => Valid(TriangleFan),
255                    _ => Invalid,
256                })
257            }
258        }
259        deserializer.deserialize_u64(Visitor)
260    }
261}
262
263impl ser::Serialize for Mode {
264    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
265    where
266        S: ser::Serializer,
267    {
268        serializer.serialize_u32(self.as_gl_enum())
269    }
270}
271
272impl Semantic {
273    fn checked(s: &str) -> Checked<Self> {
274        use self::Semantic::*;
275        use crate::validation::Checked::*;
276        match s {
277            "NORMAL" => Valid(Normals),
278            "POSITION" => Valid(Positions),
279            "TANGENT" => Valid(Tangents),
280            _ if s.starts_with("COLOR_") => match s["COLOR_".len()..].parse() {
281                Ok(set) => Valid(Colors(set)),
282                Err(_) => Invalid,
283            },
284            _ if s.starts_with("TEXCOORD_") => match s["TEXCOORD_".len()..].parse() {
285                Ok(set) => Valid(TexCoords(set)),
286                Err(_) => Invalid,
287            },
288            _ if s.starts_with("JOINTS_") => match s["JOINTS_".len()..].parse() {
289                Ok(set) => Valid(Joints(set)),
290                Err(_) => Invalid,
291            },
292            _ if s.starts_with("WEIGHTS_") => match s["WEIGHTS_".len()..].parse() {
293                Ok(set) => Valid(Weights(set)),
294                Err(_) => Invalid,
295            },
296            _ => Invalid,
297        }
298    }
299}
300
301impl ser::Serialize for Semantic {
302    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
303    where
304        S: ser::Serializer,
305    {
306        serializer.serialize_str(&self.to_string())
307    }
308}
309
310impl ToString for Semantic {
311    fn to_string(&self) -> String {
312        use self::Semantic::*;
313        match *self {
314            Positions => "POSITION".into(),
315            Normals => "NORMAL".into(),
316            Tangents => "TANGENT".into(),
317            Colors(set) => format!("COLOR_{}", set),
318            TexCoords(set) => format!("TEXCOORD_{}", set),
319            Joints(set) => format!("JOINTS_{}", set),
320            Weights(set) => format!("WEIGHTS_{}", set),
321        }
322    }
323}
324
325impl ToString for Checked<Semantic> {
326    fn to_string(&self) -> String {
327        match *self {
328            Checked::Valid(ref semantic) => semantic.to_string(),
329            Checked::Invalid => "<invalid semantic name>".into(),
330        }
331    }
332}
333
334impl<'de> de::Deserialize<'de> for Checked<Semantic> {
335    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
336    where
337        D: de::Deserializer<'de>,
338    {
339        struct Visitor;
340        impl<'de> de::Visitor<'de> for Visitor {
341            type Value = Checked<Semantic>;
342
343            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344                write!(f, "semantic name")
345            }
346
347            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
348            where
349                E: de::Error,
350            {
351                Ok(Semantic::checked(value))
352            }
353        }
354        deserializer.deserialize_str(Visitor)
355    }
356}
357
358/// Helper to initialize an attribute map in the  [ Att1 => value1, Attr2 => val2 ] form.
359#[macro_export]
360macro_rules! attribute_map {
361    ($( $key: ident => $val: expr ),*) => {{
362        use $crate::validation::Checked;
363        use $crate::mesh::Semantic;
364        let mut map = ::std::collections::HashMap::new();
365        $( map.insert(Checked::Valid(Semantic::$key), $val); )*
366        map
367    }}
368}
369
370/// Helper to initialize an attribute map in the [ Att1 => value1, Attr2 => val2 ] form where value is an Option
371#[macro_export]
372macro_rules! optional_attribute_map {
373    ($( $key: ident => $val: expr ),*) => {{
374        use $crate::validation::Checked;
375        use $crate::mesh::Semantic;
376        let mut map = ::std::collections::HashMap::new();
377        $(
378            match($val) {
379                Some(val) => {map.insert(Checked::Valid(Semantic::$key), val);}
380                None => {}
381            };
382        )*
383        map
384    }}
385}