use super::{AbsorptionUnit, GemMaterial};
use crate::{
color::{Illuminant, body_colors},
optics::zoning::ZonedAbsorption,
render_setup::{MODEL_UNIT_FACE_UP_PATH, effective_stone_width_mm},
};
pub const ZONE_SWATCH_FALLBACK_MODEL_WIDTH: f64 = 2.0;
impl GemMaterial {
#[must_use]
pub fn with_zoning(mut self, zoning: ZonedAbsorption) -> Self {
self.absorption = zoning.base.tensor.clone();
self.absorption_unit = AbsorptionUnit::PerMm;
self.zoning = Some(zoning);
self
}
}
#[must_use]
pub fn zone_swatches(material: &GemMaterial, width_mm: f32) -> Vec<[f32; 3]> {
let Some(zoning) = material.zoning.as_ref() else {
return Vec::new();
};
let scale = material.absorption_path_scale;
let sized = scale.is_finite() && scale > 0.0 && scale.to_bits() != 1.0_f32.to_bits();
let mm_per_unit = if sized {
f64::from(scale)
} else {
f64::from(effective_stone_width_mm(width_mm)) / ZONE_SWATCH_FALLBACK_MODEL_WIDTH
};
let path_mm = f64::from(MODEL_UNIT_FACE_UP_PATH) * mm_per_unit;
std::iter::once(&zoning.base)
.chain(zoning.zones.iter().map(|zone| &zone.absorption))
.map(|zone| {
body_colors(&zone.tensor, path_mm, Illuminant::D65)
.unpolarised
.srgb
.map(|v| f32::from(v) / 255.0)
})
.collect()
}