use proportion::*; #[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] pub struct Colour { /// Channel order for nybbles is `0xAARRGGBB`. pub value: u32, } impl Colour { pub const TRANSPARENT: Self = Self::rgba(0x00000000); pub const fn rgb(value: u32) -> Self { Self { value: value | 0xff000000, } } pub const fn rgba(value: u32) -> Self { Self { value } } pub const fn grey(value: u32) -> Self { Self::rgb(value * 0x111111) } pub const fn from_rgb(red: u8, green: u8, blue: u8) -> Self { let mut value = 0x0000ff00; value |= red as u32; value <<= 8; value |= green as u32; value <<= 8; value |= blue as u32; Self { value } } pub const fn from_rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Self { let mut value = alpha as u32; value <<= 8; value |= red as u32; value <<= 8; value |= green as u32; value <<= 8; value |= blue as u32; Self { value } } pub fn from_array(array: &[u8; 3]) -> &Colour { unsafe { std::mem::transmute::<&[u8; 3], &Colour>(array) } } pub fn mix(bg: Self, fg: Self, proportion: Proportion) -> Self { let proportion = Proportion::::new(proportion.as_u8()); let bg_mix = proportion.invert(); let fg_mix = proportion; let red = (bg.red() * bg_mix) + (fg.red() * fg_mix); let green = (bg.green() * bg_mix) + (fg.green() * fg_mix); let blue = (bg.blue() * bg_mix) + (fg.blue() * fg_mix); Self::from_rgb(red, green, blue) } pub fn mix_with_alpha(bg: Self, fg: Self) -> Self { let proportion = Proportion::new(fg.alpha()); let bg_mix = proportion.invert(); let fg_mix = proportion; let red = (bg.red() * bg_mix) + (fg.red() * fg_mix); let green = (bg.green() * bg_mix) + (fg.green() * fg_mix); let blue = (bg.blue() * bg_mix) + (fg.blue() * fg_mix); Self::from_rgb(red, green, blue) } pub fn as_rgb(&self) -> [u8; 3] { [self.red(), self.green(), self.blue()] } pub fn as_rgb_hex(&self) -> String { format!("{:02x}{:02x}{:02x}", self.red(), self.green(), self.blue()) } pub fn red(&self) -> u8 { (self.value >> 16) as u8 } pub fn green(&self) -> u8 { (self.value >> 8) as u8 } pub fn blue(&self) -> u8 { self.value as u8 } pub fn alpha(&self) -> u8 { (self.value >> 24) as u8 } pub fn is_opaque(&self) -> bool { self.alpha() == 0xff } pub fn with_red(&self, red: u8) -> Self { Colour::rgba((self.value & 0xffffff00) | (red as u32) << 16) } pub fn with_green(&self, green: u8) -> Self { Colour::rgba((self.value & 0xffff00ff) | (green as u32) << 8) } pub fn with_blue(&self, blue: u8) -> Self { Colour::rgba((self.value & 0xff00ffff) | blue as u32) } pub fn with_alpha(&self, alpha: u8) -> Self { Colour::rgba((self.value & 0x00ffffff) | (alpha as u32) << 24) } pub fn set_red(&mut self, red: u8) { self.value = (self.value & 0xffffff00) | (red as u32) << 16 } pub fn set_green(&mut self, green: u8) { self.value = (self.value & 0xffff00ff) | (green as u32) << 8 } pub fn set_blue(&mut self, blue: u8) { self.value = (self.value & 0xff00ffff) | blue as u32 } pub fn set_alpha(&mut self, alpha: u8) { self.value = (self.value & 0x00ffffff) | (alpha as u32) << 24 } } impl Colour { pub const WHITE: Self = Self::rgb(0xffffff); pub const BLACK: Self = Self::rgb(0x000000); pub const LIGHT_GREY: Self = Self::rgb(0xc0c0c0); pub const MID_GREY: Self = Self::rgb(0x808080); pub const DARK_GREY: Self = Self::rgb(0x404040); pub const RED: Self = Self::rgb(0xff0000); pub const GREEN: Self = Self::rgb(0x00ff00); pub const BLUE: Self = Self::rgb(0x0000ff); pub const YELLOW: Self = Self::rgb(0xffff00); pub const MAGENTA: Self = Self::rgb(0xff00ff); pub const CYAN: Self = Self::rgb(0x00ffff); pub const ORANGE: Self = Self::rgb(0xff8000); pub const PURPLE: Self = Self::rgb(0x800080); pub const TEAL: Self = Self::rgb(0x008080); } impl From for Colour { fn from(value: u32) -> Self { Colour { value } } } impl AsRef for Colour { fn as_ref(&self) -> &u32 { &self.value } } impl std::fmt::Debug for Colour { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { write!(f, "Colour {{ r:{} g:{} b:{}, a:{} }}", self.red(), self.green(), self.blue(), self.alpha() ) } } impl std::fmt::Display for Colour { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { write!(f, "#{:02x}{:02x}{:02x}{:02x}", self.red(), self.green(), self.blue(), self.alpha() ) } }