From 06ea05e1128f6ed1d7b1e74fec235950b67dcb0b Mon Sep 17 00:00:00 2001 From: Michael Sippel Date: Fri, 26 Apr 2024 14:26:40 +0200 Subject: [PATCH] add basic scene selection --- src/main.rs | 162 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 146 insertions(+), 16 deletions(-) diff --git a/src/main.rs b/src/main.rs index fac64cd..12f7da3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use { winit::event::{Event, WindowEvent}, winit::event_loop::{ControlFlow, EventLoop}, winit::window::WindowBuilder, - prisma::{Rgb,Hsv,FromColor}, + prisma::{Rgb,Hsv,FromColor, Lerp}, cgmath::{Point2, Vector2}, std::time::Duration, angle::Turns @@ -31,6 +31,9 @@ use crate::{ #[derive(Clone)] struct Inputs { t: Duration, + transition_time: Duration, + + scene_select: usize, intensity: f32, cycle_len: Duration, @@ -78,16 +81,109 @@ impl ColorGrid for Anim2 { 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( 0.0 ), + Turns( i ), 0.5, - ( inputs.t.as_millis() as f32 / inputs.cycle_len.as_millis() as f32 ) % 1.0 + (4.0*i) %1.0 ) ) } } +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( Anim2{ 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(); @@ -100,14 +196,17 @@ async fn main() { let socket = Arc::new(RwLock::new(std::net::UdpSocket::bind("0.0.0.0:4210").expect("failed to bind UDP socket"))); socket.write().unwrap().set_read_timeout(Some(std::time::Duration::from_millis(500))); socket.write().unwrap().set_write_timeout(Some(std::time::Duration::from_millis(50))); - + let inputs = Arc::new(RwLock::new( Inputs { t: Duration::from_millis(0), + transition_time: Duration::from_millis(0), intensity: 0.5, cycle_len: Duration::from_millis(300), wave_peak: 0.5, + + scene_select: 0 } )); @@ -133,14 +232,13 @@ async fn main() { .offset(Vector2::new(0.5, 0.0)) ], - Box::new( - Anim2{ inputs: inputs.clone() } - ) + Box::new( SceneLibrary::new(inputs.clone()) ) ); - let tbegin = std::time::Instant::now(); + let mut tbegin = std::time::Instant::now(); + let mut transition_begin = std::time::Instant::now(); let mut last_tap = std::time::Instant::now(); - + event_loop.run(move |event, elwt| { let tcur = std::time::Instant::now(); elwt.set_control_flow(ControlFlow::WaitUntil( @@ -148,12 +246,11 @@ async fn main() { )); inputs.write().unwrap().t = tcur - tbegin; + inputs.write().unwrap().transition_time = tcur - transition_begin; lighting_setup.update_buffers(); //lighting_setup.update_outputs(); match event { - //Event:: - Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested } if window_id == window.id() => { let (width, height) = { let size = window.inner_size(); @@ -178,12 +275,45 @@ async fn main() { winit::keyboard::Key::Character(c) => { eprintln!("pressed {}", c); - if c == "x" { - // tap tempo - let old_tap = last_tap; - last_tap = std::time::Instant::now(); + match &c[0..1] { + "x" => { + // tap tempo + let old_tap = last_tap; + last_tap = std::time::Instant::now(); - inputs.write().unwrap().cycle_len = last_tap - old_tap; + if (last_tap - old_tap) < Duration::from_millis(20000) { + inputs.write().unwrap().cycle_len = last_tap - old_tap; + } + } + + "q" => { + // sync + inputs.write().unwrap().t = Duration::from_millis(0); + tbegin = std::time::Instant::now(); + }, + + "0" => { + inputs.write().unwrap().scene_select = 0; + transition_begin = std::time::Instant::now(); + } + "1" => { + inputs.write().unwrap().scene_select = 1; + transition_begin = std::time::Instant::now(); + } + "2" => { + inputs.write().unwrap().scene_select = 2; + transition_begin = std::time::Instant::now(); + } + "3" => { + inputs.write().unwrap().scene_select = 3; + transition_begin = std::time::Instant::now(); + } + "4" => { + inputs.write().unwrap().scene_select = 4; + transition_begin = std::time::Instant::now(); + } + + _=>{} } } _ => {}