Skip to main content

concinnity_core/components/
directional_light.rs

1// Directional-light schema.
2
3/// An infinitely distant directional light (sun, moon, or sky fill).
4///
5/// Up to 4 directional lights may be declared; extras beyond 4 are silently ignored.
6/// When no directional light is present, a built-in warm sun is used as a fallback.
7///
8/// ```rust
9/// # use concinnity_core::components::DirectionalLight;
10/// DirectionalLight {
11///     direction: [-0.3, 0.85, 0.4],
12///     color: [1.0, 0.95, 0.8],
13///     intensity: 1.0,
14///     ..Default::default()
15/// };
16/// ```
17#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
18#[serde(default)]
19pub struct DirectionalLight {
20    /// Direction pointing toward the light source. Does not need to be
21    /// normalised.
22    pub direction: [f32; 3],
23    /// Linear-space RGB colour of the light.
24    pub color: [f32; 3],
25    /// Intensity multiplier applied to the colour.
26    pub intensity: f32,
27}
28
29impl DirectionalLight {
30    /// A light contributing nothing, used to pad a fixed-size set.
31    pub const ZERO: Self = Self {
32        direction: [0.0; 3],
33        color: [0.0; 3],
34        intensity: 0.0,
35    };
36}
37
38impl Default for DirectionalLight {
39    fn default() -> Self {
40        Self {
41            direction: [-0.3, 0.85, 0.4],
42            color: [1.0, 1.0, 1.0],
43            intensity: 1.0,
44        }
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn the_default_sun_points_down_from_above() {
54        // The direction is toward the light, so a positive Y component is what
55        // makes the default read as an overhead sun rather than an uplight.
56        let l = DirectionalLight::default();
57        assert!(l.direction[1] > 0.0);
58        assert_eq!(l.color, [1.0, 1.0, 1.0]);
59        assert_eq!(l.intensity, 1.0);
60    }
61
62    #[test]
63    fn an_authored_sun_parses_and_round_trips_through_postcard() {
64        let l: DirectionalLight =
65            serde_json::from_str(r#"{"direction":[0,1,0],"color":[1,0.9,0.7],"intensity":3}"#)
66                .unwrap();
67        assert_eq!(l.direction, [0.0, 1.0, 0.0]);
68        assert_eq!(l.color, [1.0, 0.9, 0.7]);
69        assert_eq!(l.intensity, 3.0);
70
71        let bytes = postcard::to_allocvec(&l).unwrap();
72        let back: DirectionalLight = postcard::from_bytes(&bytes).unwrap();
73        assert_eq!(back.color, [1.0, 0.9, 0.7]);
74        assert_eq!(back.intensity, 3.0);
75    }
76}