use std::fmt;
use std::mem;
use std::mem::ManuallyDrop;
use std::str::FromStr;
use crate::math::Zero;
#[repr(C)]
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Default)]
pub struct Rgba8 {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Rgba8 {
pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
pub fn invert(self) -> Self {
Self::new(0xff - self.r, 0xff - self.g, 0xff - self.b, self.a)
}
pub const fn alpha(self, a: u8) -> Self {
Self::new(self.r, self.g, self.b, a)
}
pub fn align<'a, S: 'a, T: AsRef<[S]> + ?Sized>(bytes: &'a T) -> &'a [Rgba8] {
let bytes = bytes.as_ref();
let (head, body, tail) = unsafe { bytes.align_to::<Rgba8>() };
if !(head.is_empty() && tail.is_empty()) {
panic!("Rgba8::align: input is not a valid `Rgba8` buffer");
}
body
}
pub fn into_vec(bytes: Vec<u8>) -> Vec<Self> {
if bytes.len() % mem::size_of::<Rgba8>() != 0 {
panic!("Rgba8::into_vec: input is not a valid `Rgba8` buffer");
}
assert_eq!(bytes.capacity() % 4, 0);
let bytes = ManuallyDrop::new(bytes);
let ptr = bytes.as_ptr();
let length = bytes.len() / 4;
let capacity = bytes.capacity() / 4;
unsafe { Vec::from_raw_parts(ptr as *mut Rgba8, length, capacity) }
}
}
impl Zero for Rgba8 {
const ZERO: Self = Rgba8::TRANSPARENT;
fn is_zero(&self) -> bool {
self == &Self::ZERO
}
}
impl fmt::Display for Rgba8 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)?;
if self.a != 0xff {
write!(f, "{:02x}", self.a)?;
}
Ok(())
}
}
impl From<Rgba<f32>> for Rgba8 {
fn from(rgba: Rgba<f32>) -> Self {
Self {
r: (rgba.r * 255.0).round() as u8,
g: (rgba.g * 255.0).round() as u8,
b: (rgba.b * 255.0).round() as u8,
a: (rgba.a * 255.0).round() as u8,
}
}
}
impl From<u32> for Rgba8 {
fn from(rgba: u32) -> Self {
unsafe { std::mem::transmute(rgba) }
}
}
impl From<Rgba8> for u32 {
fn from(rgba: Rgba8) -> Self {
unsafe { std::mem::transmute(rgba) }
}
}
impl FromStr for Rgba8 {
type Err = std::num::ParseIntError;
fn from_str(hex_code: &str) -> Result<Self, Self::Err> {
let r: u8 = u8::from_str_radix(&hex_code[1..3], 16)?;
let g: u8 = u8::from_str_radix(&hex_code[3..5], 16)?;
let b: u8 = u8::from_str_radix(&hex_code[5..7], 16)?;
let a: u8 = if hex_code.len() >= 9 {
u8::from_str_radix(&hex_code[7..9], 16)?
} else {
0xff
};
Ok(Rgba8 { r, g, b, a })
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Rgb8 {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl From<Rgba8> for Rgb8 {
fn from(rgba: Rgba8) -> Self {
Self {
r: rgba.r,
g: rgba.g,
b: rgba.b,
}
}
}
impl fmt::Display for Rgb8 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "#{:02X}{:02X}{:02X}", self.r, self.g, self.b)
}
}
#[repr(C)]
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct Rgba<T> {
pub r: T,
pub g: T,
pub b: T,
pub a: T,
}
impl<T> Rgba<T> {
pub const fn new(r: T, g: T, b: T, a: T) -> Self {
Self { r, g, b, a }
}
}
impl Rgba<f32> {
pub fn invert(self) -> Self {
Self::new(1.0 - self.r, 1.0 - self.g, 1.0 - self.b, self.a)
}
}
impl From<Rgba8> for Rgba<f32> {
fn from(rgba8: Rgba8) -> Self {
Self {
r: (rgba8.r as f32 / 255.0),
g: (rgba8.g as f32 / 255.0),
b: (rgba8.b as f32 / 255.0),
a: (rgba8.a as f32 / 255.0),
}
}
}
impl<T> From<Rgba<T>> for [T; 4] {
fn from(rgba: Rgba<T>) -> Self {
[rgba.r, rgba.g, rgba.b, rgba.a]
}
}
pub trait Color {
const WHITE: Self;
const BLACK: Self;
const TRANSPARENT: Self;
const RED: Self;
const GREEN: Self;
const BLUE: Self;
const YELLOW: Self;
}
impl Color for Rgba8 {
const WHITE: Self = Self::new(0xff, 0xff, 0xff, 0xff);
const BLACK: Self = Self::new(0, 0, 0, 0xff);
const TRANSPARENT: Self = Self::new(0, 0, 0, 0);
const RED: Self = Self::new(0xff, 0x0, 0, 0xff);
const GREEN: Self = Self::new(0, 0xff, 0, 0xff);
const BLUE: Self = Self::new(0, 0, 0xff, 0xff);
const YELLOW: Self = Self::new(0xff, 0xff, 0, 0xff);
}
impl Color for Rgba<f32> {
const WHITE: Self = Rgba::new(1.0, 1.0, 1.0, 1.0);
const BLACK: Self = Rgba::new(0.0, 0.0, 0.0, 1.0);
const TRANSPARENT: Self = Rgba::new(0.0, 0.0, 0.0, 0.0);
const RED: Self = Rgba::new(1.0, 0.0, 0.0, 1.0);
const GREEN: Self = Rgba::new(0.0, 1.0, 0.0, 1.0);
const BLUE: Self = Rgba::new(0.0, 0.0, 1.0, 1.0);
const YELLOW: Self = Self::new(1.0, 1.0, 0.0, 1.0);
}