use crate::{
core::{
algebra::Vector3,
color::Color,
define_is_as,
inspect::{Inspect, PropertyInfo},
visitor::{Visit, VisitResult, Visitor},
},
scene::{
base::{Base, BaseBuilder},
light::{directional::DirectionalLight, point::PointLight, spot::SpotLight},
},
};
use std::ops::{Deref, DerefMut};
pub mod directional;
pub mod point;
pub mod spot;
pub const DEFAULT_SCATTER_R: f32 = 0.03;
pub const DEFAULT_SCATTER_G: f32 = 0.03;
pub const DEFAULT_SCATTER_B: f32 = 0.03;
#[derive(Debug)]
pub enum Light {
Directional(DirectionalLight),
Spot(SpotLight),
Point(PointLight),
}
impl Inspect for Light {
fn properties(&self) -> Vec<PropertyInfo<'_>> {
match self {
Light::Directional(v) => v.properties(),
Light::Spot(v) => v.properties(),
Light::Point(v) => v.properties(),
}
}
}
impl Default for Light {
fn default() -> Self {
Self::Directional(Default::default())
}
}
impl Light {
fn new(id: u32) -> Result<Self, String> {
match id {
0 => Ok(Self::Spot(Default::default())),
1 => Ok(Self::Point(Default::default())),
2 => Ok(Self::Directional(Default::default())),
_ => Err(format!("Invalid light kind {}", id)),
}
}
fn id(&self) -> u32 {
match self {
Self::Spot(_) => 0,
Self::Point(_) => 1,
Self::Directional(_) => 2,
}
}
pub fn raw_copy(&self) -> Self {
match self {
Light::Directional(v) => Self::Directional(v.raw_copy()),
Light::Spot(v) => Self::Spot(v.raw_copy()),
Light::Point(v) => Self::Point(v.raw_copy()),
}
}
define_is_as!(Light : Directional -> ref DirectionalLight => fn is_directional, fn as_directional, fn as_directional_mut);
define_is_as!(Light : Spot -> ref SpotLight => fn is_spot, fn as_spot, fn as_spot_mut);
define_is_as!(Light : Point -> ref PointLight => fn is_point, fn as_point, fn as_point_mut);
}
impl Deref for Light {
type Target = BaseLight;
fn deref(&self) -> &Self::Target {
match self {
Self::Directional(v) => v.deref(),
Self::Spot(v) => v.deref(),
Self::Point(v) => v.deref(),
}
}
}
impl DerefMut for Light {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Directional(v) => v.deref_mut(),
Self::Spot(v) => v.deref_mut(),
Self::Point(v) => v.deref_mut(),
}
}
}
impl Visit for Light {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut kind_id = self.id();
kind_id.visit("KindId", visitor)?;
if visitor.is_reading() {
*self = Self::new(kind_id)?;
}
match self {
Self::Spot(spot_light) => spot_light.visit("Data", visitor)?,
Self::Point(point_light) => point_light.visit("Data", visitor)?,
Self::Directional(directional_light) => directional_light.visit("Data", visitor)?,
}
visitor.leave_region()
}
}
#[derive(Debug, Inspect)]
pub struct BaseLight {
base: Base,
color: Color,
cast_shadows: bool,
scatter: Vector3<f32>,
scatter_enabled: bool,
#[inspect(min_value = 0.0, step = 0.1)]
intensity: f32,
}
impl Deref for BaseLight {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for BaseLight {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
impl Default for BaseLight {
fn default() -> Self {
Self {
base: Default::default(),
color: Color::WHITE,
cast_shadows: true,
scatter: Vector3::new(DEFAULT_SCATTER_R, DEFAULT_SCATTER_G, DEFAULT_SCATTER_B),
scatter_enabled: true,
intensity: 1.0,
}
}
}
impl Visit for BaseLight {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.color.visit("Color", visitor)?;
self.base.visit("Base", visitor)?;
self.cast_shadows.visit("CastShadows", visitor)?;
self.scatter.visit("ScatterFactor", visitor)?;
self.scatter_enabled.visit("ScatterEnabled", visitor)?;
let _ = self.intensity.visit("Intensity", visitor);
visitor.leave_region()
}
}
impl BaseLight {
#[inline]
pub fn set_color(&mut self, color: Color) {
self.color = color;
}
#[inline]
pub fn color(&self) -> Color {
self.color
}
#[inline]
pub fn set_cast_shadows(&mut self, value: bool) {
self.cast_shadows = value;
}
#[inline]
pub fn is_cast_shadows(&self) -> bool {
self.cast_shadows
}
#[inline]
pub fn set_scatter(&mut self, f: Vector3<f32>) {
self.scatter = f;
}
#[inline]
pub fn scatter(&self) -> Vector3<f32> {
self.scatter
}
pub fn set_intensity(&mut self, intensity: f32) {
self.intensity = intensity;
}
pub fn intensity(&self) -> f32 {
self.intensity
}
#[inline]
pub fn scatter_linear(&self) -> Vector3<f32> {
self.scatter.map(|v| v.powf(2.2))
}
#[inline]
pub fn enable_scatter(&mut self, state: bool) {
self.scatter_enabled = state;
}
#[inline]
pub fn is_scatter_enabled(&self) -> bool {
self.scatter_enabled
}
pub fn raw_copy(&self) -> Self {
Self {
base: self.base.raw_copy(),
color: self.color,
cast_shadows: self.cast_shadows,
scatter: self.scatter,
scatter_enabled: self.scatter_enabled,
intensity: self.intensity,
}
}
}
pub struct BaseLightBuilder {
base_builder: BaseBuilder,
color: Color,
cast_shadows: bool,
scatter_factor: Vector3<f32>,
scatter_enabled: bool,
intensity: f32,
}
impl BaseLightBuilder {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
base_builder,
color: Color::WHITE,
cast_shadows: true,
scatter_factor: Vector3::new(DEFAULT_SCATTER_R, DEFAULT_SCATTER_G, DEFAULT_SCATTER_B),
scatter_enabled: true,
intensity: 1.0,
}
}
pub fn with_color(mut self, color: Color) -> Self {
self.color = color;
self
}
pub fn cast_shadows(mut self, cast_shadows: bool) -> Self {
self.cast_shadows = cast_shadows;
self
}
pub fn with_scatter_factor(mut self, f: Vector3<f32>) -> Self {
self.scatter_factor = f;
self
}
pub fn with_scatter_enabled(mut self, state: bool) -> Self {
self.scatter_enabled = state;
self
}
pub fn with_intensity(mut self, intensity: f32) -> Self {
self.intensity = intensity;
self
}
pub fn build(self) -> BaseLight {
BaseLight {
base: self.base_builder.build_base(),
color: self.color,
cast_shadows: self.cast_shadows,
scatter: self.scatter_factor,
scatter_enabled: self.scatter_enabled,
intensity: self.intensity,
}
}
}