219 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
mod scanner;
 | 
						|
mod fade;
 | 
						|
mod color_wipe;
 | 
						|
mod rainbow;
 | 
						|
mod fill_random;
 | 
						|
mod fill_unstable;
 | 
						|
mod blink;
 | 
						|
mod rain;
 | 
						|
mod fade_random;
 | 
						|
 | 
						|
use serde_derive::{Deserialize, Serialize};
 | 
						|
use std::fmt;
 | 
						|
use std::ops::{AddAssign, Div, Index, IndexMut, SubAssign};
 | 
						|
use rand::Rng;
 | 
						|
use rand::rngs::ThreadRng;
 | 
						|
use crate::patterns::blink::Blink;
 | 
						|
use crate::patterns::color_wipe::ColorWipe;
 | 
						|
use crate::patterns::fade::Fade;
 | 
						|
use crate::patterns::fade_random::FadeRandom;
 | 
						|
use crate::patterns::fill_random::FillRandom;
 | 
						|
use crate::patterns::fill_unstable::FillUnstable;
 | 
						|
use crate::patterns::rain::Rain;
 | 
						|
use crate::patterns::rainbow::Rainbow;
 | 
						|
use crate::patterns::scanner::Scanner;
 | 
						|
 | 
						|
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
 | 
						|
#[serde(tag = "type")]
 | 
						|
pub(crate) enum Patterns<const N: usize> {
 | 
						|
    Rainbow(Rainbow<N>),
 | 
						|
    Fade(Fade<N>),
 | 
						|
    ColorWipe(ColorWipe<N>),
 | 
						|
    Scanner(Scanner<N>),
 | 
						|
    FillRandom(FillRandom<N>),
 | 
						|
    FillUnstable(FillUnstable<N>),
 | 
						|
    Blink(Blink<N>),
 | 
						|
    Rain(Rain<N>),
 | 
						|
    FadeRandom(FadeRandom<N>)
 | 
						|
}
 | 
						|
 | 
						|
pub trait Pattern : Iterator {
 | 
						|
    type Strip;
 | 
						|
 | 
						|
    fn init(&mut self) -> Option<Self::Strip>;
 | 
						|
    fn is_last_iteration(&self) -> bool;
 | 
						|
}
 | 
						|
 | 
						|
