nightshade 0.13.3

A cross-platform data-oriented game engine.
Documentation
use serde::{Deserialize, Serialize};

use crate::ecs::material::components::{AlphaMode, Material};

use super::asset_uuid::AssetUuid;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneMaterial {
    pub base_color: [f32; 4],
    pub emissive_factor: [f32; 3],
    #[serde(default)]
    pub alpha_mode: SceneAlphaMode,
    #[serde(default = "default_alpha_cutoff")]
    pub alpha_cutoff: f32,
    #[serde(default)]
    pub base_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub base_texture_name: Option<String>,
    #[serde(default)]
    pub base_texture_uv_set: u32,
    #[serde(default)]
    pub emissive_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub emissive_texture_name: Option<String>,
    #[serde(default)]
    pub emissive_texture_uv_set: u32,
    #[serde(default)]
    pub normal_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub normal_texture_name: Option<String>,
    #[serde(default)]
    pub normal_texture_uv_set: u32,
    #[serde(default = "default_normal_scale")]
    pub normal_scale: f32,
    #[serde(default)]
    pub normal_map_flip_y: bool,
    #[serde(default)]
    pub normal_map_two_component: bool,
    #[serde(default)]
    pub metallic_roughness_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub metallic_roughness_texture_name: Option<String>,
    #[serde(default)]
    pub metallic_roughness_texture_uv_set: u32,
    #[serde(default)]
    pub occlusion_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub occlusion_texture_name: Option<String>,
    #[serde(default)]
    pub occlusion_texture_uv_set: u32,
    #[serde(default = "default_occlusion_strength")]
    pub occlusion_strength: f32,
    #[serde(default = "default_roughness")]
    pub roughness: f32,
    #[serde(default)]
    pub metallic: f32,
    #[serde(default)]
    pub unlit: bool,
    #[serde(default)]
    pub double_sided: bool,
    #[serde(default = "default_uv_scale")]
    pub uv_scale: [f32; 2],
    #[serde(default)]
    pub transmission_factor: f32,
    #[serde(default)]
    pub transmission_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub transmission_texture_name: Option<String>,
    #[serde(default)]
    pub transmission_texture_uv_set: u32,
    #[serde(default)]
    pub thickness: f32,
    #[serde(default)]
    pub thickness_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub thickness_texture_name: Option<String>,
    #[serde(default)]
    pub thickness_texture_uv_set: u32,
    #[serde(default = "default_attenuation_color")]
    pub attenuation_color: [f32; 3],
    #[serde(default = "default_attenuation_distance")]
    pub attenuation_distance: f32,
    #[serde(default = "default_ior")]
    pub ior: f32,
    #[serde(default = "default_specular_factor")]
    pub specular_factor: f32,
    #[serde(default = "default_specular_color_factor")]
    pub specular_color_factor: [f32; 3],
    #[serde(default)]
    pub specular_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub specular_texture_name: Option<String>,
    #[serde(default)]
    pub specular_texture_uv_set: u32,
    #[serde(default)]
    pub specular_color_texture_uuid: Option<AssetUuid>,
    #[serde(default)]
    pub specular_color_texture_name: Option<String>,
    #[serde(default)]
    pub specular_color_texture_uv_set: u32,
    #[serde(default = "default_emissive_strength")]
    pub emissive_strength: f32,
}

fn default_alpha_cutoff() -> f32 {
    0.5
}

fn default_roughness() -> f32 {
    0.5
}

fn default_uv_scale() -> [f32; 2] {
    [1.0, 1.0]
}

fn default_normal_scale() -> f32 {
    1.0
}

fn default_occlusion_strength() -> f32 {
    1.0
}

fn default_attenuation_color() -> [f32; 3] {
    [1.0, 1.0, 1.0]
}

fn default_attenuation_distance() -> f32 {
    f32::INFINITY
}

fn default_ior() -> f32 {
    1.5
}

