1use crate::validation::{Checked, Validate};
2use crate::{extensions, extras::Void, texture, Extras, Index};
3use gltf_derive::Validate;
4use serde::{de, ser};
5use serde_derive::{Deserialize, Serialize};
6use std::fmt;
7
8pub const VALID_ALPHA_MODES: &[&str] = &["OPAQUE", "MASK", "BLEND"];
10
11#[derive(Clone, Copy, Eq, PartialEq, Debug)]
13pub enum AlphaMode {
14 Opaque = 1,
16
17 Mask,
20
21 Blend,
24}
25
26impl ser::Serialize for AlphaMode {
27 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28 where
29 S: ser::Serializer,
30 {
31 match *self {
32 AlphaMode::Opaque => serializer.serialize_str("OPAQUE"),
33 AlphaMode::Mask => serializer.serialize_str("MASK"),
34 AlphaMode::Blend => serializer.serialize_str("BLEND"),
35 }
36 }
37}
38
39#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
41#[serde(default)]
42pub struct Material {
43 #[serde(rename = "alphaCutoff")]
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub alpha_cutoff: Option<AlphaCutoff>,
48
49 #[serde(rename = "alphaMode")]
66 pub alpha_mode: Checked<AlphaMode>,
67
68 #[serde(rename = "doubleSided")]
78 pub double_sided: bool,
79
80 #[cfg(feature = "names")]
82 #[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
83 pub name: Option<String>,
84
85 #[serde(default, rename = "pbrMetallicRoughness")]
89 pub pbr_metallic_roughness: PbrMetallicRoughness,
90
91 #[serde(rename = "normalTexture")]
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub normal_texture: Option<NormalTexture>,
100
101 #[serde(rename = "occlusionTexture")]
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub occlusion_texture: Option<OcclusionTexture>,
109
110 #[serde(rename = "emissiveTexture")]
114 #[serde(skip_serializing_if = "Option::is_none")]
115 pub emissive_texture: Option<texture::Info>,
116
117 #[serde(rename = "emissiveFactor")]
119 pub emissive_factor: EmissiveFactor,
120
121 #[serde(default, skip_serializing_if = "Option::is_none")]
123 pub extensions: Option<extensions::material::Material>,
124
125 #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
127 #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
128 pub extras: Extras,
129}
130
131impl Material {
132 pub const DEFAULT_MATERIAL: Material = Material {
134 alpha_cutoff: None,
135 alpha_mode: Checked::Valid(AlphaMode::Opaque),
136 double_sided: false,
137 #[cfg(feature = "names")]
138 name: None,
139 pbr_metallic_roughness: PbrMetallicRoughness {
140 base_color_factor: PbrBaseColorFactor([0.0, 0.0, 0.0, 0.0]),
141 base_color_texture: None,
142 metallic_factor: StrengthFactor(0.0),
143 roughness_factor: StrengthFactor(0.0),
144 metallic_roughness_texture: None,
145 extensions: None,
146 #[cfg(feature = "extras")]
147 extras: None,
148 #[cfg(not(feature = "extras"))]
149 extras: Void {
150 _allow_unknown_fields: (),
151 },
152 },
153 normal_texture: None,
154 occlusion_texture: None,
155 emissive_texture: None,
156 emissive_factor: EmissiveFactor([0.0, 0.0, 0.0]),
157 extensions: None,
158 #[cfg(feature = "extras")]
159 extras: None,
160 #[cfg(not(feature = "extras"))]
161 extras: Void {
162 _allow_unknown_fields: (),
163 },
164 };
165}
166
167#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
170#[serde(default)]
171pub struct PbrMetallicRoughness {
172 #[serde(rename = "baseColorFactor")]
174 pub base_color_factor: PbrBaseColorFactor,
175
176 #[serde(rename = "baseColorTexture")]
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub base_color_texture: Option<texture::Info>,
180
181 #[serde(rename = "metallicFactor")]
183 pub metallic_factor: StrengthFactor,
184
185 #[serde(rename = "roughnessFactor")]
190 pub roughness_factor: StrengthFactor,
191
192 #[serde(rename = "metallicRoughnessTexture")]
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub metallic_roughness_texture: Option<texture::Info>,
203
204 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub extensions: Option<extensions::material::PbrMetallicRoughness>,
207
208 #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
210 #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
211 pub extras: Extras,
212}
213
214#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
216pub struct NormalTexture {
217 pub index: Index<texture::Texture>,
219
220 #[serde(default = "material_normal_texture_scale_default")]
224 pub scale: f32,
225
226 #[serde(default, rename = "texCoord")]
228 pub tex_coord: u32,
229
230 #[serde(default, skip_serializing_if = "Option::is_none")]
232 pub extensions: Option<extensions::material::NormalTexture>,
233
234 #[serde(default)]
236 #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
237 #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
238 pub extras: Extras,
239}
240
241fn material_normal_texture_scale_default() -> f32 {
242 1.0
243}
244
245#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
247pub struct OcclusionTexture {
248 pub index: Index<texture::Texture>,
250
251 #[serde(default)]
253 pub strength: StrengthFactor,
254
255 #[serde(default, rename = "texCoord")]
257 pub tex_coord: u32,
258
259 #[serde(default, skip_serializing_if = "Option::is_none")]
261 pub extensions: Option<extensions::material::OcclusionTexture>,
262
263 #[serde(default)]
265 #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
266 #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
267 pub extras: Extras,
268}
269
270#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
272pub struct AlphaCutoff(pub f32);
273
274#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
276pub struct EmissiveFactor(pub [f32; 3]);
277
278#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
280pub struct PbrBaseColorFactor(pub [f32; 4]);
281
282#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
284pub struct StrengthFactor(pub f32);
285
286impl Default for AlphaCutoff {
287 fn default() -> Self {
288 AlphaCutoff(0.5)
289 }
290}
291
292impl Validate for AlphaCutoff {}
293
294impl Default for AlphaMode {
295 fn default() -> Self {
296 AlphaMode::Opaque
297 }
298}
299
300impl<'de> de::Deserialize<'de> for Checked<AlphaMode> {
301 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
302 where
303 D: de::Deserializer<'de>,
304 {
305 struct Visitor;
306 impl de::Visitor<'_> for Visitor {
307 type Value = Checked<AlphaMode>;
308
309 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
310 write!(f, "any of: {:?}", VALID_ALPHA_MODES)
311 }
312
313 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
314 where
315 E: de::Error,
316 {
317 use self::AlphaMode::*;
318 use crate::validation::Checked::*;
319 Ok(match value {
320 "OPAQUE" => Valid(Opaque),
321 "MASK" => Valid(Mask),
322 "BLEND" => Valid(Blend),
323 _ => Invalid,
324 })
325 }
326 }
327 deserializer.deserialize_str(Visitor)
328 }
329}
330
331impl Validate for EmissiveFactor {}
332
333impl Default for PbrBaseColorFactor {
334 fn default() -> Self {
335 PbrBaseColorFactor([1.0, 1.0, 1.0, 1.0])
336 }
337}
338
339impl Validate for PbrBaseColorFactor {}
340
341impl Default for StrengthFactor {
342 fn default() -> Self {
343 StrengthFactor(1.0)
344 }
345}
346
347impl Validate for StrengthFactor {}