use anyhow::Result;
use crate::sdf::Path;
use crate::usd::{Prim, Stage};
use crate::schemas::lux::tokens::{A_ANGLE, REL_GEOMETRY, T_DISTANT_LIGHT, T_GEOMETRY_LIGHT};
use super::common::{author_input_float, author_rel_targets};
use super::light_api::LightApiSetters;
pub fn define_distant_light<'s>(stage: &'s Stage, path: impl Into<Path>) -> Result<DistantLightAuthor<'s>> {
let prim = stage.define_prim(path)?.set_type_name(T_DISTANT_LIGHT)?;
Ok(DistantLightAuthor { prim })
}
pub struct DistantLightAuthor<'s> {
prim: Prim<'s>,
}
impl<'s> DistantLightAuthor<'s> {
pub fn into_prim(self) -> Prim<'s> {
self.prim
}
pub fn set_angle_deg(self, angle: f32) -> Result<Self> {
author_input_float(self.prim.stage(), self.prim.path(), A_ANGLE, angle)?;
Ok(self)
}
}
impl<'s> LightApiSetters<'s> for DistantLightAuthor<'s> {
fn prim(&self) -> &Prim<'s> {
&self.prim
}
}
pub fn define_geometry_light<'s>(stage: &'s Stage, path: impl Into<Path>) -> Result<GeometryLightAuthor<'s>> {
let prim = stage.define_prim(path)?.set_type_name(T_GEOMETRY_LIGHT)?;
Ok(GeometryLightAuthor { prim })
}
pub struct GeometryLightAuthor<'s> {
prim: Prim<'s>,
}
impl<'s> GeometryLightAuthor<'s> {
pub fn into_prim(self) -> Prim<'s> {
self.prim
}
pub fn set_geometry(self, geometry: impl Into<Path>) -> Result<Self> {
author_rel_targets(self.prim.stage(), self.prim.path(), REL_GEOMETRY, [geometry.into()])?;
Ok(self)
}
}
impl<'s> LightApiSetters<'s> for GeometryLightAuthor<'s> {
fn prim(&self) -> &Prim<'s> {
&self.prim
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sdf;
#[test]
fn distant_light_defaults_intensity_to_50000_per_spec() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
define_distant_light(&stage, sdf::path("/Sun")?)?.set_angle_deg(0.53)?;
let light = crate::schemas::lux::read_distant_light(&stage, &sdf::path("/Sun")?)?.expect("DistantLight");
assert!((light.common.intensity - 50000.0).abs() < 1e-3);
assert!((light.angle_deg - 0.53).abs() < 1e-3);
Ok(())
}
#[test]
fn distant_light_caller_intensity_override() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
define_distant_light(&stage, sdf::path("/Sun")?)?
.set_intensity(12000.0)?
.set_angle_deg(2.0)?;
let light = crate::schemas::lux::read_distant_light(&stage, &sdf::path("/Sun")?)?.expect("DistantLight");
assert!((light.common.intensity - 12000.0).abs() < 1e-3);
assert!((light.angle_deg - 2.0).abs() < 1e-3);
Ok(())
}
#[test]
fn geometry_light_links_source_mesh() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
stage.define_prim("/World/Emitter")?.set_type_name("Mesh")?;
define_geometry_light(&stage, sdf::path("/World/Light")?)?
.set_geometry(sdf::path("/World/Emitter")?)?
.set_intensity(200.0)?;
let light =
crate::schemas::lux::read_geometry_light(&stage, &sdf::path("/World/Light")?)?.expect("GeometryLight");
assert_eq!(light.geometry.as_deref(), Some("/World/Emitter"));
assert!((light.common.intensity - 200.0).abs() < 1e-3);
Ok(())
}
}