diff --git a/src/main.rs b/src/main.rs index 9fc4771..913205c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,14 +20,18 @@ mod view; mod stripe_driver; mod jack; +mod patterns; +mod scene_library; + use crate::{ view::ColorGrid, fixture::Fixture, setup::LightingSetup, stripe_driver::StripeDriver, - util::get_angle -}; + util::get_angle, + scene_library::SceneLibrary +}; #[derive(Clone)] pub struct Inputs { @@ -42,204 +46,6 @@ pub struct Inputs { wave_peak: f32 } - -struct Breathing { inputs: Arc> } -impl ColorGrid for Breathing { - fn get(&self, p: &Vector2) -> Rgb { - let inputs = self.inputs.read().unwrap().clone(); - - let millis = inputs.t.as_millis(); - - let p1 = p + Vector2::new(0.0,0.5); - let r2 = p1.x*p1.x + p1.y*p1.y; - let v = if r2 > 1.0 { 1.0 } else { r2 }; - let phi = ( get_angle(&p1) ); - let mirrorphi = if phi < 0.5 { phi } else { 1.0-phi }; - let gamma = - ( - (5.0) * - mirrorphi * - ( - 0.5+ 0.5*f32::sin( - inputs.t.as_millis() as f32 - / inputs.cycle_len.as_millis() as f32 - ) - ) - ) % 1.0; - - Rgb::from_color( - &Hsv::>::new( - Turns( 0.25+0.25*f32::sin(millis as f32/8000.0) + gamma*0.5 ), - 0.5 + r2 * 0.5, - inputs.wave_peak, - ) - ) - } -} -struct PastelFade { inputs: Arc> } -impl ColorGrid for PastelFade { - fn get(&self, p: &Vector2) -> Rgb { - let inputs = self.inputs.read().unwrap().clone(); -// let millis = self - - let i = ( inputs.t.as_millis() as f32 / (4.0*inputs.cycle_len.as_millis() as f32) ) % 1.0; - - Rgb::from_color( - &Hsv::>::new( - Turns( i ), - 0.5, - (4.0*i) %1.0 - ) - ) - } -} - -struct UbootPrüfstandFade { inputs: Arc> } -impl ColorGrid for UbootPrüfstandFade { - fn get(&self, p: &Vector2) -> Rgb { - let inputs = self.inputs.read().unwrap().clone(); -// let millis = self - - let i = ( inputs.t.as_millis() as f32 / (4.0*inputs.cycle_len.as_millis() as f32) ) % 1.0; - - let pi2 = 2.0 * 3.1415926; - - let col1 = - Rgb::from_color( - &Hsv::>::new( - Turns( 0.65 ), - 0.9, - 0.5 + 0.5*f32::sin(i*pi2),//(4.0*i) %1.0 - ) - ); - - let col2 = Rgb::new(0.5+0.5*f32::sin(i*pi2), 0.0, 0.0); - - let p = ( inputs.t.as_millis() as f32 / (32.0*inputs.cycle_len.as_millis() as f32)) % 1.0; - if p >= 0.7 { - col2 - } else { - col1 - } - } -} - -struct ArcticRain { inputs: Arc> } -impl ColorGrid for ArcticRain { - fn get(&self, p: &Vector2) -> Rgb { - let inputs = self.inputs.read().unwrap().clone(); -// let millis = self - - let i = ( inputs.t.as_millis() as f32 / (4.0*inputs.cycle_len.as_millis() as f32) ) % 1.0; - - let pi2 = 2.0 * 3.1415926; - - let col1 = - Rgb::from_color( - &Hsv::>::new( - Turns( 0.65 ), - 0.9, - 1.0 - ((i + (2.0-p.y/4.0)) * 12.0) % 1.0, -// (f32::sin(-p.y+i) * 12.0) % 1.0, - ) - ); - - col1 - } -} - -enum Waveform { - Sawtooth{ pulse_width: Duration }, - Square{ }, -} - -struct Strobe { - inputs: Arc>, - //waveform: Waveform, - subdivision: u32, -} - -impl ColorGrid for Strobe { - fn get(&self, p: &Vector2) -> Rgb { - let inputs = self.inputs.read().unwrap().clone(); - - let t = (self.subdivision as f32 * inputs.t.as_millis() as f32 / inputs.cycle_len.as_millis() as f32) % 1.0; - - if t < 0.6 { - Rgb::new(0.6, 0.6, 0.6) - } else { - Rgb::new(0.0, 0.0, 0.0) - } - } -} - - -pub struct SceneLibrary { - library: Vec< Box >, - current_scene: RwLock, - inputs: Arc>, - - transition_length: Duration, -// transition_curve: enum { Constant, Linear, Sigmoid, Sinus } -} - -impl SceneLibrary { - pub fn new( inputs: Arc> ) -> Self { - SceneLibrary { - library: vec![ - // 0 - Box::new( Breathing{ inputs: inputs.clone() } ), - - // 1 - 4 - Box::new( Strobe{ inputs: inputs.clone(), subdivision: 4 } ), - Box::new( Strobe{ inputs: inputs.clone(), subdivision: 8 } ), - Box::new( Strobe{ inputs: inputs.clone(), subdivision: 12 } ), - Box::new( Strobe{ inputs: inputs.clone(), subdivision: 16 } ), - - // others - Box::new( PastelFade{ inputs: inputs.clone() } ), - Box::new( UbootPrüfstandFade{ inputs: inputs.clone() } ), - Box::new( ArcticRain{ inputs: inputs.clone() } ), - ], - current_scene: RwLock::new(0), - inputs, - transition_length: Duration::from_millis(200), - } - } -} - -impl ColorGrid for SceneLibrary { - fn get(&self, p: &Vector2) -> Rgb { - let inputs = self.inputs.read().unwrap().clone(); - - let sc = *self.current_scene.read().unwrap(); - - if inputs.scene_select == sc { - // display only one animation - self.library[ sc ].get(p) - } else { - // display transition - let cur_scene = &self.library[ sc ]; - let nxt_scene = &self.library[ inputs.scene_select ]; - - // crossfade param - let w = ( inputs.transition_time.as_millis() as f32 / self.transition_length.as_millis() as f32 ); - - if w >= 1.0 { - // change own state: - *self.current_scene.write().unwrap() = inputs.scene_select; - } - - cur_scene.get(p) - .lerp( - &nxt_scene.get(p), - w - ) - } - } -} - - #[async_std::main] async fn main() { let event_loop = EventLoop::new().unwrap(); @@ -276,7 +82,7 @@ async fn main() { .offset(Vector2::new(-0.5, 0.0)), Fixture::new_stripe() -// .with_driver( Box::new(StripeDriver::new("192.168.0.112:4210", socket.clone())) ) + .with_driver( Box::new(StripeDriver::new("192.168.0.112:4210", socket.clone())) ) .offset(Vector2::new(-0.4, 0.0)), Fixture::new_stripe() @@ -284,7 +90,7 @@ async fn main() { .offset(Vector2::new(0.4, 0.0)), Fixture::new_stripe() -// .with_driver( Box::new(StripeDriver::new("192.168.0.114:4210", socket.clone()))) + .with_driver( Box::new(StripeDriver::new("192.168.0.114:4210", socket.clone()))) .offset(Vector2::new(0.5, 0.0)) ], diff --git a/src/patterns/arctic_rain.rs b/src/patterns/arctic_rain.rs new file mode 100644 index 0000000..1dd44c6 --- /dev/null +++ b/src/patterns/arctic_rain.rs @@ -0,0 +1,39 @@ +use { + std::num::NonZeroU32, + std::sync::{Arc, RwLock, Mutex}, + std::rc::Rc, + winit::event::{Event, WindowEvent}, + winit::event_loop::{ControlFlow, EventLoop}, + winit::window::WindowBuilder, + prisma::{Rgb,Hsv,FromColor, Lerp}, + cgmath::{Point2, Vector2}, + std::time::Duration, + angle::Turns, + + crate::{Inputs, view::ColorGrid} +}; + +pub struct ArcticRain { pub inputs: Arc> } +impl ColorGrid for ArcticRain { + fn get(&self, p: &Vector2) -> Rgb { + let inputs = self.inputs.read().unwrap().clone(); +// let millis = self + + let i = ( inputs.t.as_millis() as f32 / (4.0*inputs.cycle_len.as_millis() as f32) ) % 1.0; + + let pi2 = 2.0 * 3.1415926; + + let col1 = + Rgb::from_color( + &Hsv::>::new( + Turns( 0.65 ), + 0.9, + 1.0 - ((i + (2.0-p.y/4.0)) * 12.0) % 1.0, +// (f32::sin(-p.y+i) * 12.0) % 1.0, + ) + ); + + col1 + } +} + diff --git a/src/patterns/breathing.rs b/src/patterns/breathing.rs new file mode 100644 index 0000000..6b23eda --- /dev/null +++ b/src/patterns/breathing.rs @@ -0,0 +1,50 @@ +use { + std::num::NonZeroU32, + std::sync::{Arc, RwLock, Mutex}, + std::rc::Rc, + winit::event::{Event, WindowEvent}, + winit::event_loop::{ControlFlow, EventLoop}, + winit::window::WindowBuilder, + prisma::{Rgb,Hsv,FromColor, Lerp}, + cgmath::{Point2, Vector2}, + std::time::Duration, + angle::Turns, + + crate::{Inputs, view::ColorGrid, util::get_angle} +}; + + +pub struct Breathing { pub inputs: Arc> } +impl ColorGrid for Breathing { + fn get(&self, p: &Vector2) -> Rgb { + let inputs = self.inputs.read().unwrap().clone(); + + let millis = inputs.t.as_millis(); + + let p1 = p + Vector2::new(0.0,0.5); + let r2 = p1.x*p1.x + p1.y*p1.y; + let v = if r2 > 1.0 { 1.0 } else { r2 }; + let phi = ( get_angle(&p1) ); + let mirrorphi = if phi < 0.5 { phi } else { 1.0-phi }; + let gamma = + ( + (5.0) * + mirrorphi * + ( + 0.5+ 0.5*f32::sin( + inputs.t.as_millis() as f32 + / inputs.cycle_len.as_millis() as f32 + ) + ) + ) % 1.0; + + Rgb::from_color( + &Hsv::>::new( + Turns( 0.25+0.25*f32::sin(millis as f32/8000.0) + gamma*0.5 ), + 0.5 + r2 * 0.5, + inputs.wave_peak, + ) + ) + } +} + diff --git a/src/patterns/mod.rs b/src/patterns/mod.rs new file mode 100644 index 0000000..4fa24ae --- /dev/null +++ b/src/patterns/mod.rs @@ -0,0 +1,18 @@ + +pub mod breathing; +pub mod strobe; +pub mod arctic_rain; +pub mod pastel_fade; + +#[path = "uboot_prüfstand_fade.rs"] +pub mod uboot; + +pub use { + breathing::Breathing, + strobe::Strobe, + arctic_rain::ArcticRain, + pastel_fade::PastelFade, + uboot::UbootPrüfstandFade +}; + + diff --git a/src/patterns/pastel_fade.rs b/src/patterns/pastel_fade.rs new file mode 100644 index 0000000..0b6c6ff --- /dev/null +++ b/src/patterns/pastel_fade.rs @@ -0,0 +1,31 @@ +use { + std::num::NonZeroU32, + std::sync::{Arc, RwLock, Mutex}, + std::rc::Rc, + winit::event::{Event, WindowEvent}, + winit::event_loop::{ControlFlow, EventLoop}, + winit::window::WindowBuilder, + prisma::{Rgb,Hsv,FromColor, Lerp}, + cgmath::{Point2, Vector2}, + std::time::Duration, + angle::Turns, + + crate::{Inputs, view::ColorGrid, util::get_angle} +}; + +pub struct PastelFade { pub inputs: Arc> } +impl ColorGrid for PastelFade { + fn get(&self, p: &Vector2) -> Rgb { + let inputs = self.inputs.read().unwrap().clone(); + + let i = ( inputs.t.as_millis() as f32 / (4.0*inputs.cycle_len.as_millis() as f32) ) % 1.0; + + Rgb::from_color( + &Hsv::>::new( + Turns( i ), + 0.5, + (4.0*i) %1.0 + ) + ) + } +} diff --git a/src/patterns/strobe.rs b/src/patterns/strobe.rs new file mode 100644 index 0000000..79386d3 --- /dev/null +++ b/src/patterns/strobe.rs @@ -0,0 +1,35 @@ +use { + std::num::NonZeroU32, + std::sync::{Arc, RwLock, Mutex}, + std::rc::Rc, + winit::event::{Event, WindowEvent}, + winit::event_loop::{ControlFlow, EventLoop}, + winit::window::WindowBuilder, + prisma::{Rgb,Hsv,FromColor, Lerp}, + cgmath::{Point2, Vector2}, + std::time::Duration, + angle::Turns, + + crate::{Inputs, view::ColorGrid} +}; + +pub struct Strobe { + pub inputs: Arc>, + pub subdivision: u32, +} + +impl ColorGrid for Strobe { + fn get(&self, p: &Vector2) -> Rgb { + let inputs = self.inputs.read().unwrap().clone(); + + let t = (self.subdivision as f32 * inputs.t.as_millis() as f32 / inputs.cycle_len.as_millis() as f32) % 1.0; + + if t < 0.6 { + Rgb::new(0.6, 0.6, 0.6) + } else { + Rgb::new(0.0, 0.0, 0.0) + } + } +} + + diff --git a/src/patterns/uboot_prüfstand_fade.rs b/src/patterns/uboot_prüfstand_fade.rs new file mode 100644 index 0000000..2ab72f8 --- /dev/null +++ b/src/patterns/uboot_prüfstand_fade.rs @@ -0,0 +1,45 @@ +use { + std::num::NonZeroU32, + std::sync::{Arc, RwLock, Mutex}, + std::rc::Rc, + winit::event::{Event, WindowEvent}, + winit::event_loop::{ControlFlow, EventLoop}, + winit::window::WindowBuilder, + prisma::{Rgb,Hsv,FromColor, Lerp}, + cgmath::{Point2, Vector2}, + std::time::Duration, + angle::Turns, + + crate::{Inputs, view::ColorGrid} +}; + +pub struct UbootPrüfstandFade { pub inputs: Arc> } +impl ColorGrid for UbootPrüfstandFade { + fn get(&self, p: &Vector2) -> Rgb { + let inputs = self.inputs.read().unwrap().clone(); +// let millis = self + + let i = ( inputs.t.as_millis() as f32 / (4.0*inputs.cycle_len.as_millis() as f32) ) % 1.0; + + let pi2 = 2.0 * 3.1415926; + + let col1 = + Rgb::from_color( + &Hsv::>::new( + Turns( 0.65 ), + 0.9, + 0.5 + 0.5*f32::sin(i*pi2),//(4.0*i) %1.0 + ) + ); + + let col2 = Rgb::new(0.5+0.5*f32::sin(i*pi2), 0.0, 0.0); + + let p = ( inputs.t.as_millis() as f32 / (32.0*inputs.cycle_len.as_millis() as f32)) % 1.0; + if p >= 0.7 { + col2 + } else { + col1 + } + } +} + diff --git a/src/scene_library.rs b/src/scene_library.rs new file mode 100644 index 0000000..e7231fa --- /dev/null +++ b/src/scene_library.rs @@ -0,0 +1,83 @@ +use { + std::num::NonZeroU32, + std::sync::{Arc, RwLock, Mutex}, + std::rc::Rc, + winit::event::{Event, WindowEvent}, + winit::event_loop::{ControlFlow, EventLoop}, + winit::window::WindowBuilder, + prisma::{Rgb,Hsv,FromColor, Lerp}, + cgmath::{Point2, Vector2}, + std::time::Duration, + angle::Turns, + + crate::Inputs, + crate::view::ColorGrid, + crate::patterns::* +}; + + +pub struct SceneLibrary { + library: Vec< Box >, + current_scene: RwLock, + inputs: Arc>, + + transition_length: Duration, +// transition_curve: enum { Constant, Linear, Sigmoid, Sinus } +} + +impl SceneLibrary { + pub fn new( inputs: Arc> ) -> Self { + SceneLibrary { + library: vec![ + // 0 + Box::new( Breathing{ inputs: inputs.clone() } ), + + // 1 - 4 + Box::new( Strobe{ inputs: inputs.clone(), subdivision: 4 } ), + Box::new( Strobe{ inputs: inputs.clone(), subdivision: 8 } ), + Box::new( Strobe{ inputs: inputs.clone(), subdivision: 12 } ), + Box::new( Strobe{ inputs: inputs.clone(), subdivision: 16 } ), + + // others + Box::new( PastelFade{ inputs: inputs.clone() } ), + Box::new( UbootPrüfstandFade{ inputs: inputs.clone() } ), + Box::new( ArcticRain{ inputs: inputs.clone() } ), + ], + current_scene: RwLock::new(0), + inputs, + transition_length: Duration::from_millis(200), + } + } +} + +impl ColorGrid for SceneLibrary { + fn get(&self, p: &Vector2) -> Rgb { + let inputs = self.inputs.read().unwrap().clone(); + + let sc = *self.current_scene.read().unwrap(); + + if inputs.scene_select == sc { + // display only one animation + self.library[ sc ].get(p) + } else { + // display transition + let cur_scene = &self.library[ sc ]; + let nxt_scene = &self.library[ inputs.scene_select ]; + + // crossfade param + let w = ( inputs.transition_time.as_millis() as f32 / self.transition_length.as_millis() as f32 ); + + if w >= 1.0 { + // change own state: + *self.current_scene.write().unwrap() = inputs.scene_select; + } + + cur_scene.get(p) + .lerp( + &nxt_scene.get(p), + w + ) + } + } +} + diff --git a/src/stripe_driver.rs b/src/stripe_driver.rs index 2e61950..4a98b91 100644 --- a/src/stripe_driver.rs +++ b/src/stripe_driver.rs @@ -10,7 +10,7 @@ pub struct StripeDriver { } impl StripeDriver { - fn new(addr: &str, socket: Arc>) -> Self { + pub fn new(addr: &str, socket: Arc>) -> Self { StripeDriver { addr: addr.into(), socket @@ -24,9 +24,9 @@ impl FixtureDriver for StripeDriver { let mut buf = [0 as u8; STRIPE_LEN*3]; for x in 0 .. STRIPE_LEN { - buf[x*3+0] = pixels[x].green(); - buf[x*3+1] = pixels[x].red(); - buf[x*3+2] = pixels[x].blue(); + buf[x*3+0] = pixels[x].green()/2; + buf[x*3+1] = pixels[x].red()/2; + buf[x*3+2] = pixels[x].blue()/2; } self.socket.write().unwrap().send_to(&buf, &self.addr); diff --git a/src/uboot_prüfstand_fade.rs b/src/uboot_prüfstand_fade.rs new file mode 100644 index 0000000..73330b4 --- /dev/null +++ b/src/uboot_prüfstand_fade.rs @@ -0,0 +1,46 @@ +use { + std::num::NonZeroU32, + std::sync::{Arc, RwLock, Mutex}, + std::rc::Rc, + winit::event::{Event, WindowEvent}, + winit::event_loop::{ControlFlow, EventLoop}, + winit::window::WindowBuilder, + prisma::{Rgb,Hsv,FromColor, Lerp}, + cgmath::{Point2, Vector2}, + std::time::Duration, + angle::Turns, + + crate::{Inputs, view::ColorGrid} +}; + + +pub struct UbootPrüfstandFade { inputs: Arc> } +impl ColorGrid for UbootPrüfstandFade { + fn get(&self, p: &Vector2) -> Rgb { + let inputs = self.inputs.read().unwrap().clone(); +// let millis = self + + let i = ( inputs.t.as_millis() as f32 / (4.0*inputs.cycle_len.as_millis() as f32) ) % 1.0; + + let pi2 = 2.0 * 3.1415926; + + let col1 = + Rgb::from_color( + &Hsv::>::new( + Turns( 0.65 ), + 0.9, + 0.5 + 0.5*f32::sin(i*pi2),//(4.0*i) %1.0 + ) + ); + + let col2 = Rgb::new(0.5+0.5*f32::sin(i*pi2), 0.0, 0.0); + + let p = ( inputs.t.as_millis() as f32 / (32.0*inputs.cycle_len.as_millis() as f32)) % 1.0; + if p >= 0.7 { + col2 + } else { + col1 + } + } +} +