gltf_json/
mesh.rs

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