diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2023-12-24 20:58:14 +1300 |
---|---|---|
committer | Ben Bridle <bridle.benjamin@gmail.com> | 2023-12-24 20:58:14 +1300 |
commit | 8875d9d6dd48400a9ca1cf8c64889d860700d40c (patch) | |
tree | 3a8fbac5097bbf2d5dfc803ebcd80b44f6cca867 | |
download | colour-8875d9d6dd48400a9ca1cf8c64889d860700d40c.zip |
First commitv1.0.0
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Cargo.toml | 11 | ||||
-rw-r--r-- | src/lib.rs | 152 |
3 files changed, 165 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3f17d87 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "colour" +version = "1.0.0" +authors = ["Ben Bridle"] +edition = "2021" +description = "Common 8bpc ARGB colour type" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +proportion = { "git" = "git://benbridle.com/proportion", "tag" = "v1.0.0" } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..649af4a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,152 @@ +use proportion::*; + +#[derive(Copy, Clone, Default)] +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<I: proportion::Internal>(bg: Self, fg: Self, proportion: Proportion<I>) -> Self { + let proportion = Proportion::<u8>::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<u32> for Colour { + fn from(value: u32) -> Self { + Colour { value } + } +} + +impl AsRef<u32> 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> { + let string: &str = &format!( + "Colour {{ r:{} g:{} b:{} a:{}}}", + self.red(), + self.green(), + self.blue(), + self.alpha() + ); + f.write_str(string) + } +} |