use glam::Vec3;
use crate::Rgb;
use crate::math::Aabb;
#[derive(Debug, Clone, PartialEq)]
pub enum Light {
Ambient {
color: Rgb,
intensity: f32,
},
Hemisphere {
sky: Rgb,
ground: Rgb,
intensity: f32,
},
Directional(DirectionalLight),
Point(PointLight),
Spot(SpotLight),
}
#[derive(Debug, Clone, PartialEq)]
pub struct DirectionalLight {
pub color: Rgb,
pub intensity: f32,
pub direction: Vec3,
pub shadow: Option<Shadow>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Shadow {
pub map_size: u32,
pub softness: f32,
pub strength: f32,
pub bias: f32,
pub bounds: Option<Aabb>,
}
impl Default for Shadow {
fn default() -> Self {
Self {
map_size: 2048,
softness: 1.5,
strength: 1.0,
bias: 1.5,
bounds: None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct PointLight {
pub color: Rgb,
pub intensity: f32,
pub distance: f32,
pub decay: f32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SpotLight {
pub color: Rgb,
pub intensity: f32,
pub distance: f32,
pub decay: f32,
pub angle: f32,
pub penumbra: f32,
pub direction: Vec3,
}
impl Light {
pub fn ambient(color: impl Into<Rgb>, intensity: f32) -> Self {
Light::Ambient {
color: color.into(),
intensity,
}
}
pub fn hemisphere(sky: impl Into<Rgb>, ground: impl Into<Rgb>, intensity: f32) -> Self {
Light::Hemisphere {
sky: sky.into(),
ground: ground.into(),
intensity,
}
}
pub fn directional(color: impl Into<Rgb>, intensity: f32, from: Vec3) -> Self {
Light::Directional(DirectionalLight {
color: color.into(),
intensity,
direction: (-from).normalize_or(Vec3::NEG_Y),
shadow: None,
})
}
pub fn sun(color: impl Into<Rgb>, intensity: f32, from: Vec3) -> Self {
Self::directional(color, intensity, from).with_shadow(Shadow::default())
}
pub fn point(color: impl Into<Rgb>, intensity: f32, distance: f32) -> Self {
Light::Point(PointLight {
color: color.into(),
intensity,
distance,
decay: 2.0,
})
}
pub fn spot(color: impl Into<Rgb>, intensity: f32, angle: f32, penumbra: f32) -> Self {
Light::Spot(SpotLight {
color: color.into(),
intensity,
distance: 0.0,
decay: 2.0,
angle,
penumbra,
direction: Vec3::NEG_Y,
})
}
pub fn with_shadow(mut self, shadow: Shadow) -> Self {
if let Light::Directional(light) = &mut self {
light.shadow = Some(shadow);
}
self
}
pub fn pointing(mut self, direction: Vec3) -> Self {
if let Light::Directional(DirectionalLight { direction: d, .. })
| Light::Spot(SpotLight { direction: d, .. }) = &mut self
{
*d = direction.normalize_or(Vec3::NEG_Y);
}
self
}
pub fn intensity_mut(&mut self) -> &mut f32 {
match self {
Light::Ambient { intensity, .. }
| Light::Hemisphere { intensity, .. }
| Light::Directional(DirectionalLight { intensity, .. })
| Light::Point(PointLight { intensity, .. })
| Light::Spot(SpotLight { intensity, .. }) => intensity,
}
}
}