use gltf_derive::Validate;
use serde_derive::{Serialize, Deserialize};
use serde::{de, ser};
use std::fmt;
use crate::validation::{Checked, Error, Validate};
use crate::{extensions, texture, Extras, Index, Root, Path};
pub const VALID_ALPHA_MODES: &'static [&'static str] = &[
"OPAQUE",
"MASK",
"BLEND",
];
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum AlphaMode {
Opaque = 1,
Mask,
Blend,
}
impl ser::Serialize for AlphaMode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: ser::Serializer
{
match *self {
AlphaMode::Opaque => serializer.serialize_str("OPAQUE"),
AlphaMode::Mask => serializer.serialize_str("MASK"),
AlphaMode::Blend => serializer.serialize_str("BLEND"),
}
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct Material {
#[serde(rename = "alphaCutoff")]
pub alpha_cutoff: AlphaCutoff,
#[serde(rename = "alphaMode")]
pub alpha_mode: Checked<AlphaMode>,
#[serde(rename = "doubleSided")]
pub double_sided: bool,
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
#[serde(default, rename = "pbrMetallicRoughness")]
pub pbr_metallic_roughness: PbrMetallicRoughness,
#[serde(rename = "normalTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub normal_texture: Option<NormalTexture>,
#[serde(rename = "occlusionTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub occlusion_texture: Option<OcclusionTexture>,
#[serde(rename = "emissiveTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub emissive_texture: Option<texture::Info>,
#[serde(rename = "emissiveFactor")]
pub emissive_factor: EmissiveFactor,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::material::Material>,
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
pub extras: Extras,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct PbrMetallicRoughness {
#[serde(rename = "baseColorFactor")]
pub base_color_factor: PbrBaseColorFactor,
#[serde(rename = "baseColorTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub base_color_texture: Option<texture::Info>,
#[serde(rename = "metallicFactor")]
pub metallic_factor: StrengthFactor,
#[serde(rename = "roughnessFactor")]
pub roughness_factor: StrengthFactor,
#[serde(rename = "metallicRoughnessTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub metallic_roughness_texture: Option<texture::Info>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::material::PbrMetallicRoughness>,
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
pub extras: Extras,
}
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct NormalTexture {
pub index: Index<texture::Texture>,
#[serde(default = "material_normal_texture_scale_default")]
pub scale: f32,
#[serde(default, rename = "texCoord")]
pub tex_coord: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::material::NormalTexture>,
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
pub extras: Extras,
}
fn material_normal_texture_scale_default() -> f32 {
1.0
}
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct OcclusionTexture {
pub index: Index<texture::Texture>,
#[serde(default)]
pub strength: StrengthFactor,
#[serde(default, rename = "texCoord")]
pub tex_coord: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::material::OcclusionTexture>,
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
pub extras: Extras,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct AlphaCutoff(pub f32);
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
pub struct EmissiveFactor(pub [f32; 3]);
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct PbrBaseColorFactor(pub [f32; 4]);
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct StrengthFactor(pub f32);
impl Default for AlphaCutoff {
fn default() -> Self {
AlphaCutoff(0.5)
}
}
impl Default for AlphaMode {
fn default() -> Self {
AlphaMode::Opaque
}
}
impl Validate for AlphaCutoff {
fn validate_completely<P, R>(&self, _: &Root, path: P, report: &mut R)
where P: Fn() -> Path, R: FnMut(&Fn() -> Path, Error)
{
if self.0 < 0.0 {
report(&path, Error::Invalid);
}
}
}
impl<'de> de::Deserialize<'de> for Checked<AlphaMode> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: de::Deserializer<'de>
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<AlphaMode>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_ALPHA_MODES)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where E: de::Error
{
use self::AlphaMode::*;
use crate::validation::Checked::*;
Ok(match value {
"OPAQUE" => Valid(Opaque),
"MASK" => Valid(Mask),
"BLEND" => Valid(Blend),
_ => Invalid,
})
}
}
deserializer.deserialize_str(Visitor)
}
}
impl Validate for EmissiveFactor {
fn validate_completely<P, R>(&self, _: &Root, path: P, report: &mut R)
where P: Fn() -> Path, R: FnMut(&Fn() -> Path, Error)
{
for x in &self.0 {
if *x < 0.0 || *x > 1.0 {
report(&path, Error::Invalid);
break;
}
}
}
}
impl Default for PbrBaseColorFactor {
fn default() -> Self {
PbrBaseColorFactor([1.0, 1.0, 1.0, 1.0])
}
}
impl Validate for PbrBaseColorFactor {
fn validate_completely<P, R>(&self, _: &Root, path: P, report: &mut R)
where P: Fn() -> Path, R: FnMut(&Fn() -> Path, Error)
{
for x in &self.0 {
if *x < 0.0 || *x > 1.0 {
report(&path, Error::Invalid);
break;
}
}
}
}
impl Default for StrengthFactor {
fn default() -> Self {
StrengthFactor(1.0)
}
}
impl Validate for StrengthFactor {
fn validate_completely<P, R>(&self, _: &Root, path: P, report: &mut R)
where P: Fn() -> Path, R: FnMut(&Fn() -> Path, Error)
{
if self.0 < 0.0 || self.0 > 1.0 {
report(&path, Error::Invalid);
}
}
}