move patterns into separate module

This commit is contained in:
Michael Sippel 2024-04-27 21:39:22 +02:00
parent 393f7aa891
commit d56a8ab988
Signed by: senvas
GPG key ID: 060F22F65102F95C
10 changed files with 359 additions and 206 deletions

View file

@ -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<RwLock< Inputs >> }
impl ColorGrid for Breathing {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::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<RwLock< Inputs >> }
impl ColorGrid for PastelFade {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::new(
Turns( i ),
0.5,
(4.0*i) %1.0
)
)
}
}
struct UbootPrüfstandFade { inputs: Arc<RwLock< Inputs >> }
impl ColorGrid for UbootPrüfstandFade {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::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<RwLock< Inputs >> }
impl ColorGrid for ArcticRain {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::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<RwLock< Inputs >>,
//waveform: Waveform,
subdivision: u32,
}
impl ColorGrid for Strobe {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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<dyn ColorGrid> >,
current_scene: RwLock<usize>,
inputs: Arc<RwLock< Inputs >>,
transition_length: Duration,
// transition_curve: enum { Constant, Linear, Sigmoid, Sinus }
}
impl SceneLibrary {
pub fn new( inputs: Arc<RwLock<Inputs>> ) -> 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<f32>) -> Rgb<f32> {
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))
],

View file

@ -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<RwLock< Inputs >> }
impl ColorGrid for ArcticRain {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::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
}
}

50
src/patterns/breathing.rs Normal file
View file

@ -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<RwLock< Inputs >> }
impl ColorGrid for Breathing {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::new(
Turns( 0.25+0.25*f32::sin(millis as f32/8000.0) + gamma*0.5 ),
0.5 + r2 * 0.5,
inputs.wave_peak,
)
)
}
}

18
src/patterns/mod.rs Normal file
View file

@ -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
};

View file

@ -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<RwLock< Inputs >> }
impl ColorGrid for PastelFade {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::new(
Turns( i ),
0.5,
(4.0*i) %1.0
)
)
}
}

35
src/patterns/strobe.rs Normal file
View file

@ -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<RwLock< Inputs >>,
pub subdivision: u32,
}
impl ColorGrid for Strobe {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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)
}
}
}

View file

@ -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<RwLock< Inputs >> }
impl ColorGrid for UbootPrüfstandFade {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::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
}
}
}

83
src/scene_library.rs Normal file
View file

@ -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<dyn ColorGrid> >,
current_scene: RwLock<usize>,
inputs: Arc<RwLock< Inputs >>,
transition_length: Duration,
// transition_curve: enum { Constant, Linear, Sigmoid, Sinus }
}
impl SceneLibrary {
pub fn new( inputs: Arc<RwLock<Inputs>> ) -> 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<f32>) -> Rgb<f32> {
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
)
}
}
}

View file

@ -10,7 +10,7 @@ pub struct StripeDriver {
}
impl StripeDriver {
fn new(addr: &str, socket: Arc<RwLock<std::net::UdpSocket>>) -> Self {
pub fn new(addr: &str, socket: Arc<RwLock<std::net::UdpSocket>>) -> 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);

View file

@ -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<RwLock< Inputs >> }
impl ColorGrid for UbootPrüfstandFade {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
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::<f32, Turns<f32>>::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
}
}
}