use std::{
fmt::{Debug, Display},
hash::Hash,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)] pub struct Rgb16(pub u16);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)] pub struct Rgb32(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)] pub struct Rgb32X(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)] pub struct Rgb64(pub u64);
pub trait ColorFmt: private::ColorFmt + Debug + Copy + Hash + Eq + Ord + Display + Sized {
type Raw: Copy + Hash + Eq + Ord + Default + Debug + Display + Send + Sync + Sized;
type Component: Copy + Hash + Eq + Ord + Default + Debug + Display + Send + Sync + Sized;
const RGB_BIT_WIDTH: u8;
const ALPHA_BIT_WIDTH: u8;
fn decode(
&self,
) -> (
Self::Component,
Self::Component,
Self::Component,
Self::Component,
);
fn encode(
red: Self::Component,
green: Self::Component,
blue: Self::Component,
alpha: Self::Component,
) -> Self;
fn invert_alpha(&mut self);
}
mod private {
pub trait ColorFmt {
fn raw_constant() -> libplum_sys::plum_flags;
}
}
macro_rules! impl_display {
($t:ty { $adjust_rgb:expr, $adjust_alpha:expr }) => {
impl Display for $t {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let (r, g, b, a) = self.decode();
if f.alternate() {
write!(f, "(R: {r}, G: {g}, B: {b}, A: {a})")
} else {
let adjust_rgb = $adjust_rgb;
let adjust_alpha = $adjust_alpha;
write!(
f,
"#{:02x}{:02x}{:02x}{:02x}",
adjust_rgb(r),
adjust_rgb(g),
adjust_rgb(b),
adjust_alpha(a),
)
}
}
}
};
}
impl_display!(Rgb16 { |rgb| rgb << 3 | rgb >> 2, |alpha| if alpha == 0 { 0 } else { 0xFF } });
impl_display!(Rgb32 { |rgb| rgb, |alpha| alpha });
impl_display!(Rgb32X { |rgb| (rgb >> 2) as u8, |alpha| alpha * 0x55 });
impl_display!(Rgb64 { |rgb| (rgb >> 8) as u8, |alpha| (alpha >> 8) as u8 });
impl ColorFmt for Rgb16 {
type Raw = u16;
type Component = u8;
const RGB_BIT_WIDTH: u8 = 5;
const ALPHA_BIT_WIDTH: u8 = 1;
fn decode(
&self,
) -> (
Self::Component,
Self::Component,
Self::Component,
Self::Component,
) {
let trunc = |shifted| (shifted & 0x1f) as u8;
(
trunc(self.0),
trunc(self.0 >> 5),
trunc(self.0 >> 10),
(self.0 >> 15) as u8,
)
}
fn encode(
red: Self::Component,
green: Self::Component,
blue: Self::Component,
alpha: Self::Component,
) -> Self {
Self(red as u16 | (green as u16) << 5 | (blue as u16) << 10 | (alpha as u16) << 15)
}
fn invert_alpha(&mut self) {
self.0 ^= 0x8000;
}
}
impl private::ColorFmt for Rgb16 {
fn raw_constant() -> libplum_sys::plum_flags {
libplum_sys::PLUM_COLOR_16
}
}
impl ColorFmt for Rgb32 {
type Raw = u32;
type Component = u8;
const RGB_BIT_WIDTH: u8 = 8;
const ALPHA_BIT_WIDTH: u8 = 8;
fn decode(
&self,
) -> (
Self::Component,
Self::Component,
Self::Component,
Self::Component,
) {
let [red, green, blue, alpha] = self.0.to_le_bytes();
(red, green, blue, alpha)
}
fn encode(
red: Self::Component,
green: Self::Component,
blue: Self::Component,
alpha: Self::Component,
) -> Self {
Self(u32::from_le_bytes([red, green, blue, alpha]))
}
fn invert_alpha(&mut self) {
self.0 ^= 0xFF000000;
}
}
impl private::ColorFmt for Rgb32 {
fn raw_constant() -> libplum_sys::plum_flags {
libplum_sys::PLUM_COLOR_32
}
}
impl ColorFmt for Rgb32X {
type Raw = u32;
type Component = u16;
const RGB_BIT_WIDTH: u8 = 10;
const ALPHA_BIT_WIDTH: u8 = 2;
fn decode(
&self,
) -> (
Self::Component,
Self::Component,
Self::Component,
Self::Component,
) {
let trunc = |shifted| (shifted & 0x3ff) as u16;
(
trunc(self.0),
trunc(self.0 >> 10),
trunc(self.0 >> 20),
trunc(self.0 >> 30),
)
}
fn encode(
red: Self::Component,
green: Self::Component,
blue: Self::Component,
alpha: Self::Component,
) -> Self {
Self(red as u32 | (green as u32) << 10 | (blue as u32) << 20 | (alpha as u32) << 30)
}
fn invert_alpha(&mut self) {
self.0 ^= 0xC0000000;
}
}
impl private::ColorFmt for Rgb32X {
fn raw_constant() -> libplum_sys::plum_flags {
libplum_sys::PLUM_COLOR_32X
}
}
impl ColorFmt for Rgb64 {
type Raw = u64;
type Component = u16;
const RGB_BIT_WIDTH: u8 = 16;
const ALPHA_BIT_WIDTH: u8 = 16;
fn decode(
&self,
) -> (
Self::Component,
Self::Component,
Self::Component,
Self::Component,
) {
let [red_l, red_h, green_l, green_h, blue_l, blue_h, alpha_l, alpha_h] =
self.0.to_le_bytes();
(
u16::from_le_bytes([red_l, red_h]),
u16::from_le_bytes([green_l, green_h]),
u16::from_le_bytes([blue_l, blue_h]),
u16::from_le_bytes([alpha_l, alpha_h]),
)
}
fn encode(
red: Self::Component,
green: Self::Component,
blue: Self::Component,
alpha: Self::Component,
) -> Self {
Self(red as u64 | (green as u64) << 16 | (blue as u64) << 32 | (alpha as u64) << 48)
}
fn invert_alpha(&mut self) {
self.0 ^= 0xFFFF000000000000;
}
}
impl private::ColorFmt for Rgb64 {
fn raw_constant() -> libplum_sys::plum_flags {
libplum_sys::PLUM_COLOR_64
}
}