preview-rendering prototype
This commit is contained in:
commit
37ce32712b
2 changed files with 294 additions and 0 deletions
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "fragmental-light-controller"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
winit = "*"
|
||||
softbuffer = "0.4.2"
|
||||
cgmath = "*"
|
||||
prisma = "0.1.1"
|
||||
angular-units = "*"
|
||||
|
||||
[dependencies.async-std]
|
||||
version = "1.9.0"
|
||||
features = ["unstable", "attributes"]
|
||||
|
278
src/main.rs
Normal file
278
src/main.rs
Normal file
|
@ -0,0 +1,278 @@
|
|||
extern crate angular_units as angle;
|
||||
|
||||
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},
|
||||
cgmath::{Point2, Vector2},
|
||||
std::time::Duration,
|
||||
angle::Turns
|
||||
};
|
||||
|
||||
trait ColorGrid {
|
||||
fn get(&self, pos: &Vector2<f32>) -> Rgb<f32>;
|
||||
}
|
||||
|
||||
struct TestAnimation {
|
||||
t: Arc<RwLock<Duration>>
|
||||
}
|
||||
|
||||
fn get_angle(p: &Vector2<f32>) -> f32 {
|
||||
let pi=3.1415926;
|
||||
let pi2 = 2.0*pi;
|
||||
|
||||
if p.x < 0.0 {
|
||||
(p.y / p.x).atan() / pi2 + 0.75
|
||||
} else if p.x == 0.0 && p.y == 0.0 {
|
||||
0.0
|
||||
} else {
|
||||
if p.y < 0.0 {
|
||||
(-p.x / p.y).atan() / pi2
|
||||
} else {
|
||||
(p.y / p.x).atan() / pi2 + 0.25
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorGrid for TestAnimation {
|
||||
fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
|
||||
let millis = self.t.read().unwrap().as_millis();
|
||||
|
||||
let p1 = p + Vector2::new(0.0,1.0);
|
||||
let r2 = p1.x*p1.x + p1.y*p1.y;
|
||||
let v = if r2 > 1.0 { 1.0 } else { r2 };
|
||||
|
||||
let phi : f32 = (
|
||||
(millis as f32 / 4000.0) +
|
||||
(
|
||||
100.0 + (millis%20000) as f32 / 300.0
|
||||
) * get_angle(&p1)
|
||||
) % 1.0;
|
||||
|
||||
Rgb::from_color(
|
||||
&Hsv::<f32, Turns<f32>>::new(
|
||||
Turns( ((millis as f32 / 8000.0) + phi*0.2)%1.0 ),
|
||||
0.5 + r2 * 0.5,
|
||||
phi,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct Fixture {
|
||||
resolution: Vector2<u32>,
|
||||
position: Vector2<f32>,
|
||||
rotation: f32,
|
||||
scale: f32,
|
||||
brightness: f32,
|
||||
buffer: Vec< Rgb<u8> >
|
||||
}
|
||||
|
||||
impl Fixture {
|
||||
pub fn new_stripe() -> Self {
|
||||
let mut fixture = Fixture {
|
||||
resolution: Vector2::new(1, 72),
|
||||
position: Vector2::new(0.0, 0.0),
|
||||
rotation: 0.0,
|
||||
scale: 0.01,
|
||||
brightness: 0.8,
|
||||
buffer: Vec::new()
|
||||
};
|
||||
fixture.buffer.resize(
|
||||
(fixture.resolution.x*fixture.resolution.y) as usize,
|
||||
Rgb::new(0,0,0));
|
||||
fixture
|
||||
}
|
||||
|
||||
pub fn new_matrix() -> Self {
|
||||
let mut fixture = Fixture {
|
||||
resolution: Vector2::new(15, 20),
|
||||
position: Vector2::new(0.0, 0.0),
|
||||
rotation: 0.0,
|
||||
scale: 0.03,
|
||||
brightness: 0.8,
|
||||
buffer: Vec::new()
|
||||
};
|
||||
fixture.buffer.resize(
|
||||
(fixture.resolution.x*fixture.resolution.y) as usize,
|
||||
Rgb::new(0,0,0)
|
||||
);
|
||||
fixture
|
||||
}
|
||||
|
||||
fn offset(mut self, offset: Vector2<f32>) -> Self {
|
||||
self.position += offset;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_global_pos(&self, pixel_pos: &Vector2<u32>) -> Vector2<f32> {
|
||||
let centered_pixpos : Vector2<f32>
|
||||
= pixel_pos.map(|f| f as f32) - (self.resolution.map(|f| f as f32)/2.0);
|
||||
self.position + centered_pixpos * self.scale
|
||||
}
|
||||
|
||||
pub fn update_buffer(&mut self, view: &Box<dyn ColorGrid>) {
|
||||
for xi in 0 .. self.resolution.x {
|
||||
for yi in 0 ..self.resolution.y {
|
||||
let gpos = self.get_global_pos(&Vector2::new(xi, yi));
|
||||
let col = view.get(&gpos);
|
||||
|
||||
let index = xi + yi * self.resolution.x;
|
||||
self.buffer[index as usize] = Rgb::new(
|
||||
(col.red() * 255.0 * self.brightness) as u8,
|
||||
(col.green() * 255.0 * self.brightness) as u8,
|
||||
(col.blue() * 255.0 * self.brightness) as u8
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LightingSetup {
|
||||
fixtures: Vec<Fixture>,
|
||||
t: Arc<RwLock<Duration>>,
|
||||
|
||||
view: Box<dyn ColorGrid>
|
||||
}
|
||||
|
||||
impl LightingSetup {
|
||||
fn new(fixtures: Vec<Fixture>) -> Self {
|
||||
let t = Arc::new(RwLock::new(Duration::from_millis(0)));
|
||||
LightingSetup {
|
||||
fixtures,
|
||||
t: t.clone(),
|
||||
view: Box::new(
|
||||
TestAnimation{ t }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn update_buffers(&mut self) {
|
||||
for fixture in self.fixtures.iter_mut() {
|
||||
fixture.update_buffer( &self.view );
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_preview(
|
||||
&self,
|
||||
buffer: &mut softbuffer::Buffer<'_, Arc<winit::window::Window>, Arc<winit::window::Window>>,
|
||||
width: u32,
|
||||
height: u32
|
||||
) {
|
||||
// pixels per Unit
|
||||
let mindim = u32::min(width, height);
|
||||
let midx = width/2;
|
||||
let midy = height/2;
|
||||
|
||||
// background
|
||||
for index in 0..(width * height) {
|
||||
let y = index / width;
|
||||
let x = index % width;
|
||||
|
||||
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 color = self.view.get(&Vector2::new(xf, yf));
|
||||
|
||||
let red = (color.red() * 32.0) as u32;
|
||||
let green = (color.green() * 32.0) as u32;
|
||||
let blue = (color.blue() * 32.0) as u32;
|
||||
|
||||
buffer[index as usize] = blue | (green << 8) | (red << 16);
|
||||
}
|
||||
|
||||
for fixture in self.fixtures.iter() {
|
||||
let pixel_width = fixture.scale * mindim as f32;
|
||||
|
||||
for fx in 0..fixture.resolution.x {
|
||||
for fy in 0..fixture.resolution.y {
|
||||
// get global position for pixel
|
||||
let gpos = fixture.get_global_pos(&Vector2::new(fx, fy));
|
||||
|
||||
// get start coordinates for pixel
|
||||
let xi = (midx as f32 + gpos.x*mindim as f32) as u32;
|
||||
let yi = (midy as f32 - gpos.y*mindim as f32) as u32;
|
||||
|
||||
let col = fixture.buffer[(fx+fy*fixture.resolution.x) as usize];
|
||||
let bufval = col.blue() as u32 | ((col.green() as u32) << 8) | ((col.red() as u32) << 16);
|
||||
|
||||
// draw pixel
|
||||
for xl in 0..(pixel_width*0.6) as u32 {
|
||||
for yl in 0..(pixel_width*0.6) as u32 {
|
||||
if (xi+xl) < width && (yi+yl) < height {
|
||||
let index = (xi+xl) + (yi+yl)*width;
|
||||
buffer[index as usize] = bufval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let event_loop = EventLoop::new().unwrap();
|
||||
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
||||
let context = softbuffer::Context::new(window.clone()).unwrap();
|
||||
let mut surface = Arc::new(Mutex::new(softbuffer::Surface::new(&context, window.clone()).unwrap()));
|
||||
|
||||
let dim = Arc::new(Mutex::new((1 as u32,1 as u32)));
|
||||
|
||||
let mut lighting_setup = LightingSetup::new(
|
||||
vec![
|
||||
Fixture::new_matrix(),
|
||||
Fixture::new_stripe().offset(Vector2::new(-0.5, 0.0)),
|
||||
Fixture::new_stripe().offset(Vector2::new(-0.4, 0.0)),
|
||||
Fixture::new_stripe().offset(Vector2::new( 0.4, 0.0)),
|
||||
Fixture::new_stripe().offset(Vector2::new( 0.5, 0.0))
|
||||
]
|
||||
);
|
||||
|
||||
let tbegin = std::time::Instant::now();
|
||||
event_loop.run(move |event, elwt| {
|
||||
let tcur = std::time::Instant::now();
|
||||
elwt.set_control_flow(ControlFlow::WaitUntil(
|
||||
tcur + Duration::from_millis(10)
|
||||
));
|
||||
|
||||
*lighting_setup.t.write().unwrap() = tcur - tbegin;
|
||||
lighting_setup.update_buffers();
|
||||
|
||||
match event {
|
||||
Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested } if window_id == window.id() => {
|
||||
let (width, height) = {
|
||||
let size = window.inner_size();
|
||||
(size.width, size.height)
|
||||
};
|
||||
|
||||
*dim.lock().unwrap() = (width, height);
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
window_id,
|
||||
} if window_id == window.id() => {
|
||||
elwt.exit();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let (width, height) = *dim.lock().unwrap();
|
||||
surface.lock().unwrap()
|
||||
.resize(
|
||||
NonZeroU32::new(width).unwrap(),
|
||||
NonZeroU32::new(height).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Ok(mut buf) = surface.lock().unwrap().buffer_mut() {
|
||||
lighting_setup.draw_preview( &mut buf, width, height );
|
||||
buf.present().unwrap();
|
||||
}
|
||||
}).unwrap();
|
||||
}
|
Loading…
Reference in a new issue