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, skip_serializing_if = "is_default_alpha_mode")]
pub alpha_mode: SceneAlphaMode,
#[serde(
default = "default_alpha_cutoff",
skip_serializing_if = "is_default_alpha_cutoff"
)]
pub alpha_cutoff: f32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub base_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub base_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub base_texture_uv_set: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub emissive_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub emissive_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub emissive_texture_uv_set: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub normal_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub normal_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub normal_texture_uv_set: u32,
#[serde(
default = "default_normal_scale",
skip_serializing_if = "is_default_normal_scale"
)]
pub normal_scale: f32,
#[serde(default, skip_serializing_if = "is_false")]
pub normal_map_flip_y: bool,
#[serde(default, skip_serializing_if = "is_false")]
pub normal_map_two_component: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metallic_roughness_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metallic_roughness_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub metallic_roughness_texture_uv_set: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub occlusion_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub occlusion_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub occlusion_texture_uv_set: u32,
#[serde(
default = "default_occlusion_strength",
skip_serializing_if = "is_default_occlusion_strength"
)]
pub occlusion_strength: f32,
#[serde(
default = "default_roughness",
skip_serializing_if = "is_default_roughness"
)]
pub roughness: f32,
#[serde(default, skip_serializing_if = "is_zero_f32")]
pub metallic: f32,
#[serde(default, skip_serializing_if = "is_false")]
pub unlit: bool,
#[serde(default, skip_serializing_if = "is_false")]
pub double_sided: bool,
#[serde(
default = "default_uv_scale",
skip_serializing_if = "is_default_uv_scale"
)]
pub uv_scale: [f32; 2],
#[serde(default, skip_serializing_if = "is_zero_f32")]
pub transmission_factor: f32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub transmission_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub transmission_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub transmission_texture_uv_set: u32,
#[serde(default, skip_serializing_if = "is_zero_f32")]
pub thickness: f32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub thickness_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub thickness_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub thickness_texture_uv_set: u32,
#[serde(
default = "default_attenuation_color",
skip_serializing_if = "is_default_attenuation_color"
)]
pub attenuation_color: [f32; 3],
#[serde(
default = "default_attenuation_distance",
skip_serializing_if = "is_default_attenuation_distance"
)]
pub attenuation_distance: f32,
#[serde(default = "default_ior", skip_serializing_if = "is_default_ior")]
pub ior: f32,
#[serde(
default = "default_specular_factor",
skip_serializing_if = "is_default_specular_factor"
)]
pub specular_factor: f32,
#[serde(
default = "default_specular_color_factor",
skip_serializing_if = "is_default_specular_color_factor"
)]
pub specular_color_factor: [f32; 3],
#[serde(default, skip_serializing_if = "Option::is_none")]
pub specular_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub specular_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub specular_texture_uv_set: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub specular_color_texture_uuid: Option<AssetUuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub specular_color_texture_name: Option<String>,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub specular_color_texture_uv_set: u32,
#[serde(
default = "default_emissive_strength",
skip_serializing_if = "is_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
}
fn is_default_alpha_mode(value: &SceneAlphaMode) -> bool {
*value == SceneAlphaMode::Opaque
}
fn is_default_alpha_cutoff(value: &f32) -> bool {
(*value - 0.5).abs() < f32::EPSILON
}
pub(crate) fn is_zero_u32(value: &u32) -> bool {
*value == 0
}
fn is_default_normal_scale(value: &f32) -> bool {
(*value - 1.0).abs() < f32::EPSILON
}
pub(crate) fn is_false(value: &bool) -> bool {
!*value
}
fn is_default_occlusion_strength(value: &f32) -> bool {
(*value - 1.0).abs() < f32::EPSILON
}
fn is_default_roughness(value: &f32) -> bool {
(*value - 0.5).abs() < f32::EPSILON
}
pub(crate) fn is_zero_f32(value: &f32) -> bool {
value.abs() < f32::EPSILON
}
fn is_default_uv_scale(value: &[f32; 2]) -> bool {
(value[0] - 1.0).abs() < f32::EPSILON && (value[1] - 1.0).abs() < f32::EPSILON
}
fn is_default_attenuation_color(value: &[f32; 3]) -> bool {
(value[0] - 1.0).abs() < f32::EPSILON
&& (value[1] - 1.0).abs() < f32::EPSILON
&& (value[2] - 1.0).abs() < f32::EPSILON
}
fn is_default_attenuation_distance(value: &f32) -> bool {
value.is_infinite() && value.is_sign_positive()
}
fn is_default_ior(value: &f32) -> bool {
(*value - 1.5).abs() < f32::EPSILON
}
fn is_default_specular_factor(value: &f32) -> bool {
(*value - 1.0).abs() < f32::EPSILON
}
fn is_default_specular_color_factor(value: &[f32; 3]) -> bool {
(value[0] - 1.0).abs() < f32::EPSILON
&& (value[1] - 1.0).abs() < f32::EPSILON
&& (value[2] - 1.0).abs() < f32::EPSILON
}
fn is_default_emissive_strength(value: &f32) -> bool {
(*value - 1.0).abs() < f32::EPSILON
}
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,
}
}
}