1use crate::validation::{Checked, Validate};
2use crate::{extensions, image, Extras, Index};
3use gltf_derive::Validate;
4use serde::{de, ser};
5use serde_derive::{Deserialize, Serialize};
6use std::fmt;
7
8pub const NEAREST: u32 = 9728;
10
11pub const LINEAR: u32 = 9729;
13
14pub const NEAREST_MIPMAP_NEAREST: u32 = 9984;
16
17pub const LINEAR_MIPMAP_NEAREST: u32 = 9985;
19
20pub const NEAREST_MIPMAP_LINEAR: u32 = 9986;
22
23pub const LINEAR_MIPMAP_LINEAR: u32 = 9987;
25
26pub const CLAMP_TO_EDGE: u32 = 33_071;
28
29pub const MIRRORED_REPEAT: u32 = 33_648;
31
32pub const REPEAT: u32 = 10_497;
34
35pub const VALID_MAG_FILTERS: &[u32] = &[NEAREST, LINEAR];
37
38pub const VALID_MIN_FILTERS: &[u32] = &[
40    NEAREST,
41    LINEAR,
42    NEAREST_MIPMAP_NEAREST,
43    LINEAR_MIPMAP_NEAREST,
44    NEAREST_MIPMAP_LINEAR,
45    LINEAR_MIPMAP_LINEAR,
46];
47
48pub const VALID_WRAPPING_MODES: &[u32] = &[CLAMP_TO_EDGE, MIRRORED_REPEAT, REPEAT];
50
51#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
53pub enum MagFilter {
54    Nearest = 1,
56
57    Linear,
59}
60
61impl MagFilter {
62    pub fn as_gl_enum(&self) -> u32 {
64        match *self {
65            MagFilter::Nearest => NEAREST,
66            MagFilter::Linear => LINEAR,
67        }
68    }
69}
70
71#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
73pub enum MinFilter {
74    Nearest = 1,
76
77    Linear,
79
80    NearestMipmapNearest,
82
83    LinearMipmapNearest,
85
86    NearestMipmapLinear,
88
89    LinearMipmapLinear,
91}
92
93impl MinFilter {
94    pub fn as_gl_enum(&self) -> u32 {
96        match *self {
97            MinFilter::Nearest => NEAREST,
98            MinFilter::Linear => LINEAR,
99            MinFilter::NearestMipmapNearest => NEAREST_MIPMAP_NEAREST,
100            MinFilter::LinearMipmapNearest => LINEAR_MIPMAP_NEAREST,
101            MinFilter::NearestMipmapLinear => NEAREST_MIPMAP_LINEAR,
102            MinFilter::LinearMipmapLinear => LINEAR_MIPMAP_LINEAR,
103        }
104    }
105}
106
107#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
109pub enum WrappingMode {
110    ClampToEdge = 1,
112
113    MirroredRepeat,
115
116    Repeat,
118}
119
120impl WrappingMode {
121    pub fn as_gl_enum(&self) -> u32 {
123        match *self {
124            WrappingMode::ClampToEdge => CLAMP_TO_EDGE,
125            WrappingMode::MirroredRepeat => MIRRORED_REPEAT,
126            WrappingMode::Repeat => REPEAT,
127        }
128    }
129}
130
131#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
133#[serde(default)]
134pub struct Sampler {
135    #[serde(rename = "magFilter")]
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub mag_filter: Option<Checked<MagFilter>>,
139
140    #[serde(rename = "minFilter")]
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub min_filter: Option<Checked<MinFilter>>,
144
145    #[cfg(feature = "names")]
147    #[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
148    pub name: Option<String>,
149
150    #[serde(default, rename = "wrapS")]
152    pub wrap_s: Checked<WrappingMode>,
153
154    #[serde(default, rename = "wrapT")]
156    pub wrap_t: Checked<WrappingMode>,
157
158    #[serde(default, skip_serializing_if = "Option::is_none")]
160    pub extensions: Option<extensions::texture::Sampler>,
161
162    #[serde(default)]
164    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
165    #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
166    pub extras: Extras,
167}
168
169fn source_default() -> Index<image::Image> {
170    Index::new(u32::MAX)
171}
172
173fn source_is_empty(source: &Index<image::Image>) -> bool {
174    source.value() == u32::MAX as usize
175}
176
177fn source_validate<P, R>(source: &Index<image::Image>, root: &crate::Root, path: P, report: &mut R)
178where
179    P: Fn() -> crate::Path,
180    R: FnMut(&dyn Fn() -> crate::Path, crate::validation::Error),
181{
182    if cfg!(feature = "allow_empty_texture") {
183        if !source_is_empty(source) {
184            source.validate(root, path, report);
185        }
186    } else if source_is_empty(source) {
187        report(&path, crate::validation::Error::Missing);
188    } else {
189        source.validate(root, &path, report);
190    }
191}
192
193#[derive(Clone, Debug, Deserialize, Serialize)]
195pub struct Texture {
196    #[cfg(feature = "names")]
198    #[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
199    pub name: Option<String>,
200
201    #[serde(skip_serializing_if = "Option::is_none")]
203    pub sampler: Option<Index<Sampler>>,
204
205    #[serde(default = "source_default", skip_serializing_if = "source_is_empty")]
207    pub source: Index<image::Image>,
208
209    #[serde(default, skip_serializing_if = "Option::is_none")]
211    pub extensions: Option<extensions::texture::Texture>,
212
213    #[serde(default)]
215    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
216    #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
217    pub extras: Extras,
218}
219
220impl Validate for Texture {
221    fn validate<P, R>(&self, root: &crate::Root, path: P, report: &mut R)
222    where
223        P: Fn() -> crate::Path,
224        R: FnMut(&dyn Fn() -> crate::Path, crate::validation::Error),
225    {
226        self.sampler
227            .validate(root, || path().field("sampler"), report);
228        self.extensions
229            .validate(root, || path().field("extensions"), report);
230        source_validate(&self.source, root, || path().field("source"), report);
231    }
232}
233
234#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
235pub struct Info {
237    pub index: Index<Texture>,
239
240    #[serde(default, rename = "texCoord")]
242    pub tex_coord: u32,
243
244    #[serde(default, skip_serializing_if = "Option::is_none")]
246    pub extensions: Option<extensions::texture::Info>,
247
248    #[serde(default)]
250    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
251    #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
252    pub extras: Extras,
253}
254
255impl<'de> de::Deserialize<'de> for Checked<MagFilter> {
256    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
257    where
258        D: de::Deserializer<'de>,
259    {
260        struct Visitor;
261        impl<'de> de::Visitor<'de> for Visitor {
262            type Value = Checked<MagFilter>;
263
264            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
265                write!(f, "any of: {:?}", VALID_MAG_FILTERS)
266            }
267
268            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
269            where
270                E: de::Error,
271            {
272                use self::MagFilter::*;
273                use crate::validation::Checked::*;
274                Ok(match value as u32 {
275                    NEAREST => Valid(Nearest),
276                    LINEAR => Valid(Linear),
277                    _ => Invalid,
278                })
279            }
280        }
281        deserializer.deserialize_u64(Visitor)
282    }
283}
284
285impl<'de> de::Deserialize<'de> for Checked<MinFilter> {
286    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
287    where
288        D: de::Deserializer<'de>,
289    {
290        struct Visitor;
291        impl<'de> de::Visitor<'de> for Visitor {
292            type Value = Checked<MinFilter>;
293
294            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
295                write!(f, "any of: {:?}", VALID_MIN_FILTERS)
296            }
297
298            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
299            where
300                E: de::Error,
301            {
302                use self::MinFilter::*;
303                use crate::validation::Checked::*;
304                Ok(match value as u32 {
305                    NEAREST => Valid(Nearest),
306                    LINEAR => Valid(Linear),
307                    NEAREST_MIPMAP_NEAREST => Valid(NearestMipmapNearest),
308                    LINEAR_MIPMAP_NEAREST => Valid(LinearMipmapNearest),
309                    NEAREST_MIPMAP_LINEAR => Valid(NearestMipmapLinear),
310                    LINEAR_MIPMAP_LINEAR => Valid(LinearMipmapLinear),
311                    _ => Invalid,
312                })
313            }
314        }
315        deserializer.deserialize_u64(Visitor)
316    }
317}
318
319impl ser::Serialize for MinFilter {
320    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
321    where
322        S: ser::Serializer,
323    {
324        serializer.serialize_u32(self.as_gl_enum())
325    }
326}
327
328impl<'de> de::Deserialize<'de> for Checked<WrappingMode> {
329    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
330    where
331        D: de::Deserializer<'de>,
332    {
333        struct Visitor;
334        impl<'de> de::Visitor<'de> for Visitor {
335            type Value = Checked<WrappingMode>;
336
337            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
338                write!(f, "any of: {:?}", VALID_WRAPPING_MODES)
339            }
340
341            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
342            where
343                E: de::Error,
344            {
345                use self::WrappingMode::*;
346                use crate::validation::Checked::*;
347                Ok(match value as u32 {
348                    CLAMP_TO_EDGE => Valid(ClampToEdge),
349                    MIRRORED_REPEAT => Valid(MirroredRepeat),
350                    REPEAT => Valid(Repeat),
351                    _ => Invalid,
352                })
353            }
354        }
355        deserializer.deserialize_u64(Visitor)
356    }
357}
358
359impl ser::Serialize for MagFilter {
360    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
361    where
362        S: ser::Serializer,
363    {
364        serializer.serialize_u32(self.as_gl_enum())
365    }
366}
367
368impl Default for WrappingMode {
369    fn default() -> Self {
370        WrappingMode::Repeat
371    }
372}
373
374impl ser::Serialize for WrappingMode {
375    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
376    where
377        S: ser::Serializer,
378    {
379        serializer.serialize_u32(self.as_gl_enum())
380    }
381}
382
383#[cfg(test)]
384mod tests {
385    #[test]
386    fn deserialize_source() {
387        let json = r#"{"asset":{"version":"2.0"},"textures":[{"source": 0}]}"#;
388        let root = serde_json::from_str::<crate::Root>(json).unwrap();
389        assert_eq!(0, root.textures[0].source.value());
390    }
391
392    #[test]
393    fn deserialize_empty_source() {
394        let json = r#"{"asset":{"version":"2.0"},"textures":[{}]}"#;
395        let root = serde_json::from_str::<crate::Root>(json).unwrap();
396        assert_eq!(u32::MAX as usize, root.textures[0].source.value());
397    }
398
399    #[test]
400    fn serialize_source() {
401        let root = crate::Root {
402            textures: vec![crate::Texture {
403                #[cfg(feature = "names")]
404                name: None,
405                sampler: None,
406                source: crate::Index::new(0),
407                extensions: None,
408                extras: Default::default(),
409            }],
410            ..Default::default()
411        };
412        let json = serde_json::to_string(&root).unwrap();
413        assert_eq!(
414            r#"{"asset":{"version":"2.0"},"textures":[{"source":0}]}"#,
415            &json
416        );
417    }
418
419    #[test]
420    fn serialize_empty_source() {
421        let root = crate::Root {
422            textures: vec![crate::Texture {
423                #[cfg(feature = "names")]
424                name: None,
425                sampler: None,
426                source: crate::Index::new(u32::MAX),
427                extensions: None,
428                extras: Default::default(),
429            }],
430            ..Default::default()
431        };
432        let json = serde_json::to_string(&root).unwrap();
433        assert_eq!(r#"{"asset":{"version":"2.0"},"textures":[{}]}"#, &json);
434    }
435
436    #[test]
437    fn validate_source() {
438        use crate::validation::{Error, Validate};
439        use crate::Path;
440        let json = r#"{"asset":{"version":"2.0"},"textures":[{"source":0}]}"#;
441        let root = serde_json::from_str::<crate::Root>(json).unwrap();
442        let mut errors = Vec::new();
443        root.textures[0].validate(
444            &root,
445            || Path::new().field("textures").index(0),
446            &mut |path, error| {
447                errors.push((path(), error));
448            },
449        );
450        assert_eq!(1, errors.len());
451        let (path, error) = &errors[0];
452        assert_eq!("textures[0].source", path.as_str());
453        assert_eq!(Error::IndexOutOfBounds, *error);
454    }
455
456    #[test]
457    fn validate_empty_source() {
458        use crate::validation::{Error, Validate};
459        use crate::Path;
460        let json = r#"{"asset":{"version":"2.0"},"textures":[{}]}"#;
461        let root = serde_json::from_str::<crate::Root>(json).unwrap();
462        let mut errors = Vec::new();
463        root.textures[0].validate(
464            &root,
465            || Path::new().field("textures").index(0),
466            &mut |path, error| {
467                errors.push((path(), error));
468            },
469        );
470        if cfg!(feature = "allow_empty_texture") {
471            assert!(errors.is_empty());
472        } else {
473            assert_eq!(1, errors.len());
474            let (path, error) = &errors[0];
475            assert_eq!("textures[0].source", path.as_str());
476            assert_eq!(Error::Missing, *error);
477        }
478    }
479}