fn default_specular_factor() -> f32 {
    1.0
}

fn default_specular_color_factor() -> [f32; 3] {
    [1.0, 1.0, 1.0]
}

fn default_emissive_strength() -> f32 {
    1.0
}

impl Default for SceneMaterial {
    fn default() -> Self {
        Self {
            base_color: [1.0, 1.0, 1.0, 1.0],
            emissive_factor: [0.0, 0.0, 0.0],
            alpha_mode: SceneAlphaMode::Opaque,
            alpha_cutoff: 0.5,
            base_texture_uuid: None,
            base_texture_name: None,
            base_texture_uv_set: 0,
            emissive_texture_uuid: None,
            emissive_texture_name: None,
            emissive_texture_uv_set: 0,
            normal_texture_uuid: None,
            normal_texture_name: None,
            normal_texture_uv_set: 0,
            normal_scale: 1.0,
            normal_map_flip_y: false,
            normal_map_two_component: false,
            metallic_roughness_texture_uuid: None,
            metallic_roughness_texture_name: None,
            metallic_roughness_texture_uv_set: 0,
            occlusion_texture_uuid: None,
            occlusion_texture_name: None,
            occlusion_texture_uv_set: 0,
            occlusion_strength: 1.0,
            roughness: 0.5,
            metallic: 0.0,
            unlit: false,
            double_sided: false,
            uv_scale: [1.0, 1.0],
            transmission_factor: 0.0,
            transmission_texture_uuid: None,
            transmission_texture_name: None,
            transmission_texture_uv_set: 0,
            thickness: 0.0,
            thickness_texture_uuid: None,
            thickness_texture_name: None,
            thickness_texture_uv_set: 0,
            attenuation_color: [1.0, 1.0, 1.0],
            attenuation_distance: f32::INFINITY,
            ior: 1.5,
            specular_factor: 1.0,
            specular_color_factor: [1.0, 1.0, 1.0],
            specular_texture_uuid: None,
            specular_texture_name: None,
            specular_texture_uv_set: 0,
            specular_color_texture_uuid: None,
            specular_color_texture_name: None,
            specular_color_texture_uv_set: 0,
            emissive_strength: 1.0,
        }
    }
}

impl SceneMaterial {
    pub fn to_material(&self) -> Material {
        Material {
            base_color: self.base_color,
            emissive_factor: self.emissive_factor,
            alpha_mode: self.alpha_mode.into(),
            alpha_cutoff: self.alpha_cutoff,
            base_texture: self.base_texture_name.clone(),
            base_texture_uv_set: self.base_texture_uv_set,
            emissive_texture: self.emissive_texture_name.clone(),
            emissive_texture_uv_set: self.emissive_texture_uv_set,
            normal_texture: self.normal_texture_name.clone(),
            normal_texture_uv_set: self.normal_texture_uv_set,
            normal_scale: self.normal_scale,
            normal_map_flip_y: self.normal_map_flip_y,
            normal_map_two_component: self.normal_map_two_component,
            metallic_roughness_texture: self.metallic_roughness_texture_name.clone(),
            metallic_roughness_texture_uv_set: self.metallic_roughness_texture_uv_set,
            occlusion_texture: self.occlusion_texture_name.clone(),
            occlusion_texture_uv_set: self.occlusion_texture_uv_set,
            occlusion_strength: self.occlusion_strength,
            roughness: self.roughness,
            metallic: self.metallic,
            unlit: self.unlit,
            double_sided: self.double_sided,
            uv_scale: self.uv_scale,
            transmission_factor: self.transmission_factor,
            transmission_texture: self.transmission_texture_name.clone(),
            transmission_texture_uv_set: self.transmission_texture_uv_set,
            thickness: self.thickness,
            thickness_texture: self.thickness_texture_name.clone(),
            thickness_texture_uv_set: self.thickness_texture_uv_set,
            attenuation_color: self.attenuation_color,
            attenuation_distance: self.attenuation_distance,
            ior: self.ior,
            specular_factor: self.specular_factor,
            specular_color_factor: self.specular_color_factor,
            specular_texture: self.specular_texture_name.clone(),
            specular_texture_uv_set: self.specular_texture_uv_set,
            specular_color_texture: self.specular_color_texture_name.clone(),
            specular_color_texture_uv_set: self.specular_color_texture_uv_set,
            emissive_strength: self.emissive_strength,
        }
    }
}

