1#![allow(clippy::question_mark)]
39
40pub mod extensions;
41
42use nanoserde::{DeJson, SerJson};
43use std::fmt::Debug;
44
45pub trait Extensions: DeJson + SerJson {
46 type RootExtensions: DeJson + SerJson + Default + Debug + Clone;
47 type TextureExtensions: DeJson + SerJson + Default + Debug + Clone;
48 type TextureInfoExtensions: DeJson + SerJson + Default + Debug + Clone;
49 type MaterialExtensions: DeJson + SerJson + Default + Debug + Clone;
50 type BufferExtensions: DeJson + SerJson + Default + Debug + Clone;
51 type NodeExtensions: DeJson + SerJson + Default + Debug + Clone;
52 type NodeExtras: DeJson + SerJson + Default + Debug + Clone;
53 type BufferViewExtensions: DeJson + SerJson + Default + Debug + Clone;
54}
55
56impl Extensions for () {
57 type RootExtensions = ();
58 type TextureExtensions = ();
59 type TextureInfoExtensions = ();
60 type MaterialExtensions = ();
61 type BufferExtensions = ();
62 type NodeExtensions = ();
63 type NodeExtras = ();
64 type BufferViewExtensions = ();
65}
66
67#[derive(Debug, DeJson, SerJson)]
69pub struct Gltf<E: Extensions> {
70 pub asset: Asset,
71 #[cfg(feature = "names")]
72 #[nserde(default, rename = "extensionsUsed")]
73 pub extensions_used: Vec<String>,
74 #[cfg(feature = "names")]
75 #[nserde(default, rename = "extensionsRequired")]
76 pub extensions_required: Vec<String>,
77 #[nserde(default)]
78 pub extensions: E::RootExtensions,
79 #[nserde(default)]
80 pub scene: usize,
81 #[nserde(default)]
82 pub scenes: Vec<Scene>,
83 #[nserde(default)]
84 pub nodes: Vec<Node<E>>,
85 #[nserde(default)]
86 pub materials: Vec<Material<E>>,
87 #[nserde(default)]
88 pub meshes: Vec<Mesh>,
89 #[nserde(default)]
90 pub textures: Vec<Texture<E>>,
91 #[nserde(default)]
92 pub images: Vec<Image>,
93 #[nserde(default)]
94 pub accessors: Vec<Accessor>,
95 #[nserde(rename = "bufferViews")]
96 #[nserde(default)]
97 pub buffer_views: Vec<BufferView<E>>,
98 #[nserde(default)]
99 pub animations: Vec<Animation>,
100 #[nserde(default)]
101 pub skins: Vec<Skin>,
102 #[nserde(default)]
103 pub samplers: Vec<Sampler>,
104 #[nserde(default)]
105 pub buffers: Vec<Buffer<E>>,
106 #[nserde(default)]
107 pub cameras: Vec<Camera>,
108}
109
110impl<E: Extensions> Gltf<E> {
111 pub fn from_bytes(bytes: &[u8]) -> Result<(Self, Option<&[u8]>), nanoserde::DeJsonErr> {
115 if !bytes.starts_with(b"glTF") {
117 return Ok((Self::from_json_bytes(bytes)?, None));
118 }
119
120 let json_chunk_length = u32::from_le_bytes(bytes[12..16].try_into().unwrap());
124
125 let json_chunk_end = 20 + json_chunk_length as usize;
126
127 let json_chunk_bytes = &bytes[20..20 + json_chunk_length as usize];
128
129 let json = Self::from_json_bytes(json_chunk_bytes)?;
130
131 let binary_buffer = if bytes.len() != json_chunk_end {
132 Some(&bytes[json_chunk_end + 8..])
133 } else {
134 None
135 };
136
137 Ok((json, binary_buffer))
138 }
139
140 pub fn write_to_glb<W: std::io::Write>(
141 &self,
142 bytes: &[u8],
143 mut writer: W,
144 ) -> std::io::Result<()> {
145 writer.write_all(b"glTF")?;
146 let version = 2_u32;
147 writer.write_all(&version.to_le_bytes())?;
148 let string = self.serialize_json();
149 let header_len = 4 + 4 + 4;
150 let json_chunk_len = 4 + 4 + string.len() as u32;
151 let binary_chunk_len = 4 + 4 + bytes.len() as u32;
152 let total_len = header_len + json_chunk_len + binary_chunk_len;
153 writer.write_all(&total_len.to_le_bytes())?;
154
155 writer.write_all(&(string.len() as u32).to_le_bytes())?;
156 writer.write_all(b"JSON")?;
157 writer.write_all(string.as_bytes())?;
158
159 writer.write_all(&(bytes.len() as u32).to_le_bytes())?;
160 writer.write_all(b"BIN\0")?;
161 writer.write_all(bytes)?;
162 Ok(())
163 }
164
165 pub fn from_json_bytes(bytes: &[u8]) -> Result<Self, nanoserde::DeJsonErr> {
166 match std::str::from_utf8(bytes) {
167 Ok(string) => Self::from_json_string(string),
168 Err(error) => Err(nanoserde::DeJsonState::default().err_parse(&error.to_string())),
169 }
170 }
171
172 pub fn from_json_string(string: &str) -> Result<Self, nanoserde::DeJsonErr> {
173 Self::deserialize_json(string)
174 }
175}
176
177#[derive(Debug, DeJson, SerJson)]
178pub struct Skin {
179 #[nserde(rename = "inverseBindMatrices")]
180 pub inverse_bind_matrices: Option<usize>,
181 pub skeleton: Option<usize>,
182 pub joints: Vec<usize>,
183 #[cfg(feature = "names")]
184 pub name: Option<String>,
185}
186
187#[derive(Debug, DeJson, SerJson)]
188pub struct Animation {
189 pub channels: Vec<Channel>,
190 pub samplers: Vec<AnimationSampler>,
191 #[cfg(feature = "names")]
192 pub name: Option<String>,
193}
194
195#[derive(Debug, DeJson, SerJson)]
196pub struct Channel {
197 pub sampler: usize,
198 pub target: Target,
199}
200
201#[derive(Debug, DeJson, SerJson)]
202pub struct Target {
203 pub node: Option<usize>,
204 pub path: TargetPath,
205}
206
207#[derive(Debug, DeJson, SerJson)]
208pub struct AnimationSampler {
209 pub input: usize,
210 #[nserde(default)]
211 pub interpolation: Interpolation,
212 pub output: usize,
213}
214
215#[derive(Debug, DeJson, SerJson)]
216pub struct Asset {
217 #[cfg(feature = "names")]
218 generator: Option<String>,
219 version: String,
220}
221
222#[derive(Default, Debug, DeJson, SerJson, Clone, Copy)]
223pub enum Interpolation {
224 #[default]
225 #[nserde(rename = "LINEAR")]
226 Linear,
227 #[nserde(rename = "STEP")]
228 Step,
229 #[nserde(rename = "CUBICSPLINE")]
230 CubicSpline,
231}
232
233#[derive(Debug, DeJson, SerJson)]
234pub enum TargetPath {
235 #[nserde(rename = "translation")]
236 Translation,
237 #[nserde(rename = "rotation")]
238 Rotation,
239 #[nserde(rename = "scale")]
240 Scale,
241 #[nserde(rename = "weights")]
242 Weights,
243}
244
245#[derive(Debug, DeJson, SerJson)]
246pub struct Buffer<E: Extensions> {
247 pub uri: Option<String>,
248 #[nserde(rename = "byteLength")]
249 pub byte_length: usize,
250 #[cfg(feature = "names")]
251 pub name: Option<String>,
252 #[nserde(default)]
253 pub extensions: E::BufferExtensions,
254}
255
256#[derive(Debug, DeJson, SerJson)]
257pub struct Node<E: Extensions> {
258 pub camera: Option<usize>,
259 #[nserde(default)]
260 pub children: Vec<usize>,
261 pub skin: Option<usize>,
262 pub matrix: Option<[f32; 16]>,
263 pub mesh: Option<usize>,
264 #[cfg(feature = "names")]
265 pub name: Option<String>,
266 pub rotation: Option<[f32; 4]>,
267 pub scale: Option<[f32; 3]>,
268 pub translation: Option<[f32; 3]>,
269 #[nserde(default)]
270 pub extensions: E::NodeExtensions,
271 #[nserde(default)]
272 pub extras: E::NodeExtras,
273}
274
275impl<E: Extensions> Node<E> {
276 pub fn transform(&self) -> NodeTransform {
277 match self.matrix {
278 Some(matrix) => match (self.translation, self.rotation, self.scale) {
279 (Some(translation), Some(rotation), Some(scale)) => NodeTransform::Set {
281 translation,
282 rotation,
283 scale,
284 },
285 _ => NodeTransform::Matrix(matrix),
286 },
287 None => {
288 let translation = self.translation.unwrap_or([0.0; 3]);
289 let rotation = self.rotation.unwrap_or([0.0, 0.0, 0.0, 1.0]);
290 let scale = self.scale.unwrap_or([1.0; 3]);
291 NodeTransform::Set {
292 translation,
293 rotation,
294 scale,
295 }
296 }
297 }
298 }
299}
300
301#[derive(Debug)]
302pub enum NodeTransform {
303 Matrix([f32; 16]),
304 Set {
305 translation: [f32; 3],
306 rotation: [f32; 4],
307 scale: [f32; 3],
308 },
309}
310
311#[derive(Debug, DeJson, SerJson)]
312pub struct Mesh {
313 #[cfg(feature = "names")]
314 pub name: Option<String>,
315 pub primitives: Vec<Primitive>,
316 pub weights: Option<Vec<f32>>,
317}
318
319#[derive(Debug, DeJson, SerJson)]
320pub struct Primitive {
321 pub attributes: Attributes,
322 pub indices: Option<usize>,
323 pub material: Option<usize>,
324 #[nserde(default)]
325 pub mode: PrimitiveMode,
326 pub targets: Option<Vec<Attributes>>,
327}
328
329#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
330pub enum PrimitiveMode {
331 Points,
332 Lines,
333 LineLoop,
334 LineStrip,
335 #[default]
336 Triangles,
337 TriangleStrip,
338 TriangleFan,
339}
340
341impl DeJson for PrimitiveMode {
342 fn de_json(
343 state: &mut nanoserde::DeJsonState,
344 input: &mut core::str::Chars,
345 ) -> Result<Self, nanoserde::DeJsonErr> {
346 let ty = match &state.tok {
347 nanoserde::DeJsonTok::U64(ty) => match ty {
348 0 => Self::Points,
349 1 => Self::Lines,
350 2 => Self::LineLoop,
351 3 => Self::LineStrip,
352 4 => Self::Triangles,
353 5 => Self::TriangleStrip,
354 6 => Self::TriangleFan,
355 _ => return Err(state.err_range(&ty.to_string())),
356 },
357 _ => return Err(state.err_token("U64")),
358 };
359
360 state.next_tok(input)?;
361
362 Ok(ty)
363 }
364}
365
366impl SerJson for PrimitiveMode {
367 fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
368 match self {
369 Self::Points => 0,
370 Self::Lines => 1,
371 Self::LineLoop => 2,
372 Self::LineStrip => 3,
373 Self::Triangles => 4,
374 Self::TriangleStrip => 5,
375 Self::TriangleFan => 6,
376 }
377 .ser_json(d, s)
378 }
379}
380
381#[derive(Debug, DeJson, SerJson)]
382pub struct Attributes {
383 #[nserde(rename = "POSITION")]
384 pub position: Option<usize>,
385 #[nserde(rename = "TANGENT")]
386 pub tangent: Option<usize>,
387 #[nserde(rename = "NORMAL")]
388 pub normal: Option<usize>,
389 #[nserde(rename = "TEXCOORD_0")]
390 pub texcoord_0: Option<usize>,
391 #[nserde(rename = "TEXCOORD_1")]
392 pub texcoord_1: Option<usize>,
393 #[nserde(rename = "JOINTS_0")]
394 pub joints_0: Option<usize>,
395 #[nserde(rename = "WEIGHTS_0")]
396 pub weights_0: Option<usize>,
397}
398
399#[derive(Debug, DeJson, SerJson, Clone)]
400pub struct Image {
401 #[nserde(rename = "bufferView")]
402 pub buffer_view: Option<usize>,
403 pub uri: Option<String>,
404 #[nserde(rename = "mimeType")]
405 pub mime_type: Option<String>,
406 #[cfg(feature = "names")]
407 pub name: Option<String>,
408}
409
410#[derive(Debug, DeJson, SerJson)]
411pub struct Texture<E: Extensions> {
412 pub sampler: Option<usize>,
413 pub source: Option<usize>,
414 #[cfg(feature = "names")]
415 pub name: Option<String>,
416 #[nserde(default)]
417 pub extensions: E::TextureExtensions,
418}
419
420#[derive(Debug, DeJson, SerJson)]
421pub struct BufferView<E: Extensions> {
422 pub buffer: usize,
423 #[nserde(rename = "byteLength")]
424 pub byte_length: usize,
425 #[nserde(rename = "byteOffset")]
426 #[nserde(default)]
427 pub byte_offset: usize,
428 #[nserde(rename = "byteStride")]
429 pub byte_stride: Option<usize>,
430 #[nserde(default)]
431 pub target: u32,
432 #[cfg(feature = "names")]
433 pub name: Option<String>,
434 #[nserde(default)]
435 pub extensions: E::BufferViewExtensions,
436}
437
438#[derive(Debug, DeJson, SerJson)]
439pub struct Accessor {
440 #[nserde(rename = "bufferView")]
441 pub buffer_view: Option<usize>,
442 #[nserde(rename = "componentType")]
443 pub component_type: ComponentType,
444 pub count: usize,
445 pub sparse: Option<Sparse>,
446 pub max: Option<Vec<f32>>,
448 pub min: Option<Vec<f32>>,
449 #[nserde(rename = "type")]
450 pub accessor_type: AccessorType,
451 #[cfg(feature = "names")]
452 pub name: Option<String>,
453 #[nserde(rename = "byteOffset")]
454 #[nserde(default)]
455 pub byte_offset: usize,
456 #[nserde(default)]
457 pub normalized: bool,
458}
459
460impl Accessor {
461 pub fn byte_length<E: Extensions>(&self, buffer_view: &BufferView<E>) -> usize {
462 self.count
463 * buffer_view.byte_stride.unwrap_or_else(|| {
464 self.component_type.byte_size() * self.accessor_type.num_components()
465 })
466 }
467}
468
469#[derive(Debug, DeJson, SerJson)]
470pub struct Sparse {
471 pub count: usize,
472 pub indices: SparseIndices,
473 pub values: SparseValues,
474}
475
476#[derive(Debug, DeJson, SerJson)]
477pub struct SparseIndices {
478 #[nserde(rename = "bufferView")]
479 pub buffer_view: usize,
480 #[nserde(rename = "byteOffset")]
481 #[nserde(default)]
482 pub byte_offset: usize,
483 #[nserde(rename = "componentType")]
484 pub component_type: ComponentType,
485}
486
487#[derive(Debug, DeJson, SerJson)]
488pub struct SparseValues {
489 #[nserde(rename = "bufferView")]
490 pub buffer_view: usize,
491 #[nserde(rename = "byteOffset")]
492 #[nserde(default)]
493 pub byte_offset: usize,
494}
495
496#[derive(Debug, Clone, Copy, PartialEq, Eq)]
497pub enum ComponentType {
498 UnsignedByte,
499 Byte,
500 UnsignedShort,
501 Short,
502 UnsignedInt,
503 Float,
504}
505
506impl ComponentType {
507 pub fn byte_size(&self) -> usize {
508 match self {
509 Self::UnsignedByte | Self::Byte => 1,
510 Self::UnsignedShort | Self::Short => 2,
511 Self::UnsignedInt | Self::Float => 4,
512 }
513 }
514}
515
516impl DeJson for ComponentType {
517 fn de_json(
518 state: &mut nanoserde::DeJsonState,
519 input: &mut core::str::Chars,
520 ) -> Result<Self, nanoserde::DeJsonErr> {
521 let ty = match &state.tok {
522 nanoserde::DeJsonTok::U64(ty) => match ty {
523 5120 => Self::Byte,
524 5121 => Self::UnsignedByte,
525 5122 => Self::Short,
526 5123 => Self::UnsignedShort,
527 5125 => Self::UnsignedInt,
528 5126 => Self::Float,
529 _ => return Err(state.err_range(&ty.to_string())),
530 },
531 _ => return Err(state.err_token("U64")),
532 };
533
534 state.next_tok(input)?;
535
536 Ok(ty)
537 }
538}
539
540impl SerJson for ComponentType {
541 fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
542 match self {
543 Self::Byte => 5120,
544 Self::UnsignedByte => 5121,
545 Self::Short => 5122,
546 Self::UnsignedShort => 5123,
547 Self::UnsignedInt => 5125,
548 Self::Float => 5126,
549 }
550 .ser_json(d, s)
551 }
552}
553
554#[derive(Debug, DeJson, SerJson, PartialEq, Clone, Copy)]
555pub enum AccessorType {
556 #[nserde(rename = "SCALAR")]
557 Scalar,
558 #[nserde(rename = "VEC2")]
559 Vec2,
560 #[nserde(rename = "VEC3")]
561 Vec3,
562 #[nserde(rename = "VEC4")]
563 Vec4,
564 #[nserde(rename = "MAT2")]
565 Mat2,
566 #[nserde(rename = "MAT3")]
567 Mat3,
568 #[nserde(rename = "MAT4")]
569 Mat4,
570}
571
572impl AccessorType {
573 pub fn num_components(&self) -> usize {
574 match self {
575 Self::Scalar => 1,
576 Self::Vec2 => 2,
577 Self::Vec3 => 3,
578 Self::Vec4 | Self::Mat2 => 4,
579 Self::Mat3 => 9,
580 Self::Mat4 => 16,
581 }
582 }
583}
584
585#[derive(Debug, DeJson, SerJson, Clone)]
586pub struct Material<E: Extensions> {
587 #[nserde(rename = "alphaMode")]
588 #[nserde(default)]
589 pub alpha_mode: AlphaMode,
590 #[nserde(default)]
591 pub extensions: E::MaterialExtensions,
592 #[cfg(feature = "names")]
593 pub name: Option<String>,
594 #[nserde(rename = "pbrMetallicRoughness")]
595 #[nserde(default)]
596 pub pbr_metallic_roughness: PbrMetallicRoughness<E>,
597 #[nserde(rename = "normalTexture")]
598 pub normal_texture: Option<NormalTextureInfo<E>>,
599 #[nserde(rename = "occlusionTexture")]
600 pub occlusion_texture: Option<OcclusionTextureInfo<E>>,
601 #[nserde(rename = "emissiveTexture")]
602 pub emissive_texture: Option<TextureInfo<E>>,
603 #[nserde(rename = "emissiveFactor")]
604 #[nserde(default)]
605 pub emissive_factor: [f32; 3],
606 #[nserde(rename = "alphaCutoff")]
607 #[nserde(default = "0.5")]
608 pub alpha_cutoff: f32,
609 #[nserde(rename = "doubleSided")]
610 #[nserde(default)]
611 pub double_sided: bool,
612}
613
614#[derive(Default, Debug, DeJson, SerJson, Clone, Copy)]
615pub enum AlphaMode {
616 #[default]
617 #[nserde(rename = "OPAQUE")]
618 Opaque,
619 #[nserde(rename = "MASK")]
620 Mask,
621 #[nserde(rename = "BLEND")]
622 Blend,
623}
624
625#[derive(Debug, DeJson, SerJson, Clone)]
626pub struct PbrMetallicRoughness<E: Extensions> {
627 #[nserde(rename = "baseColorFactor")]
628 #[nserde(default = "[1.0, 1.0, 1.0, 1.0]")]
629 pub base_color_factor: [f32; 4],
630 #[nserde(rename = "baseColorTexture")]
631 pub base_color_texture: Option<TextureInfo<E>>,
632 #[nserde(rename = "metallicFactor")]
633 #[nserde(default = "1.0")]
634 pub metallic_factor: f32,
635 #[nserde(rename = "roughnessFactor")]
636 #[nserde(default = "1.0")]
637 pub roughness_factor: f32,
638 #[nserde(rename = "metallicRoughnessTexture")]
639 pub metallic_roughness_texture: Option<TextureInfo<E>>,
640}
641
642impl<E: Extensions> Default for PbrMetallicRoughness<E> {
643 fn default() -> Self {
644 Self {
645 base_color_factor: [1.0; 4],
646 base_color_texture: None,
647 metallic_factor: 1.0,
648 roughness_factor: 1.0,
649 metallic_roughness_texture: None,
650 }
651 }
652}
653
654#[derive(Debug, DeJson, SerJson, Clone)]
655pub struct TextureInfo<E: Extensions> {
656 pub index: usize,
657 #[nserde(rename = "texCoord")]
658 #[nserde(default)]
659 pub tex_coord: usize,
660 #[nserde(default)]
661 pub extensions: E::TextureInfoExtensions,
662}
663
664#[derive(Debug, DeJson, SerJson, Clone)]
665pub struct NormalTextureInfo<E: Extensions> {
666 pub index: usize,
667 #[nserde(rename = "texCoord")]
668 #[nserde(default)]
669 pub tex_coord: usize,
670 #[nserde(default = "1.0")]
671 pub scale: f32,
672 #[nserde(default)]
673 pub extensions: E::TextureInfoExtensions,
674}
675
676#[derive(Debug, DeJson, SerJson, Clone)]
677pub struct OcclusionTextureInfo<E: Extensions> {
678 pub index: usize,
679 #[nserde(rename = "texCoord")]
680 #[nserde(default)]
681 pub tex_coord: usize,
682 #[nserde(default = "1.0")]
683 pub strength: f32,
684 #[nserde(default)]
685 pub extensions: E::TextureInfoExtensions,
686}
687
688#[derive(Debug, DeJson, SerJson)]
689pub struct Sampler {
690 #[nserde(rename = "magFilter")]
691 pub mag_filter: Option<FilterMode>,
692 #[nserde(rename = "minFilter")]
693 pub min_filter: Option<MinFilter>,
694 #[nserde(rename = "wrapS")]
695 #[nserde(default)]
696 pub wrap_s: SamplerWrap,
697 #[nserde(rename = "wrapT")]
698 #[nserde(default)]
699 pub wrap_t: SamplerWrap,
700 #[cfg(feature = "names")]
701 pub name: Option<String>,
702}
703
704#[derive(Debug, PartialEq)]
705pub enum FilterMode {
706 Nearest,
707 Linear,
708}
709
710impl DeJson for FilterMode {
711 fn de_json(
712 state: &mut nanoserde::DeJsonState,
713 input: &mut core::str::Chars,
714 ) -> Result<Self, nanoserde::DeJsonErr> {
715 let ty = match &state.tok {
716 nanoserde::DeJsonTok::U64(ty) => match ty {
717 9728 => Self::Nearest,
718 9729 => Self::Linear,
719 _ => return Err(state.err_range(&ty.to_string())),
720 },
721 _ => return Err(state.err_token("U64")),
722 };
723
724 state.next_tok(input)?;
725
726 Ok(ty)
727 }
728}
729
730impl SerJson for FilterMode {
731 fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
732 match self {
733 Self::Nearest => 9728,
734 Self::Linear => 9729,
735 }
736 .ser_json(d, s)
737 }
738}
739
740#[derive(Debug, PartialEq)]
741pub struct MinFilter {
742 pub mode: FilterMode,
743 pub mipmap: Option<FilterMode>,
744}
745
746impl DeJson for MinFilter {
747 fn de_json(
748 state: &mut nanoserde::DeJsonState,
749 input: &mut core::str::Chars,
750 ) -> Result<Self, nanoserde::DeJsonErr> {
751 let ty = match &state.tok {
752 nanoserde::DeJsonTok::U64(ty) => match ty {
753 9728 => Self {
754 mode: FilterMode::Nearest,
755 mipmap: None,
756 },
757 9729 => Self {
758 mode: FilterMode::Linear,
759 mipmap: None,
760 },
761 9984 => Self {
762 mode: FilterMode::Nearest,
763 mipmap: Some(FilterMode::Nearest),
764 },
765 9985 => Self {
766 mode: FilterMode::Linear,
767 mipmap: Some(FilterMode::Nearest),
768 },
769 9986 => Self {
770 mode: FilterMode::Nearest,
771 mipmap: Some(FilterMode::Linear),
772 },
773 9987 => Self {
774 mode: FilterMode::Linear,
775 mipmap: Some(FilterMode::Linear),
776 },
777 _ => return Err(state.err_range(&ty.to_string())),
778 },
779 _ => return Err(state.err_token("U64")),
780 };
781
782 state.next_tok(input)?;
783
784 Ok(ty)
785 }
786}
787
788impl SerJson for MinFilter {
789 fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
790 match &self {
791 MinFilter {
792 mode: FilterMode::Nearest,
793 mipmap: None,
794 } => 9728,
795 MinFilter {
796 mode: FilterMode::Linear,
797 mipmap: None,
798 } => 9729,
799 MinFilter {
800 mode: FilterMode::Nearest,
801 mipmap: Some(FilterMode::Nearest),
802 } => 9984,
803 MinFilter {
804 mode: FilterMode::Linear,
805 mipmap: Some(FilterMode::Nearest),
806 } => 9985,
807 MinFilter {
808 mode: FilterMode::Nearest,
809 mipmap: Some(FilterMode::Linear),
810 } => 9986,
811 MinFilter {
812 mode: FilterMode::Linear,
813 mipmap: Some(FilterMode::Linear),
814 } => 9987,
815 }
816 .ser_json(d, s)
817 }
818}
819
820#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
821pub enum SamplerWrap {
822 ClampToEdge,
823 MirroredRepeat,
824 #[default]
825 Repeat,
826}
827
828impl DeJson for SamplerWrap {
829 fn de_json(
830 state: &mut nanoserde::DeJsonState,
831 input: &mut core::str::Chars,
832 ) -> Result<Self, nanoserde::DeJsonErr> {
833 let ty = match &state.tok {
834 nanoserde::DeJsonTok::U64(ty) => match ty {
835 33071 => Self::ClampToEdge,
836 33648 => Self::MirroredRepeat,
837 10497 => Self::Repeat,
838 _ => return Err(state.err_range(&ty.to_string())),
839 },
840 _ => return Err(state.err_token("U64")),
841 };
842
843 state.next_tok(input)?;
844
845 Ok(ty)
846 }
847}
848
849impl SerJson for SamplerWrap {
850 fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
851 match self {
852 Self::ClampToEdge => 33071,
853 Self::MirroredRepeat => 33648,
854 Self::Repeat => 10497,
855 }
856 .ser_json(d, s)
857 }
858}
859
860#[derive(Debug, DeJson, SerJson, Clone)]
861pub struct Camera {
862 pub perspective: Option<CameraPerspective>,
863 pub orthographic: Option<CameraOrthographic>,
864 #[nserde(rename = "type")]
865 pub ty: CameraType,
866 #[cfg(feature = "names")]
867 pub name: Option<String>,
868}
869
870#[derive(Debug, DeJson, SerJson, Clone, Copy)]
871pub struct CameraPerspective {
872 pub yfov: f32,
873 pub znear: f32,
874 pub zfar: Option<f32>,
875 #[nserde(rename = "aspectRatio")]
876 pub aspect_ratio: Option<f32>,
877}
878
879#[derive(Debug, DeJson, SerJson, Clone, Copy)]
880pub struct CameraOrthographic {
881 pub xmag: f32,
882 pub ymag: f32,
883 pub zfar: f32,
884 pub znear: f32,
885}
886
887#[derive(Debug, DeJson, SerJson, Clone, Copy, PartialEq, Eq)]
888pub enum CameraType {
889 #[nserde(rename = "perspective")]
890 Perspective,
891 #[nserde(rename = "orthographic")]
892 Orthographic,
893}
894
895#[derive(Debug, DeJson, SerJson, Clone)]
896pub struct Scene {
897 #[cfg(feature = "names")]
898 pub name: Option<String>,
899 pub nodes: Vec<usize>,
900}
901
902pub mod default_extensions {
903 use crate::extensions;
904 use nanoserde::{DeJson, SerJson};
905
906 #[derive(Debug, Default, Clone, Copy, DeJson, SerJson)]
907 pub struct Extensions;
908
909 impl super::Extensions for Extensions {
910 type RootExtensions = RootExtensions;
911 type TextureExtensions = TextureExtensions;
912 type TextureInfoExtensions = TextureInfoExtensions;
913 type MaterialExtensions = MaterialExtensions<Self>;
914 type BufferExtensions = BufferExtensions;
915 type NodeExtensions = NodeExtensions;
916 type NodeExtras = NodeExtras;
917 type BufferViewExtensions = BufferViewExtensions;
918 }
919
920 #[derive(Debug, DeJson, SerJson, Default, Clone)]
921 pub struct RootExtensions {
922 #[nserde(rename = "KHR_lights_punctual")]
923 pub khr_lights_punctual: Option<extensions::khr_lights_punctual::Root>,
924 }
925
926 #[derive(Debug, DeJson, SerJson, Default, Clone)]
927 pub struct BufferExtensions {
928 #[nserde(rename = "EXT_meshopt_compression")]
929 pub ext_meshopt_compression: Option<extensions::ExtMeshoptCompressionBuffer>,
930 }
931
932 #[derive(Debug, DeJson, SerJson, Default, Clone)]
933 pub struct NodeExtensions {
934 #[nserde(rename = "EXT_mesh_gpu_instancing")]
935 pub ext_mesh_gpu_instancing: Option<extensions::ExtMeshGpuInstancing>,
936 #[nserde(rename = "MSFT_lod")]
937 pub msft_lod: Option<extensions::MsftLod>,
938 #[nserde(rename = "KHR_lights_punctual")]
939 pub khr_lights_punctual: Option<extensions::khr_lights_punctual::Node>,
940 }
941
942 #[derive(Debug, DeJson, SerJson, Default, Clone)]
943 pub struct NodeExtras {
944 #[nserde(rename = "MSFT_screencoverage")]
945 pub msft_screencoverage: Option<Vec<f32>>,
946 }
947
948 #[derive(Debug, DeJson, SerJson, Default, Clone)]
949 pub struct TextureExtensions {
950 #[nserde(rename = "KHR_texture_basisu")]
951 pub khr_texture_basisu: Option<extensions::KhrTextureBasisu>,
952 }
953
954 #[derive(Debug, DeJson, SerJson, Default, Clone)]
955 pub struct BufferViewExtensions {
956 #[nserde(rename = "EXT_meshopt_compression")]
957 pub ext_meshopt_compression: Option<extensions::ExtMeshoptCompression>,
958 }
959
960 #[derive(Debug, DeJson, SerJson, Default, Clone)]
961 pub struct MaterialExtensions<E: super::Extensions> {
962 #[nserde(rename = "KHR_materials_sheen")]
963 pub khr_materials_sheen: Option<extensions::KhrMaterialsSheen<E>>,
964 #[nserde(rename = "KHR_materials_emissive_strength")]
965 pub khr_materials_emissive_strength: Option<extensions::KhrMaterialsEmissiveStrength>,
966 #[nserde(rename = "KHR_materials_unlit")]
967 pub khr_materials_unlit: Option<extensions::KhrMaterialsUnlit>,
968 #[nserde(rename = "KHR_materials_ior")]
969 pub khr_materials_ior: Option<extensions::KhrMaterialsIor>,
970 #[nserde(rename = "KHR_materials_specular")]
971 pub khr_materials_specular: Option<extensions::KhrMaterialsSpecular<E>>,
972 #[nserde(rename = "KHR_materials_transmission")]
973 pub khr_materials_transmission: Option<extensions::KhrMaterialsTransmission<E>>,
974 }
975
976 #[derive(Debug, DeJson, SerJson, Default, Clone, Copy)]
977 pub struct TextureInfoExtensions {
978 #[nserde(rename = "KHR_texture_transform")]
979 pub khr_texture_transform: Option<extensions::KhrTextureTransform>,
980 }
981}
982
983#[cfg(test)]
984mod tests {
985 use super::*;
986 use nanoserde::{DeJson, SerJson};
987
988 fn test_roundtrip<T: DeJson + SerJson + PartialEq + Debug>(value: &T) {
989 assert_eq!(
990 *value,
991 T::deserialize_json(&value.serialize_json()).unwrap()
992 );
993 }
994
995 #[test]
996 fn test_primitive_mode_roundtrip() {
997 for variant in &[
998 PrimitiveMode::Points,
999 PrimitiveMode::Lines,
1000 PrimitiveMode::LineLoop,
1001 PrimitiveMode::LineStrip,
1002 PrimitiveMode::Triangles,
1003 PrimitiveMode::TriangleStrip,
1004 PrimitiveMode::TriangleFan,
1005 ] {
1006 test_roundtrip(variant);
1007 }
1008 }
1009
1010 #[test]
1011 fn test_component_type_roundtrip() {
1012 for variant in &[
1013 ComponentType::UnsignedByte,
1014 ComponentType::Byte,
1015 ComponentType::UnsignedShort,
1016 ComponentType::Short,
1017 ComponentType::UnsignedInt,
1018 ComponentType::Float,
1019 ] {
1020 test_roundtrip(variant);
1021 }
1022 }
1023
1024 #[test]
1025 fn test_filter_mode_roundtrip() {
1026 for variant in &[FilterMode::Nearest, FilterMode::Linear] {
1027 test_roundtrip(variant);
1028 }
1029 }
1030
1031 #[test]
1032 fn test_min_filter_roundtrip() {
1033 for variant in &[
1034 MinFilter {
1035 mode: FilterMode::Nearest,
1036 mipmap: None,
1037 },
1038 MinFilter {
1039 mode: FilterMode::Linear,
1040 mipmap: None,
1041 },
1042 MinFilter {
1043 mode: FilterMode::Nearest,
1044 mipmap: Some(FilterMode::Nearest),
1045 },
1046 MinFilter {
1047 mode: FilterMode::Linear,
1048 mipmap: Some(FilterMode::Nearest),
1049 },
1050 MinFilter {
1051 mode: FilterMode::Nearest,
1052 mipmap: Some(FilterMode::Linear),
1053 },
1054 MinFilter {
1055 mode: FilterMode::Linear,
1056 mipmap: Some(FilterMode::Linear),
1057 },
1058 ] {
1059 test_roundtrip(variant);
1060 }
1061 }
1062
1063 #[test]
1064 fn test_sampler_wrap_roundtrip() {
1065 for variant in &[
1066 SamplerWrap::ClampToEdge,
1067 SamplerWrap::MirroredRepeat,
1068 SamplerWrap::Repeat,
1069 ] {
1070 test_roundtrip(variant);
1071 }
1072 }
1073}