use crate::core::pbrt::Float; use super::geometry::Point2f; use super::transform::SquareMatrix; use super::color::{RGBSigmoidPolynomial, RGBToSpectrumTable, RGB, XYZ}; use super::spectrum::{DenselySampledSpectrum, Spectrum, SampledSpectrum}; use std::cmp::{Eq, PartialEq}; use std::sync::Arc; #[derive(Clone)] pub struct RGBColorspace { r: Point2f, g: Point2f, b: Point2f, w: Point2f, illuminant: Spectrum, rgb_to_spectrum_table: Arc, xyz_from_rgb: SquareMatrix, rgb_from_xyz: SquareMatrix, } impl RGBColorspace { pub fn new(r: Point2f, g: Point2f, b: Point2f, illuminant: Spectrum, rgb_to_spectrum_table: RGBToSpectrumTable) -> Self { let w_xyz = illuminant.to_xyz(); let w = w_xyz.xy(); let r_xyz = XYZ::from_xyy(r, 1.0); let g_xyz = XYZ::from_xyy(g, 1.0); let b_xyz = XYZ::from_xyy(b, 1.0); let rgb_values = [[r_xyz.x(), g_xyz.x(), b_xyz.x()], [r_xyz.y(), g_xyz.y(), b_xyz.y()], [r_xyz.z(), g_xyz.z(), g_xyz.z()]]; let rgb: SquareMatrix = SquareMatrix { m: rgb_values }; let c = match rgb.inverse() { Some(inv_matrix) => { inv_matrix * w_xyz }, None => { panic!("Cannot create RGBColorspace: The RGB primaries form a singular matrix."); } }; let xyz_from_rgb_m = [[c[0], 0.0, 0.0], [0.0, c[1], 0.0], [0.0, 0.0, c[2]]]; let xyz_from_rgb = rgb * SquareMatrix { m: xyz_from_rgb_m }; let rgb_from_xyz = xyz_from_rgb.inverse().expect("Failed to invert the XYZfromRGB matrix. Is it singular?"); Self { r, g, b, w, illuminant, rgb_to_spectrum_table: Arc::new(rgb_to_spectrum_table), xyz_from_rgb, rgb_from_xyz } } pub fn to_xyz(&self, rgb: RGB) -> XYZ { self.xyz_from_rgb.transform_to_xyz(rgb) } pub fn to_rgb(&self, xyz: XYZ) -> RGB { self.rgb_from_xyz.transform_to_rgb(xyz) } pub fn to_rgb_coeffs(&self, rgb: RGB) -> RGBSigmoidPolynomial { self.rgb_to_spectrum_table.to_polynomial(rgb) } pub fn convert_colorspace(&self, other: &RGBColorspace) -> SquareMatrix { if self == other { return SquareMatrix::default() } self.rgb_from_xyz * other.xyz_from_rgb } } impl PartialEq for RGBColorspace { fn eq(&self, other: &Self) -> bool { self.r == other.r && self.g == other.g && self.b == other.b && self.w == other.w && Arc::ptr_eq(&self.rgb_to_spectrum_table, &other.rgb_to_spectrum_table) } }