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}