nightshade 0.8.2

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

use crate::ecs::camera::{Camera, OrthographicCamera, PerspectiveCamera, Projection};
use crate::ecs::light::{Light, LightType};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SceneLight {
    Directional {
        color: [f32; 3],
        intensity: f32,
        cast_shadows: bool,
        shadow_bias: f32,
    },
    Point {
        color: [f32; 3],
        intensity: f32,
        range: f32,
        cast_shadows: bool,
        shadow_bias: f32,
    },
    Spot {
        color: [f32; 3],
        intensity: f32,
        range: f32,
        inner_cone_angle: f32,
        outer_cone_angle: f32,
        cast_shadows: bool,
        shadow_bias: f32,
    },
}

impl SceneLight {
    pub fn directional(color: [f32; 3], intensity: f32) -> Self {
        Self::Directional {
            color,
            intensity,
            cast_shadows: true,
            shadow_bias: 0.005,
        }
    }

    pub fn point(color: [f32; 3], intensity: f32, range: f32) -> Self {
        Self::Point {
            color,
            intensity,
            range,
            cast_shadows: false,
            shadow_bias: 0.0,
        }
    }

    pub fn spot(
        color: [f32; 3],
        intensity: f32,
        range: f32,
        inner_cone_angle: f32,
        outer_cone_angle: f32,
    ) -> Self {
        Self::Spot {
            color,
            intensity,
            range,
            inner_cone_angle,
            outer_cone_angle,
            cast_shadows: false,
            shadow_bias: 0.0,
        }
    }

    pub fn to_light(&self) -> Light {
        match self {
            SceneLight::Directional {
                color,
                intensity,
                cast_shadows,
                shadow_bias,
            } => Light {
                light_type: LightType::Directional,
                color: nalgebra_glm::Vec3::new(color[0], color[1], color[2]),
                intensity: *intensity,
                range: 0.0,
                inner_cone_angle: 0.0,
                outer_cone_angle: 0.0,
                cast_shadows: *cast_shadows,
                shadow_bias: *shadow_bias,
            },
            SceneLight::Point {
                color,
                intensity,
                range,
                cast_shadows,
                shadow_bias,
            } => Light {
                light_type: LightType::Point,
                color: nalgebra_glm::Vec3::new(color[0], color[1], color[2]),
                intensity: *intensity,
                range: *range,
                inner_cone_angle: 0.0,
                outer_cone_angle: 0.0,
                cast_shadows: *cast_shadows,
                shadow_bias: *shadow_bias,
            },
            SceneLight::Spot {
                color,
                intensity,
                range,
                inner_cone_angle,
                outer_cone_angle,
                cast_shadows,
                shadow_bias,
            } => Light {
                light_type: LightType::Spot,
                color: nalgebra_glm::Vec3::new(color[0], color[1], color[2]),
                intensity: *intensity,
                range: *range,
                inner_cone_angle: *inner_cone_angle,
                outer_cone_angle: *outer_cone_angle,
                cast_shadows: *cast_shadows,
                shadow_bias: *shadow_bias,
            },
        }
    }
}

impl From<&Light> for SceneLight {
    fn from(light: &Light) -> Self {
        let color = [light.color.x, light.color.y, light.color.z];
        match light.light_type {
            LightType::Directional => SceneLight::Directional {
                color,
                intensity: light.intensity,
                cast_shadows: light.cast_shadows,
                shadow_bias: light.shadow_bias,
            },
            LightType::Point => SceneLight::Point {
                color,
                intensity: light.intensity,
                range: light.range,
                cast_shadows: light.cast_shadows,
                shadow_bias: light.shadow_bias,
            },
            LightType::Spot => SceneLight::Spot {
                color,
                intensity: light.intensity,
                range: light.range,
                inner_cone_angle: light.inner_cone_angle,
                outer_cone_angle: light.outer_cone_angle,
                cast_shadows: light.cast_shadows,
                shadow_bias: light.shadow_bias,
            },
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SceneCamera {
    Perspective {
        aspect_ratio: Option<f32>,
        y_fov_rad: f32,
        z_far: Option<f32>,
        z_near: f32,
    },
    Orthographic {
        x_mag: f32,
        y_mag: f32,
        z_far: f32,
        z_near: f32,
    },
}

impl SceneCamera {
    pub fn perspective(y_fov_rad: f32, z_near: f32) -> Self {
        Self::Perspective {
            aspect_ratio: None,
            y_fov_rad,
            z_far: None,
            z_near,
        }
    }

    pub fn orthographic(x_mag: f32, y_mag: f32, z_near: f32, z_far: f32) -> Self {
        Self::Orthographic {
            x_mag,
            y_mag,
            z_far,
            z_near,
        }
    }

    pub fn to_camera(&self) -> Camera {
        match self {
            SceneCamera::Perspective {
                aspect_ratio,
                y_fov_rad,
                z_far,
                z_near,
            } => Camera {
                projection: Projection::Perspective(PerspectiveCamera {
                    aspect_ratio: *aspect_ratio,
                    y_fov_rad: *y_fov_rad,
                    z_far: *z_far,
                    z_near: *z_near,
                }),
                smoothing: None,
            },
            SceneCamera::Orthographic {
                x_mag,
                y_mag,
                z_far,
                z_near,
            } => Camera {
                projection: Projection::Orthographic(OrthographicCamera {
                    x_mag: *x_mag,
                    y_mag: *y_mag,
                    z_far: *z_far,
                    z_near: *z_near,
                }),
                smoothing: None,
            },
        }
    }
}

impl From<&Camera> for SceneCamera {
    fn from(camera: &Camera) -> Self {
        match &camera.projection {
            Projection::Perspective(perspective) => SceneCamera::Perspective {
                aspect_ratio: perspective.aspect_ratio,
                y_fov_rad: perspective.y_fov_rad,
                z_far: perspective.z_far,
                z_near: perspective.z_near,
            },
            Projection::Orthographic(orthographic) => SceneCamera::Orthographic {
                x_mag: orthographic.x_mag,
                y_mag: orthographic.y_mag,
                z_far: orthographic.z_far,
                z_near: orthographic.z_near,
            },
        }
    }
}