pub mod cie; pub mod color; pub mod colorspace; pub mod data; pub mod rgb; pub mod sampled; pub mod simple; use crate::core::pbrt::Float; use crate::utils::file::read_float_file; use enum_dispatch::enum_dispatch; pub use color::{RGB, XYZ}; pub use colorspace::RGBColorSpace; pub use data::*; pub use rgb::*; pub use sampled::{CIE_Y_INTEGRAL, LAMBDA_MAX, LAMBDA_MIN}; pub use sampled::{N_SPECTRUM_SAMPLES, SampledSpectrum, SampledWavelengths}; pub use simple::*; // #[enum_dispatch] pub trait SpectrumProvider: Copy { fn evaluate(&self, lambda: Float) -> Float; fn max_value(&self) -> Float; } #[cfg(not(target_arch = "spirv"))] impl SpectrumProvider for std::sync::Arc { fn evaluate(&self, lambda: Float) -> Float { (**self).evaluate(lambda) } fn max_value(&self) -> Float { (**self).max_value() } } #[cfg(target_arch = "spirv")] // or target_os = "cuda" impl SpectrumProvider for u32 { fn evaluate(&self, lambda: Float) -> Float { // Here you would call a global function that accesses // a static buffer of spectra data crate::gpu::lookup_global_spectrum(*self, lambda) } fn max_value(&self) -> Float { crate::gpu::lookup_global_spectrum_max(*self) } } #[enum_dispatch(SpectrumTrait)] #[derive(Debug, Clone)] pub enum Spectrum { Constant(ConstantSpectrum), DenselySampled(DenselySampledSpectrum), PiecewiseLinear(PiecewiseLinearSpectrum), Blackbody(BlackbodySpectrum), RGBAlbedo(RGBAlbedoSpectrum), RGBIlluminant(RGBIlluminantSpectrum), RGBUnbounded(RGBUnboundedSpectrum), } impl Spectrum { pub fn std_illuminant_d65() -> Self { todo!() } pub fn to_xyz(&self) -> XYZ { let x = self.inner_product(data::cie_x()); let y = self.inner_product(data::cie_y()); let z = self.inner_product(data::cie_z()); XYZ::new(x, y, z) / CIE_Y_INTEGRAL } fn to_rgb(&self, cs: &RGBColorSpace) -> RGB { let xyz = self.to_xyz(); cs.to_rgb(xyz) } pub fn sample(&self, wavelengths: &SampledWavelengths) -> SampledSpectrum { SampledSpectrum::from_fn(|i| self.evaluate(wavelengths[i])) } pub fn inner_product(&self, other: &Spectrum) -> Float { let mut integral = 0.0; // Iterate integer wavelengths. for lambda in LAMBDA_MIN..=LAMBDA_MAX { let l = lambda as Float; integral += self.evaluate(l) * other.evaluate(l); } integral } pub fn is_constant(&self) -> bool { matches!(self, Spectrum::Constant(_)) } }