openconfiguration 1.7.0

OpenConfiguration (OC) is a modular, efficient and flexible approach for the uni-directional exchange of visual e-commerce configurations.
Documentation
use std::collections::HashMap;

use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::{color::Color, impl_visitable_noop, support::Visitable};

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Visitable, Default)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
#[serde(rename_all = "camelCase", rename = "igMaterial")]
pub struct Material {
    pub shininess: Option<f64>,

    /// Diffuse property. Both color and map are supported.
    /// Color and map replace each other.
    pub diffuse: Option<AlphaColorMap>,

    /// Specular color.
    pub specular: Option<ColorNoMap>,

    /// Emission color
    pub emission: Option<ColorNoMap>,

    /// Normal map.
    pub normal: Option<BasicMap>,

    /// Metallness map.
    pub metalness: Option<BasicMap>,

    /// Roughness map.
    pub roughness: Option<BasicMap>,

    /// Sheen map.
    pub sheen: Option<BasicMap>,

    /// Alpha value or map. Value and map replace each other.
    /// Values in the range 0.0 to 1.0. 0.0 is transparent, 1.0 is opaque.
    /// Map is grayscale. Black is transparent, white is opaque.
    pub alpha: Option<ValueMap>,

    /// Diffuse delta map. The delta map modifies the diffuse
    /// color/map and typically has it's own mapping.
    ///
    /// Format: 24 Bit (RGB)
    ///
    /// The handling (for each channel/color) is:
    /// - linear mapping of [0, 255] to [0, 2]
    /// - multiplication with the diffuse/color value
    ///
    /// 0 sets the original value to 0.
    /// 127/128 keeps the original value.
    /// 255 doubles the original value.
    pub diffuse_delta: Option<TextureMap>,

    /// Roughness delta map. The delta map modifies the roughness
    /// value/map and typically has it's own mapping.
    ///
    /// Format: 8 Bit (Grayscale)
    ///
    /// The handling is:
    /// - linear mapping of [0, 255] to [0, 2]
    /// - multiplication with the roughness value
    ///
    /// 0 sets the original value to 0.
    /// 127/128 keeps the original value.
    /// 255 doubles the original value.
    pub roughness_delta: Option<TextureMap>,

    /// Displacement map for material structures. Used only for high def renderings
    /// with suitable high def meshes
    pub displacement: Option<TextureMap>,

    /// Default mapping, may be overridden by specific texture maps.
    pub mapping: Option<TextureMapping>,

    /// Taxonomy information according to docs/ig_Taxonomy
    #[serde(
        deserialize_with = "crate::utils::deserialize_optional_map_without_null_values",
        default
    )]
    pub taxonomy: Option<HashMap<String, Value>>,

    /// Optional geometry-related parameters, to be resolved at client-side.
    ///
    /// "DisplacementBase"
    /// Like in Blender
    ///
    /// "DisplacementScale"
    /// Like in Blender
    ///
    /// "DoNotRescale":
    /// Marks the material as not re-scaleable. Re-scaling can be applied
    /// for psychological reasons, for instance.
    /// Target type: Boolean
    ///
    /// "Overlay":
    /// For alpha-map materials, tells the renderer that the associated geometry
    /// should be an overlay to other geometries at the same location.
    /// Target type: Boolean
    ///
    /// IGXC Compatibility: Metamaterial parameters but without redundancy.
    #[serde(
        deserialize_with = "crate::utils::deserialize_optional_map_without_null_values",
        default
    )]
    pub parameters: Option<HashMap<String, Value>>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Visitable)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
/// Texture map with additional scalar value. The relationship between both
/// will be defined in the application context.
pub struct ValueMap {
    #[serde(flatten)]
    pub basic: BasicMap,

    /// A scalar value. If the map is supported or not, and it's relation-
    /// ship to a map entry, is defined in the outer context.
    pub value: Option<f64>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Visitable)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
pub struct AlphaColorMap {
    #[serde(flatten)]
    pub color_map: ColorMap,

    pub alpha_mode: Option<AlphaMode>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum AlphaMode {
    /// The alpha channel is considered, if the transparency value is at least 0.1.
    /// If the Material has an alphamap, it is also considered.
    Standard,
    /// The alpha channel is always used "as is".
    /// Alphamap and Transparency setting are ignored.
    RGBA,
}

impl_visitable_noop!(AlphaMode);

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Visitable)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
/// Color without texture map
pub struct ColorNoMap {
    /// A color value.
    pub color: Option<Color>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Visitable)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
/// Texture map with additional color value. The relationship between both
/// will be defined in the application context.
pub struct ColorMap {
    #[serde(flatten)]
    pub basic: BasicMap,

    /// A color value.
    pub color: Option<Color>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Visitable)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
pub struct BasicMap {
    pub map: Option<TextureMap>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
pub struct TextureMap {
    /// The mandatory format of the map.
    pub map_format: TextureMapFormat,

    /// Absolute or relative path to the texture image.
    pub map: String,

    /// An optional UV mapping.	  
    pub mapping: Option<TextureMapping>,
}

impl Visitable for TextureMap {
    fn visit_with(&mut self, visitor: &mut dyn crate::support::Visitor) {
        visitor.visit_texture_map(self);
        visitor.visit_path(&mut self.map);
    }
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum TextureMapFormat {
    JPEG,
    PNG,
    WEBP,
}

impl_visitable_noop!(TextureMapFormat);

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
/// A Transformation of the UV Set for a Material  
/// Ordering R///S///T///V  
/// Also see ThreeJS issue #15831
///
/// This order minimizes shearing and improves content creation.
///
/// Combination with a GeometryMapping looks like this:
/// GS///GT///GR///MR///MS///MT///V
///
/// GR .. Matrix of GeometryMapping.Rotation
/// GS .. Matrix of GeometryMapping.Scale///
/// GT .. Matrix of GeometryMapping.Translation///
///
/// MR .. Matrix of TextureMapping.Rotation
/// MS .. Matrix of TextureMapping.Scale///
/// MT .. Matrix of TextureMapping.Translation///
///
/// V .. (UV)-Vector to be transformed
///
/// Rotation is clockwise in degrees
pub struct TextureMapping {
    pub translation_s: f64,

    pub translation_t: f64,

    pub rotation: f64,

    #[serde(default = "default_scale")]
    /// default value = 1
    pub scale_s: f64,

    #[serde(default = "default_scale")]
    /// default value = 1
    pub scale_t: f64,
}

impl_visitable_noop!(TextureMapping);

fn default_scale() -> f64 {
    1.0
}