dreamwell-engine 1.0.0

Dreamwell pure-logic engine library — transforms, hierarchy, canon pipeline, spatial math, hashing, tile rules, validation, waymark schema, material/lighting descriptors. No SpacetimeDB dependency.
Documentation
//! Light descriptor types shared between engine and GPU crates.

use serde::{Deserialize, Serialize};

/// Directional light (sun, moon). Infinite range, parallel rays.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct DirectionalLightDesc {
    /// Light direction (normalized, points toward light source).
    pub direction: [f32; 3],
    /// Light color (RGB linear).
    pub color: [f32; 3],
    /// Illuminance in lux.
    pub intensity_lux: f32,
}

impl Default for DirectionalLightDesc {
    fn default() -> Self {
        Self {
            direction: [0.0, -1.0, 0.0],
            color: [1.0, 1.0, 1.0],
            intensity_lux: 100_000.0,
        }
    }
}

/// Point light (omni-directional, finite range).
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct PointLightDesc {
    /// World-space position.
    pub position: [f32; 3],
    /// Light color (RGB linear).
    pub color: [f32; 3],
    /// Luminous intensity in lumens.
    pub intensity_lumens: f32,
    /// Attenuation range in world units. Light contribution is zero beyond this.
    pub range: f32,
}

impl Default for PointLightDesc {
    fn default() -> Self {
        Self {
            position: [0.0, 3.0, 0.0],
            color: [1.0, 1.0, 1.0],
            intensity_lumens: 800.0,
            range: 10.0,
        }
    }
}

/// Spot light (cone-shaped, finite range).
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct SpotLightDesc {
    /// World-space position.
    pub position: [f32; 3],
    /// Cone direction (normalized).
    pub direction: [f32; 3],
    /// Light color (RGB linear).
    pub color: [f32; 3],
    /// Luminous intensity in lumens.
    pub intensity_lumens: f32,
    /// Attenuation range in world units.
    pub range: f32,
    /// Cosine of inner cone half-angle (full intensity inside).
    pub inner_cos: f32,
    /// Cosine of outer cone half-angle (zero intensity outside).
    pub outer_cos: f32,
}

impl Default for SpotLightDesc {
    fn default() -> Self {
        Self {
            position: [0.0, 3.0, 0.0],
            direction: [0.0, -1.0, 0.0],
            color: [1.0, 1.0, 1.0],
            intensity_lumens: 800.0,
            range: 10.0,
            inner_cos: 0.9659, // cos(15 degrees)
            outer_cos: 0.8660, // cos(30 degrees)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn directional_default() {
        let d = DirectionalLightDesc::default();
        assert_eq!(d.direction, [0.0, -1.0, 0.0]);
        assert!(d.intensity_lux > 0.0);
    }

    #[test]
    fn point_default() {
        let p = PointLightDesc::default();
        assert!(p.range > 0.0);
        assert!(p.intensity_lumens > 0.0);
    }

    #[test]
    fn spot_cone_angles() {
        let s = SpotLightDesc::default();
        assert!(s.inner_cos > s.outer_cos, "inner cone must be tighter than outer");
    }

    #[test]
    fn serde_roundtrip() {
        let d = DirectionalLightDesc::default();
        let json = serde_json::to_string(&d).unwrap();
        let back: DirectionalLightDesc = serde_json::from_str(&json).unwrap();
        assert_eq!(d, back);
    }
}