primase_core/
spot_frustum.rs1use serde::Serialize;
3
4use crate::{Component, Entity, Geometry, JsonError, Light, LightKind, World};
5
6#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
13pub struct SpotFrustum {
14 pub horizontal_half_angle: f32,
15 pub vertical_half_angle: f32,
16 pub near: f32,
17}
18
19impl Component for SpotFrustum {
20 const NAME: &'static str = "core.spot_frustum";
21 const GEOMETRY: Geometry = Geometry::None;
22 fn to_json(&self) -> Result<Option<serde_json::Value>, JsonError> {
23 crate::json::to_value(self).map(Some)
24 }
25 fn verify(&self, e: Entity, w: &World) -> Result<(), String> {
28 let half = 0.0..std::f32::consts::FRAC_PI_2;
29 for (axis, angle) in [
30 ("horizontal", self.horizontal_half_angle),
31 ("vertical", self.vertical_half_angle),
32 ] {
33 if !(half.contains(&angle) && angle > 0.0) {
34 return Err(format!(
35 "a spot frustum's {axis} half-angle {angle} not in (0, pi / 2)"
36 ));
37 }
38 }
39 if !(self.near.is_finite() && self.near >= 0.0) {
40 return Err(format!(
41 "a spot frustum's near plane {} not finite and non-negative",
42 self.near
43 ));
44 }
45 match w.get::<Light>(e) {
46 Some(Light {
47 kind: LightKind::Spot { .. },
48 range,
49 ..
50 }) => match range {
51 Some(r) if *r <= self.near => Err(format!(
52 "a spot frustum's near plane {} not before the light's range {r}",
53 self.near
54 )),
55 _ => Ok(()),
56 },
57 _ => Err("a spot frustum on an entity with no spot light".into()),
58 }
59 }
60}