impl From<&Material> for SceneMaterial {
    fn from(material: &Material) -> Self {
        Self {
            base_color: material.base_color,
            emissive_factor: material.emissive_factor,
            alpha_mode: material.alpha_mode.into(),
            alpha_cutoff: material.alpha_cutoff,
            base_texture_uuid: None,
            base_texture_name: material.base_texture.clone(),
            base_texture_uv_set: material.base_texture_uv_set,
            emissive_texture_uuid: None,
            emissive_texture_name: material.emissive_texture.clone(),
            emissive_texture_uv_set: material.emissive_texture_uv_set,
            normal_texture_uuid: None,
            normal_texture_name: material.normal_texture.clone(),
            normal_texture_uv_set: material.normal_texture_uv_set,
            normal_scale: material.normal_scale,
            normal_map_flip_y: material.normal_map_flip_y,
            normal_map_two_component: material.normal_map_two_component,
            metallic_roughness_texture_uuid: None,
            metallic_roughness_texture_name: material.metallic_roughness_texture.clone(),
            metallic_roughness_texture_uv_set: material.metallic_roughness_texture_uv_set,
            occlusion_texture_uuid: None,
            occlusion_texture_name: material.occlusion_texture.clone(),
            occlusion_texture_uv_set: material.occlusion_texture_uv_set,
            occlusion_strength: material.occlusion_strength,
            roughness: material.roughness,
            metallic: material.metallic,
            unlit: material.unlit,
            double_sided: material.double_sided,
            uv_scale: material.uv_scale,
            transmission_factor: material.transmission_factor,
            transmission_texture_uuid: None,
            transmission_texture_name: material.transmission_texture.clone(),
            transmission_texture_uv_set: material.transmission_texture_uv_set,
            thickness: material.thickness,
            thickness_texture_uuid: None,
            thickness_texture_name: material.thickness_texture.clone(),
            thickness_texture_uv_set: material.thickness_texture_uv_set,
            attenuation_color: material.attenuation_color,
            attenuation_distance: material.attenuation_distance,
            ior: material.ior,
            specular_factor: material.specular_factor,
            specular_color_factor: material.specular_color_factor,
            specular_texture_uuid: None,
            specular_texture_name: material.specular_texture.clone(),
            specular_texture_uv_set: material.specular_texture_uv_set,
            specular_color_texture_uuid: None,
            specular_color_texture_name: material.specular_color_texture.clone(),
            specular_color_texture_uv_set: material.specular_color_texture_uv_set,
            emissive_strength: material.emissive_strength,
        }
    }
}

#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
pub enum SceneAlphaMode {
    #[default]
    Opaque,
    Mask,
    Blend,
}

impl From<AlphaMode> for SceneAlphaMode {
    fn from(mode: AlphaMode) -> Self {
        match mode {
            AlphaMode::Opaque => SceneAlphaMode::Opaque,
            AlphaMode::Mask => SceneAlphaMode::Mask,
            AlphaMode::Blend => SceneAlphaMode::Blend,
        }
    }
}

impl From<SceneAlphaMode> for AlphaMode {
    fn from(mode: SceneAlphaMode) -> Self {
        match mode {
            SceneAlphaMode::Opaque => AlphaMode::Opaque,
            SceneAlphaMode::Mask => AlphaMode::Mask,
            SceneAlphaMode::Blend => AlphaMode::Blend,
        }
    }
}