1use crate::validation::{Checked, Error, Validate};
2use crate::{extensions, texture, Index, Path, Root};
3use serde::{de, ser};
4use serde_derive::{Deserialize, Serialize};
5use shine_gltf_macro::Validate;
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 pub alpha_cutoff: AlphaCutoff,
46
47 #[serde(rename = "alphaMode")]
64 pub alpha_mode: Checked<AlphaMode>,
65
66 #[serde(rename = "doubleSided")]
76 pub double_sided: bool,
77
78 #[serde(default, rename = "pbrMetallicRoughness")]
82 pub pbr_metallic_roughness: PbrMetallicRoughness,
83
84 #[serde(rename = "normalTexture")]
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub normal_texture: Option<NormalTexture>,
93
94 #[serde(rename = "occlusionTexture")]
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub occlusion_texture: Option<OcclusionTexture>,
102
103 #[serde(rename = "emissiveTexture")]
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub emissive_texture: Option<texture::Info>,
109
110 #[serde(rename = "emissiveFactor")]
112 pub emissive_factor: EmissiveFactor,
113
114 #[serde(default, skip_serializing_if = "Option::is_none")]
116 pub extensions: Option<extensions::material::Material>,
117}
118
119#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
122#[serde(default)]
123pub struct PbrMetallicRoughness {
124 #[serde(rename = "baseColorFactor")]
126 pub base_color_factor: PbrBaseColorFactor,
127
128 #[serde(rename = "baseColorTexture")]
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub base_color_texture: Option<texture::Info>,
132
133 #[serde(rename = "metallicFactor")]
135 pub metallic_factor: StrengthFactor,
136
137 #[serde(rename = "roughnessFactor")]
142 pub roughness_factor: StrengthFactor,
143
144 #[serde(rename = "metallicRoughnessTexture")]
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub metallic_roughness_texture: Option<texture::Info>,
155
156 #[serde(default, skip_serializing_if = "Option::is_none")]
158 pub extensions: Option<extensions::material::PbrMetallicRoughness>,
159}
160
161#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
163pub struct NormalTexture {
164 pub index: Index<texture::Texture>,
166
167 #[serde(default = "material_normal_texture_scale_default")]
171 pub scale: f32,
172
173 #[serde(default, rename = "texCoord")]
175 pub tex_coord: u32,
176
177 #[serde(default, skip_serializing_if = "Option::is_none")]
179 pub extensions: Option<extensions::material::NormalTexture>,
180}
181
182fn material_normal_texture_scale_default() -> f32 {
183 1.0
184}
185
186#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
188pub struct OcclusionTexture {
189 pub index: Index<texture::Texture>,
191
192 #[serde(default)]
194 pub strength: StrengthFactor,
195
196 #[serde(default, rename = "texCoord")]
198 pub tex_coord: u32,
199
200 #[serde(default, skip_serializing_if = "Option::is_none")]
202 pub extensions: Option<extensions::material::OcclusionTexture>,
203}
204
205#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
207pub struct AlphaCutoff(pub f32);
208
209#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
211pub struct EmissiveFactor(pub [f32; 3]);
212
213#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
215pub struct PbrBaseColorFactor(pub [f32; 4]);
216
217#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
219pub struct StrengthFactor(pub f32);
220
221impl Default for AlphaCutoff {
222 fn default() -> Self {
223 AlphaCutoff(0.5)
224 }
225}
226
227impl Default for AlphaMode {
228 fn default() -> Self {
229 AlphaMode::Opaque
230 }
231}
232
233impl Validate for AlphaCutoff {
234 fn validate_completely<P, R>(&self, _: &Root, path: P, report: &mut R)
235 where
236 P: Fn() -> Path,
237 R: FnMut(&dyn Fn() -> Path, Error),
238 {
239 if self.0 < 0.0 {
240 report(&path, Error::Invalid);
241 }
242 }
243}
244
245impl<'de> de::Deserialize<'de> for Checked<AlphaMode> {
246 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
247 where
248 D: de::Deserializer<'de>,
249 {
250 struct Visitor;
251 impl<'de> de::Visitor<'de> for Visitor {
252 type Value = Checked<AlphaMode>;
253
254 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 write!(f, "any of: {:?}", VALID_ALPHA_MODES)
256 }
257
258 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
259 where
260 E: de::Error,
261 {
262 use self::AlphaMode::*;
263 use crate::validation::Checked::*;
264 Ok(match value {
265 "OPAQUE" => Valid(Opaque),
266 "MASK" => Valid(Mask),
267 "BLEND" => Valid(Blend),
268 _ => Invalid,
269 })
270 }
271 }
272 deserializer.deserialize_str(Visitor)
273 }
274}
275
276impl Validate for EmissiveFactor {
277 fn validate_completely<P, R>(&self, _: &Root, path: P, report: &mut R)
278 where
279 P: Fn() -> Path,
280 R: FnMut(&dyn Fn() -> Path, Error),
281 {
282 for x in &self.0 {
283 if *x < 0.0 || *x > 1.0 {
284 report(&path, Error::Invalid);
285 break;
287 }
288 }
289 }
290}
291
292impl Default for PbrBaseColorFactor {
293 fn default() -> Self {
294 PbrBaseColorFactor([1.0, 1.0, 1.0, 1.0])
295 }
296}
297
298impl Validate for PbrBaseColorFactor {
299 fn validate_completely<P, R>(&self, _: &Root, path: P, report: &mut R)
300 where
301 P: Fn() -> Path,
302 R: FnMut(&dyn Fn() -> Path, Error),
303 {
304 for x in &self.0 {
305 if *x < 0.0 || *x > 1.0 {
306 report(&path, Error::Invalid);
307 break;
309 }
310 }
311 }
312}
313
314impl Default for StrengthFactor {
315 fn default() -> Self {
316 StrengthFactor(1.0)
317 }
318}
319
320impl Validate for StrengthFactor {
321 fn validate_completely<P, R>(&self, _: &Root, path: P, report: &mut R)
322 where
323 P: Fn() -> Path,
324 R: FnMut(&dyn Fn() -> Path, Error),
325 {
326 if self.0 < 0.0 || self.0 > 1.0 {
327 report(&path, Error::Invalid);
328 }
329 }
330}