Compare commits

...

6 commits

17 changed files with 458 additions and 232 deletions

154
src/controller.rs Normal file
View file

@ -0,0 +1,154 @@
use {
std::time::{Instant, Duration},
crate::waveform::Waveform,
};
pub struct Controller {
pub tbegin: Instant,
pub transition_begin: Instant,
pub last_tap: Instant,
pub ctrl: bool
}
impl Controller {
pub fn new() -> Self {
Controller {
tbegin: Instant::now(),
transition_begin: Instant::now(),
last_tap: Instant::now(),
ctrl: false
}
}
pub fn handle_key(
&mut self,
event: winit::event::KeyEvent,
inputs: &mut crate::inputs::Inputs,
setup: &mut crate::setup::LightingSetup
) {
if event.state == winit::event::ElementState::Released {
match event.logical_key {
winit::keyboard::Key::Named(
winit::keyboard::NamedKey::Control
) => {
eprintln!("released control");
self.ctrl = false;
}
_ => {}
}
} else
if event.state == winit::event::ElementState::Pressed {
match event.logical_key {
winit::keyboard::Key::Named(
winit::keyboard::NamedKey::Control
) => {
eprintln!("pressed control");
self.ctrl = true;
}
winit::keyboard::Key::Character(c) => {
eprintln!("pressed {}", c);
if self.ctrl {
if c.is_ascii() {
match &c[0..1] {
"0" => {
if let Some(f) = setup.fixtures.get_mut(0) {
eprintln!("toggle mirror_y of fixture 0");
f.mirror_y = !f.mirror_y;
}
}
"1" => {
if let Some(f) = setup.fixtures.get_mut(1) {
eprintln!("toggle mirror_y of fixture 1");
f.mirror_y = !f.mirror_y;
}
}
"2" => {
if let Some(f) = setup.fixtures.get_mut(2) {
eprintln!("toggle mirror_y of fixture 2");
f.mirror_y = !f.mirror_y;
}
}
"3" => {
if let Some(f) = setup.fixtures.get_mut(3) {
eprintln!("toggle mirror_y of fixture 3");
f.mirror_y = !f.mirror_y;
}
}
"4" => {
if let Some(f) = setup.fixtures.get_mut(4) {
eprintln!("toggle mirror_y of fixture 4");
f.mirror_y = !f.mirror_y;
}
}
_ => {}
}
}
} else {
if c.is_ascii() {
match &c[0..1] {
"x" => {
// tap tempo
let old_tap = self.last_tap;
self.last_tap = std::time::Instant::now();
if (self.last_tap - old_tap) < Duration::from_millis(20000) {
inputs.cycle_len = self.last_tap - old_tap;
}
}
"q" => {
// sync
inputs.t = Duration::from_millis(0);
self.tbegin = std::time::Instant::now();
},
"0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9" => {
let idx = c.chars().nth(0).unwrap().to_digit(10).unwrap() as u32;
inputs.scene_select = idx as usize;
self.transition_begin = std::time::Instant::now();
}
"r" => { inputs.master_wave = match inputs.master_wave {
None => Some(Waveform::Sine),
Some(Waveform::Sine) => Some(Waveform::Triangle),
Some(Waveform::Triangle) => Some(Waveform::Square),
Some(Waveform::Square) => Some(Waveform::Sawtooth),
Some(Waveform::Sawtooth) => None
}
}
"," => { inputs.master_wave = None; }
"n" => { inputs.master_intensity += 0.1; }
"m" => { inputs.master_intensity -= 0.1; }
"s" => { inputs.master_subdivision +=1; }
"b" => { inputs.master_subdivision -=1; }
"o" => { inputs.wheel +=1; }
"z" => { inputs.wheel -=1; }
"e" => { inputs.wheel2 += 1; }
"p"=> { inputs.wheel2 -= 1; }
"a"=> { inputs.wheel3 -= 1; }
"i" => { inputs.wheel3 += 1; }
"-" => { inputs.master_intensity *= -1.0; }
"." => {
if inputs.active {
eprintln!("DEACTIVATED");
inputs.active = false;
} else {
inputs.active = true;
eprintln!("ACTIVATED");
}
}
_=>{}
}
}
eprintln!("--------------");
eprintln!("updated inputs:\n {:?}", inputs);
eprintln!("--------------");
}
}
_ => {}
}
}
}
}

View file

