use core::{array::IntoIter, iter::Iterator, ops::Index};
use crate::util::component::Component;
use super::{ColorCorrection, LinearSrgb};
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum LedColor<C> {
Rgb(LedRgb<C>),
Rgbw(LedRgbw<C>),
}
impl<C: Component> LedColor<C> {
pub fn from_linear_srgb(
linear_srgb: LinearSrgb,
channels: LedChannels,
brightness: f32,
correction: ColorCorrection,
) -> LedColor<C> {
match channels {
LedChannels::Rgb(rgb_channels) => {
let rgb = LedRgb::from_linear_srgb(linear_srgb, brightness, correction);
LedColor::Rgb(rgb.reorder(rgb_channels))
}
LedChannels::Rgbw(rgbw_channels) => {
let rgbw = LedRgbw::from_linear_srgb(linear_srgb, brightness, correction);
LedColor::Rgbw(rgbw.reorder(rgbw_channels))
}
}
}
}
impl<C> AsRef<[C]> for LedColor<C> {
#[inline]
fn as_ref(&self) -> &[C] {
use LedColor::*;
match self {
Rgb(rgb) => rgb.as_ref(),
Rgbw(rgbw) => rgbw.as_ref(),
}
}
}
pub enum LedColorIntoIter<C> {
Rgb(IntoIter<C, 3>),
Rgbw(IntoIter<C, 4>),
}
impl<C> Iterator for LedColorIntoIter<C> {
type Item = C;
fn next(&mut self) -> Option<Self::Item> {
use LedColorIntoIter::*;
match self {
Rgb(rgb_iter) => rgb_iter.next(),
Rgbw(rgbw_iter) => rgbw_iter.next(),
}
}
}
impl<C> IntoIterator for LedColor<C> {
type Item = C;
type IntoIter = LedColorIntoIter<C>;
fn into_iter(self) -> Self::IntoIter {
use LedColor::*;
match self {
Rgb(rgb) => LedColorIntoIter::Rgb(rgb.into_iter()),
Rgbw(rgbw) => LedColorIntoIter::Rgbw(rgbw.into_iter()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct LedRgb<C>([C; 3]);
impl<C: Component> LedRgb<C> {
pub fn from_linear_srgb(
linear_srgb: LinearSrgb,
brightness: f32,
correction: ColorCorrection,
) -> Self {
let LinearSrgb { red, green, blue } = linear_srgb;
let red = red * correction.red;
let green = green * correction.green;
let blue = blue * correction.blue;
let red = red * brightness;
let green = green * brightness;
let blue = blue * brightness;
let red = red.clamp(0., 1.);
let green = green.clamp(0., 1.);
let blue = blue.clamp(0., 1.);
Self([
C::from_normalized_f32(red),
C::from_normalized_f32(green),
C::from_normalized_f32(blue),
])
}
pub fn reorder(self, channels: RgbChannels) -> Self {
Self(channels.reorder(self.0))
}
}
impl<C> AsRef<[C]> for LedRgb<C> {
#[inline]
fn as_ref(&self) -> &[C] {
&self.0
}
}
impl<C> IntoIterator for LedRgb<C> {
type Item = C;
type IntoIter = IntoIter<C, 3>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<C> Index<usize> for LedRgb<C> {
type Output = C;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct LedRgbw<C>([C; 4]);
impl<C: Component> LedRgbw<C> {
pub fn from_linear_srgb(
linear_srgb: LinearSrgb,
brightness: f32,
correction: ColorCorrection,
) -> Self {
let LinearSrgb { red, green, blue } = linear_srgb;
let white = red.min(green).min(blue);
let red = red - white;
let green = green - white;
let blue = blue - white;
let red = red * correction.red;
let green = green * correction.green;
let blue = blue * correction.blue;
let red = red * brightness;
let green = green * brightness;
let blue = blue * brightness;
let white = white * brightness;
let red = red.clamp(0., 1.);
let green = green.clamp(0., 1.);
let blue = blue.clamp(0., 1.);
let white = white.clamp(0., 1.);
Self([
C::from_normalized_f32(red),
C::from_normalized_f32(green),
C::from_normalized_f32(blue),
C::from_normalized_f32(white),
])
}
pub fn reorder(self, channels: RgbwChannels) -> Self {
Self(channels.reorder(self.0))
}
}
impl<C> AsRef<[C]> for LedRgbw<C> {
#[inline]
fn as_ref(&self) -> &[C] {
&self.0
}
}
impl<C> IntoIterator for LedRgbw<C> {
type Item = C;
type IntoIter = IntoIter<C, 4>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<C> Index<usize> for LedRgbw<C> {
type Output = C;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum LedChannels {
Rgb(RgbChannels),
Rgbw(RgbwChannels),
}
impl LedChannels {
pub const fn channel_count(&self) -> usize {
match self {
LedChannels::Rgb(_) => 3,
LedChannels::Rgbw(_) => 4,
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum RgbChannels {
RGB,
RBG,
GRB,
GBR,
BRG,
BGR,
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum RgbwChannels {
WRGB,
RWGB,
RGWB,
RGBW,
WRBG,
RWBG,
RBWG,
RBGW,
WGRB,
GWRB,
GRWB,
GRBW,
WGBR,
GWBR,
GBWR,
GBRW,
WBRG,
BWRG,
BRWG,
BRGW,
WBGR,
BWGR,
BGWR,
BGRW,
}
impl RgbChannels {
pub fn reorder<Word: Copy>(&self, rgb: [Word; 3]) -> [Word; 3] {
use RgbChannels::*;
match self {
RGB => [rgb[0], rgb[1], rgb[2]],
RBG => [rgb[0], rgb[2], rgb[1]],
GRB => [rgb[1], rgb[0], rgb[2]],
GBR => [rgb[1], rgb[2], rgb[0]],
BRG => [rgb[2], rgb[0], rgb[1]],
BGR => [rgb[2], rgb[1], rgb[0]],
}
}
}
impl RgbwChannels {
pub fn reorder<Word: Copy>(&self, rgbw: [Word; 4]) -> [Word; 4] {
use RgbwChannels::*;
match self {
WRGB => [rgbw[3], rgbw[0], rgbw[1], rgbw[2]],
RWGB => [rgbw[0], rgbw[3], rgbw[1], rgbw[2]],
RGWB => [rgbw[0], rgbw[1], rgbw[3], rgbw[2]],
RGBW => [rgbw[0], rgbw[1], rgbw[2], rgbw[3]],
WRBG => [rgbw[3], rgbw[0], rgbw[2], rgbw[1]],
RWBG => [rgbw[0], rgbw[3], rgbw[2], rgbw[1]],
RBWG => [rgbw[0], rgbw[2], rgbw[3], rgbw[1]],
RBGW => [rgbw[0], rgbw[2], rgbw[1], rgbw[3]],
WGRB => [rgbw[3], rgbw[1], rgbw[0], rgbw[2]],
GWRB => [rgbw[1], rgbw[3], rgbw[0], rgbw[2]],
GRWB => [rgbw[1], rgbw[0], rgbw[3], rgbw[2]],
GRBW => [rgbw[1], rgbw[0], rgbw[2], rgbw[3]],
WGBR => [rgbw[3], rgbw[1], rgbw[2], rgbw[0]],
GWBR => [rgbw[1], rgbw[3], rgbw[2], rgbw[0]],
GBWR => [rgbw[1], rgbw[2], rgbw[3], rgbw[0]],
GBRW => [rgbw[1], rgbw[2], rgbw[0], rgbw[3]],
WBRG => [rgbw[3], rgbw[2], rgbw[0], rgbw[1]],
BWRG => [rgbw[2], rgbw[3], rgbw[0], rgbw[1]],
BRWG => [rgbw[2], rgbw[0], rgbw[3], rgbw[1]],
BRGW => [rgbw[2], rgbw[0], rgbw[1], rgbw[3]],
WBGR => [rgbw[3], rgbw[2], rgbw[1], rgbw[0]],
BWGR => [rgbw[2], rgbw[3], rgbw[1], rgbw[0]],
BGWR => [rgbw[2], rgbw[1], rgbw[3], rgbw[0]],
BGRW => [rgbw[2], rgbw[1], rgbw[0], rgbw[3]],
}
}
}