impl<const N: usize> Iterator for Patterns<N> {
 | 
						|
    type Item = Strip<N>;
 | 
						|
 | 
						|
    fn next(&mut self) -> Option<Self::Item> {
 | 
						|
        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(),
 | 
						|
            Patterns::Blink(p) => p.next(),
 | 
						|
            Patterns::Rain(p) => p.next(),
 | 
						|
            Patterns::FadeRandom(p) => p.next(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<const N: usize> Pattern for Patterns<N> {
 | 
						|
    type Strip = Strip<N>;
 | 
						|
 | 
						|
    fn init(&mut self) -> Option<Self::Strip> {
 | 
						|
        match self {
 | 
						|
            Patterns::Rainbow(p) => p.init(),
 | 
						|
            Patterns::Fade(p) => p.init(),
 | 
						|
            Patterns::ColorWipe(p) => p.init(),
 | 
						|
            Patterns::Scanner(p) => p.init(),
 | 
						|
            Patterns::FillRandom(p) => p.init(),
 | 
						|
            Patterns::FillUnstable(p) => p.init(),
 | 
						|
            Patterns::Blink(p) => p.init(),
 | 
						|
            Patterns::Rain(p) => p.init(),
 | 
						|
            Patterns::FadeRandom(p) => p.init(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    fn is_last_iteration(&self) -> bool {
 | 
						|
        match self {
 | 
						|
            Patterns::Rainbow(p) => p.is_last_iteration(),
 | 
						|
            Patterns::Fade(p) => p.is_last_iteration(),
 | 
						|
            Patterns::ColorWipe(p) => p.is_last_iteration(),
 | 
						|
            Patterns::Scanner(p) => p.is_last_iteration(),
 | 
						|
            Patterns::FillRandom(p) => p.is_last_iteration(),
 | 
						|
            Patterns::FillUnstable(p) => p.is_last_iteration(),
 | 
						|
            Patterns::Blink(p) => p.is_last_iteration(),
 | 
						|
            Patterns::Rain(p) => p.is_last_iteration(),
 | 
						|
            Patterns::FadeRandom(p) => p.is_last_iteration(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
///
 | 
						|
/// 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<u8> 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) {
 | 
						|
        self.red = self.red.saturating_sub(rhs.red);
 | 
						|
        self.green = self.red.saturating_sub(rhs.green);
 | 
						|
        self.blue = self.red.saturating_sub(rhs.blue);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl AddAssign for PixelColor {
 | 
						|
    fn add_assign(&mut self, rhs: Self) {
 | 
						|
        self.red = self.red.saturating_add(rhs.red);
 | 
						|
        self.green = self.red.saturating_add(rhs.green);
 | 
						|
        self.blue = self.red.saturating_add(rhs.blue);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl PixelColor {
 | 
						|
    /// apply random delta to pixel and return computed value
 | 
						|
    ///
 | 
						|
    /// # Arguments
 | 
						|
    ///
 | 
						|
    /// * `pixel`: pixel to apply delta
 | 
						|
    /// * `stability`: amplitude of delta between 0 and `stability`
 | 
						|
    ///
 | 
						|
    /// returns: PixelColor
 | 
						|
    ///
 | 
						|
    pub fn random_delta(&self, stability: usize, rng: &mut ThreadRng) -> PixelColor {
 | 
						|
        let red_delta = rng.gen_range(0..stability) as u8;
 | 
						|
        let green_delta = rng.gen_range(0..stability) as u8;
 | 
						|
        let blue_delta = rng.gen_range(0..stability) as u8;
 | 
						|
        let operation = rng.gen_bool(0.5);
 | 
						|
        let red;
 | 
						|
        let green;
 | 
						|
        let blue;
 | 
						|
        if operation {
 | 
						|
            red = self.red.saturating_add(red_delta);
 | 
						|
            green = self.green.saturating_add(green_delta);
 | 
						|
            blue = self.blue.saturating_add(blue_delta);
 | 
						|
        } else {
 | 
						|
            red = self.red.saturating_sub(red_delta);
 | 
						|
            green = self.green.saturating_sub(green_delta);
 | 
						|
            blue = self.blue.saturating_sub(blue_delta);
 | 
						|
        }
 | 
						|
        PixelColor {
 | 
						|
            red,
 | 
						|
            green,
 | 
						|
            blue
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
///
 | 
						|
/// a basic newtype based on a fix array size.
 | 
						|
///
 | 
						|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
 | 
						|
pub struct Strip<const N: usize>([Option<PixelColor>; N]);
 | 
						|
 | 
						|
impl<const N: usize> Default for Strip<N> {
 | 
						|
    fn default() -> Self {
 | 
						|
        Strip([None; N])
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<const N: usize> Index<usize> for Strip<N> {
 | 
						|
    type Output = Option<PixelColor>;
 | 
						|
 | 
						|
    fn index(&self, index: usize) -> &Self::Output {
 | 
						|
        &self.0[index]
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<const N: usize> IndexMut<usize> for Strip<N> {
 | 
						|
    fn index_mut(&mut self, index: usize) -> &mut Option<PixelColor> {
 | 
						|
        &mut self.0[index]
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<const N: usize> Strip<N> {
 | 
						|
    pub fn to_array(self) -> Vec<u8> {
 | 
						|
        let mut data: Vec<u8> = vec![];
 | 
						|
 | 
						|
        for i in 0..N {
 | 
						|
            let color = self[i].unwrap_or(PixelColor::default());
 | 
						|
            data.append(&mut vec![color.green, color.red, color.blue]);
 | 
						|
        }
 | 
						|
        data
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn new(color: PixelColor) -> Strip<N> {
 | 
						|
        Strip { 0: [Some(color); N] }
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn fill(&mut self, color: PixelColor) {
 | 
						|
        self.0.fill(Some(color));
 | 
						|
    }
 | 
						|
} |