#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Color {
pub const TRANSPARENT: Self = Self::rgba(0, 0, 0, 0);
pub const BLACK: Self = Self::rgb(0, 0, 0);
pub const WHITE: Self = Self::rgb(255, 255, 255);
#[inline]
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b, a: 255 }
}
#[inline]
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
#[inline]
pub const fn from_argb8888(v: u32) -> Self {
Self {
a: (v >> 24) as u8,
r: (v >> 16) as u8,
g: (v >> 8) as u8,
b: v as u8,
}
}
#[inline]
pub const fn from_rgb888(v: u32) -> Self {
Self::from_argb8888(v | 0xFF00_0000)
}
#[inline]
pub const fn to_argb8888(self) -> u32 {
(self.a as u32) << 24 | (self.r as u32) << 16 | (self.g as u32) << 8 | self.b as u32
}
#[inline]
pub const fn is_opaque(self) -> bool {
self.a == 255
}
#[inline]
pub const fn is_transparent(self) -> bool {
self.a == 0
}
#[inline]
pub const fn with_alpha(self, a: u8) -> Color {
Color { a, ..self }
}
#[inline]
pub const fn mix(self, other: Color, t: u8) -> Color {
Color {
r: lerp(self.r, other.r, t),
g: lerp(self.g, other.g, t),
b: lerp(self.b, other.b, t),
a: lerp(self.a, other.a, t),
}
}
}
#[inline]
const fn lerp(a: u8, b: u8, t: u8) -> u8 {
let (a, b, t) = (a as u32, b as u32, t as u32);
((a * (255 - t) + b * t + 127) / 255) as u8
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn argb_round_trip() {
let c = Color::rgba(0x12, 0x34, 0x56, 0x78);
assert_eq!(c.to_argb8888(), 0x7812_3456);
assert_eq!(Color::from_argb8888(0x7812_3456), c);
}
#[test]
fn rgb_is_opaque() {
assert!(Color::from_rgb888(0x1E1E2E).is_opaque());
assert_eq!(Color::from_rgb888(0x1E1E2E).to_argb8888(), 0xFF1E_1E2E);
}
}