From a9abc2e05b70e1f45c05f761c41e858e2cbaaa9e Mon Sep 17 00:00:00 2001 From: Tobias Ollive Date: Fri, 11 Mar 2022 18:43:48 +0100 Subject: [PATCH] add rain pattern --- spectacle.yml | 22 +++++++--- src/patterns.rs | 22 +++++++++- src/patterns/blink.rs | 23 +++++++--- src/patterns/color_wipe.rs | 26 ++++++++--- src/patterns/fade.rs | 16 ++++--- src/patterns/fill_random.rs | 26 ++++++++--- src/patterns/fill_unstable.rs | 26 ++++++++--- src/patterns/rain.rs | 82 +++++++++++++++++++++++++---------- src/patterns/rainbow.rs | 21 ++++++--- src/patterns/scanner.rs | 30 ++++++++++--- 10 files changed, 220 insertions(+), 74 deletions(-) diff --git a/spectacle.yml b/spectacle.yml index f2e3a6f..64d4c99 100644 --- a/spectacle.yml +++ b/spectacle.yml @@ -17,17 +17,27 @@ # blue: 255 # max_iteration: 10 # period: 50 + - pattern: + type: Rain + color: &blue + red: 0 + green: 0 + blue: 255 + background_color: &black + red: 0 + green: 0 + blue: 0 + stability: 10 + lines: 5 + period: 200 - pattern: type: Fade - nbr_iterations: 20 + steps: 20 begin_color: &red red: 255 green: 0 blue: 0 - end_color: &blue - red: 0 - green: 0 - blue: 255 + end_color: *blue period: 200 - pattern: type: ColorWipe @@ -60,6 +70,6 @@ max_iteration: 200 period: 10 - pattern: - type: ColorWipe + type: Scanner color: *blue period: 100 \ No newline at end of file diff --git a/src/patterns.rs b/src/patterns.rs index c60428f..8cb3ba0 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -15,6 +15,7 @@ use crate::patterns::color_wipe::ColorWipe; use crate::patterns::fade::Fade; 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; @@ -28,12 +29,14 @@ pub(crate) enum Patterns { FillRandom(FillRandom), FillUnstable(FillUnstable), Blink(Blink), + Rain(Rain), } pub trait Pattern : Iterator { type Strip; - fn init(&self) -> Option; + fn init(&mut self) -> Option; + fn is_last_iteration(&self) -> bool; } impl Iterator for Patterns { @@ -48,6 +51,7 @@ impl Iterator for Patterns { Patterns::FillRandom(p) => p.next(), Patterns::FillUnstable(p) => p.next(), Patterns::Blink(p) => p.next(), + Patterns::Rain(p) => p.next(), } } } @@ -55,7 +59,7 @@ impl Iterator for Patterns { impl Pattern for Patterns { type Strip = Strip; - fn init(&self) -> Option { + fn init(&mut self) -> Option { match self { Patterns::Rainbow(p) => p.init(), Patterns::Fade(p) => p.init(), @@ -64,6 +68,20 @@ impl Pattern for Patterns { Patterns::FillRandom(p) => p.init(), Patterns::FillUnstable(p) => p.init(), Patterns::Blink(p) => p.init(), + Patterns::Rain(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(), } } } diff --git a/src/patterns/blink.rs b/src/patterns/blink.rs index 1df8f3e..f6ca981 100644 --- a/src/patterns/blink.rs +++ b/src/patterns/blink.rs @@ -17,9 +17,22 @@ pub struct Blink { impl Pattern for Blink { type Strip = Strip; - fn init(&self) -> Option { + fn init(&mut self) -> Option { None } + + fn is_last_iteration(&self) -> bool { + match self.max_iteration { + None => { false } + Some(max_iter) => { + if self.current_iteration >= max_iter { + true + } else { + false + } + } + } + } } impl Iterator for Blink { @@ -29,12 +42,10 @@ impl Iterator for Blink { let value = self.fade.next(); match value { None => { - if let Some(iter_max) = self.max_iteration { - if self.current_iteration >= iter_max { - return None; - } - self.current_iteration += 1; + if self.is_last_iteration() { + return None; } + self.current_iteration += 1; self.fade.current_iteration = 0; std::mem::swap(&mut self.fade.begin_color, &mut self.fade.end_color); self.fade.next() diff --git a/src/patterns/color_wipe.rs b/src/patterns/color_wipe.rs index af441bd..a8ff360 100644 --- a/src/patterns/color_wipe.rs +++ b/src/patterns/color_wipe.rs @@ -23,29 +23,43 @@ pub struct ColorWipe { impl Pattern for ColorWipe { type Strip = Strip; - fn init(&self) -> Option { + fn init(&mut self) -> Option { if let Some(color) = self.background_color { Some(Strip::::new(color)) } else { None } } + + fn is_last_iteration(&self) -> bool { + match self.max_iteration { + None => { false } + Some(max_iter) => { + if self.current_iteration >= max_iter { + true + } else { + false + } + } + } + } } impl Iterator for ColorWipe { type Item = Strip; fn next(&mut self) -> Option { + if self.is_last_iteration() { + return None; + } + 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] = Some(self.color); diff --git a/src/patterns/fade.rs b/src/patterns/fade.rs index 4bfeee6..d660846 100644 --- a/src/patterns/fade.rs +++ b/src/patterns/fade.rs @@ -8,7 +8,7 @@ use serde::{Serialize, Deserialize}; pub struct Fade { #[serde(default)] pub(crate) current_iteration: usize, - pub(crate) nbr_iterations: usize, + pub(crate) steps: usize, pub(crate) begin_color: PixelColor, pub(crate) end_color: PixelColor, } @@ -20,9 +20,13 @@ fn fade_value(value_start: u8, value_end: u8, index: usize, nbr_iter: usize) -> impl Pattern for Fade { type Strip = Strip; - fn init(&self) -> Option { + fn init(&mut self) -> Option { None } + + fn is_last_iteration(&self) -> bool { + self.current_iteration >= self.steps + } } impl Iterator for Fade { @@ -31,7 +35,7 @@ impl Iterator for Fade { fn next(&mut self) -> Option { let mut strip = Strip::default(); - if self.current_iteration >= self.nbr_iterations { + if self.is_last_iteration() { return None; } @@ -39,19 +43,19 @@ impl Iterator for Fade { self.begin_color.red, self.end_color.red, self.current_iteration, - self.nbr_iterations, + self.steps, ); let green = fade_value( self.begin_color.green, self.end_color.green, self.current_iteration, - self.nbr_iterations, + self.steps, ); let blue = fade_value( self.begin_color.blue, self.end_color.blue, self.current_iteration, - self.nbr_iterations, + self.steps, ); let current_color = PixelColor { red, green, blue }; diff --git a/src/patterns/fill_random.rs b/src/patterns/fill_random.rs index c0d41a4..727b37a 100644 --- a/src/patterns/fill_random.rs +++ b/src/patterns/fill_random.rs @@ -11,26 +11,37 @@ pub struct FillRandom { pub(crate) color: PixelColor, pub(crate) stability: usize, pub(crate) max_iteration: Option, + #[serde(default)] + pub(crate) current_iteration: usize, } impl Pattern for FillRandom { type Strip = Strip; - fn init(&self) -> Option { + fn init(&mut self) -> Option { None } + + fn is_last_iteration(&self) -> bool { + match self.max_iteration { + None => { false } + Some(max_iter) => { + if self.current_iteration >= max_iter { + true + } else { + false + } + } + } + } } 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); - } + if self.is_last_iteration() { + return None; } let mut strip = Strip::::default(); @@ -55,6 +66,7 @@ impl Iterator for FillRandom { let c = PixelColor { red, green, blue }; strip[i] = Some(c); } + self.current_iteration += 1; Some(strip) } } \ No newline at end of file diff --git a/src/patterns/fill_unstable.rs b/src/patterns/fill_unstable.rs index 09331d9..4a39b4c 100644 --- a/src/patterns/fill_unstable.rs +++ b/src/patterns/fill_unstable.rs @@ -11,26 +11,37 @@ pub struct FillUnstable { pub(crate) color: PixelColor, pub(crate) stability: usize, pub(crate) max_iteration: Option, + #[serde(default)] + pub(crate) current_iteration: usize, } impl Pattern for FillUnstable { type Strip = Strip; - fn init(&self) -> Option { + fn init(&mut self) -> Option { None } + + fn is_last_iteration(&self) -> bool { + match self.max_iteration { + None => { false } + Some(max_iter) => { + if self.current_iteration >= max_iter { + true + } else { + false + } + } + } + } } 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); - } + if self.is_last_iteration() { + return None; } let mut strip = Strip::::default(); @@ -52,6 +63,7 @@ impl Iterator for FillUnstable { blue = self.color.blue.saturating_sub(blue_delta); } strip.fill(PixelColor { red, green, blue }); + self.current_iteration += 1; Some(strip) } } \ No newline at end of file diff --git a/src/patterns/rain.rs b/src/patterns/rain.rs index 47a1c18..990e4ae 100644 --- a/src/patterns/rain.rs +++ b/src/patterns/rain.rs @@ -1,47 +1,81 @@ -use crate::patterns::PixelColor; +use rand::Rng; +use crate::patterns::{Pattern, PixelColor}; use crate::Strip; use serde::{Serialize, Deserialize}; -/// # scanner pattern -/// color one pixel with a color and leave a train of this color fading to black +/// # rain pattern +/// randomly fall colors from top or bottom. +/// /// /// # note /// -/// background_color work only for color not set by scanner pattern +/// `stability` is the probability (between 0 an 1) that any led will light on. +/// The probability of at least one led light on is `stability*number of lines` +/// +/// this pattern works only for 5x5 square #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] -pub struct Scanner { - #[serde(default)] - current_iteration: usize, +pub struct Rain { pub(crate) color: PixelColor, pub(crate) background_color: Option, + pub(crate) max_iteration: Option, + #[serde(default)] + pub(crate) current_iteration: usize, pub(crate) stability: usize, + pub(crate) lines: usize, #[serde(skip)] - strip : Strip, + drops : Strip, } -impl Iterator for Scanner { +impl Pattern for Rain { + type Strip = Strip; + + fn init(&mut self) -> Option { + if let Some(color) = self.background_color { + self.drops = Strip::::new(color); + Some(Strip::::new(color)) + } else { + None + } + } + + fn is_last_iteration(&self) -> bool { + match self.max_iteration { + None => { false } + Some(max_iter) => { + if self.current_iteration >= max_iter { + true + } else { + false + } + } + } + } +} + +impl Iterator for Rain { 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; + for i in 0..(N-self.lines) { + strip[i+self.lines] = self.drops[i]; } - let mut c = self.color; - for i in min_led..current_led { - strip[i] = Some(c); - c = c / 2; + let mut rng = rand::thread_rng(); + for i in 0..self.lines { + if rng.gen_bool(self.stability as f64 / 100 as f64) { + strip[i] = Some(self.color); + } else { + let c = strip[i+self.lines]; + if self.background_color != c && c != Some(PixelColor::default()) { + strip[i] = Some(strip[i+self.lines].unwrap()/ 2); + } else { + strip[i] = self.background_color; + } + } } + self.drops = strip.clone(); + self.current_iteration += 1; Some(strip) } diff --git a/src/patterns/rainbow.rs b/src/patterns/rainbow.rs index 629e896..590f9af 100644 --- a/src/patterns/rainbow.rs +++ b/src/patterns/rainbow.rs @@ -23,19 +23,30 @@ pub struct Rainbow { impl Pattern for Rainbow { type Strip = Strip; - fn init(&self) -> Option { + fn init(&mut self) -> Option { None } + + fn is_last_iteration(&self) -> bool { + match self.max_iteration { + None => { false } + Some(max_iter) => { + if self.current_iteration >= max_iter { + true + } else { + false + } + } + } + } } 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; - } + if self.is_last_iteration() { + return None; } let mut strip = Strip::default(); let step = self.step.unwrap_or(255 / N); diff --git a/src/patterns/scanner.rs b/src/patterns/scanner.rs index 73b74e1..bfd2022 100644 --- a/src/patterns/scanner.rs +++ b/src/patterns/scanner.rs @@ -14,29 +14,49 @@ pub struct Scanner { pub(crate) current_iteration: usize, pub(crate) color: PixelColor, pub(crate) background_color: Option, + #[serde(default)] + pub(crate) max_iteration: Option, } impl Pattern for Scanner { type Strip = Strip; - fn init(&self) -> Option { + fn init(&mut self) -> Option { if let Some(color) = self.background_color { Some(Strip::::new(color)) } else { None } } + + fn is_last_iteration(&self) -> bool { + match self.max_iteration { + None => { false } + Some(max_iter) => { + if self.current_iteration >= max_iter { + true + } else { + false + } + } + } + } } 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); + if self.is_last_iteration() { + return None; + } + + let mut strip : Strip; + + if let Some(color) = self.background_color { + strip = Strip::new(color); } else { - strip.fill(PixelColor::default()); + strip = Strip::default(); } let current_led = self.current_iteration % N;