use super::{ DenselySampledSpectrum, RGBColorSpace, SampledSpectrum, SampledWavelengths, LAMBDA_MAX, LAMBDA_MIN, N_SPECTRUM_SAMPLES, }; use crate::core::color::{RGBSigmoidPolynomial, RGB, XYZ}; use crate::core::spectrum::SpectrumTrait; use crate::utils::Ptr; use crate::Float; #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct RGBAlbedoSpectrum { pub rsp: RGBSigmoidPolynomial, } impl RGBAlbedoSpectrum { pub fn new(cs: &RGBColorSpace, rgb: RGB) -> Self { Self { rsp: cs.to_rgb_coeffs(rgb), } } } impl SpectrumTrait for RGBAlbedoSpectrum { fn evaluate(&self, lambda: Float) -> Float { self.rsp.evaluate(lambda) } fn max_value(&self) -> Float { self.rsp.max_value() } } #[repr(C)] #[derive(Debug, Default, Clone, Copy)] pub struct UnboundedRGBSpectrum { pub scale: Float, pub rsp: RGBSigmoidPolynomial, } impl UnboundedRGBSpectrum { pub fn new(cs: RGBColorSpace, rgb: RGB) -> Self { let m = rgb.r.max(rgb.g).max(rgb.b); let scale = 2.0 * m; let scaled_rgb = if scale != 0.0 { rgb / scale } else { RGB::new(0.0, 0.0, 0.0) }; Self { scale, rsp: cs.to_rgb_coeffs(scaled_rgb), } } } impl SpectrumTrait for UnboundedRGBSpectrum { fn evaluate(&self, lambda: Float) -> Float { self.scale * self.rsp.evaluate(lambda) } fn max_value(&self) -> Float { self.scale * self.rsp.max_value() } } #[derive(Debug, Clone, Copy, Default)] pub struct RGBIlluminantSpectrum { pub scale: Float, pub rsp: RGBSigmoidPolynomial, pub illuminant: Ptr, } impl RGBIlluminantSpectrum { pub fn new(cs: &RGBColorSpace, rgb: RGB) -> Self { let illuminant = cs.illuminant; let m = rgb.max_component_value(); let scale = 2. * m; let rsp = cs.to_rgb_coeffs(if scale != 0. { rgb / scale } else { RGB::new(0., 0., 0.) }); Self { scale, rsp, illuminant, } } } impl SpectrumTrait for RGBIlluminantSpectrum { fn evaluate(&self, lambda: Float) -> Float { if self.illuminant.is_null() { return 0.; } self.scale * self.rsp.evaluate(lambda) * self.illuminant.evaluate(lambda) } fn sample(&self, lambda: &SampledWavelengths) -> SampledSpectrum { if self.illuminant.is_null() { return SampledSpectrum::new(0.); } SampledSpectrum::from_fn(|i| self.scale * self.rsp.evaluate(lambda[i])) } fn max_value(&self) -> Float { if self.illuminant.is_null() { return 0.; } self.scale * self.rsp.max_value() * self.illuminant.max_value() } } #[derive(Debug, Clone, Copy)] pub struct RGBSpectrum { pub c: [Float; 3], } #[derive(Debug, Clone, Copy)] pub struct RGBUnboundedSpectrum { pub scale: Float, pub rsp: RGBSigmoidPolynomial, } impl Default for RGBUnboundedSpectrum { fn default() -> Self { Self { scale: 0.0, rsp: RGBSigmoidPolynomial::default(), } } } impl RGBUnboundedSpectrum { pub fn new(cs: &RGBColorSpace, rgb: RGB) -> Self { let m = rgb.max_component_value(); let scale = 2.0 * m; let rgb_norm = if scale > 0.0 { rgb / scale } else { RGB::new(0.0, 0.0, 0.0) }; let rsp = cs.to_rgb_coeffs(rgb_norm); Self { scale, rsp } } } impl SpectrumTrait for RGBUnboundedSpectrum { fn evaluate(&self, lambda: Float) -> Float { self.scale * self.rsp.evaluate(lambda) } fn max_value(&self) -> Float { self.scale * self.rsp.max_value() } }