use super::rgb::RGB;
use std::cmp::PartialOrd;
use std::f32::NAN;
pub fn min<T: PartialOrd>(lhs: T, rhs: T) -> T { if lhs < rhs { lhs } else { rhs } }
pub fn max<T: PartialOrd>(lhs: T, rhs: T) -> T { if lhs < rhs { rhs } else { lhs } }
macro_rules! min {
($x:expr, $y:expr) => ( min($x, $y) );
($x:expr, $($y:expr),*) => ( min($x, min!($($y),*)) );
}
macro_rules! max {
($x:expr, $y:expr) => ( max($x, $y) );
($x:expr, $($y:expr),*) => ( max($x, max!($($y),*)) );
}
pub fn pack_chanel_value(value: f32, power: f32, limit: usize) -> u64 { (value * limit as f32 / power).round() as u64 }
pub fn unpack_chanel_value(value: u64, limit: usize, power: f32) -> f32 { value as f32 * power / limit as f32 }
pub fn get_hue(rgb: RGB) -> f32 {
let RGB{red, green, blue} = rgb;
let max = max!(red, green, blue);
let min = min!(red, green, blue);
let color = max - min;
if color == 0.0 { return NAN; }
let hue = if max == red {
((green - blue) / color)
} else if max == green {
((blue - red) / color) + 2.0
} else {
((red - green) / color) + 4.0
};
(hue % 6.0) * 60.0
}
pub fn get_hsv_saturation(rgb: RGB) -> f32 {
let RGB{red, green, blue} = rgb;
let max = max!(red, green, blue);
let min = min!(red, green, blue);
let color = max - min;
color / get_value(rgb)
}
pub fn get_hsl_saturation(rgb: RGB) -> f32 {
let RGB{red, green, blue} = rgb;
let max = max!(red, green, blue);
let min = min!(red, green, blue);
let color = max - min;
color / (1.0 - (2.0 * get_lightness(rgb) - 1.0).abs())
}
pub fn get_hsi_saturation(rgb: RGB) -> f32 {
let RGB{red, green, blue} = rgb;
let min = min!(red, green, blue);
1.0 - (min / get_intensity(rgb))
}
pub fn get_value(rgb: RGB) -> f32 { let RGB{red, green, blue} = rgb; max!(red, green, blue) }
pub fn get_lightness(rgb: RGB) -> f32 {
let RGB{red, green, blue} = rgb;
let max = max!(red, green, blue);
let min = min!(red, green, blue);
(max + min) / 2.0
}
pub fn get_intensity(rgb: RGB) -> f32 {
let RGB{red, green, blue} = rgb;
(red + green + blue) / 3.0
}
pub fn rgb_from_hcm(hue: f32, color: f32, min: f32) -> RGB {
let (r1, g1, b1) = if hue.is_nan() {
(0.0, 0.0, 0.0)
} else {
assert!(0.0 <= hue && hue < 360.0);
let hue = (hue - (hue / 360.0).floor() * 360.0) / 60.0;
let x = color * (1.0 - ((hue % 2.0) - 1.0).abs());
if hue >= 5.0 {
(color, 0.0, x)
} else if hue >= 4.0 {
(x, 0.0, color)
} else if hue >= 3.0 {
(0.0, x, color)
} else if hue >= 2.0 {
(0.0, color, x)
} else if hue >= 1.0 {
(x, color, 0.0)
} else if hue >= 0.0 {
(color, x, 0.0)
} else {
unreachable!()
}
};
return RGB::new(r1 + min, g1 + min, b1 + min);
}