use rand::Rng; use serde_derive::{Deserialize, Serialize}; use std::fmt; use std::ops::{Div, Index, IndexMut, SubAssign}; #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] #[serde(tag = "type")] pub(crate) enum Patterns { Rainbow(Rainbow), Fade(Fade), ColorWipe(ColorWipe), Scanner(Scanner), FillRandom(FillRandom), FillUnstable(FillUnstable) } impl Iterator for Patterns { type Item = Strip; fn next(&mut self) -> Option { match self { Patterns::Rainbow(p) => p.next(), Patterns::Fade(p) => p.next(), Patterns::ColorWipe(p) => p.next(), Patterns::Scanner(p) => p.next(), Patterns::FillRandom(p) => p.next(), Patterns::FillUnstable(p) => p.next(), } } } /// /// a struct for an RGB color #[derive(Clone, Copy, Debug, Serialize, Deserialize, Default, Eq, Hash, PartialEq)] pub struct PixelColor { pub(crate) red: u8, pub(crate) green: u8, pub(crate) blue: u8, } impl fmt::Display for PixelColor { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[{},{},{}]", self.red, self.green, self.blue) } } impl Div for PixelColor { type Output = PixelColor; fn div(self, rhs: u8) -> Self::Output { PixelColor { red: self.red / rhs, green: self.green / rhs, blue: self.blue / rhs, } } } impl SubAssign for PixelColor { fn sub_assign(&mut self, rhs: Self) { println!("self.red {}, red {}", self.red, rhs.red); self.red = self.red.saturating_sub(rhs.red); self.green = self.red.saturating_sub(rhs.green); self.blue = self.red.saturating_sub(rhs.blue); } } /// /// a basic newtype based on a fix array size. /// #[derive(Copy, Clone)] pub struct Strip([PixelColor; N]); impl Default for Strip { fn default() -> Self { Strip([PixelColor::default(); N]) } } impl Index for Strip { type Output = PixelColor; fn index(&self, index: usize) -> &Self::Output { &self.0[index] } } impl IndexMut for Strip { fn index_mut(&mut self, index: usize) -> &mut PixelColor { &mut self.0[index] } } impl Strip { pub fn to_array(self) -> Vec { let mut data: Vec = vec![]; for i in 0..N { data.append(&mut vec![self[i].green, self[i].red, self[i].blue]); } data } pub fn fill(&mut self, color: PixelColor) { self.0.fill(color); } } /// # Rainbow pattern /// /// every pattern implement the iterator trait /// /// This pattern display a moving rainbow over the strip /// /// ### Note /// /// If max iteration is let to None, it's an infinite pattern. /// #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct Rainbow { pub(crate) current_iteration: usize, pub(crate) max_iteration: Option, pub(crate) step: Option, } impl Iterator for Rainbow { type Item = Strip; fn next(&mut self) -> Option { if let Some(nbr_iteration) = self.max_iteration { if nbr_iteration == self.current_iteration { return None; } } let mut strip = Strip::default(); let step = self.step.unwrap_or(255 / N); for i in 0..N { let pos = (i * step + self.current_iteration) as u8; strip[i] = wheel(pos) } self.current_iteration += 1; Some(strip) } } /// compute **rgb** pixel color according to the **hsv** wheel /// /// # Arguments /// /// * `index`: position in the hsv wheel /// /// returns: PixelColor /// fn wheel(index: u8) -> PixelColor { let pos = 255 - index; match pos { 0..=85 => PixelColor { red: 255 - (pos * 3), green: 0, blue: pos * 3, }, 86..=170 => { let pos = pos - 85; PixelColor { red: 0, green: pos * 3, blue: 255 - (pos * 3), } } _ => { let pos = pos - 170; PixelColor { red: pos * 3, green: 255 - (pos * 3), blue: 0, } } } } /// # Colorwipe pattern /// every pattern implement the iterator trait /// /// This pattern fill the strip with a specific color, one by one. /// /// ### Note /// /// setting max_iteration to None lead the pattern to loop infinitely /// #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct ColorWipe { pub(crate) current_iteration: usize, pub(crate) max_iteration: Option, pub(crate) color: PixelColor, pub(crate) background_color: Option, } impl Iterator for ColorWipe { type Item = Strip; fn next(&mut self) -> Option { let mut strip = Strip::default(); if let Some(c) = self.background_color { strip.fill(c); } let iteration = self.current_iteration % N; if let Some(max_iteration) = self.max_iteration { if self.current_iteration >= max_iteration { return None; } } for i in 0..iteration { strip[i] = self.color; } self.current_iteration += 1; Some(strip) } } /// # fade pattern /// fade from one color to an other #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct Fade { pub(crate) current_iteration: usize, pub(crate) nbr_iterations: usize, pub(crate) begin_color: PixelColor, pub(crate) end_color: PixelColor, } fn fade_value(value_start: u8, value_end: u8, index: usize, nbr_iter: usize) -> u8 { ((value_start as usize * (nbr_iter - index) + value_end as usize * index) / nbr_iter) as u8 } impl Iterator for Fade { type Item = Strip; fn next(&mut self) -> Option { let mut strip = Strip::default(); if self.current_iteration >= self.nbr_iterations { return None; } let red = fade_value( self.begin_color.red, self.end_color.red, self.current_iteration, self.nbr_iterations, ); let green = fade_value( self.begin_color.green, self.end_color.green, self.current_iteration, self.nbr_iterations, ); let blue = fade_value( self.begin_color.blue, self.end_color.blue, self.current_iteration, self.nbr_iterations, ); let current_color = PixelColor { red, green, blue }; strip.fill(current_color); self.current_iteration += 1; Some(strip) } } /// # scanner pattern /// color one pixel with a color and leave a train of this color fading to black /// /// # note /// /// background_color work only for color not set by scanner pattern #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct Scanner { pub(crate) current_iteration: usize, pub(crate) color: PixelColor, pub(crate) background_color: Option, } impl Iterator for Scanner { type Item = Strip; fn next(&mut self) -> Option { let mut strip = Strip::::default(); if let Some(c) = self.background_color { strip.fill(c); } else { strip.fill(PixelColor::default()); } let current_led = self.current_iteration % N; let min_led; if current_led < 8 { min_led = 0; } else { min_led = current_led - 8; } let mut c = self.color; for i in min_led..current_led { strip[i] = c; c = c / 2; } self.current_iteration += 1; Some(strip) } } /// # FillRandom /// /// fill strip with color then apply random variation to each pixel #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct FillRandom { pub(crate) color: PixelColor, pub(crate) stability: usize, pub(crate) max_iteration: Option, } impl Iterator for FillRandom { type Item = Strip; fn next(&mut self) -> Option { if let Some(iteration) = self.max_iteration { if iteration == 0 { return None; } else { self.max_iteration = Some(iteration - 1); } } let mut strip = Strip::::default(); let mut rng = rand::thread_rng(); for i in 0..N { let red_delta = rng.gen_range(0..self.stability) as u8; let green_delta = rng.gen_range(0..self.stability) as u8; let blue_delta = rng.gen_range(0..self.stability) as u8; let operation = rng.gen_bool(0.5); let red; let green; let blue; if operation { red = self.color.red.saturating_add(red_delta); green = self.color.green.saturating_add(green_delta); blue = self.color.blue.saturating_add(blue_delta); } else { red = self.color.red.saturating_sub(red_delta); green = self.color.green.saturating_sub(green_delta); blue = self.color.blue.saturating_sub(blue_delta); } let c = PixelColor { red, green, blue }; strip[i] = c; } Some(strip) } } /// # FillUnstable /// /// fill strip with color then apply same random variation to all pixel #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct FillUnstable { pub(crate) color: PixelColor, pub(crate) stability: usize, pub(crate) max_iteration: Option, } impl Iterator for FillUnstable { type Item = Strip; fn next(&mut self) -> Option { if let Some(iteration) = self.max_iteration { if iteration == 0 { return None; } else { self.max_iteration = Some(iteration - 1); } } let mut strip = Strip::::default(); let mut rng = rand::thread_rng(); let red_delta = rng.gen_range(0..self.stability) as u8; let green_delta = rng.gen_range(0..self.stability) as u8; let blue_delta = rng.gen_range(0..self.stability) as u8; let operation = rng.gen_bool(0.5); let red; let green; let blue; if operation { red = self.color.red.saturating_add(red_delta); green = self.color.green.saturating_add(green_delta); blue = self.color.blue.saturating_add(blue_delta); } else { red = self.color.red.saturating_sub(red_delta); green = self.color.green.saturating_sub(green_delta); blue = self.color.blue.saturating_sub(blue_delta); } strip.fill(PixelColor { red, green, blue }); Some(strip) } }