use alloc::string::String;
use scenix_core::{Color, TextureId};
use scenix_math::Vec3;
use crate::traits::{
AlphaMode, FEATURE_ALBEDO_TEXTURE, FEATURE_EMISSIVE_TEXTURE,
FEATURE_METALLIC_ROUGHNESS_TEXTURE, FEATURE_NORMAL_TEXTURE, FEATURE_OCCLUSION_TEXTURE,
Material, PipelineKey, ShaderKind, double_sided_bit, option_texture_bit,
};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PbrMaterial {
pub name: String,
pub albedo: Color,
pub albedo_texture: Option<TextureId>,
pub metallic: f32,
pub roughness: f32,
pub metallic_roughness_texture: Option<TextureId>,
pub normal_texture: Option<TextureId>,
pub occlusion_texture: Option<TextureId>,
pub emissive: Vec3,
pub emissive_texture: Option<TextureId>,
pub alpha_mode: AlphaMode,
pub double_sided: bool,
}
impl PbrMaterial {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn named(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
#[inline]
pub const fn albedo(mut self, albedo: Color) -> Self {
self.albedo = albedo;
self
}
#[inline]
pub fn metallic_roughness(mut self, metallic: f32, roughness: f32) -> Self {
self.metallic = metallic.clamp(0.0, 1.0);
self.roughness = roughness.clamp(0.0, 1.0);
self
}
#[inline]
pub const fn alpha_mode(mut self, alpha_mode: AlphaMode) -> Self {
self.alpha_mode = alpha_mode;
self
}
#[inline]
pub const fn double_sided(mut self, double_sided: bool) -> Self {
self.double_sided = double_sided;
self
}
pub(crate) fn feature_bits(&self) -> u64 {
double_sided_bit(self.double_sided)
| option_texture_bit(&self.albedo_texture, FEATURE_ALBEDO_TEXTURE)
| option_texture_bit(
&self.metallic_roughness_texture,
FEATURE_METALLIC_ROUGHNESS_TEXTURE,
)
| option_texture_bit(&self.normal_texture, FEATURE_NORMAL_TEXTURE)
| option_texture_bit(&self.occlusion_texture, FEATURE_OCCLUSION_TEXTURE)
| option_texture_bit(&self.emissive_texture, FEATURE_EMISSIVE_TEXTURE)
}
}
impl Default for PbrMaterial {
#[inline]
fn default() -> Self {
Self {
name: String::new(),
albedo: Color::WHITE,
albedo_texture: None,
metallic: 0.0,
roughness: 1.0,
metallic_roughness_texture: None,
normal_texture: None,
occlusion_texture: None,
emissive: Vec3::ZERO,
emissive_texture: None,
alpha_mode: AlphaMode::Opaque,
double_sided: false,
}
}
}
impl Material for PbrMaterial {
#[inline]
fn pipeline_key(&self) -> PipelineKey {
PipelineKey::new(
ShaderKind::Pbr,
self.alpha_mode.pipeline_alpha(),
self.feature_bits(),
)
}
#[inline]
fn is_transparent(&self) -> bool {
self.alpha_mode.is_transparent()
}
#[inline]
fn double_sided(&self) -> bool {
self.double_sided
}
#[inline]
fn alpha_cutoff(&self) -> Option<f32> {
self.alpha_mode.cutoff()
}
}