summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Bridle <bridle.benjamin@gmail.com>2023-12-24 20:58:14 +1300
committerBen Bridle <bridle.benjamin@gmail.com>2023-12-24 20:58:14 +1300
commit8875d9d6dd48400a9ca1cf8c64889d860700d40c (patch)
tree3a8fbac5097bbf2d5dfc803ebcd80b44f6cca867
downloadcolour-8875d9d6dd48400a9ca1cf8c64889d860700d40c.zip
First commitv1.0.0
-rw-r--r--.gitignore2
-rw-r--r--Cargo.toml11
-rw-r--r--src/lib.rs152
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)
+ }
+}