use std::ops::{Deref, DerefMut};
use color::{AlphaColor, ColorSpace, LinearSrgb, Srgb};
use glam::{vec4, Vec4};
use crate::prelude::{Interpolatable, Opacity};
use super::{ComponentVec, PointWise};
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Rgba(pub Vec4);
impl PointWise for Rgba {}
impl Opacity for Rgba {
fn set_opacity(&mut self, opacity: f32) -> &mut Self {
self.0.w = opacity;
self
}
}
impl Opacity for ComponentVec<Rgba> {
fn set_opacity(&mut self, opacity: f32) -> &mut Self {
self.iter_mut().for_each(|rgba| {
rgba.set_opacity(opacity);
});
self
}
}
impl<CS: ColorSpace> From<AlphaColor<CS>> for Rgba {
fn from(value: AlphaColor<CS>) -> Self {
let rgba = value.convert::<LinearSrgb>().components;
Self(Vec4::from_array(rgba))
}
}
impl From<Rgba> for AlphaColor<Srgb> {
fn from(value: Rgba) -> AlphaColor<Srgb> {
let linear_rgba = value.0.to_array();
AlphaColor::<LinearSrgb>::new(linear_rgba).convert()
}
}
impl Default for Rgba {
fn default() -> Self {
vec4(1.0, 0.0, 0.0, 1.0).into()
}
}
impl From<Vec4> for Rgba {
fn from(value: Vec4) -> Self {
Self(value)
}
}
impl Deref for Rgba {
type Target = Vec4;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Rgba {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Interpolatable for Rgba {
fn lerp(&self, target: &Self, t: f32) -> Self {
Self(self.0.lerp(target.0, t))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_convertion() {
let approx = |a: f32, b: f32| (a - b).abs() < 0.001;
let color = AlphaColor::from_rgb8(85, 133, 217);
assert!(approx(color.components[0], 0.333));
assert!(approx(color.components[1], 0.522));
assert!(approx(color.components[2], 0.851));
let linear_rgba = Rgba::from(color);
assert!(approx(linear_rgba.x, 0.091));
assert!(approx(linear_rgba.y, 0.235));
assert!(approx(linear_rgba.z, 0.694));
}
}