goth_gltf/
lib.rs

1//! Goth-gltf aims to be a low-level, unopinionated reader for gltf files.
2//!
3//! Basic example:
4//! ```no_run
5//! let filename = std::env::args().nth(1).unwrap();
6//! let bytes = std::fs::read(&filename).unwrap();
7//! let (gltf, _): (
8//!     goth_gltf::Gltf<goth_gltf::default_extensions::Extensions>,
9//!     _,
10//! ) = goth_gltf::Gltf::from_bytes(&bytes).unwrap();
11//! println!("{:#?}", gltf);
12//! ```
13//!
14//! # In comparison with [gltf-rs], it:
15//!
16//! - Represents the gltf JSON structure transparently
17//! - Uses nanoserde instead of serde
18//! - Supports a wider range of extensions
19//! - Has no code specific for loading images or reading attributes out of buffers
20//!
21//! # Extensions Implemented
22//!
23//! - `KHR_lights_punctual`
24//! - `KHR_materials_emissive_strength`
25//! - `KHR_materials_ior`
26//! - `KHR_materials_sheen`
27//! - `KHR_materials_unlit`
28//! - `KHR_texture_basisu`
29//! - `KHR_texture_transform`
30//! - `KHR_materials_transmission`
31//! - `EXT_mesh_gpu_instancing`
32//! - `EXT_meshopt_compression`
33//! - `MSFT_lod`
34//! - `MSFT_screencoverage`
35//!
36//! [gltf-rs]: https://github.com/gltf-rs/gltf
37
38#![allow(clippy::question_mark)]
39
40pub mod extensions;
41/// Basic support for reading primitive data from buffer views and accessors.
42#[cfg(feature = "primitive_reader")]
43pub mod primitive_reader;
44
45use nanoserde::DeJson;
46use std::fmt::Debug;
47
48pub trait Extensions: DeJson {
49    type RootExtensions: DeJson + Default + Debug + Clone;
50    type TextureExtensions: DeJson + Default + Debug + Clone;
51    type TextureInfoExtensions: DeJson + Default + Debug + Clone;
52    type MaterialExtensions: DeJson + Default + Debug + Clone;
53    type BufferExtensions: DeJson + Default + Debug + Clone;
54    type NodeExtensions: DeJson + Default + Debug + Clone;
55    type NodeExtras: DeJson + Default + Debug + Clone;
56    type BufferViewExtensions: DeJson + Default + Debug + Clone;
57}
58
59impl Extensions for () {
60    type RootExtensions = ();
61    type TextureExtensions = ();
62    type TextureInfoExtensions = ();
63    type MaterialExtensions = ();
64    type BufferExtensions = ();
65    type NodeExtensions = ();
66    type NodeExtras = ();
67    type BufferViewExtensions = ();
68}
69
70/// A parsed gltf document.
71#[derive(Debug, DeJson)]
72pub struct Gltf<E: Extensions> {
73    #[nserde(default)]
74    pub images: Vec<Image>,
75    #[nserde(default)]
76    pub textures: Vec<Texture<E>>,
77    #[nserde(default)]
78    pub materials: Vec<Material<E>>,
79    #[nserde(default)]
80    pub buffers: Vec<Buffer<E>>,
81    #[nserde(rename = "bufferViews")]
82    #[nserde(default)]
83    pub buffer_views: Vec<BufferView<E>>,
84    #[nserde(default)]
85    pub accessors: Vec<Accessor>,
86    #[nserde(default)]
87    pub meshes: Vec<Mesh>,
88    #[nserde(default)]
89    pub animations: Vec<Animation>,
90    #[nserde(default)]
91    pub nodes: Vec<Node<E>>,
92    #[nserde(default)]
93    pub skins: Vec<Skin>,
94    #[nserde(default)]
95    pub samplers: Vec<Sampler>,
96    #[nserde(default)]
97    pub cameras: Vec<Camera>,
98    #[nserde(default)]
99    pub extensions: E::RootExtensions,
100    #[nserde(default)]
101    pub scenes: Vec<Scene>,
102    #[nserde(default)]
103    pub scene: usize,
104}
105
106impl<E: Extensions> Gltf<E> {
107    /// Load a gltf from either a gltf or a glb file.
108    ///
109    /// In the case of a .glb, the binary buffer chunk will be returned as well.
110    pub fn from_bytes(bytes: &[u8]) -> Result<(Self, Option<&[u8]>), nanoserde::DeJsonErr> {
111        // Check for the 4-byte magic.
112        if !bytes.starts_with(b"glTF") {
113            return Ok((Self::from_json_bytes(bytes)?, None));
114        }
115
116        // There's always a json chunk at the start:
117        // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#structured-json-content
118
119        let json_chunk_length = u32::from_le_bytes(bytes[12..16].try_into().unwrap());
120
121        let json_chunk_end = 20 + json_chunk_length as usize;
122
123        let json_chunk_bytes = &bytes[20..20 + json_chunk_length as usize];
124
125        let json = Self::from_json_bytes(json_chunk_bytes)?;
126
127        let binary_buffer = if bytes.len() != json_chunk_end {
128            Some(&bytes[json_chunk_end + 8..])
129        } else {
130            None
131        };
132
133        Ok((json, binary_buffer))
134    }
135
136    pub fn from_json_bytes(bytes: &[u8]) -> Result<Self, nanoserde::DeJsonErr> {
137        match std::str::from_utf8(bytes) {
138            Ok(string) => Self::from_json_string(string),
139            Err(error) => Err(nanoserde::DeJsonState::default().err_parse(&error.to_string())),
140        }
141    }
142
143    pub fn from_json_string(string: &str) -> Result<Self, nanoserde::DeJsonErr> {
144        Self::deserialize_json(string)
145    }
146}
147
148#[derive(Debug, DeJson)]
149pub struct Skin {
150    #[nserde(rename = "inverseBindMatrices")]
151    pub inverse_bind_matrices: Option<usize>,
152    pub skeleton: Option<usize>,
153    pub joints: Vec<usize>,
154    #[cfg(feature = "names")]
155    pub name: Option<String>,
156}
157
158#[derive(Debug, DeJson)]
159pub struct Animation {
160    pub channels: Vec<Channel>,
161    pub samplers: Vec<AnimationSampler>,
162    #[cfg(feature = "names")]
163    pub name: Option<String>,
164}
165
166#[derive(Debug, DeJson)]
167pub struct Channel {
168    pub sampler: usize,
169    pub target: Target,
170}
171
172#[derive(Debug, DeJson)]
173pub struct Target {
174    pub node: Option<usize>,
175    pub path: TargetPath,
176}
177
178#[derive(Debug, DeJson)]
179pub struct AnimationSampler {
180    pub input: usize,
181    #[nserde(default)]
182    pub interpolation: Interpolation,
183    pub output: usize,
184}
185
186#[derive(Debug, DeJson, Clone, Copy)]
187pub enum Interpolation {
188    #[nserde(rename = "LINEAR")]
189    Linear,
190    #[nserde(rename = "STEP")]
191    Step,
192    #[nserde(rename = "CUBICSPLINE")]
193    CubicSpline,
194}
195
196impl Default for Interpolation {
197    fn default() -> Self {
198        Self::Linear
199    }
200}
201
202#[derive(Debug, DeJson)]
203pub enum TargetPath {
204    #[nserde(rename = "translation")]
205    Translation,
206    #[nserde(rename = "rotation")]
207    Rotation,
208    #[nserde(rename = "scale")]
209    Scale,
210    #[nserde(rename = "weights")]
211    Weights,
212}
213
214#[derive(Debug, DeJson)]
215pub struct Buffer<E: Extensions> {
216    pub uri: Option<String>,
217    #[nserde(rename = "byteLength")]
218    pub byte_length: usize,
219    #[cfg(feature = "names")]
220    pub name: Option<String>,
221    #[nserde(default)]
222    pub extensions: E::BufferExtensions,
223}
224
225#[derive(Debug, DeJson)]
226pub struct Node<E: Extensions> {
227    pub camera: Option<usize>,
228    #[nserde(default)]
229    pub children: Vec<usize>,
230    pub skin: Option<usize>,
231    pub matrix: Option<[f32; 16]>,
232    pub mesh: Option<usize>,
233    pub rotation: Option<[f32; 4]>,
234    pub scale: Option<[f32; 3]>,
235    pub translation: Option<[f32; 3]>,
236    #[cfg(feature = "names")]
237    pub name: Option<String>,
238    #[nserde(default)]
239    pub extensions: E::NodeExtensions,
240    #[nserde(default)]
241    pub extras: E::NodeExtras,
242}
243
244impl<E: Extensions> Node<E> {
245    pub fn transform(&self) -> NodeTransform {
246        match self.matrix {
247            Some(matrix) => match (self.translation, self.rotation, self.scale) {
248                // If both a matrix and a full transform set is specified, then just use the transform.
249                (Some(translation), Some(rotation), Some(scale)) => NodeTransform::Set {
250                    translation,
251                    rotation,
252                    scale,
253                },
254                _ => NodeTransform::Matrix(matrix),
255            },
256            None => {
257                let translation = self.translation.unwrap_or([0.0; 3]);
258                let rotation = self.rotation.unwrap_or([0.0, 0.0, 0.0, 1.0]);
259                let scale = self.scale.unwrap_or([1.0; 3]);
260                NodeTransform::Set {
261                    translation,
262                    rotation,
263                    scale,
264                }
265            }
266        }
267    }
268}
269
270pub enum NodeTransform {
271    Matrix([f32; 16]),
272    Set {
273        translation: [f32; 3],
274        rotation: [f32; 4],
275        scale: [f32; 3],
276    },
277}
278
279#[derive(Debug, DeJson)]
280pub struct Mesh {
281    pub primitives: Vec<Primitive>,
282    pub weights: Option<Vec<f32>>,
283    #[cfg(feature = "names")]
284    pub name: Option<String>,
285}
286
287#[derive(Debug, DeJson)]
288pub struct Primitive {
289    pub attributes: Attributes,
290    pub indices: Option<usize>,
291    pub material: Option<usize>,
292    #[nserde(default)]
293    pub mode: PrimitiveMode,
294    pub targets: Option<Vec<Attributes>>,
295}
296
297#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298pub enum PrimitiveMode {
299    Points,
300    Lines,
301    LineLoop,
302    LineStrip,
303    Triangles,
304    TriangleStrip,
305    TriangleFan,
306}
307
308impl Default for PrimitiveMode {
309    fn default() -> Self {
310        Self::Triangles
311    }
312}
313
314impl DeJson for PrimitiveMode {
315    fn de_json(
316        state: &mut nanoserde::DeJsonState,
317        input: &mut core::str::Chars,
318    ) -> Result<Self, nanoserde::DeJsonErr> {
319        let ty = match &state.tok {
320            nanoserde::DeJsonTok::U64(ty) => match ty {
321                0 => Self::Points,
322                1 => Self::Lines,
323                2 => Self::LineLoop,
324                3 => Self::LineStrip,
325                4 => Self::Triangles,
326                5 => Self::TriangleStrip,
327                6 => Self::TriangleFan,
328                _ => return Err(state.err_range(&ty.to_string())),
329            },
330            _ => return Err(state.err_token("U64")),
331        };
332
333        state.next_tok(input)?;
334
335        Ok(ty)
336    }
337}
338
339#[derive(Debug, DeJson)]
340pub struct Attributes {
341    #[nserde(rename = "POSITION")]
342    pub position: Option<usize>,
343    #[nserde(rename = "TANGENT")]
344    pub tangent: Option<usize>,
345    #[nserde(rename = "NORMAL")]
346    pub normal: Option<usize>,
347    #[nserde(rename = "TEXCOORD_0")]
348    pub texcoord_0: Option<usize>,
349    #[nserde(rename = "TEXCOORD_1")]
350    pub texcoord_1: Option<usize>,
351    #[nserde(rename = "JOINTS_0")]
352    pub joints_0: Option<usize>,
353    #[nserde(rename = "WEIGHTS_0")]
354    pub weights_0: Option<usize>,
355}
356
357#[derive(Debug, DeJson, Clone)]
358pub struct Image {
359    pub uri: Option<String>,
360    #[nserde(rename = "mimeType")]
361    pub mime_type: Option<String>,
362    #[nserde(rename = "bufferView")]
363    pub buffer_view: Option<usize>,
364    #[cfg(feature = "names")]
365    pub name: Option<String>,
366}
367
368#[derive(Debug, DeJson)]
369pub struct Texture<E: Extensions> {
370    pub sampler: Option<usize>,
371    pub source: Option<usize>,
372    #[cfg(feature = "names")]
373    pub name: Option<String>,
374    #[nserde(default)]
375    pub extensions: E::TextureExtensions,
376}
377
378#[derive(Debug, DeJson)]
379pub struct BufferView<E: Extensions> {
380    pub buffer: usize,
381    #[nserde(rename = "byteOffset")]
382    #[nserde(default)]
383    pub byte_offset: usize,
384    #[nserde(rename = "byteLength")]
385    pub byte_length: usize,
386    #[nserde(rename = "byteStride")]
387    pub byte_stride: Option<usize>,
388    #[cfg(feature = "names")]
389    pub name: Option<String>,
390    #[nserde(default)]
391    pub extensions: E::BufferViewExtensions,
392}
393
394#[derive(Debug, DeJson)]
395pub struct Accessor {
396    #[nserde(rename = "bufferView")]
397    pub buffer_view: Option<usize>,
398    #[nserde(rename = "byteOffset")]
399    #[nserde(default)]
400    pub byte_offset: usize,
401    #[nserde(rename = "componentType")]
402    pub component_type: ComponentType,
403    #[nserde(default)]
404    pub normalized: bool,
405    pub count: usize,
406    #[nserde(rename = "type")]
407    pub accessor_type: AccessorType,
408    pub sparse: Option<Sparse>,
409    // todo: these could be changed to enum { Int, Float }.
410    pub min: Option<Vec<f32>>,
411    pub max: Option<Vec<f32>>,
412    #[cfg(feature = "names")]
413    pub name: Option<String>,
414}
415
416impl Accessor {
417    pub fn byte_length<E: Extensions>(&self, buffer_view: &BufferView<E>) -> usize {
418        self.count
419            * buffer_view.byte_stride.unwrap_or_else(|| {
420                self.component_type.byte_size() * self.accessor_type.num_components()
421            })
422    }
423}
424
425#[derive(Debug, DeJson)]
426pub struct Sparse {
427    pub count: usize,
428    pub indices: SparseIndices,
429    pub values: SparseValues,
430}
431
432#[derive(Debug, DeJson)]
433pub struct SparseIndices {
434    #[nserde(rename = "bufferView")]
435    pub buffer_view: usize,
436    #[nserde(rename = "byteOffset")]
437    #[nserde(default)]
438    pub byte_offset: usize,
439    #[nserde(rename = "componentType")]
440    pub component_type: ComponentType,
441}
442
443#[derive(Debug, DeJson)]
444pub struct SparseValues {
445    #[nserde(rename = "bufferView")]
446    pub buffer_view: usize,
447    #[nserde(rename = "byteOffset")]
448    #[nserde(default)]
449    pub byte_offset: usize,
450}
451
452#[derive(Debug, Clone, Copy, PartialEq, Eq)]
453pub enum ComponentType {
454    UnsignedByte,
455    Byte,
456    UnsignedShort,
457    Short,
458    UnsignedInt,
459    Float,
460}
461
462impl ComponentType {
463    pub fn byte_size(&self) -> usize {
464        match self {
465            Self::UnsignedByte | Self::Byte => 1,
466            Self::UnsignedShort | Self::Short => 2,
467            Self::UnsignedInt | Self::Float => 4,
468        }
469    }
470}
471
472impl DeJson for ComponentType {
473    fn de_json(
474        state: &mut nanoserde::DeJsonState,
475        input: &mut core::str::Chars,
476    ) -> Result<Self, nanoserde::DeJsonErr> {
477        let ty = match &state.tok {
478            nanoserde::DeJsonTok::U64(ty) => match ty {
479                5120 => Self::Byte,
480                5121 => Self::UnsignedByte,
481                5122 => Self::Short,
482                5123 => Self::UnsignedShort,
483                5125 => Self::UnsignedInt,
484                5126 => Self::Float,
485                _ => return Err(state.err_range(&ty.to_string())),
486            },
487            _ => return Err(state.err_token("U64")),
488        };
489
490        state.next_tok(input)?;
491
492        Ok(ty)
493    }
494}
495
496#[derive(Debug, DeJson, PartialEq, Clone, Copy)]
497pub enum AccessorType {
498    #[nserde(rename = "SCALAR")]
499    Scalar,
500    #[nserde(rename = "VEC2")]
501    Vec2,
502    #[nserde(rename = "VEC3")]
503    Vec3,
504    #[nserde(rename = "VEC4")]
505    Vec4,
506    #[nserde(rename = "MAT2")]
507    Mat2,
508    #[nserde(rename = "MAT3")]
509    Mat3,
510    #[nserde(rename = "MAT4")]
511    Mat4,
512}
513
514impl AccessorType {
515    pub fn num_components(&self) -> usize {
516        match self {
517            Self::Scalar => 1,
518            Self::Vec2 => 2,
519            Self::Vec3 => 3,
520            Self::Vec4 | Self::Mat2 => 4,
521            Self::Mat3 => 9,
522            Self::Mat4 => 16,
523        }
524    }
525}
526
527#[derive(Debug, DeJson, Clone)]
528pub struct Material<E: Extensions> {
529    #[nserde(rename = "pbrMetallicRoughness")]
530    #[nserde(default)]
531    pub pbr_metallic_roughness: PbrMetallicRoughness<E>,
532    #[nserde(rename = "normalTexture")]
533    pub normal_texture: Option<NormalTextureInfo<E>>,
534    #[nserde(rename = "occlusionTexture")]
535    pub occlusion_texture: Option<OcclusionTextureInfo<E>>,
536    #[nserde(rename = "emissiveTexture")]
537    pub emissive_texture: Option<TextureInfo<E>>,
538    #[nserde(rename = "emissiveFactor")]
539    #[nserde(default)]
540    pub emissive_factor: [f32; 3],
541    #[nserde(rename = "alphaMode")]
542    #[nserde(default)]
543    pub alpha_mode: AlphaMode,
544    #[nserde(rename = "alphaCutoff")]
545    #[nserde(default = "0.5")]
546    pub alpha_cutoff: f32,
547    #[nserde(rename = "doubleSided")]
548    #[nserde(default)]
549    pub double_sided: bool,
550    #[cfg(feature = "names")]
551    pub name: Option<String>,
552    #[nserde(default)]
553    pub extensions: E::MaterialExtensions,
554}
555
556#[derive(Debug, DeJson, Clone, Copy)]
557pub enum AlphaMode {
558    #[nserde(rename = "OPAQUE")]
559    Opaque,
560    #[nserde(rename = "MASK")]
561    Mask,
562    #[nserde(rename = "BLEND")]
563    Blend,
564}
565
566impl Default for AlphaMode {
567    fn default() -> Self {
568        Self::Opaque
569    }
570}
571
572#[derive(Debug, DeJson, Clone)]
573pub struct PbrMetallicRoughness<E: Extensions> {
574    #[nserde(rename = "baseColorFactor")]
575    #[nserde(default = "[1.0, 1.0, 1.0, 1.0]")]
576    pub base_color_factor: [f32; 4],
577    #[nserde(rename = "baseColorTexture")]
578    pub base_color_texture: Option<TextureInfo<E>>,
579    #[nserde(rename = "metallicFactor")]
580    #[nserde(default = "1.0")]
581    pub metallic_factor: f32,
582    #[nserde(rename = "roughnessFactor")]
583    #[nserde(default = "1.0")]
584    pub roughness_factor: f32,
585    #[nserde(rename = "metallicRoughnessTexture")]
586    pub metallic_roughness_texture: Option<TextureInfo<E>>,
587}
588
589impl<E: Extensions> Default for PbrMetallicRoughness<E> {
590    fn default() -> Self {
591        Self {
592            base_color_factor: [1.0; 4],
593            base_color_texture: None,
594            metallic_factor: 1.0,
595            roughness_factor: 1.0,
596            metallic_roughness_texture: None,
597        }
598    }
599}
600
601#[derive(Debug, DeJson, Clone)]
602pub struct TextureInfo<E: Extensions> {
603    pub index: usize,
604    #[nserde(rename = "texCoord")]
605    #[nserde(default)]
606    pub tex_coord: usize,
607    #[nserde(default)]
608    pub extensions: E::TextureInfoExtensions,
609}
610
611#[derive(Debug, DeJson, Clone)]
612pub struct NormalTextureInfo<E: Extensions> {
613    pub index: usize,
614    #[nserde(rename = "texCoord")]
615    #[nserde(default)]
616    pub tex_coord: usize,
617    #[nserde(default = "1.0")]
618    pub scale: f32,
619    #[nserde(default)]
620    pub extensions: E::TextureInfoExtensions,
621}
622
623#[derive(Debug, DeJson, Clone)]
624pub struct OcclusionTextureInfo<E: Extensions> {
625    pub index: usize,
626    #[nserde(rename = "texCoord")]
627    #[nserde(default)]
628    pub tex_coord: usize,
629    #[nserde(default = "1.0")]
630    pub strength: f32,
631    #[nserde(default)]
632    pub extensions: E::TextureInfoExtensions,
633}
634
635#[derive(Debug, DeJson)]
636pub struct Sampler {
637    #[nserde(rename = "magFilter")]
638    pub mag_filter: Option<FilterMode>,
639    #[nserde(rename = "minFilter")]
640    pub min_filter: Option<MinFilter>,
641    #[nserde(rename = "wrapS")]
642    #[nserde(default)]
643    pub wrap_s: SamplerWrap,
644    #[nserde(rename = "wrapT")]
645    #[nserde(default)]
646    pub wrap_t: SamplerWrap,
647    #[cfg(feature = "names")]
648    pub name: Option<String>,
649}
650
651#[derive(Debug)]
652pub enum FilterMode {
653    Nearest,
654    Linear,
655}
656
657impl DeJson for FilterMode {
658    fn de_json(
659        state: &mut nanoserde::DeJsonState,
660        input: &mut core::str::Chars,
661    ) -> Result<Self, nanoserde::DeJsonErr> {
662        let ty = match &state.tok {
663            nanoserde::DeJsonTok::U64(ty) => match ty {
664                9728 => Self::Nearest,
665                9729 => Self::Linear,
666                _ => return Err(state.err_range(&ty.to_string())),
667            },
668            _ => return Err(state.err_token("U64")),
669        };
670
671        state.next_tok(input)?;
672
673        Ok(ty)
674    }
675}
676
677#[derive(Debug)]
678pub struct MinFilter {
679    pub mode: FilterMode,
680    pub mipmap: Option<FilterMode>,
681}
682
683impl DeJson for MinFilter {
684    fn de_json(
685        state: &mut nanoserde::DeJsonState,
686        input: &mut core::str::Chars,
687    ) -> Result<Self, nanoserde::DeJsonErr> {
688        let ty = match &state.tok {
689            nanoserde::DeJsonTok::U64(ty) => match ty {
690                9728 => Self {
691                    mode: FilterMode::Nearest,
692                    mipmap: None,
693                },
694                9729 => Self {
695                    mode: FilterMode::Linear,
696                    mipmap: None,
697                },
698                9984 => Self {
699                    mode: FilterMode::Nearest,
700                    mipmap: Some(FilterMode::Nearest),
701                },
702                9985 => Self {
703                    mode: FilterMode::Linear,
704                    mipmap: Some(FilterMode::Nearest),
705                },
706                9986 => Self {
707                    mode: FilterMode::Nearest,
708                    mipmap: Some(FilterMode::Linear),
709                },
710                9987 => Self {
711                    mode: FilterMode::Linear,
712                    mipmap: Some(FilterMode::Linear),
713                },
714                _ => return Err(state.err_range(&ty.to_string())),
715            },
716            _ => return Err(state.err_token("U64")),
717        };
718
719        state.next_tok(input)?;
720
721        Ok(ty)
722    }
723}
724
725#[derive(Debug)]
726pub enum SamplerWrap {
727    ClampToEdge,
728    MirroredRepeat,
729    Repeat,
730}
731
732impl DeJson for SamplerWrap {
733    fn de_json(
734        state: &mut nanoserde::DeJsonState,
735        input: &mut core::str::Chars,
736    ) -> Result<Self, nanoserde::DeJsonErr> {
737        let ty = match &state.tok {
738            nanoserde::DeJsonTok::U64(ty) => match ty {
739                33071 => Self::ClampToEdge,
740                33648 => Self::MirroredRepeat,
741                10497 => Self::Repeat,
742                _ => return Err(state.err_range(&ty.to_string())),
743            },
744            _ => return Err(state.err_token("U64")),
745        };
746
747        state.next_tok(input)?;
748
749        Ok(ty)
750    }
751}
752
753impl Default for SamplerWrap {
754    fn default() -> Self {
755        Self::Repeat
756    }
757}
758
759#[derive(Debug, DeJson)]
760pub struct Camera {
761    pub perspective: Option<CameraPerspective>,
762    pub orthographic: Option<CameraOrthographic>,
763    #[nserde(rename = "type")]
764    pub ty: CameraType,
765    #[cfg(feature = "names")]
766    pub name: Option<String>,
767}
768
769#[derive(Debug, DeJson)]
770pub struct CameraPerspective {
771    pub yfov: f32,
772    pub znear: f32,
773    pub zfar: Option<f32>,
774    #[nserde(rename = "aspectRatio")]
775    pub aspect_ratio: Option<f32>,
776}
777
778#[derive(Debug, DeJson, Clone, Copy)]
779pub struct CameraOrthographic {
780    pub xmag: f32,
781    pub ymag: f32,
782    pub zfar: f32,
783    pub znear: f32,
784}
785
786#[derive(Debug, DeJson)]
787pub enum CameraType {
788    #[nserde(rename = "perspective")]
789    Perspective,
790    #[nserde(rename = "orthographic")]
791    Orthographic,
792}
793
794#[derive(Debug, DeJson, Clone)]
795pub struct Scene {
796    pub nodes: Vec<usize>,
797    #[cfg(feature = "names")]
798    pub name: Option<String>,
799}
800
801pub mod default_extensions {
802    use crate::extensions;
803    use nanoserde::DeJson;
804
805    #[derive(Debug, Default, Clone, Copy, DeJson)]
806    pub struct Extensions;
807
808    impl super::Extensions for Extensions {
809        type RootExtensions = RootExtensions;
810        type TextureExtensions = TextureExtensions;
811        type TextureInfoExtensions = TextureInfoExtensions;
812        type MaterialExtensions = MaterialExtensions<Self>;
813        type BufferExtensions = BufferExtensions;
814        type NodeExtensions = NodeExtensions;
815        type NodeExtras = NodeExtras;
816        type BufferViewExtensions = BufferViewExtensions;
817    }
818
819    #[derive(Debug, DeJson, Default, Clone)]
820    pub struct RootExtensions {
821        #[nserde(rename = "KHR_lights_punctual")]
822        pub khr_lights_punctual: Option<extensions::KhrLightsPunctual>,
823    }
824
825    #[derive(Debug, DeJson, Default, Clone)]
826    pub struct BufferExtensions {
827        #[nserde(rename = "EXT_meshopt_compression")]
828        pub ext_meshopt_compression: Option<extensions::ExtMeshoptCompressionBuffer>,
829    }
830
831    #[derive(Debug, DeJson, Default, Clone)]
832    pub struct NodeExtensions {
833        #[nserde(rename = "EXT_mesh_gpu_instancing")]
834        pub ext_mesh_gpu_instancing: Option<extensions::ExtMeshGpuInstancing>,
835        #[nserde(rename = "MSFT_lod")]
836        pub msft_lod: Option<extensions::MsftLod>,
837    }
838
839    #[derive(Debug, DeJson, Default, Clone)]
840    pub struct NodeExtras {
841        #[nserde(rename = "MSFT_screencoverage")]
842        pub msft_screencoverage: Option<Vec<f32>>,
843    }
844
845    #[derive(Debug, Default, DeJson, Clone)]
846    pub struct TextureExtensions {
847        #[nserde(rename = "KHR_texture_basisu")]
848        pub khr_texture_basisu: Option<extensions::KhrTextureBasisu>,
849    }
850
851    #[derive(Debug, DeJson, Default, Clone)]
852    pub struct BufferViewExtensions {
853        #[nserde(rename = "EXT_meshopt_compression")]
854        pub ext_meshopt_compression: Option<extensions::ExtMeshoptCompression>,
855    }
856
857    #[derive(Debug, DeJson, Default, Clone)]
858    pub struct MaterialExtensions<E: super::Extensions> {
859        #[nserde(rename = "KHR_materials_sheen")]
860        pub khr_materials_sheen: Option<extensions::KhrMaterialsSheen<E>>,
861        #[nserde(rename = "KHR_materials_emissive_strength")]
862        pub khr_materials_emissive_strength: Option<extensions::KhrMaterialsEmissiveStrength>,
863        #[nserde(rename = "KHR_materials_unlit")]
864        pub khr_materials_unlit: Option<extensions::KhrMaterialsUnlit>,
865        #[nserde(rename = "KHR_materials_ior")]
866        pub khr_materials_ior: Option<extensions::KhrMaterialsIor>,
867        #[nserde(rename = "KHR_materials_specular")]
868        pub khr_materials_specular: Option<extensions::KhrMaterialsSpecular<E>>,
869        #[nserde(rename = "KHR_materials_transmission")]
870        pub khr_materials_transmission: Option<extensions::KhrMaterialsTransmission<E>>,
871    }
872
873    #[derive(Debug, DeJson, Default, Clone, Copy)]
874    pub struct TextureInfoExtensions {
875        #[nserde(rename = "KHR_texture_transform")]
876        pub khr_texture_transform: Option<extensions::KhrTextureTransform>,
877    }
878}