@ -15,19 +15,21 @@ pub struct Fixture {
pub position: Vector2<f32>, pub position: Vector2<f32>,
pub rotation: f32, pub rotation: f32,
pub scale: f32, pub scale: f32,
pub mirror_y: bool,
pub brightness: f32, pub brightness: f32,
pub buffer: Vec< Rgb<u8> >, pub buffer: Vec< Rgb<u8> >,
pub driver: Option<Box<dyn FixtureDriver>> pub driver: Option<Box<dyn FixtureDriver>>
} }
impl Fixture { impl Fixture {
pub fn new_stripe() -> Self { pub fn new_stripe(mirror_y: bool) -> Self {
let mut fixture = Fixture { let mut fixture = Fixture {
resolution: Vector2::new(1, 72), resolution: Vector2::new(1, 72),
position: Vector2::new(0.0, 0.0), position: Vector2::new(0.0, 0.0),
rotation: 0.0, rotation: 0.0,
scale: 0.015, scale: 0.015,
brightness: 0.8, brightness: 0.8,
mirror_y,
buffer: Vec::new(), buffer: Vec::new(),
driver: None driver: None
}; };
@ -43,6 +45,7 @@ impl Fixture {
position: Vector2::new(0.0, 0.0), position: Vector2::new(0.0, 0.0),
rotation: 0.0, rotation: 0.0,
scale: 0.03, scale: 0.03,
mirror_y: false,
brightness: 0.8, brightness: 0.8,
buffer: Vec::new(), buffer: Vec::new(),
driver: None driver: None
@ -70,12 +73,17 @@ impl Fixture {
self.position + centered_pixpos * self.scale self.position + centered_pixpos * self.scale
} }
pub fn update_buffer(&mut self, view: &Box<dyn ColorGrid>) { pub fn update_buffer(&mut self, view: &dyn crate::view::Animation) {
for xi in 0 .. self.resolution.x { for xi in 0 .. self.resolution.x {
for yi in 0 ..self.resolution.y { for yi in 0 ..self.resolution.y {
let gpos = self.get_global_pos(&Vector2::new(xi, yi)); let gpos = self.get_global_pos(&Vector2::new(xi, yi));
let col = view.get(&gpos); let col = view.get(&gpos);
let yi = if self.mirror_y {
self.resolution.y - 1 - yi
} else {
yi
};
let index = xi + yi * self.resolution.x; let index = xi + yi * self.resolution.x;
self.buffer[index as usize] = Rgb::new( self.buffer[index as usize] = Rgb::new(
(col.red() * 255.0 * self.brightness) as u8, (col.red() * 255.0 * self.brightness) as u8,

49
src/inputs.rs Normal file
View file

@ -0,0 +1,49 @@
use {
std::time::Duration,
crate::waveform::Waveform
};
#[derive(Clone, Debug)]
pub struct Inputs {
pub t: Duration,
pub transition_time: Duration,
pub scene_select: usize,
pub cycle_len: Duration,
pub wave_peak: f32,
pub master_wave: Option< Waveform >,
pub master_subdivision: i32,
pub master_intensity: f32,
pub wheel: i32,
pub wheel2: i32,
pub wheel3: i32,
pub active: bool,
}
impl Default for Inputs {
fn default() -> Inputs {
Inputs {
t: Duration::from_millis(0),
transition_time: Duration::from_millis(0),
cycle_len: Duration::from_millis(300),
wave_peak: 0.5,
scene_select: 0,
master_wave: None,
master_subdivision: 0,
master_intensity: 1.0,
wheel: 0,
wheel2: 0,
wheel3: 0,
active: false,
}
}
}

View file

@ -16,10 +16,12 @@ use {
mod util; mod util;
mod fixture; mod fixture;
mod setup; mod setup;
mod inputs;
mod view; mod view;
mod stripe_driver; mod stripe_driver;
mod jack; mod jack;
mod waveform; mod waveform;
mod controller;
mod patterns; mod patterns;
mod scene_library; mod scene_library;
@ -32,25 +34,10 @@ use crate::{
util::get_angle, util::get_angle,
scene_library::SceneLibrary, scene_library::SceneLibrary,
waveform::Waveform waveform::Waveform,
inputs::Inputs
}; };
#[derive(Clone, Debug)]
pub struct Inputs {
t: Duration,
transition_time: Duration,
scene_select: usize,
cycle_len: Duration,
wave_peak: f32,
master_wave: Option< Waveform >,
master_subdivision: i32,
master_intensity: f32,
wheel: i32,
wheel2: i32,
}
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let event_loop = EventLoop::new().unwrap(); let event_loop = EventLoop::new().unwrap();
@ -64,64 +51,52 @@ async fn main() {
socket.write().unwrap().set_read_timeout(Some(std::time::Duration::from_millis(1))); socket.write().unwrap().set_read_timeout(Some(std::time::Duration::from_millis(1)));
socket.write().unwrap().set_write_timeout(Some(std::time::Duration::from_millis(1))); socket.write().unwrap().set_write_timeout(Some(std::time::Duration::from_millis(1)));
let inputs = Arc::new(RwLock::new( let mut inputs = Inputs::default();
Inputs {
t: Duration::from_millis(0),
transition_time: Duration::from_millis(0),
cycle_len: Duration::from_millis(300),
wave_peak: 0.5,
scene_select: 0,
master_wave: None,
master_subdivision: 0,
master_intensity: 1.0,
wheel: 0,
wheel2: 0
}
));
let mut lighting_setup = LightingSetup::new( let mut lighting_setup = LightingSetup::new(
vec![ vec![
Fixture::new_matrix(), Fixture::new_matrix(),
// .with_driver( Box::new(MatrixTcpDriver::new("ip:port")) ), // .with_driver( Box::new(MatrixTcpDriver::new("ip:port")) ),
Fixture::new_stripe() Fixture::new_stripe(false)
.with_driver( Box::new(StripeDriver::new("192.168.0.111:4210", socket.clone())) ) .with_driver( Box::new(StripeDriver::new("192.168.0.114:4210", socket.clone())) )
.offset(Vector2::new(-0.5, 0.0)), .offset(Vector2::new(-0.5, 0.0)),
Fixture::new_stripe() Fixture::new_stripe(true)
.with_driver( Box::new(StripeDriver::new("192.168.0.112:4210", socket.clone())) ) .with_driver( Box::new(StripeDriver::new("192.168.0.113:4210", socket.clone())) )
.offset(Vector2::new(-0.4, 0.0)), .offset(Vector2::new(-0.4, 0.0)),
Fixture::new_stripe() Fixture::new_stripe(true)
.with_driver( Box::new(StripeDriver::new("192.168.0.113:4210", socket.clone())) ) .with_driver( Box::new(StripeDriver::new("192.168.0.112:4210", socket.clone())) )
.offset(Vector2::new(0.4, 0.0)), .offset(Vector2::new(0.4, 0.0)),
Fixture::new_stripe() Fixture::new_stripe(false)
.with_driver( Box::new(StripeDriver::new("192.168.0.114:4210", socket.clone()))) .with_driver( Box::new(StripeDriver::new("192.168.0.111:4210", socket.clone())))
.offset(Vector2::new(0.5, 0.0)) .offset(Vector2::new(0.5, 0.0))
], ],
Box::new( SceneLibrary::new(inputs.clone()) ) Box::new( SceneLibrary::new() )
); );
let mut tbegin = std::time::Instant::now(); let mut controller = controller::Controller::new();
let mut transition_begin = std::time::Instant::now();
let mut last_tap = std::time::Instant::now();
let mut z = 0;
let mut frame_count = 0; let mut frame_count = 0;
let mut fps_sum_window = std::time::Instant::now(); let mut fps_sum_window = std::time::Instant::now();
let mut active = false; lighting_setup.advance( &inputs );
for i in 0..5 { for i in 0..5 {
lighting_setup.sync_fixture(i); lighting_setup.sync_fixture(i);
} }
event_loop.run(move |event, elwt| { event_loop.run(move |event, elwt| {
let tcur = std::time::Instant::now(); let tcur = std::time::Instant::now();
elwt.set_control_flow(
ControlFlow::WaitUntil(
tcur + Duration::from_millis(25)
));
// FPS statistics
if (tcur - fps_sum_window).as_millis() > 5000 { if (tcur - fps_sum_window).as_millis() > 5000 {
let avg_fps = (1000.0 * frame_count as f32) / ((tcur - fps_sum_window).as_millis() as f32); let avg_fps = (1000.0 * frame_count as f32) / ((tcur - fps_sum_window).as_millis() as f32);
eprintln!("avg fps: {}", avg_fps); eprintln!("avg fps: {}", avg_fps);
@ -131,15 +106,13 @@ async fn main() {
frame_count += 1; frame_count += 1;
} }
elwt.set_control_flow(ControlFlow:: // update animation
WaitUntil( inputs.t = tcur - controller.tbegin;
tcur + Duration::from_millis(25) inputs.transition_time = tcur - controller.transition_begin;
)); lighting_setup.advance( &inputs );
inputs.write().unwrap().t = tcur - tbegin;
inputs.write().unwrap().transition_time = tcur - transition_begin;
lighting_setup.update_buffers();
if active { // refresh fixture outputs
if inputs.active {
// sync // sync
let mut rbuf = [0 as u8; 8]; let mut rbuf = [0 as u8; 8];
@ -185,76 +158,12 @@ async fn main() {
window_id: _, window_id: _,
event: winit::event::WindowEvent::KeyboardInput{ device_id, event, is_synthetic } event: winit::event::WindowEvent::KeyboardInput{ device_id, event, is_synthetic }
} => { } => {
if event.state == winit::event::ElementState::Pressed { controller.handle_key(
match event.logical_key { event, &mut inputs, &mut lighting_setup
winit::keyboard::Key::Character(c) => { );
eprintln!("pressed {}", c); }
let mut inputs = inputs.write().unwrap(); _ => {}
if c.is_ascii() {
match &c[0..1] {
"x" => {
// tap tempo
let old_tap = last_tap;
last_tap = std::time::Instant::now();
if (last_tap - old_tap) < Duration::from_millis(20000) {
inputs.cycle_len = last_tap - old_tap;
}
}
"q" => {
// sync
inputs.t = Duration::from_millis(0);
tbegin = std::time::Instant::now();
},
"0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9" => {
let idx = c.chars().nth(0).unwrap().to_digit(10).unwrap() as u32;
inputs.scene_select = idx as usize;
transition_begin = std::time::Instant::now();
}
"r" => { inputs.master_wave = match inputs.master_wave {
None => Some(Waveform::Sine),
Some(Waveform::Sine) => Some(Waveform::Triangle),
Some(Waveform::Triangle) => Some(Waveform::Square),
Some(Waveform::Square) => Some(Waveform::Sawtooth),
Some(Waveform::Sawtooth) => None
}
}
"," => { inputs.master_wave = None; }
"n" => { inputs.master_intensity += 0.1; }
"m" => { inputs.master_intensity -= 0.1; }
"s" => { inputs.master_subdivision +=1; }
"b" => { inputs.master_subdivision -=1; }
"o" => { inputs.wheel +=1; }
"z" => { inputs.wheel -=1; }
"e" => { inputs.wheel2 += 1; }
"p"=> { inputs.wheel2 -= 1; }
"-" => { inputs.master_intensity *= -1.0; }
"." => {
if active {
eprintln!("DEACTIVATED");
active = false;
} else {
active = true;
eprintln!("ACTIVATED");
}
}
_=>{}
}
eprintln!("--------------");
eprintln!("updated inputs:\n {:?}", inputs);
eprintln!("--------------");
}
}
_ => {}
}
}
}
_ => {}
} }
let (width, height) = *dim.lock().unwrap(); let (width, height) = *dim.lock().unwrap();

View file

@ -10,22 +10,27 @@ use {
std::time::Duration, std::time::Duration,
angle::Turns, angle::Turns,
crate::{Inputs, view::ColorGrid} crate::{Inputs, view::{ColorGrid, Animation}}
}; };
#[derive(Default)]
pub struct Alternate { pub struct Alternate {
pub inputs: Arc<RwLock< Inputs >>, pub inputs: Inputs,
}
impl Animation for Alternate {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
}
} }
impl ColorGrid for Alternate { impl ColorGrid for Alternate {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone();
let switch = 0; let switch = 0;
let t = (inputs.wheel as f32 * inputs.t.as_millis() as f32 / inputs.cycle_len.as_millis() as f32) % 1.0; let t = (self.inputs.wheel as f32 * self.inputs.t.as_millis() as f32 / self.inputs.cycle_len.as_millis() as f32) % 1.0;
if ((50.0+p.y*128.0) / inputs.wheel as f32) as u32 % 2 == 0 { if ((50.0+p.y*128.0) / self.inputs.wheel as f32) as u32 % 2 == 0 {
if t < 0.5 { if t < 0.5 {
Rgb::new(0.5, 0.2, 0.2) Rgb::new(0.5, 0.2, 0.2)
} else { } else {
@ -38,9 +43,6 @@ impl ColorGrid for Alternate {
Rgb::new(0.0, 0.0, 0.6) Rgb::new(0.0, 0.0, 0.6)
} }
} }
} }
} }

View file

@ -10,16 +10,21 @@ use {
std::time::Duration, std::time::Duration,
angle::Turns, angle::Turns,
crate::{Inputs, view::ColorGrid} crate::{Inputs, view::{ColorGrid, Animation}}
}; };
pub struct ArcticRain { pub inputs: Arc<RwLock< Inputs >> } #[derive(Default)]
pub struct ArcticRain { pub inputs: Inputs }
impl Animation for ArcticRain {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
}
}
impl ColorGrid for ArcticRain { impl ColorGrid for ArcticRain {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone(); let i = ( self.inputs.t.as_millis() as f32 / (4.0*self.inputs.cycle_len.as_millis() as f32) ) % 1.0;
// 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 pi2 = 2.0 * 3.1415926;
@ -27,9 +32,9 @@ impl ColorGrid for ArcticRain {
Rgb::from_color( Rgb::from_color(
&Hsv::<f32, Turns<f32>>::new( &Hsv::<f32, Turns<f32>>::new(
// Turns( 0.65 + 0.3*(inputs.wheel%10) as f32*0.1 ), // Turns( 0.65 + 0.3*(inputs.wheel%10) as f32*0.1 ),
Turns( (inputs.wheel.abs() % 256) as f32 / 256.0 ), Turns( (self.inputs.wheel.abs() % 256) as f32 / 256.0 ),
0.9, 0.9,
1.0 - ((i + (2.0-p.y/4.0)) * 12.0) % 1.0, 1.0 - ((i + (2.0-p.y/(0.2*(1+self.inputs.wheel3.abs()) as f32))) * 12.0) % 1.0,
// (f32::sin(-p.y+i) * 12.0) % 1.0, // (f32::sin(-p.y+i) * 12.0) % 1.0,
) )
); );

View file

@ -9,17 +9,25 @@ use {
cgmath::{Point2, Vector2}, cgmath::{Point2, Vector2},
std::time::Duration, std::time::Duration,
angle::Turns, angle::Turns,
crate::{
crate::{Inputs, view::ColorGrid, util::get_angle} Inputs,
view::{ColorGrid, Animation},
util::get_angle
}
}; };
#[derive(Default)]
pub struct Breathing { pub inputs: Inputs }
impl Animation for Breathing {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
}
}
pub struct Breathing { pub inputs: Arc<RwLock< Inputs >> }
impl ColorGrid for Breathing { impl ColorGrid for Breathing {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone(); let millis = self.inputs.t.as_millis();
let millis = inputs.t.as_millis();
let p1 = p + Vector2::new(0.0,0.5); let p1 = p + Vector2::new(0.0,0.5);
let r2 = p1.x*p1.x + p1.y*p1.y; let r2 = p1.x*p1.x + p1.y*p1.y;
@ -32,8 +40,8 @@ impl ColorGrid for Breathing {
mirrorphi * mirrorphi *
( (
0.5+ 0.5*f32::sin( 0.5+ 0.5*f32::sin(
inputs.t.as_millis() as f32 self.inputs.t.as_millis() as f32
/ inputs.cycle_len.as_millis() as f32 / self.inputs.cycle_len.as_millis() as f32
) )
) )
) % 1.0; ) % 1.0;
@ -42,7 +50,7 @@ impl ColorGrid for Breathing {
&Hsv::<f32, Turns<f32>>::new( &Hsv::<f32, Turns<f32>>::new(
Turns( 0.25+0.25*f32::sin(millis as f32/8000.0) + gamma*0.5 ), Turns( 0.25+0.25*f32::sin(millis as f32/8000.0) + gamma*0.5 ),
0.5 + r2 * 0.5, 0.5 + r2 * 0.5,
inputs.wave_peak, self.inputs.wave_peak,
) )
) )
} }

View file

@ -7,6 +7,7 @@ pub mod gastel_fade;
pub mod wheel; pub mod wheel;
pub mod wave_fade; pub mod wave_fade;
pub mod alternate; pub mod alternate;
pub mod oneshotman;
#[path = "uboot_prüfstand_fade.rs"] #[path = "uboot_prüfstand_fade.rs"]
pub mod uboot; pub mod uboot;
@ -20,7 +21,8 @@ pub use {
wave_fade::WaveFade, wave_fade::WaveFade,
uboot::UbootPrüfstandFade, uboot::UbootPrüfstandFade,
wheel::Wheel, wheel::Wheel,
alternate::Alternate alternate::Alternate,
oneshotman::OneShotMan
}; };

View file

@ -0,0 +1,48 @@
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, Animation}, util::get_angle}
};
#[derive(Default)]
pub struct OneShotMan {
pub inputs: Inputs,
velocity: f32,
pos: f32,
last_t: std::time::Duration
}
impl Animation for OneShotMan {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
self.velocity = (inputs.wheel as f32) / 16.0;
self.pos = -0.8 + self.velocity * (self.inputs.t.as_millis() as f32) / 1000.0;
}
}
q
impl ColorGrid for OneShotMan {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
if p.y < self.pos {
Rgb::from_color(
&Hsv::<f32, Turns<f32>>::new(
Turns( (self.inputs.wheel2 as f32 / 64.0).abs() % 1.0 ),
0.8,
f32::exp( -(1.0 + (self.inputs.wheel3 as f32) * (self.pos - p.y)) )
)
)
} else {
Rgb::new(0.0,0.0,0.0)
}
}
}

View file

@ -10,15 +10,21 @@ use {
std::time::Duration, std::time::Duration,
angle::Turns, angle::Turns,
crate::{Inputs, view::ColorGrid, util::get_angle} crate::{Inputs, view::{ColorGrid, Animation}, util::get_angle}
}; };
pub struct PastelFade { pub inputs: Arc<RwLock< Inputs >> } #[derive(Default)]
pub struct PastelFade { pub inputs: Inputs }
impl Animation for PastelFade {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
}
}
impl ColorGrid for PastelFade { impl ColorGrid for PastelFade {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone(); let i = ( 5.0 + 0.7 * self.inputs.t.as_millis() as f32 / (16.0*self.inputs.cycle_len.as_millis() as f32) ) % 1.0;
let i = ( 5.0 + 0.7 * inputs.t.as_millis() as f32 / (16.0*inputs.cycle_len.as_millis() as f32) ) % 1.0;
Rgb::from_color( Rgb::from_color(
&Hsv::<f32, Turns<f32>>::new( &Hsv::<f32, Turns<f32>>::new(

View file

@ -10,18 +10,23 @@ use {
std::time::Duration, std::time::Duration,
angle::Turns, angle::Turns,
crate::{Inputs, view::ColorGrid} crate::{Inputs, view::{ColorGrid, Animation}}
}; };
#[derive(Default)]
pub struct Strobe { pub struct Strobe {
pub inputs: Arc<RwLock< Inputs >>, pub inputs: Inputs,
}
impl Animation for Strobe {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
}
} }
impl ColorGrid for Strobe { impl ColorGrid for Strobe {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone(); let t = (self.inputs.wheel as f32 * self.inputs.t.as_millis() as f32 / self.inputs.cycle_len.as_millis() as f32) % 1.0;
let t = (inputs.wheel as f32 * inputs.t.as_millis() as f32 / inputs.cycle_len.as_millis() as f32) % 1.0;
if t < 0.6 { if t < 0.6 {
Rgb::new(0.3, 0.3, 0.3) Rgb::new(0.3, 0.3, 0.3)

View file

@ -10,16 +10,21 @@ use {
std::time::Duration, std::time::Duration,
angle::Turns, angle::Turns,
crate::{Inputs, view::ColorGrid} crate::{Inputs, view::{ColorGrid, Animation}}
}; };
pub struct UbootPrüfstandFade { pub inputs: Arc<RwLock< Inputs >> } #[derive(Default)]
pub struct UbootPrüfstandFade { pub inputs: Inputs }
impl Animation for UbootPrüfstandFade {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
}
}
impl ColorGrid for UbootPrüfstandFade { impl ColorGrid for UbootPrüfstandFade {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone(); let i = ( self.inputs.t.as_millis() as f32 / (4.0*self.inputs.cycle_len.as_millis() as f32) ) % 1.0;
// 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 pi2 = 2.0 * 3.1415926;
@ -34,7 +39,7 @@ impl ColorGrid for UbootPrüfstandFade {
let col2 = Rgb::new(0.8, 0.0, 0.0); let col2 = Rgb::new(0.8, 0.0, 0.0);
let p = ( inputs.t.as_millis() as f32 / (32.0*inputs.cycle_len.as_millis() as f32)) % 1.0; let p = ( self.inputs.t.as_millis() as f32 / (32.0*self.inputs.cycle_len.as_millis() as f32)) % 1.0;
if p >= 0.7 { if p >= 0.7 {
col2 col2
} else { } else {

View file

@ -10,21 +10,25 @@ use {
std::time::Duration, std::time::Duration,
angle::Turns, angle::Turns,
crate::{Inputs, view::ColorGrid, util::get_angle, waveform::Waveform} crate::{Inputs, view::{ColorGrid, Animation}, util::get_angle, waveform::Waveform}
}; };
pub struct WaveFade { pub inputs: Arc<RwLock< Inputs >>, pub struct WaveFade { pub inputs: Inputs,
pub hue: f32, pub hue: f32,
} }
impl Animation for WaveFade {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
}
}
impl ColorGrid for WaveFade { impl ColorGrid for WaveFade {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone(); let nt = ( self.inputs.t.as_millis() as f32 / self.inputs.cycle_len.as_millis() as f32 );
let nt = ( inputs.t.as_millis() as f32 / inputs.cycle_len.as_millis() as f32 );
let i = let i =
match inputs.wheel % 4 { match self.inputs.wheel % 4 {
0 => Waveform::Sine{}.get_norm(nt), 0 => Waveform::Sine{}.get_norm(nt),
1 => Waveform::Triangle{}.get_norm(nt), 1 => Waveform::Triangle{}.get_norm(nt),
2 => Waveform::Sawtooth{}.get_norm(nt), 2 => Waveform::Sawtooth{}.get_norm(nt),

View file

@ -10,16 +10,21 @@ use {
std::time::Duration, std::time::Duration,
angle::Turns, angle::Turns,
crate::{Inputs, view::ColorGrid, util::get_angle} crate::{Inputs, view::{ColorGrid, Animation}, util::get_angle}
}; };
#[derive(Default)]
pub struct Wheel { pub inputs: Inputs }
impl Animation for Wheel {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
}
}
pub struct Wheel { pub inputs: Arc<RwLock< Inputs >> }
impl ColorGrid for Wheel { impl ColorGrid for Wheel {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone(); let millis = self.inputs.t.as_millis();
let millis = inputs.t.as_millis();
let p1 = p + Vector2::new(0.0,0.5); let p1 = p + Vector2::new(0.0,0.5);
let r2 = p1.x*p1.x + p1.y*p1.y; let r2 = p1.x*p1.x + p1.y*p1.y;
@ -31,8 +36,8 @@ impl ColorGrid for Wheel {
(5.0) * (5.0) *
mirrorphi * mirrorphi *
( (
inputs.t.as_millis() as f32 self.inputs.t.as_millis() as f32
/ (inputs.cycle_len.as_millis() as f32 * (1.0 + (inputs.wheel as f32).abs())) / (self.inputs.cycle_len.as_millis() as f32 * (1.0 + (self.inputs.wheel as f32).abs()))
) )
); );
@ -40,7 +45,7 @@ impl ColorGrid for Wheel {
&Hsv::<f32, Turns<f32>>::new( &Hsv::<f32, Turns<f32>>::new(
Turns( gamma*0.5 ), Turns( gamma*0.5 ),
0.5 + r2 * 0.5, 0.5 + r2 * 0.5,
(inputs.wheel as f32 / 16.0), (self.inputs.wheel as f32 / 16.0),
) )
) )
} }

View file

@ -11,56 +11,67 @@ use {
angle::Turns, angle::Turns,
crate::Inputs, crate::Inputs,
crate::view::ColorGrid, crate::view::{ColorGrid, Animation},
crate::patterns::* crate::patterns::*
}; };
pub struct SceneLibrary { pub struct SceneLibrary {
library: Vec< Box<dyn ColorGrid> >, library: Vec< Box<dyn Animation> >,
current_scene: RwLock<usize>, current_scene: usize,
inputs: Arc<RwLock< Inputs >>, inputs: Inputs,
transition_length: Duration, transition_length: Duration,
// transition_curve: enum { Constant, Linear, Sigmoid, Sinus } // transition_curve: enum { Constant, Linear, Sigmoid, Sinus }
} }
impl SceneLibrary { impl SceneLibrary {
pub fn new( inputs: Arc<RwLock<Inputs>> ) -> Self { pub fn new() -> Self {
SceneLibrary { SceneLibrary {
library: vec![ library: vec![
// 0 // 0
Box::new( Breathing{ inputs: inputs.clone() } ), Box::new( Breathing::default() ),
// 1 // 1
Box::new( Strobe{ inputs: inputs.clone() } ), Box::new( Strobe::default() ),
// 2 // 2
Box::new( WaveFade{ inputs: inputs.clone(), hue: 0.5 } ), // Box::new( WaveFade{ inputs: inputs.clone(), hue: 0.5 } ),
// 3 // 3
Box::new( UbootPrüfstandFade{ inputs: inputs.clone() } ), Box::new( UbootPrüfstandFade::default() ),
//4 //4
Box::new( ArcticRain{ inputs: inputs.clone() } ), Box::new( ArcticRain::default() ),
//5 //5
Box::new( Wheel{ inputs: inputs.clone() } ), Box::new( Wheel::default() ),
//6 //6
Box::new( Alternate{ inputs: inputs.clone() } ), Box::new( Alternate::default() ),
//7 //7
Box::new( PastelFade{ inputs: inputs.clone() } ), Box::new( PastelFade::default() ),
//8
Box::new( OneShotMan::default() )
], ],
current_scene: RwLock::new(0), current_scene: 0,
inputs, inputs: Inputs::default(),
transition_length: Duration::from_millis(200), transition_length: Duration::from_millis(200),
} }
} }
} }
impl Animation for SceneLibrary {
fn advance(&mut self, inputs: &Inputs) {
self.inputs = inputs.clone();
if self.inputs.transition_time.as_millis() as f32 > self.transition_length.as_millis() as f32 {
// change own state:
self.current_scene = self.inputs.scene_select;
}
if let Some(a) = self.library.get_mut(self.current_scene) {
a.advance( inputs );
}
}
}
impl ColorGrid for SceneLibrary { impl ColorGrid for SceneLibrary {
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> { fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
let inputs = self.inputs.read().unwrap().clone(); let mut intensity: f32 = self.inputs.master_intensity;
let sc = *self.current_scene.read().unwrap();
let mut intensity: f32 = inputs.master_intensity;
if intensity > 1.0 { if intensity > 1.0 {
intensity = 1.0; intensity = 1.0;
} }
@ -68,20 +79,19 @@ impl ColorGrid for SceneLibrary {
intensity = -1.0; intensity = -1.0;
} }
if let Some(w) = inputs.master_wave { if let Some(w) = self.inputs.master_wave.clone() {
intensity *= w.get_doub( intensity *= w.get_doub(
inputs.t.as_millis() as f32 self.inputs.t.as_millis() as f32
/ inputs.cycle_len.as_millis() as f32 / self.inputs.cycle_len.as_millis() as f32
); );
} }
if inputs.scene_select < self.library.len() { if self.inputs.scene_select < self.library.len() {
if self.inputs.scene_select == self.current_scene {
if inputs.scene_select == sc {
// display only one animation // display only one animation
let mut hsv = Hsv::from_color( let mut hsv = Hsv::from_color(
&self.library[ sc ].get(p) &self.library[ self.current_scene ].get(p)
); );
hsv = Hsv::<f32>::new( hsv = Hsv::<f32>::new(
@ -93,24 +103,18 @@ impl ColorGrid for SceneLibrary {
Rgb::from_color(&hsv) Rgb::from_color(&hsv)
} else { } else {
// display transition // display transition
let cur_scene = &self.library[ sc ]; let cur_scene = &self.library[ self.current_scene ];
let nxt_scene = &self.library[ inputs.scene_select ]; let nxt_scene = &self.library[ self.inputs.scene_select ];
// crossfade param // crossfade param
let w = ( inputs.transition_time.as_millis() as f32 / self.transition_length.as_millis() as f32 ); let w = ( self.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) cur_scene.get(p)
.lerp( .lerp(
&nxt_scene.get(p), &nxt_scene.get(p),
w w
) )
}
}
} else { } else {
Rgb::new(0.0, 0.0, 0.0) Rgb::new(0.0, 0.0, 0.0)
} }

View file

@ -1,7 +1,8 @@
use { use {
crate::{ crate::{
fixture::Fixture, fixture::Fixture,
view::ColorGrid inputs::Inputs,
view::{ColorGrid, Animation}
}, },
cgmath::Vector2, cgmath::Vector2,
std::time::Duration, std::time::Duration,
@ -9,25 +10,25 @@ use {
}; };
pub struct LightingSetup { pub struct LightingSetup {
fixtures: Vec<Fixture>, pub fixtures: Vec<Fixture>,
t: Arc<RwLock<Duration>>, t: Arc<RwLock<Duration>>,
view: Box<dyn ColorGrid> animation: Box<dyn Animation>
} }
impl LightingSetup { impl LightingSetup {
pub fn new(fixtures: Vec<Fixture>, view: Box<dyn ColorGrid>) -> Self { pub fn new(fixtures: Vec<Fixture>, animation: Box<dyn Animation>) -> Self {
let t = Arc::new(RwLock::new(Duration::from_millis(0))); let t = Arc::new(RwLock::new(Duration::from_millis(0)));
LightingSetup { LightingSetup {
fixtures, fixtures,
t: t.clone(), t: t.clone(),
view animation
} }
} }
pub fn update_buffers(&mut self) { pub fn update_buffers(&mut self) {
for fixture in self.fixtures.iter_mut() { for fixture in self.fixtures.iter_mut() {
fixture.update_buffer( &self.view ); fixture.update_buffer( self.animation.as_ref() );
} }
} }
@ -46,6 +47,11 @@ impl LightingSetup {
} }
} }
pub fn advance(&mut self, inputs: &Inputs) {
self.animation.advance(inputs);
self.update_buffers();
}
pub fn draw_preview( pub fn draw_preview(
&self, &self,
buffer: &mut softbuffer::Buffer<'_, Arc<winit::window::Window>, Arc<winit::window::Window>>, buffer: &mut softbuffer::Buffer<'_, Arc<winit::window::Window>, Arc<winit::window::Window>>,
@ -65,7 +71,7 @@ impl LightingSetup {
let xf = (x as f32 - width as f32/2.0) / mindim as f32; let xf = (x as f32 - width as f32/2.0) / mindim as f32;
let yf = -(y as f32 - height as f32/2.0) / mindim as f32; let yf = -(y as f32 - height as f32/2.0) / mindim as f32;
let color = self.view.get(&Vector2::new(xf, yf)); let color = self.animation.get(&Vector2::new(xf, yf));
let red = (color.red() * 16.0) as u32; let red = (color.red() * 16.0) as u32;

View file

@ -1,9 +1,15 @@
use { use {
cgmath::Vector2, cgmath::Vector2,
prisma::Rgb prisma::Rgb,
crate::inputs::Inputs
}; };
pub trait ColorGrid { pub trait ColorGrid {
fn get(&self, pos: &Vector2<f32>) -> Rgb<f32>; fn get(&self, pos: &Vector2<f32>) -> Rgb<f32>;
} }
pub trait Animation : ColorGrid {
fn advance(&mut self, inputs: &Inputs);
}