Skip to main content

mugltf/
model.rs

1//! glTF 2.0 data model.
2
3use alloc::string::String;
4use alloc::vec::Vec;
5use alloc::{borrow::ToOwned, collections::BTreeMap};
6use mugl::{gl_const, AddressMode, FilterMode, PrimitiveTopology};
7
8/// Id type.
9pub type Id = usize;
10
11/// Size type.
12pub type Size = usize;
13
14/// Float type.
15pub type Float = f32;
16
17pub type Map<K, V> = BTreeMap<K, V>;
18
19/// The root object for a glTF asset.
20/// See: <https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html>
21#[derive(Clone, Debug, Default)]
22#[cfg_attr(
23    feature = "serde",
24    derive(serde::Serialize, serde::Deserialize),
25    serde(rename_all = "camelCase"),
26    serde(default)
27)]
28#[repr(C)]
29pub struct Gltf {
30    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
31    pub accessors: Vec<Accessor>,
32    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
33    pub animations: Vec<Animation>,
34    pub asset: Asset,
35    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
36    pub buffers: Vec<Buffer>,
37    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
38    pub buffer_views: Vec<BufferView>,
39    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
40    pub cameras: Vec<Camera>,
41    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
42    pub images: Vec<Image>,
43    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
44    pub materials: Vec<Material>,
45    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
46    pub meshes: Vec<Mesh>,
47    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
48    pub nodes: Vec<Node>,
49    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
50    pub samplers: Vec<Sampler>,
51    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
52    pub scene: Option<Id>,
53    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
54    pub scenes: Vec<Scene>,
55    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
56    pub skins: Vec<Skin>,
57    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
58    pub textures: Vec<Texture>,
59    #[cfg(feature = "gltf-extras")]
60    #[cfg_attr(
61        feature = "serde",
62        serde(default),
63        serde(skip_serializing_if = "serde_json::Value::is_null")
64    )]
65    pub extras: Extras,
66    #[cfg(feature = "gltf-extensions")]
67    #[cfg_attr(
68        feature = "serde",
69        serde(default),
70        serde(skip_serializing_if = "Option::is_none")
71    )]
72    pub extensions: Option<Extensions>,
73    #[cfg(feature = "gltf-extensions")]
74    #[cfg_attr(
75        feature = "serde",
76        serde(default),
77        serde(skip_serializing_if = "Vec::is_empty")
78    )]
79    pub extensions_used: Vec<String>,
80    #[cfg(feature = "gltf-extensions")]
81    #[cfg_attr(
82        feature = "serde",
83        serde(default),
84        serde(skip_serializing_if = "Vec::is_empty")
85    )]
86    pub extensions_required: Vec<String>,
87}
88
89/// Application-specific data.
90#[cfg(feature = "serde")]
91pub type Extras = serde_json::Value;
92
93/// JSON object with extension-specific objects.
94#[cfg(feature = "serde")]
95pub type Extensions = Map<String, serde_json::Value>;
96
97/// Metadata about the glTF asset.
98#[derive(Clone, Debug)]
99#[cfg_attr(
100    feature = "serde",
101    derive(serde::Serialize, serde::Deserialize),
102    serde(rename_all = "camelCase")
103)]
104#[repr(C)]
105pub struct Asset {
106    #[cfg_attr(
107        feature = "serde",
108        serde(default),
109        serde(skip_serializing_if = "String::is_empty")
110    )]
111    pub copyright: String,
112    #[cfg_attr(
113        feature = "serde",
114        serde(default),
115        serde(skip_serializing_if = "String::is_empty")
116    )]
117    pub generator: String,
118    pub version: String,
119    #[cfg_attr(
120        feature = "serde",
121        serde(default),
122        serde(skip_serializing_if = "String::is_empty")
123    )]
124    pub min_version: String,
125    #[cfg(feature = "gltf-extras")]
126    #[cfg_attr(
127        feature = "serde",
128        serde(default),
129        serde(skip_serializing_if = "serde_json::Value::is_null")
130    )]
131    pub extras: Extras,
132    #[cfg(feature = "gltf-extensions")]
133    #[cfg_attr(
134        feature = "serde",
135        serde(default),
136        serde(skip_serializing_if = "Option::is_none")
137    )]
138    pub extensions: Option<Extensions>,
139}
140
141impl Default for Asset {
142    fn default() -> Self {
143        Self {
144            copyright: Default::default(),
145            generator: Default::default(),
146            version: "2.0".to_owned(),
147            min_version: Default::default(),
148            #[cfg(feature = "gltf-extras")]
149            extras: Default::default(),
150            #[cfg(feature = "gltf-extensions")]
151            extensions: Default::default(),
152        }
153    }
154}
155
156#[derive(Clone, Debug)]
157#[cfg_attr(
158    feature = "serde",
159    derive(serde::Serialize, serde::Deserialize),
160    serde(rename_all = "camelCase")
161)]
162#[repr(C)]
163pub struct Accessor {
164    #[cfg_attr(
165        feature = "serde",
166        serde(default),
167        serde(skip_serializing_if = "Option::is_none")
168    )]
169    pub buffer_view: Option<Id>,
170    #[cfg_attr(feature = "serde", serde(default))]
171    pub byte_offset: Size,
172    pub component_type: AccessorComponentType,
173    #[cfg_attr(feature = "serde", serde(default), serde(skip_serializing_if = "is_false"))]
174    pub normalized: bool,
175    pub count: Size,
176    #[cfg_attr(feature = "serde", serde(rename = "type"))]
177    pub ty: AccessorType,
178    #[cfg_attr(
179        feature = "serde",
180        serde(default),
181        serde(skip_serializing_if = "Vec::is_empty")
182    )]
183    pub max: Vec<f64>,
184    #[cfg_attr(
185        feature = "serde",
186        serde(default),
187        serde(skip_serializing_if = "Vec::is_empty")
188    )]
189    pub min: Vec<f64>,
190    #[cfg_attr(
191        feature = "serde",
192        serde(default),
193        serde(skip_serializing_if = "Option::is_none")
194    )]
195    pub sparse: Option<AccessorSparse>,
196    #[cfg(feature = "gltf-name")]
197    #[cfg_attr(
198        feature = "serde",
199        serde(default),
200        serde(skip_serializing_if = "String::is_empty")
201    )]
202    pub name: String,
203    #[cfg(feature = "gltf-extras")]
204    #[cfg_attr(
205        feature = "serde",
206        serde(default),
207        serde(skip_serializing_if = "serde_json::Value::is_null")
208    )]
209    pub extras: Extras,
210    #[cfg(feature = "gltf-extensions")]
211    #[cfg_attr(
212        feature = "serde",
213        serde(default),
214        serde(skip_serializing_if = "Option::is_none")
215    )]
216    pub extensions: Option<Extensions>,
217}
218
219#[derive(Clone, Debug)]
220#[cfg_attr(
221    feature = "serde",
222    derive(serde::Serialize, serde::Deserialize),
223    serde(rename_all = "camelCase")
224)]
225#[repr(C)]
226pub struct AccessorSparse {
227    pub count: Size,
228    pub indices: AccessorSparseIndices,
229    pub values: AccessorSparseValues,
230    #[cfg(feature = "gltf-extras")]
231    #[cfg_attr(
232        feature = "serde",
233        serde(default),
234        serde(skip_serializing_if = "serde_json::Value::is_null")
235    )]
236    pub extras: Extras,
237    #[cfg(feature = "gltf-extensions")]
238    #[cfg_attr(
239        feature = "serde",
240        serde(default),
241        serde(skip_serializing_if = "Option::is_none")
242    )]
243    pub extensions: Option<Extensions>,
244}
245
246#[derive(Clone, Debug)]
247#[cfg_attr(
248    feature = "serde",
249    derive(serde::Serialize, serde::Deserialize),
250    serde(rename_all = "camelCase")
251)]
252#[repr(C)]
253pub struct AccessorSparseIndices {
254    pub buffer_view: Id,
255    #[cfg_attr(feature = "serde", serde(default))]
256    pub byte_offset: Size,
257    pub component_type: AccessorIndicesComponentType,
258    #[cfg(feature = "gltf-extras")]
259    #[cfg_attr(
260        feature = "serde",
261        serde(default),
262        serde(skip_serializing_if = "serde_json::Value::is_null")
263    )]
264    pub extras: Extras,
265    #[cfg(feature = "gltf-extensions")]
266    #[cfg_attr(
267        feature = "serde",
268        serde(default),
269        serde(skip_serializing_if = "Option::is_none")
270    )]
271    pub extensions: Option<Extensions>,
272}
273
274#[derive(Clone, Debug)]
275#[cfg_attr(
276    feature = "serde",
277    derive(serde::Serialize, serde::Deserialize),
278    serde(rename_all = "camelCase")
279)]
280#[repr(C)]
281pub struct AccessorSparseValues {
282    pub buffer_view: Id,
283    #[cfg_attr(feature = "serde", serde(default))]
284    pub byte_offset: Size,
285    #[cfg(feature = "gltf-extras")]
286    #[cfg_attr(
287        feature = "serde",
288        serde(default),
289        serde(skip_serializing_if = "serde_json::Value::is_null")
290    )]
291    pub extras: Extras,
292    #[cfg(feature = "gltf-extensions")]
293    #[cfg_attr(
294        feature = "serde",
295        serde(default),
296        serde(skip_serializing_if = "Option::is_none")
297    )]
298    pub extensions: Option<Extensions>,
299}
300
301#[derive(Clone, Copy, Debug)]
302#[cfg_attr(
303    feature = "serde",
304    derive(serde::Serialize, serde::Deserialize),
305    serde(rename_all = "UPPERCASE")
306)]
307#[repr(u32)]
308pub enum AccessorType {
309    Scalar,
310    Vec2,
311    Vec3,
312    Vec4,
313    Mat2,
314    Mat3,
315    Mat4,
316}
317
318#[derive(Clone, Copy, Debug)]
319#[cfg_attr(
320    feature = "serde",
321    derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr)
322)]
323#[repr(u32)]
324pub enum AccessorComponentType {
325    Byte = gl_const::BYTE,
326    UnsignedByte = gl_const::UNSIGNED_BYTE,
327    Short = gl_const::SHORT,
328    UnsignedShort = gl_const::UNSIGNED_SHORT,
329    UnsignedInt = gl_const::UNSIGNED_INT,
330    Float = gl_const::FLOAT,
331}
332
333#[derive(Clone, Copy, Debug)]
334#[cfg_attr(
335    feature = "serde",
336    derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr)
337)]
338#[repr(u32)]
339pub enum AccessorIndicesComponentType {
340    UnsignedByte = gl_const::UNSIGNED_BYTE,
341    UnsignedShort = gl_const::UNSIGNED_SHORT,
342    UnsignedInt = gl_const::UNSIGNED_INT,
343}
344
345#[derive(Clone, Debug)]
346#[cfg_attr(
347    feature = "serde",
348    derive(serde::Serialize, serde::Deserialize),
349    serde(rename_all = "camelCase")
350)]
351#[repr(C)]
352pub struct Animation {
353    pub channels: Vec<AnimationChannel>,
354    pub samplers: Vec<AnimationSampler>,
355    #[cfg(feature = "gltf-name")]
356    #[cfg_attr(
357        feature = "serde",
358        serde(default),
359        serde(skip_serializing_if = "String::is_empty")
360    )]
361    pub name: String,
362    #[cfg(feature = "gltf-extras")]
363    #[cfg_attr(
364        feature = "serde",
365        serde(default),
366        serde(skip_serializing_if = "serde_json::Value::is_null")
367    )]
368    pub extras: Extras,
369    #[cfg(feature = "gltf-extensions")]
370    #[cfg_attr(
371        feature = "serde",
372        serde(default),
373        serde(skip_serializing_if = "Option::is_none")
374    )]
375    pub extensions: Option<Extensions>,
376}
377
378#[derive(Clone, Debug)]
379#[cfg_attr(
380    feature = "serde",
381    derive(serde::Serialize, serde::Deserialize),
382    serde(rename_all = "camelCase")
383)]
384#[repr(C)]
385pub struct AnimationChannel {
386    pub sampler: Id,
387    pub target: AnimationChannelTarget,
388    #[cfg(feature = "gltf-extras")]
389    #[cfg_attr(
390        feature = "serde",
391        serde(default),
392        serde(skip_serializing_if = "serde_json::Value::is_null")
393    )]
394    pub extras: Extras,
395    #[cfg(feature = "gltf-extensions")]
396    #[cfg_attr(
397        feature = "serde",
398        serde(default),
399        serde(skip_serializing_if = "Option::is_none")
400    )]
401    pub extensions: Option<Extensions>,
402}
403
404#[derive(Clone, Debug)]
405#[cfg_attr(
406    feature = "serde",
407    derive(serde::Serialize, serde::Deserialize),
408    serde(rename_all = "camelCase")
409)]
410#[repr(C)]
411pub struct AnimationChannelTarget {
412    pub node: Id,
413    pub path: NodePath,
414    #[cfg(feature = "gltf-extras")]
415    #[cfg_attr(
416        feature = "serde",
417        serde(default),
418        serde(skip_serializing_if = "serde_json::Value::is_null")
419    )]
420    pub extras: Extras,
421    #[cfg(feature = "gltf-extensions")]
422    #[cfg_attr(
423        feature = "serde",
424        serde(default),
425        serde(skip_serializing_if = "Option::is_none")
426    )]
427    pub extensions: Option<Extensions>,
428}
429
430#[derive(Clone, Copy, Debug)]
431#[cfg_attr(
432    feature = "serde",
433    derive(serde::Serialize, serde::Deserialize),
434    serde(rename_all = "lowercase")
435)]
436#[repr(u32)]
437pub enum NodePath {
438    Weights,
439    Translation,
440    Rotation,
441    Scale,
442}
443
444#[derive(Clone, Debug)]
445#[cfg_attr(
446    feature = "serde",
447    derive(serde::Serialize, serde::Deserialize),
448    serde(rename_all = "camelCase")
449)]
450#[repr(C)]
451pub struct AnimationSampler {
452    pub input: Id,
453    pub output: Id,
454    pub interpolation: Interpolation,
455    #[cfg(feature = "gltf-extras")]
456    #[cfg_attr(
457        feature = "serde",
458        serde(default),
459        serde(skip_serializing_if = "serde_json::Value::is_null")
460    )]
461    pub extras: Extras,
462    #[cfg(feature = "gltf-extensions")]
463    #[cfg_attr(
464        feature = "serde",
465        serde(default),
466        serde(skip_serializing_if = "Option::is_none")
467    )]
468    pub extensions: Option<Extensions>,
469}
470
471#[derive(Clone, Copy, Debug)]
472#[cfg_attr(
473    feature = "serde",
474    derive(serde::Serialize, serde::Deserialize),
475    serde(rename_all = "UPPERCASE")
476)]
477#[repr(u32)]
478pub enum Interpolation {
479    Linear,
480    Step,
481    Cubicspline,
482}
483
484#[derive(Clone, Debug)]
485#[cfg_attr(
486    feature = "serde",
487    derive(serde::Serialize, serde::Deserialize),
488    serde(rename_all = "camelCase")
489)]
490#[repr(C)]
491pub struct Buffer {
492    #[cfg_attr(
493        feature = "serde",
494        serde(default),
495        serde(skip_serializing_if = "String::is_empty")
496    )]
497    pub uri: String,
498    pub byte_length: Size,
499    #[cfg(feature = "gltf-name")]
500    #[cfg_attr(
501        feature = "serde",
502        serde(default),
503        serde(skip_serializing_if = "String::is_empty")
504    )]
505    pub name: String,
506    #[cfg(feature = "gltf-extras")]
507    #[cfg_attr(
508        feature = "serde",
509        serde(default),
510        serde(skip_serializing_if = "serde_json::Value::is_null")
511    )]
512    pub extras: Extras,
513    #[cfg(feature = "gltf-extensions")]
514    #[cfg_attr(
515        feature = "serde",
516        serde(default),
517        serde(skip_serializing_if = "Option::is_none")
518    )]
519    pub extensions: Option<Extensions>,
520}
521
522#[derive(Clone, Debug, Default)]
523#[cfg_attr(
524    feature = "serde",
525    derive(serde::Serialize, serde::Deserialize),
526    serde(rename_all = "camelCase"),
527    serde(default)
528)]
529#[repr(C)]
530pub struct BufferView {
531    pub buffer: Id,
532    pub byte_offset: Size,
533    pub byte_length: Size,
534    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "is_zero"))]
535    pub byte_stride: Size,
536    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
537    pub target: Option<BufferViewTarget>,
538    #[cfg(feature = "gltf-name")]
539    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
540    pub name: String,
541    #[cfg(feature = "gltf-extras")]
542    #[cfg_attr(
543        feature = "serde",
544        serde(default),
545        serde(skip_serializing_if = "serde_json::Value::is_null")
546    )]
547    pub extras: Extras,
548    #[cfg(feature = "gltf-extensions")]
549    #[cfg_attr(
550        feature = "serde",
551        serde(default),
552        serde(skip_serializing_if = "Option::is_none")
553    )]
554    pub extensions: Option<Extensions>,
555}
556
557#[derive(Clone, Copy, Debug)]
558#[cfg_attr(
559    feature = "serde",
560    derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr)
561)]
562#[repr(u32)]
563pub enum BufferViewTarget {
564    Vertex = gl_const::ARRAY_BUFFER,
565    Index = gl_const::ELEMENT_ARRAY_BUFFER,
566}
567
568#[derive(Clone, Debug)]
569#[cfg_attr(
570    feature = "serde",
571    derive(serde::Serialize, serde::Deserialize),
572    serde(rename_all = "camelCase"),
573    serde(tag = "type")
574)]
575#[repr(C)]
576pub enum Camera {
577    Orthographic {
578        orthographic: CameraOrthographic,
579        #[cfg(feature = "gltf-name")]
580        #[cfg_attr(
581            feature = "serde",
582            serde(default),
583            serde(skip_serializing_if = "String::is_empty")
584        )]
585        name: String,
586        #[cfg(feature = "gltf-extras")]
587        #[cfg_attr(
588            feature = "serde",
589            serde(default),
590            serde(skip_serializing_if = "serde_json::Value::is_null")
591        )]
592        extras: Extras,
593        #[cfg(feature = "gltf-extensions")]
594        #[cfg_attr(
595            feature = "serde",
596            serde(default),
597            serde(skip_serializing_if = "Option::is_none")
598        )]
599        extensions: Option<Extensions>,
600    },
601    Perspective {
602        perspective: CameraPerspective,
603        #[cfg(feature = "gltf-name")]
604        #[cfg_attr(
605            feature = "serde",
606            serde(default),
607            serde(skip_serializing_if = "String::is_empty")
608        )]
609        name: String,
610        #[cfg(feature = "gltf-extras")]
611        #[cfg_attr(
612            feature = "serde",
613            serde(default),
614            serde(skip_serializing_if = "serde_json::Value::is_null")
615        )]
616        extras: Extras,
617        #[cfg(feature = "gltf-extensions")]
618        #[cfg_attr(
619            feature = "serde",
620            serde(default),
621            serde(skip_serializing_if = "Option::is_none")
622        )]
623        extensions: Option<Extensions>,
624    },
625}
626
627#[derive(Clone, Debug)]
628#[cfg_attr(
629    feature = "serde",
630    derive(serde::Serialize, serde::Deserialize),
631    serde(rename_all = "camelCase")
632)]
633#[repr(C)]
634pub struct CameraOrthographic {
635    pub xmag: Float,
636    pub ymag: Float,
637    pub zfar: Float,
638    pub znear: Float,
639    #[cfg(feature = "gltf-extras")]
640    #[cfg_attr(
641        feature = "serde",
642        serde(default),
643        serde(skip_serializing_if = "serde_json::Value::is_null")
644    )]
645    pub extras: Extras,
646    #[cfg(feature = "gltf-extensions")]
647    #[cfg_attr(
648        feature = "serde",
649        serde(default),
650        serde(skip_serializing_if = "Option::is_none")
651    )]
652    pub extensions: Option<Extensions>,
653}
654
655#[derive(Clone, Debug)]
656#[cfg_attr(
657    feature = "serde",
658    derive(serde::Serialize, serde::Deserialize),
659    serde(rename_all = "camelCase"),
660    serde(default)
661)]
662#[repr(C)]
663pub struct CameraPerspective {
664    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
665    pub aspect_ratio: Option<Float>,
666    pub yfov: Float,
667    pub zfar: Float,
668    pub znear: Float,
669    #[cfg(feature = "gltf-extras")]
670    #[cfg_attr(
671        feature = "serde",
672        serde(default),
673        serde(skip_serializing_if = "serde_json::Value::is_null")
674    )]
675    pub extras: Extras,
676    #[cfg(feature = "gltf-extensions")]
677    #[cfg_attr(
678        feature = "serde",
679        serde(default),
680        serde(skip_serializing_if = "Option::is_none")
681    )]
682    pub extensions: Option<Extensions>,
683}
684
685impl Default for CameraPerspective {
686    fn default() -> Self {
687        Self {
688            aspect_ratio: None,
689            yfov: 0.,
690            zfar: Float::INFINITY,
691            znear: 0.,
692            #[cfg(feature = "gltf-extras")]
693            extras: Default::default(),
694            #[cfg(feature = "gltf-extensions")]
695            extensions: Default::default(),
696        }
697    }
698}
699
700#[derive(Clone, Debug, Default)]
701#[cfg_attr(
702    feature = "serde",
703    derive(serde::Serialize, serde::Deserialize),
704    serde(rename_all = "camelCase"),
705    serde(default)
706)]
707#[repr(C)]
708pub struct Image {
709    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
710    pub uri: String,
711    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
712    pub mime_type: String,
713    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
714    pub buffer_view: Option<Id>,
715    #[cfg(feature = "gltf-name")]
716    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
717    pub name: String,
718    #[cfg(feature = "gltf-extras")]
719    #[cfg_attr(
720        feature = "serde",
721        serde(default),
722        serde(skip_serializing_if = "serde_json::Value::is_null")
723    )]
724    pub extras: Extras,
725    #[cfg(feature = "gltf-extensions")]
726    #[cfg_attr(
727        feature = "serde",
728        serde(default),
729        serde(skip_serializing_if = "Option::is_none")
730    )]
731    pub extensions: Option<Extensions>,
732}
733
734#[derive(Clone, Debug)]
735#[cfg_attr(
736    feature = "serde",
737    derive(serde::Serialize, serde::Deserialize),
738    serde(rename_all = "camelCase"),
739    serde(default)
740)]
741#[repr(C)]
742pub struct Material {
743    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
744    pub pbr_metallic_roughness: Option<PbrMetallicRoughness>,
745    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
746    pub normal_texture: Option<NormalTextureInfo>,
747    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
748    pub occlusion_texture: Option<OcclusionTextureInfo>,
749    pub emissive_factor: [Float; 3],
750    pub alpha_mode: AlphaMode,
751    pub alpha_cutoff: Float,
752    pub double_sided: bool,
753    #[cfg(feature = "gltf-name")]
754    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
755    pub name: String,
756    #[cfg(feature = "gltf-extras")]
757    #[cfg_attr(
758        feature = "serde",
759        serde(default),
760        serde(skip_serializing_if = "serde_json::Value::is_null")
761    )]
762    pub extras: Extras,
763    #[cfg(feature = "gltf-extensions")]
764    #[cfg_attr(
765        feature = "serde",
766        serde(default),
767        serde(skip_serializing_if = "Option::is_none")
768    )]
769    pub extensions: Option<Extensions>,
770}
771
772impl Default for Material {
773    fn default() -> Self {
774        Self {
775            pbr_metallic_roughness: None,
776            normal_texture: None,
777            occlusion_texture: None,
778            emissive_factor: [0., 0., 0.],
779            alpha_mode: Default::default(),
780            alpha_cutoff: 0.5,
781            double_sided: false,
782            #[cfg(feature = "gltf-name")]
783            name: Default::default(),
784            #[cfg(feature = "gltf-extras")]
785            extras: Default::default(),
786            #[cfg(feature = "gltf-extensions")]
787            extensions: Default::default(),
788        }
789    }
790}
791
792#[derive(Clone, Debug)]
793#[cfg_attr(
794    feature = "serde",
795    derive(serde::Serialize, serde::Deserialize),
796    serde(rename_all = "camelCase"),
797    serde(default)
798)]
799#[repr(C)]
800pub struct PbrMetallicRoughness {
801    pub base_color_factor: [Float; 4],
802    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
803    pub base_color_texture: Option<TextureInfo>,
804    pub metallic_factor: Float,
805    pub roughness_factor: Float,
806    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
807    pub metallic_roughness_texture: Option<TextureInfo>,
808    #[cfg(feature = "gltf-extras")]
809    #[cfg_attr(
810        feature = "serde",
811        serde(default),
812        serde(skip_serializing_if = "serde_json::Value::is_null")
813    )]
814    pub extras: Extras,
815    #[cfg(feature = "gltf-extensions")]
816    #[cfg_attr(
817        feature = "serde",
818        serde(default),
819        serde(skip_serializing_if = "Option::is_none")
820    )]
821    pub extensions: Option<Extensions>,
822}
823
824impl Default for PbrMetallicRoughness {
825    fn default() -> Self {
826        Self {
827            base_color_factor: [1., 1., 1., 1.],
828            base_color_texture: None,
829            metallic_factor: 1.,
830            roughness_factor: 1.,
831            metallic_roughness_texture: None,
832            #[cfg(feature = "gltf-extras")]
833            extras: Default::default(),
834            #[cfg(feature = "gltf-extensions")]
835            extensions: Default::default(),
836        }
837    }
838}
839
840#[derive(Clone, Debug, Default)]
841#[cfg_attr(
842    feature = "serde",
843    derive(serde::Serialize, serde::Deserialize),
844    serde(rename_all = "camelCase"),
845    serde(default)
846)]
847#[repr(C)]
848pub struct TextureInfo {
849    pub index: Id,
850    pub tex_coord: Size,
851    #[cfg(feature = "gltf-extras")]
852    #[cfg_attr(
853        feature = "serde",
854        serde(default),
855        serde(skip_serializing_if = "serde_json::Value::is_null")
856    )]
857    pub extras: Extras,
858    #[cfg(feature = "gltf-extensions")]
859    #[cfg_attr(
860        feature = "serde",
861        serde(default),
862        serde(skip_serializing_if = "Option::is_none")
863    )]
864    pub extensions: Option<Extensions>,
865}
866
867#[derive(Clone, Debug)]
868#[cfg_attr(
869    feature = "serde",
870    derive(serde::Serialize, serde::Deserialize),
871    serde(rename_all = "camelCase"),
872    serde(default)
873)]
874#[repr(C)]
875pub struct NormalTextureInfo {
876    pub index: Id,
877    pub tex_coord: Size,
878    pub scale: Float,
879    #[cfg(feature = "gltf-extras")]
880    #[cfg_attr(
881        feature = "serde",
882        serde(default),
883        serde(skip_serializing_if = "serde_json::Value::is_null")
884    )]
885    pub extras: Extras,
886    #[cfg(feature = "gltf-extensions")]
887    #[cfg_attr(
888        feature = "serde",
889        serde(default),
890        serde(skip_serializing_if = "Option::is_none")
891    )]
892    pub extensions: Option<Extensions>,
893}
894
895impl Default for NormalTextureInfo {
896    fn default() -> Self {
897        Self {
898            index: 0,
899            tex_coord: 0,
900            scale: 1.,
901            #[cfg(feature = "gltf-extras")]
902            extras: Default::default(),
903            #[cfg(feature = "gltf-extensions")]
904            extensions: Default::default(),
905        }
906    }
907}
908
909#[derive(Clone, Debug)]
910#[cfg_attr(
911    feature = "serde",
912    derive(serde::Serialize, serde::Deserialize),
913    serde(rename_all = "camelCase"),
914    serde(default)
915)]
916#[repr(C)]
917pub struct OcclusionTextureInfo {
918    pub index: Id,
919    pub tex_coord: Size,
920    pub strength: Float,
921    #[cfg(feature = "gltf-extras")]
922    #[cfg_attr(
923        feature = "serde",
924        serde(default),
925        serde(skip_serializing_if = "serde_json::Value::is_null")
926    )]
927    pub extras: Extras,
928    #[cfg(feature = "gltf-extensions")]
929    #[cfg_attr(
930        feature = "serde",
931        serde(default),
932        serde(skip_serializing_if = "Option::is_none")
933    )]
934    pub extensions: Option<Extensions>,
935}
936
937impl Default for OcclusionTextureInfo {
938    fn default() -> Self {
939        Self {
940            index: 0,
941            tex_coord: 0,
942            strength: 1.,
943            #[cfg(feature = "gltf-extras")]
944            extras: Default::default(),
945            #[cfg(feature = "gltf-extensions")]
946            extensions: Default::default(),
947        }
948    }
949}
950
951#[derive(Clone, Copy, Debug)]
952#[cfg_attr(
953    feature = "serde",
954    derive(serde::Serialize, serde::Deserialize),
955    serde(rename_all = "UPPERCASE")
956)]
957#[repr(u32)]
958pub enum AlphaMode {
959    Opaque,
960    Mask,
961    Blend,
962}
963
964impl Default for AlphaMode {
965    fn default() -> Self {
966        Self::Opaque
967    }
968}
969
970#[derive(Clone, Debug)]
971#[cfg_attr(
972    feature = "serde",
973    derive(serde::Serialize, serde::Deserialize),
974    serde(rename_all = "camelCase")
975)]
976#[repr(C)]
977pub struct Mesh {
978    pub primitives: Vec<MeshPrimitive>,
979    #[cfg_attr(
980        feature = "serde",
981        serde(default),
982        serde(skip_serializing_if = "Vec::is_empty")
983    )]
984    pub weights: Vec<Float>,
985    #[cfg(feature = "gltf-name")]
986    #[cfg_attr(
987        feature = "serde",
988        serde(default),
989        serde(skip_serializing_if = "String::is_empty")
990    )]
991    pub name: String,
992    #[cfg(feature = "gltf-extras")]
993    #[cfg_attr(
994        feature = "serde",
995        serde(default),
996        serde(skip_serializing_if = "serde_json::Value::is_null")
997    )]
998    pub extras: Extras,
999    #[cfg(feature = "gltf-extensions")]
1000    #[cfg_attr(
1001        feature = "serde",
1002        serde(default),
1003        serde(skip_serializing_if = "Option::is_none")
1004    )]
1005    pub extensions: Option<Extensions>,
1006}
1007
1008#[derive(Clone, Debug)]
1009#[cfg_attr(
1010    feature = "serde",
1011    derive(serde::Serialize, serde::Deserialize),
1012    serde(rename_all = "camelCase")
1013)]
1014#[repr(C)]
1015pub struct MeshPrimitive {
1016    pub attributes: Map<String, Id>,
1017    #[cfg_attr(
1018        feature = "serde",
1019        serde(default),
1020        serde(skip_serializing_if = "Option::is_none")
1021    )]
1022    pub indices: Option<Id>,
1023    #[cfg_attr(
1024        feature = "serde",
1025        serde(default),
1026        serde(skip_serializing_if = "Option::is_none")
1027    )]
1028    pub material: Option<Id>,
1029    #[cfg_attr(feature = "serde", serde(default))]
1030    pub mode: PrimitiveTopology,
1031    #[cfg_attr(
1032        feature = "serde",
1033        serde(default),
1034        serde(skip_serializing_if = "Vec::is_empty")
1035    )]
1036    pub targets: Vec<Map<String, Id>>,
1037    #[cfg(feature = "gltf-extras")]
1038    #[cfg_attr(
1039        feature = "serde",
1040        serde(default),
1041        serde(skip_serializing_if = "serde_json::Value::is_null")
1042    )]
1043    pub extras: Extras,
1044    #[cfg(feature = "gltf-extensions")]
1045    #[cfg_attr(
1046        feature = "serde",
1047        serde(default),
1048        serde(skip_serializing_if = "Option::is_none")
1049    )]
1050    pub extensions: Option<Extensions>,
1051}
1052
1053#[derive(Clone, Debug, Default)]
1054#[cfg_attr(
1055    feature = "serde",
1056    derive(serde::Serialize, serde::Deserialize),
1057    serde(rename_all = "camelCase"),
1058    serde(default)
1059)]
1060#[repr(C)]
1061pub struct Node {
1062    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1063    pub camera: Option<Id>,
1064    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
1065    pub children: Vec<Id>,
1066    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1067    pub skin: Option<Id>,
1068    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1069    pub matrix: Option<[Float; 16]>,
1070    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1071    pub mesh: Option<Id>,
1072    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1073    pub rotation: Option<[Float; 4]>,
1074    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1075    pub scale: Option<[Float; 3]>,
1076    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1077    pub translation: Option<[Float; 3]>,
1078    #[cfg_attr(
1079        feature = "serde",
1080        serde(default),
1081        serde(skip_serializing_if = "Vec::is_empty")
1082    )]
1083    pub weights: Vec<Float>,
1084    #[cfg(feature = "gltf-name")]
1085    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
1086    pub name: String,
1087    #[cfg(feature = "gltf-extras")]
1088    #[cfg_attr(
1089        feature = "serde",
1090        serde(default),
1091        serde(skip_serializing_if = "serde_json::Value::is_null")
1092    )]
1093    pub extras: Extras,
1094    #[cfg(feature = "gltf-extensions")]
1095    #[cfg_attr(
1096        feature = "serde",
1097        serde(default),
1098        serde(skip_serializing_if = "Option::is_none")
1099    )]
1100    pub extensions: Option<Extensions>,
1101}
1102
1103#[derive(Clone, Debug)]
1104#[cfg_attr(
1105    feature = "serde",
1106    derive(serde::Serialize, serde::Deserialize),
1107    serde(rename_all = "camelCase"),
1108    serde(default)
1109)]
1110#[repr(C)]
1111pub struct Sampler {
1112    #[cfg_attr(
1113        feature = "serde",
1114        serde(default),
1115        serde(skip_serializing_if = "Option::is_none")
1116    )]
1117    pub mag_filter: Option<FilterMode>,
1118    #[cfg_attr(
1119        feature = "serde",
1120        serde(default),
1121        serde(skip_serializing_if = "Option::is_none")
1122    )]
1123    pub min_filter: Option<MinFilterMode>,
1124    pub wrap_s: AddressMode,
1125    pub wrap_t: AddressMode,
1126    #[cfg(feature = "gltf-name")]
1127    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
1128    pub name: String,
1129    #[cfg(feature = "gltf-extras")]
1130    #[cfg_attr(
1131        feature = "serde",
1132        serde(default),
1133        serde(skip_serializing_if = "serde_json::Value::is_null")
1134    )]
1135    pub extras: Extras,
1136    #[cfg(feature = "gltf-extensions")]
1137    #[cfg_attr(
1138        feature = "serde",
1139        serde(default),
1140        serde(skip_serializing_if = "Option::is_none")
1141    )]
1142    pub extensions: Option<Extensions>,
1143}
1144
1145impl Default for Sampler {
1146    fn default() -> Self {
1147        Self {
1148            mag_filter: None,
1149            min_filter: None,
1150            wrap_s: AddressMode::Repeat,
1151            wrap_t: AddressMode::Repeat,
1152            #[cfg(feature = "gltf-name")]
1153            name: Default::default(),
1154            #[cfg(feature = "gltf-extras")]
1155            extras: Default::default(),
1156            #[cfg(feature = "gltf-extensions")]
1157            extensions: Default::default(),
1158        }
1159    }
1160}
1161
1162#[derive(Clone, Copy, Debug)]
1163#[cfg_attr(
1164    feature = "serde",
1165    derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr)
1166)]
1167#[repr(u32)]
1168pub enum MinFilterMode {
1169    Nearest = gl_const::NEAREST,
1170    Linear = gl_const::LINEAR,
1171    NearestMipmapNearest = gl_const::NEAREST_MIPMAP_NEAREST,
1172    NearestMipmapLinear = gl_const::NEAREST_MIPMAP_LINEAR,
1173    LinearMipmapNearest = gl_const::LINEAR_MIPMAP_NEAREST,
1174    LinearMipmapLinear = gl_const::LINEAR_MIPMAP_LINEAR,
1175}
1176
1177impl Default for MinFilterMode {
1178    fn default() -> Self {
1179        Self::Nearest
1180    }
1181}
1182
1183#[derive(Clone, Debug, Default)]
1184#[cfg_attr(
1185    feature = "serde",
1186    derive(serde::Serialize, serde::Deserialize),
1187    serde(rename_all = "camelCase"),
1188    serde(default)
1189)]
1190#[repr(C)]
1191pub struct Scene {
1192    pub nodes: Vec<Id>,
1193    #[cfg(feature = "gltf-name")]
1194    #[cfg_attr(
1195        feature = "serde",
1196        serde(default),
1197        serde(skip_serializing_if = "String::is_empty")
1198    )]
1199    pub name: String,
1200    #[cfg(feature = "gltf-extras")]
1201    #[cfg_attr(
1202        feature = "serde",
1203        serde(default),
1204        serde(skip_serializing_if = "serde_json::Value::is_null")
1205    )]
1206    pub extras: Extras,
1207    #[cfg(feature = "gltf-extensions")]
1208    #[cfg_attr(
1209        feature = "serde",
1210        serde(default),
1211        serde(skip_serializing_if = "Option::is_none")
1212    )]
1213    pub extensions: Option<Extensions>,
1214}
1215
1216#[derive(Clone, Debug)]
1217#[cfg_attr(
1218    feature = "serde",
1219    derive(serde::Serialize, serde::Deserialize),
1220    serde(rename_all = "camelCase")
1221)]
1222#[repr(C)]
1223pub struct Skin {
1224    #[cfg_attr(
1225        feature = "serde",
1226        serde(default),
1227        serde(skip_serializing_if = "Option::is_none")
1228    )]
1229    pub inverse_bind_matrices: Option<Id>,
1230    #[cfg_attr(
1231        feature = "serde",
1232        serde(default),
1233        serde(skip_serializing_if = "Option::is_none")
1234    )]
1235    pub skeleton: Option<Id>,
1236    pub joints: Vec<Id>,
1237    #[cfg(feature = "gltf-name")]
1238    #[cfg_attr(
1239        feature = "serde",
1240        serde(default),
1241        serde(skip_serializing_if = "String::is_empty")
1242    )]
1243    pub name: String,
1244    #[cfg(feature = "gltf-extras")]
1245    #[cfg_attr(
1246        feature = "serde",
1247        serde(default),
1248        serde(skip_serializing_if = "serde_json::Value::is_null")
1249    )]
1250    pub extras: Extras,
1251    #[cfg(feature = "gltf-extensions")]
1252    #[cfg_attr(
1253        feature = "serde",
1254        serde(default),
1255        serde(skip_serializing_if = "Option::is_none")
1256    )]
1257    pub extensions: Option<Extensions>,
1258}
1259
1260#[derive(Clone, Debug, Default)]
1261#[cfg_attr(
1262    feature = "serde",
1263    derive(serde::Serialize, serde::Deserialize),
1264    serde(rename_all = "camelCase"),
1265    serde(default)
1266)]
1267#[repr(C)]
1268pub struct Texture {
1269    #[cfg_attr(
1270        feature = "serde",
1271        serde(default),
1272        serde(skip_serializing_if = "Option::is_none")
1273    )]
1274    pub sampler: Option<Id>,
1275    #[cfg_attr(
1276        feature = "serde",
1277        serde(default),
1278        serde(skip_serializing_if = "Option::is_none")
1279    )]
1280    pub source: Option<Id>,
1281    #[cfg(feature = "gltf-name")]
1282    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
1283    pub name: String,
1284    #[cfg(feature = "gltf-extras")]
1285    #[cfg_attr(
1286        feature = "serde",
1287        serde(default),
1288        serde(skip_serializing_if = "serde_json::Value::is_null")
1289    )]
1290    pub extras: Extras,
1291    #[cfg(feature = "gltf-extensions")]
1292    #[cfg_attr(
1293        feature = "serde",
1294        serde(default),
1295        serde(skip_serializing_if = "Option::is_none")
1296    )]
1297    pub extensions: Option<Extensions>,
1298}
1299
1300/// Checks if size is 0
1301#[cfg(feature = "serde")]
1302#[inline]
1303fn is_zero(size: &Size) -> bool {
1304    *size == 0
1305}
1306
1307/// Checks if bool is false
1308#[cfg(feature = "serde")]
1309#[inline]
1310fn is_false(b: &bool) -> bool {
1311    !*b
1312}