1use crate::{texture, Document};
2
3pub use json::material::AlphaMode;
4#[cfg(feature = "extensions")]
5use serde_json::{Map, Value};
6
7#[derive(Clone, Debug)]
9pub struct Material<'a> {
10 document: &'a Document,
12
13 index: Option<usize>,
15
16 json: &'a json::material::Material,
18}
19
20impl<'a> Material<'a> {
21 pub(crate) fn new(
23 document: &'a Document,
24 index: usize,
25 json: &'a json::material::Material,
26 ) -> Self {
27 Self {
28 document,
29 index: Some(index),
30 json,
31 }
32 }
33
34 pub(crate) fn default(document: &'a Document) -> Self {
36 Self {
37 document,
38 index: None,
39 json: &json::material::Material::DEFAULT_MATERIAL,
40 }
41 }
42
43 pub fn index(&self) -> Option<usize> {
47 self.index
48 }
49
50 pub fn alpha_cutoff(&self) -> Option<f32> {
52 self.json.alpha_cutoff.map(|value| value.0)
53 }
54
55 pub fn alpha_mode(&self) -> AlphaMode {
69 self.json.alpha_mode.unwrap()
70 }
71
72 pub fn double_sided(&self) -> bool {
79 self.json.double_sided
80 }
81
82 #[cfg(feature = "names")]
84 #[cfg_attr(docsrs, doc(cfg(feature = "names")))]
85 pub fn name(&self) -> Option<&'a str> {
86 self.json.name.as_deref()
87 }
88
89 pub fn pbr_metallic_roughness(&self) -> PbrMetallicRoughness<'a> {
92 PbrMetallicRoughness::new(self.document, &self.json.pbr_metallic_roughness)
93 }
94
95 #[cfg(feature = "extensions")]
97 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
98 pub fn extensions(&self) -> Option<&Map<String, Value>> {
99 let ext = self.json.extensions.as_ref()?;
100 Some(&ext.others)
101 }
102
103 #[cfg(feature = "extensions")]
105 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
106 pub fn extension_value(&self, key: &str) -> Option<&Value> {
107 let ext = self.json.extensions.as_ref()?;
108 ext.others.get(key)
109 }
110
111 #[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
114 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
115 pub fn pbr_specular_glossiness(&self) -> Option<PbrSpecularGlossiness<'a>> {
116 self.json
117 .extensions
118 .as_ref()?
119 .pbr_specular_glossiness
120 .as_ref()
121 .map(|x| PbrSpecularGlossiness::new(self.document, x))
122 }
123
124 #[cfg(feature = "KHR_materials_transmission")]
126 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
127 pub fn transmission(&self) -> Option<Transmission<'a>> {
128 self.json
129 .extensions
130 .as_ref()?
131 .transmission
132 .as_ref()
133 .map(|x| Transmission::new(self.document, x))
134 }
135
136 #[cfg(feature = "KHR_materials_ior")]
138 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_ior")))]
139 pub fn ior(&self) -> Option<f32> {
140 self.json.extensions.as_ref()?.ior.as_ref().map(|x| x.ior.0)
141 }
142
143 #[cfg(feature = "KHR_materials_emissive_strength")]
145 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_emissive_strength")))]
146 pub fn emissive_strength(&self) -> Option<f32> {
147 self.json
148 .extensions
149 .as_ref()?
150 .emissive_strength
151 .as_ref()
152 .map(|x| x.emissive_strength.0)
153 }
154
155 #[cfg(feature = "KHR_materials_volume")]
157 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
158 pub fn volume(&self) -> Option<Volume<'a>> {
159 self.json
160 .extensions
161 .as_ref()?
162 .volume
163 .as_ref()
164 .map(|x| Volume::new(self.document, x))
165 }
166
167 #[cfg(feature = "KHR_materials_specular")]
169 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
170 pub fn specular(&self) -> Option<Specular<'a>> {
171 self.json
172 .extensions
173 .as_ref()?
174 .specular
175 .as_ref()
176 .map(|x| Specular::new(self.document, x))
177 }
178
179 #[cfg(feature = "KHR_materials_clearcoat")]
183 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_clearcoat")))]
184 pub fn clearcoat(&self) -> Option<Clearcoat> {
185 self.json
186 .extensions
187 .as_ref()?
188 .clearcoat
189 .as_ref()
190 .map(|clearcoat| Clearcoat::new(self.document, clearcoat))
191 }
192
193 #[cfg(feature = "KHR_materials_sheen")]
197 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_sheen")))]
198 pub fn sheen(&self) -> Option<Sheen> {
199 self.json
200 .extensions
201 .as_ref()?
202 .sheen
203 .as_ref()
204 .map(|sheen| Sheen::new(self.document, sheen))
205 }
206
207 pub fn normal_texture(&self) -> Option<NormalTexture<'a>> {
219 self.json.normal_texture.as_ref().map(|json| {
220 let texture = self.document.textures().nth(json.index.value()).unwrap();
221 NormalTexture::new(texture, json)
222 })
223 }
224
225 pub fn occlusion_texture(&self) -> Option<OcclusionTexture<'a>> {
234 self.json.occlusion_texture.as_ref().map(|json| {
235 let texture = self.document.textures().nth(json.index.value()).unwrap();
236 OcclusionTexture::new(texture, json)
237 })
238 }
239
240 pub fn emissive_texture(&self) -> Option<texture::Info<'a>> {
248 self.json.emissive_texture.as_ref().map(|json| {
249 let texture = self.document.textures().nth(json.index.value()).unwrap();
250 texture::Info::new(texture, json)
251 })
252 }
253
254 pub fn emissive_factor(&self) -> [f32; 3] {
258 self.json.emissive_factor.0
259 }
260
261 #[cfg(feature = "KHR_materials_unlit")]
268 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_unlit")))]
269 pub fn unlit(&self) -> bool {
270 self.json
271 .extensions
272 .as_ref()
273 .map_or(false, |extensions| extensions.unlit.is_some())
274 }
275
276 pub fn extras(&self) -> &'a json::Extras {
278 &self.json.extras
279 }
280}
281
282pub struct PbrMetallicRoughness<'a> {
285 document: &'a Document,
287
288 json: &'a json::material::PbrMetallicRoughness,
290}
291
292impl<'a> PbrMetallicRoughness<'a> {
293 pub(crate) fn new(
295 document: &'a Document,
296 json: &'a json::material::PbrMetallicRoughness,
297 ) -> Self {
298 Self { document, json }
299 }
300
301 pub fn base_color_factor(&self) -> [f32; 4] {
305 self.json.base_color_factor.0
306 }
307
308 pub fn base_color_texture(&self) -> Option<texture::Info<'a>> {
311 self.json.base_color_texture.as_ref().map(|json| {
312 let texture = self.document.textures().nth(json.index.value()).unwrap();
313 texture::Info::new(texture, json)
314 })
315 }
316
317 pub fn metallic_factor(&self) -> f32 {
321 self.json.metallic_factor.0
322 }
323
324 pub fn roughness_factor(&self) -> f32 {
331 self.json.roughness_factor.0
332 }
333
334 pub fn metallic_roughness_texture(&self) -> Option<texture::Info<'a>> {
341 self.json.metallic_roughness_texture.as_ref().map(|json| {
342 let texture = self.document.textures().nth(json.index.value()).unwrap();
343 texture::Info::new(texture, json)
344 })
345 }
346
347 #[cfg(feature = "extensions")]
349 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
350 pub fn extensions(&self) -> Option<&Map<String, Value>> {
351 let ext = self.json.extensions.as_ref()?;
352 Some(&ext.others)
353 }
354
355 #[cfg(feature = "extensions")]
357 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
358 pub fn extension_value(&self, key: &str) -> Option<&Value> {
359 let ext = self.json.extensions.as_ref()?;
360 ext.others.get(key)
361 }
362
363 pub fn extras(&self) -> &'a json::Extras {
365 &self.json.extras
366 }
367}
368
369#[cfg(feature = "KHR_materials_transmission")]
372#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
373pub struct Transmission<'a> {
374 document: &'a Document,
376
377 json: &'a json::extensions::material::Transmission,
379}
380
381#[cfg(feature = "KHR_materials_transmission")]
382#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
383impl<'a> Transmission<'a> {
384 pub(crate) fn new(
386 document: &'a Document,
387 json: &'a json::extensions::material::Transmission,
388 ) -> Self {
389 Self { document, json }
390 }
391
392 pub fn transmission_factor(&self) -> f32 {
396 self.json.transmission_factor.0
397 }
398
399 pub fn transmission_texture(&self) -> Option<texture::Info<'a>> {
401 self.json.transmission_texture.as_ref().map(|json| {
402 let texture = self.document.textures().nth(json.index.value()).unwrap();
403 texture::Info::new(texture, json)
404 })
405 }
406
407 pub fn extras(&self) -> &'a json::Extras {
409 &self.json.extras
410 }
411}
412
413#[cfg(feature = "KHR_materials_volume")]
415#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
416pub struct Volume<'a> {
417 document: &'a Document,
419
420 json: &'a json::extensions::material::Volume,
422}
423
424#[cfg(feature = "KHR_materials_volume")]
425#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
426impl<'a> Volume<'a> {
427 pub(crate) fn new(
429 document: &'a Document,
430 json: &'a json::extensions::material::Volume,
431 ) -> Self {
432 Self { document, json }
433 }
434
435 pub fn thickness_factor(&self) -> f32 {
441 self.json.thickness_factor.0
442 }
443
444 pub fn thickness_texture(&self) -> Option<texture::Info<'a>> {
447 self.json.thickness_texture.as_ref().map(|json| {
448 let texture = self.document.textures().nth(json.index.value()).unwrap();
449 texture::Info::new(texture, json)
450 })
451 }
452
453 pub fn attenuation_distance(&self) -> f32 {
457 self.json.attenuation_distance.0
458 }
459
460 pub fn attenuation_color(&self) -> [f32; 3] {
463 self.json.attenuation_color.0
464 }
465
466 pub fn extras(&self) -> &'a json::Extras {
468 &self.json.extras
469 }
470}
471
472#[cfg(feature = "KHR_materials_specular")]
474#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
475pub struct Specular<'a> {
476 document: &'a Document,
478
479 json: &'a json::extensions::material::Specular,
481}
482
483#[cfg(feature = "KHR_materials_specular")]
484#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
485impl<'a> Specular<'a> {
486 pub(crate) fn new(
488 document: &'a Document,
489 json: &'a json::extensions::material::Specular,
490 ) -> Self {
491 Self { document, json }
492 }
493
494 pub fn specular_factor(&self) -> f32 {
496 self.json.specular_factor.0
497 }
498
499 pub fn specular_texture(&self) -> Option<texture::Info<'a>> {
503 self.json.specular_texture.as_ref().map(|json| {
504 let texture = self.document.textures().nth(json.index.value()).unwrap();
505 texture::Info::new(texture, json)
506 })
507 }
508
509 pub fn specular_color_factor(&self) -> [f32; 3] {
511 self.json.specular_color_factor.0
512 }
513
514 pub fn specular_color_texture(&self) -> Option<texture::Info<'a>> {
518 self.json.specular_color_texture.as_ref().map(|json| {
519 let texture = self.document.textures().nth(json.index.value()).unwrap();
520 texture::Info::new(texture, json)
521 })
522 }
523
524 pub fn extras(&self) -> &'a json::Extras {
526 &self.json.extras
527 }
528}
529
530#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
533#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
534pub struct PbrSpecularGlossiness<'a> {
535 document: &'a Document,
537
538 json: &'a json::extensions::material::PbrSpecularGlossiness,
540}
541
542#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
543#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
544impl<'a> PbrSpecularGlossiness<'a> {
545 pub(crate) fn new(
547 document: &'a Document,
548 json: &'a json::extensions::material::PbrSpecularGlossiness,
549 ) -> Self {
550 Self { document, json }
551 }
552
553 pub fn diffuse_factor(&self) -> [f32; 4] {
557 self.json.diffuse_factor.0
558 }
559
560 pub fn diffuse_texture(&self) -> Option<texture::Info<'a>> {
562 self.json.diffuse_texture.as_ref().map(|json| {
563 let texture = self.document.textures().nth(json.index.value()).unwrap();
564 texture::Info::new(texture, json)
565 })
566 }
567
568 pub fn specular_factor(&self) -> [f32; 3] {
572 self.json.specular_factor.0
573 }
574
575 pub fn glossiness_factor(&self) -> f32 {
583 self.json.glossiness_factor.0
584 }
585
586 pub fn specular_glossiness_texture(&self) -> Option<texture::Info<'a>> {
592 self.json.specular_glossiness_texture.as_ref().map(|json| {
593 let texture = self.document.textures().nth(json.index.value()).unwrap();
594 texture::Info::new(texture, json)
595 })
596 }
597
598 pub fn extras(&self) -> &'a json::Extras {
600 &self.json.extras
601 }
602}
603
604pub struct NormalTexture<'a> {
606 texture: texture::Texture<'a>,
608
609 json: &'a json::material::NormalTexture,
611}
612
613impl<'a> NormalTexture<'a> {
614 pub(crate) fn new(
616 texture: texture::Texture<'a>,
617 json: &'a json::material::NormalTexture,
618 ) -> Self {
619 Self { texture, json }
620 }
621
622 pub fn scale(&self) -> f32 {
624 self.json.scale
625 }
626
627 pub fn tex_coord(&self) -> u32 {
629 self.json.tex_coord
630 }
631
632 pub fn texture(&self) -> texture::Texture<'a> {
634 self.texture.clone()
635 }
636
637 #[cfg(feature = "KHR_texture_transform")]
639 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_texture_transform")))]
640 pub fn texture_transform(&self) -> Option<texture::TextureTransform<'a>> {
641 self.json
642 .extensions
643 .as_ref()?
644 .texture_transform
645 .as_ref()
646 .map(texture::TextureTransform::new)
647 }
648
649 #[cfg(feature = "extensions")]
651 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
652 pub fn extensions(&self) -> Option<&Map<String, Value>> {
653 let ext = self.json.extensions.as_ref()?;
654 Some(&ext.others)
655 }
656
657 #[cfg(feature = "extensions")]
659 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
660 pub fn extension_value(&self, key: &str) -> Option<&Value> {
661 let ext = self.json.extensions.as_ref()?;
662 ext.others.get(key)
663 }
664
665 pub fn extras(&self) -> &'a json::Extras {
667 &self.json.extras
668 }
669}
670
671pub struct OcclusionTexture<'a> {
673 texture: texture::Texture<'a>,
675
676 json: &'a json::material::OcclusionTexture,
678}
679
680impl<'a> OcclusionTexture<'a> {
681 pub(crate) fn new(
683 texture: texture::Texture<'a>,
684 json: &'a json::material::OcclusionTexture,
685 ) -> Self {
686 Self { texture, json }
687 }
688
689 pub fn strength(&self) -> f32 {
691 self.json.strength.0
692 }
693
694 pub fn tex_coord(&self) -> u32 {
696 self.json.tex_coord
697 }
698
699 pub fn texture(&self) -> texture::Texture<'a> {
701 self.texture.clone()
702 }
703
704 #[cfg(feature = "KHR_texture_transform")]
706 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_texture_transform")))]
707 pub fn texture_transform(&self) -> Option<texture::TextureTransform<'a>> {
708 self.json
709 .extensions
710 .as_ref()?
711 .texture_transform
712 .as_ref()
713 .map(texture::TextureTransform::new)
714 }
715
716 #[cfg(feature = "extensions")]
718 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
719 pub fn extensions(&self) -> Option<&Map<String, Value>> {
720 let ext = self.json.extensions.as_ref()?;
721 Some(&ext.others)
722 }
723
724 #[cfg(feature = "extensions")]
726 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
727 pub fn extension_value(&self, key: &str) -> Option<&Value> {
728 let ext = self.json.extensions.as_ref()?;
729 ext.others.get(key)
730 }
731
732 pub fn extras(&self) -> &'a json::Extras {
734 &self.json.extras
735 }
736}
737
738impl<'a> AsRef<texture::Texture<'a>> for NormalTexture<'a> {
739 fn as_ref(&self) -> &texture::Texture<'a> {
740 &self.texture
741 }
742}
743
744impl<'a> AsRef<texture::Texture<'a>> for OcclusionTexture<'a> {
745 fn as_ref(&self) -> &texture::Texture<'a> {
746 &self.texture
747 }
748}
749
750#[cfg(feature = "KHR_materials_clearcoat")]
754#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_clearcoat")))]
755pub struct Clearcoat<'a> {
756 document: &'a Document,
758
759 json: &'a json::extensions::material::Clearcoat,
761}
762
763#[cfg(feature = "KHR_materials_clearcoat")]
764#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_clearcoat")))]
765impl<'a> Clearcoat<'a> {
766 pub(crate) fn new(
768 document: &'a Document,
769 json: &'a json::extensions::material::Clearcoat,
770 ) -> Self {
771 Self { document, json }
772 }
773
774 pub fn clearcoat_factor(&self) -> f32 {
778 self.json.clearcoat_factor.0
779 }
780
781 pub fn clearcoat_texture(&self) -> Option<texture::Info<'a>> {
783 self.json.clearcoat_texture.as_ref().map(|json| {
784 let texture = self.document.textures().nth(json.index.value()).unwrap();
785 texture::Info::new(texture, json)
786 })
787 }
788
789 pub fn clearcoat_roughness_factor(&self) -> f32 {
793 self.json.clearcoat_roughness_factor.0
794 }
795
796 pub fn clearcoat_roughness_texture(&self) -> Option<texture::Info<'a>> {
798 self.json.clearcoat_roughness_texture.as_ref().map(|json| {
799 let texture = self.document.textures().nth(json.index.value()).unwrap();
800 texture::Info::new(texture, json)
801 })
802 }
803
804 pub fn clearcoat_normal_texture(&self) -> Option<NormalTexture> {
806 self.json.clearcoat_normal_texture.as_ref().map(|json| {
807 let texture = self.document.textures().nth(json.index.value()).unwrap();
808 NormalTexture::new(texture, json)
809 })
810 }
811
812 pub fn extras(&self) -> &'a json::Extras {
814 &self.json.extras
815 }
816}
817
818#[cfg(feature = "KHR_materials_sheen")]
822#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_sheen")))]
823pub struct Sheen<'a> {
824 document: &'a Document,
826
827 json: &'a json::extensions::material::Sheen,
829}
830
831#[cfg(feature = "KHR_materials_sheen")]
832#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_sheen")))]
833impl<'a> Sheen<'a> {
834 pub(crate) fn new(document: &'a Document, json: &'a json::extensions::material::Sheen) -> Self {
836 Self { document, json }
837 }
838
839 pub fn sheen_color_factor(&self) -> [f32; 3] {
843 self.json.sheen_color_factor.0
844 }
845
846 pub fn sheen_color_texture(&self) -> Option<texture::Info<'a>> {
848 self.json.sheen_color_texture.as_ref().map(|json| {
849 let texture = self.document.textures().nth(json.index.value()).unwrap();
850 texture::Info::new(texture, json)
851 })
852 }
853
854 pub fn sheen_roughness_factor(&self) -> f32 {
858 self.json.sheen_roughness_factor.0
859 }
860
861 pub fn sheen_roughness_texture(&self) -> Option<texture::Info<'a>> {
863 self.json.sheen_roughness_texture.as_ref().map(|json| {
864 let texture = self.document.textures().nth(json.index.value()).unwrap();
865 texture::Info::new(texture, json)
866 })
867 }
868
869 pub fn extras(&self) -> &'a json::Extras {
871 &self.json.extras
872 }
873}