1use crate::{texture, Document};
2
3pub use json::material::AlphaMode;
4#[cfg(feature = "extensions")]
5use serde_json::{Map, Value};
6
7lazy_static! {
8 static ref DEFAULT_MATERIAL: json::material::Material = Default::default();
9}
10
11#[derive(Clone, Debug)]
13pub struct Material<'a> {
14 document: &'a Document,
16
17 index: Option<usize>,
19
20 json: &'a json::material::Material,
22}
23
24impl<'a> Material<'a> {
25 pub(crate) fn new(
27 document: &'a Document,
28 index: usize,
29 json: &'a json::material::Material,
30 ) -> Self {
31 Self {
32 document,
33 index: Some(index),
34 json,
35 }
36 }
37
38 pub(crate) fn default(document: &'a Document) -> Self {
40 Self {
41 document,
42 index: None,
43 json: &DEFAULT_MATERIAL,
44 }
45 }
46
47 pub fn index(&self) -> Option<usize> {
51 self.index
52 }
53
54 pub fn alpha_cutoff(&self) -> Option<f32> {
56 self.json.alpha_cutoff.map(|value| value.0)
57 }
58
59 pub fn alpha_mode(&self) -> AlphaMode {
73 self.json.alpha_mode.unwrap()
74 }
75
76 pub fn double_sided(&self) -> bool {
83 self.json.double_sided
84 }
85
86 #[cfg(feature = "names")]
88 #[cfg_attr(docsrs, doc(cfg(feature = "names")))]
89 pub fn name(&self) -> Option<&'a str> {
90 self.json.name.as_deref()
91 }
92
93 pub fn pbr_metallic_roughness(&self) -> PbrMetallicRoughness<'a> {
96 PbrMetallicRoughness::new(self.document, &self.json.pbr_metallic_roughness)
97 }
98
99 #[cfg(feature = "extensions")]
101 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
102 pub fn extensions(&self) -> Option<&Map<String, Value>> {
103 let ext = self.json.extensions.as_ref()?;
104 Some(&ext.others)
105 }
106
107 #[cfg(feature = "extensions")]
109 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
110 pub fn extension_value(&self, key: &str) -> Option<&Value> {
111 let ext = self.json.extensions.as_ref()?;
112 ext.others.get(key)
113 }
114
115 #[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
118 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
119 pub fn pbr_specular_glossiness(&self) -> Option<PbrSpecularGlossiness<'a>> {
120 self.json
121 .extensions
122 .as_ref()?
123 .pbr_specular_glossiness
124 .as_ref()
125 .map(|x| PbrSpecularGlossiness::new(self.document, x))
126 }
127
128 #[cfg(feature = "KHR_materials_transmission")]
130 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
131 pub fn transmission(&self) -> Option<Transmission<'a>> {
132 self.json
133 .extensions
134 .as_ref()?
135 .transmission
136 .as_ref()
137 .map(|x| Transmission::new(self.document, x))
138 }
139
140 #[cfg(feature = "KHR_materials_ior")]
142 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_ior")))]
143 pub fn ior(&self) -> Option<f32> {
144 self.json.extensions.as_ref()?.ior.as_ref().map(|x| x.ior.0)
145 }
146
147 #[cfg(feature = "KHR_materials_emissive_strength")]
149 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_emissive_strength")))]
150 pub fn emissive_strength(&self) -> Option<f32> {
151 self.json
152 .extensions
153 .as_ref()?
154 .emissive_strength
155 .as_ref()
156 .map(|x| x.emissive_strength.0)
157 }
158
159 #[cfg(feature = "KHR_materials_volume")]
161 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
162 pub fn volume(&self) -> Option<Volume<'a>> {
163 self.json
164 .extensions
165 .as_ref()?
166 .volume
167 .as_ref()
168 .map(|x| Volume::new(self.document, x))
169 }
170
171 #[cfg(feature = "KHR_materials_specular")]
173 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
174 pub fn specular(&self) -> Option<Specular<'a>> {
175 self.json
176 .extensions
177 .as_ref()?
178 .specular
179 .as_ref()
180 .map(|x| Specular::new(self.document, x))
181 }
182
183 pub fn normal_texture(&self) -> Option<NormalTexture<'a>> {
195 self.json.normal_texture.as_ref().map(|json| {
196 let texture = self.document.textures().nth(json.index.value()).unwrap();
197 NormalTexture::new(texture, json)
198 })
199 }
200
201 pub fn occlusion_texture(&self) -> Option<OcclusionTexture<'a>> {
210 self.json.occlusion_texture.as_ref().map(|json| {
211 let texture = self.document.textures().nth(json.index.value()).unwrap();
212 OcclusionTexture::new(texture, json)
213 })
214 }
215
216 pub fn emissive_texture(&self) -> Option<texture::Info<'a>> {
224 self.json.emissive_texture.as_ref().map(|json| {
225 let texture = self.document.textures().nth(json.index.value()).unwrap();
226 texture::Info::new(texture, json)
227 })
228 }
229
230 pub fn emissive_factor(&self) -> [f32; 3] {
234 self.json.emissive_factor.0
235 }
236
237 #[cfg(feature = "KHR_materials_unlit")]
244 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_unlit")))]
245 pub fn unlit(&self) -> bool {
246 self.json
247 .extensions
248 .as_ref()
249 .map_or(false, |extensions| extensions.unlit.is_some())
250 }
251
252 pub fn extras(&self) -> &'a json::Extras {
254 &self.json.extras
255 }
256}
257
258pub struct PbrMetallicRoughness<'a> {
261 document: &'a Document,
263
264 json: &'a json::material::PbrMetallicRoughness,
266}
267
268impl<'a> PbrMetallicRoughness<'a> {
269 pub(crate) fn new(
271 document: &'a Document,
272 json: &'a json::material::PbrMetallicRoughness,
273 ) -> Self {
274 Self { document, json }
275 }
276
277 pub fn base_color_factor(&self) -> [f32; 4] {
281 self.json.base_color_factor.0
282 }
283
284 pub fn base_color_texture(&self) -> Option<texture::Info<'a>> {
287 self.json.base_color_texture.as_ref().map(|json| {
288 let texture = self.document.textures().nth(json.index.value()).unwrap();
289 texture::Info::new(texture, json)
290 })
291 }
292
293 pub fn metallic_factor(&self) -> f32 {
297 self.json.metallic_factor.0
298 }
299
300 pub fn roughness_factor(&self) -> f32 {
307 self.json.roughness_factor.0
308 }
309
310 pub fn metallic_roughness_texture(&self) -> Option<texture::Info<'a>> {
317 self.json.metallic_roughness_texture.as_ref().map(|json| {
318 let texture = self.document.textures().nth(json.index.value()).unwrap();
319 texture::Info::new(texture, json)
320 })
321 }
322
323 #[cfg(feature = "extensions")]
325 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
326 pub fn extensions(&self) -> Option<&Map<String, Value>> {
327 let ext = self.json.extensions.as_ref()?;
328 Some(&ext.others)
329 }
330
331 #[cfg(feature = "extensions")]
333 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
334 pub fn extension_value(&self, key: &str) -> Option<&Value> {
335 let ext = self.json.extensions.as_ref()?;
336 ext.others.get(key)
337 }
338
339 pub fn extras(&self) -> &'a json::Extras {
341 &self.json.extras
342 }
343}
344
345#[cfg(feature = "KHR_materials_transmission")]
348#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
349pub struct Transmission<'a> {
350 document: &'a Document,
352
353 json: &'a json::extensions::material::Transmission,
355}
356
357#[cfg(feature = "KHR_materials_transmission")]
358#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
359impl<'a> Transmission<'a> {
360 pub(crate) fn new(
362 document: &'a Document,
363 json: &'a json::extensions::material::Transmission,
364 ) -> Self {
365 Self { document, json }
366 }
367
368 pub fn transmission_factor(&self) -> f32 {
372 self.json.transmission_factor.0
373 }
374
375 pub fn transmission_texture(&self) -> Option<texture::Info<'a>> {
377 self.json.transmission_texture.as_ref().map(|json| {
378 let texture = self.document.textures().nth(json.index.value()).unwrap();
379 texture::Info::new(texture, json)
380 })
381 }
382
383 pub fn extras(&self) -> &'a json::Extras {
385 &self.json.extras
386 }
387}
388
389#[cfg(feature = "KHR_materials_volume")]
391#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
392pub struct Volume<'a> {
393 document: &'a Document,
395
396 json: &'a json::extensions::material::Volume,
398}
399
400#[cfg(feature = "KHR_materials_volume")]
401#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
402impl<'a> Volume<'a> {
403 pub(crate) fn new(
405 document: &'a Document,
406 json: &'a json::extensions::material::Volume,
407 ) -> Self {
408 Self { document, json }
409 }
410
411 pub fn thickness_factor(&self) -> f32 {
417 self.json.thickness_factor.0
418 }
419
420 pub fn thickness_texture(&self) -> Option<texture::Info<'a>> {
423 self.json.thickness_texture.as_ref().map(|json| {
424 let texture = self.document.textures().nth(json.index.value()).unwrap();
425 texture::Info::new(texture, json)
426 })
427 }
428
429 pub fn attenuation_distance(&self) -> f32 {
433 self.json.attenuation_distance.0
434 }
435
436 pub fn attenuation_color(&self) -> [f32; 3] {
439 self.json.attenuation_color.0
440 }
441
442 pub fn extras(&self) -> &'a json::Extras {
444 &self.json.extras
445 }
446}
447
448#[cfg(feature = "KHR_materials_specular")]
450#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
451pub struct Specular<'a> {
452 document: &'a Document,
454
455 json: &'a json::extensions::material::Specular,
457}
458
459#[cfg(feature = "KHR_materials_specular")]
460#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
461impl<'a> Specular<'a> {
462 pub(crate) fn new(
464 document: &'a Document,
465 json: &'a json::extensions::material::Specular,
466 ) -> Self {
467 Self { document, json }
468 }
469
470 pub fn specular_factor(&self) -> f32 {
472 self.json.specular_factor.0
473 }
474
475 pub fn specular_texture(&self) -> Option<texture::Info<'a>> {
479 self.json.specular_texture.as_ref().map(|json| {
480 let texture = self.document.textures().nth(json.index.value()).unwrap();
481 texture::Info::new(texture, json)
482 })
483 }
484
485 pub fn specular_color_factor(&self) -> [f32; 3] {
487 self.json.specular_color_factor.0
488 }
489
490 pub fn specular_color_texture(&self) -> Option<texture::Info<'a>> {
494 self.json.specular_color_texture.as_ref().map(|json| {
495 let texture = self.document.textures().nth(json.index.value()).unwrap();
496 texture::Info::new(texture, json)
497 })
498 }
499
500 pub fn extras(&self) -> &'a json::Extras {
502 &self.json.extras
503 }
504}
505
506#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
509#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
510pub struct PbrSpecularGlossiness<'a> {
511 document: &'a Document,
513
514 json: &'a json::extensions::material::PbrSpecularGlossiness,
516}
517
518#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
519#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
520impl<'a> PbrSpecularGlossiness<'a> {
521 pub(crate) fn new(
523 document: &'a Document,
524 json: &'a json::extensions::material::PbrSpecularGlossiness,
525 ) -> Self {
526 Self { document, json }
527 }
528
529 pub fn diffuse_factor(&self) -> [f32; 4] {
533 self.json.diffuse_factor.0
534 }
535
536 pub fn diffuse_texture(&self) -> Option<texture::Info<'a>> {
538 self.json.diffuse_texture.as_ref().map(|json| {
539 let texture = self.document.textures().nth(json.index.value()).unwrap();
540 texture::Info::new(texture, json)
541 })
542 }
543
544 pub fn specular_factor(&self) -> [f32; 3] {
548 self.json.specular_factor.0
549 }
550
551 pub fn glossiness_factor(&self) -> f32 {
559 self.json.glossiness_factor.0
560 }
561
562 pub fn specular_glossiness_texture(&self) -> Option<texture::Info<'a>> {
568 self.json.specular_glossiness_texture.as_ref().map(|json| {
569 let texture = self.document.textures().nth(json.index.value()).unwrap();
570 texture::Info::new(texture, json)
571 })
572 }
573
574 pub fn extras(&self) -> &'a json::Extras {
576 &self.json.extras
577 }
578}
579
580pub struct NormalTexture<'a> {
582 texture: texture::Texture<'a>,
584
585 json: &'a json::material::NormalTexture,
587}
588
589impl<'a> NormalTexture<'a> {
590 pub(crate) fn new(
592 texture: texture::Texture<'a>,
593 json: &'a json::material::NormalTexture,
594 ) -> Self {
595 Self { texture, json }
596 }
597
598 pub fn scale(&self) -> f32 {
600 self.json.scale
601 }
602
603 pub fn tex_coord(&self) -> u32 {
605 self.json.tex_coord
606 }
607
608 pub fn texture(&self) -> texture::Texture<'a> {
610 self.texture.clone()
611 }
612
613 #[cfg(feature = "extensions")]
615 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
616 pub fn extensions(&self) -> Option<&Map<String, Value>> {
617 let ext = self.json.extensions.as_ref()?;
618 Some(&ext.others)
619 }
620
621 #[cfg(feature = "extensions")]
623 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
624 pub fn extension_value(&self, key: &str) -> Option<&Value> {
625 let ext = self.json.extensions.as_ref()?;
626 ext.others.get(key)
627 }
628
629 pub fn extras(&self) -> &'a json::Extras {
631 &self.json.extras
632 }
633}
634
635pub struct OcclusionTexture<'a> {
637 texture: texture::Texture<'a>,
639
640 json: &'a json::material::OcclusionTexture,
642}
643
644impl<'a> OcclusionTexture<'a> {
645 pub(crate) fn new(
647 texture: texture::Texture<'a>,
648 json: &'a json::material::OcclusionTexture,
649 ) -> Self {
650 Self { texture, json }
651 }
652
653 pub fn strength(&self) -> f32 {
655 self.json.strength.0
656 }
657
658 pub fn tex_coord(&self) -> u32 {
660 self.json.tex_coord
661 }
662
663 pub fn texture(&self) -> texture::Texture<'a> {
665 self.texture.clone()
666 }
667
668 #[cfg(feature = "extensions")]
670 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
671 pub fn extensions(&self) -> Option<&Map<String, Value>> {
672 let ext = self.json.extensions.as_ref()?;
673 Some(&ext.others)
674 }
675
676 #[cfg(feature = "extensions")]
678 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
679 pub fn extension_value(&self, key: &str) -> Option<&Value> {
680 let ext = self.json.extensions.as_ref()?;
681 ext.others.get(key)
682 }
683
684 pub fn extras(&self) -> &'a json::Extras {
686 &self.json.extras
687 }
688}
689
690impl<'a> AsRef<texture::Texture<'a>> for NormalTexture<'a> {
691 fn as_ref(&self) -> &texture::Texture<'a> {
692 &self.texture
693 }
694}
695
696impl<'a> AsRef<texture::Texture<'a>> for OcclusionTexture<'a> {
697 fn as_ref(&self) -> &texture::Texture<'a> {
698 &self.texture
699 }
700}