use core::marker::PhantomData;
use crate::{
bool_mask::LazySelect,
num::{
Abs, Arithmetics, Clamp, Exp, FromScalar, One, PartialCmp, Powf, Real, Signum, Sqrt, Zero,
},
white_point::{self, WhitePoint},
Xyz,
};
#[derive(Clone, Copy)]
#[non_exhaustive]
pub struct Parameters<WpParam, T> {
pub white_point: WpParam,
pub adapting_luminance: T,
pub background_luminance: T,
pub surround: Surround<T>,
pub discounting: Discounting<T>,
}
impl<WpParam, T> Parameters<WpParam, T>
where
WpParam: WhitePointParameter<T>,
{
fn into_any_white_point(self) -> Parameters<Xyz<white_point::Any, T>, T> {
Parameters {
white_point: self.white_point.into_xyz(),
adapting_luminance: self.adapting_luminance,
background_luminance: self.background_luminance,
surround: self.surround,
discounting: self.discounting,
}
}
}
impl<Wp, T> Parameters<StaticWp<Wp>, T> {
#[inline]
pub fn default_static_wp(adapting_luminance: T) -> Self
where
T: Real,
{
Self {
white_point: StaticWp(PhantomData),
adapting_luminance,
background_luminance: T::from_f64(0.2),
surround: Surround::Average,
discounting: Discounting::Auto,
}
}
}
impl<T> Parameters<Xyz<white_point::Any, T>, T> {
#[inline]
pub fn default_dynamic_wp(white_point: Xyz<white_point::Any, T>, adapting_luminance: T) -> Self
where
T: Real,
{
Self {
white_point,
adapting_luminance,
background_luminance: T::from_f64(0.2),
surround: Surround::Average,
discounting: Discounting::Auto,
}
}
}
impl<WpParam, T> Parameters<WpParam, T> {
pub fn bake(self) -> BakedParameters<WpParam, T>
where
BakedParameters<WpParam, T>: From<Self>,
{
self.into()
}
}
#[cfg(all(test, feature = "approx"))]
impl<Wp> Parameters<StaticWp<Wp>, f64> {
pub(crate) const TEST_DEFAULTS: Self = Self {
white_point: StaticWp(PhantomData),
adapting_luminance: 40.0f64,
background_luminance: 0.2f64, surround: Surround::Average,
discounting: Discounting::Auto,
};
}
pub struct BakedParameters<WpParam, T> {
pub(crate) inner: super::math::DependentParameters<T>,
white_point: PhantomData<WpParam>,
}
impl<WpParam, T> Clone for BakedParameters<WpParam, T>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
white_point: PhantomData,
}
}
}
impl<WpParam, T> Copy for BakedParameters<WpParam, T> where T: Copy {}
impl<WpParam, T> From<Parameters<WpParam, T>> for BakedParameters<WpParam, T>
where
WpParam: WhitePointParameter<T>,
T: Real
+ FromScalar<Scalar = T>
+ One
+ Zero
+ Clamp
+ PartialCmp
+ Arithmetics
+ Powf
+ Sqrt
+ Exp
+ Abs
+ Signum
+ Clone,
T::Mask: LazySelect<T>,
{
fn from(value: Parameters<WpParam, T>) -> Self {
Self {
inner: super::math::prepare_parameters(value.into_any_white_point()),
white_point: PhantomData,
}
}
}
#[derive(Clone, Copy)]
#[non_exhaustive]
pub enum Surround<T> {
Dark,
Dim,
Average,
Percent(T),
}
impl<T> Surround<T> {
pub(crate) fn into_percent(self) -> T
where
T: Real + Clamp,
{
match self {
Surround::Dark => T::from_f64(0.0),
Surround::Dim => T::from_f64(10.0),
Surround::Average => T::from_f64(20.0),
Surround::Percent(value) => value.clamp(T::from_f64(0.0), T::from_f64(20.0)),
}
}
}
#[derive(Clone, Copy)]
#[non_exhaustive]
pub enum Discounting<T> {
Auto,
Custom(T),
}
pub trait WhitePointParameter<T> {
type StaticWp;
fn into_xyz(self) -> Xyz<white_point::Any, T>;
}
impl<T> WhitePointParameter<T> for Xyz<white_point::Any, T> {
type StaticWp = white_point::Any;
fn into_xyz(self) -> Xyz<white_point::Any, T> {
self
}
}
pub struct StaticWp<Wp>(PhantomData<Wp>);
impl<T, Wp> WhitePointParameter<T> for StaticWp<Wp>
where
Wp: WhitePoint<T>,
{
type StaticWp = Wp;
fn into_xyz(self) -> Xyz<white_point::Any, T> {
Wp::get_xyz()
}
}
impl<Wp> Clone for StaticWp<Wp> {
fn clone(&self) -> Self {
*self
}
}
impl<Wp> Copy for StaticWp<Wp> {}