use pixels::{Pixels, SurfaceTexture};
use std::{
fmt,
sync::{
Arc,
mpsc::{Receiver, SendError, Sender, channel},
},
thread::JoinHandle,
};
use vzense_rust::Resolution;
use winit::{
application::ApplicationHandler,
dpi::LogicalSize,
event::{ElementState, MouseButton, WindowEvent},
event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
window::{Window, WindowAttributes, WindowId},
};
pub enum BottomView {
Color,
Touch,
Ir,
}
impl fmt::Display for BottomView {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BottomView::Color => write!(f, "Color"),
BottomView::Touch => write!(f, "Touch"),
BottomView::Ir => write!(f, "IR"),
}
}
}
pub enum WindowMessage {
MouseClick,
Exit,
}
#[derive(Debug, Clone)]
pub struct VideoBuffer(pub Arc<Vec<u8>>);
impl VideoBuffer {
fn new(pixel_count: usize) -> Self {
VideoBuffer(Arc::new(
std::iter::repeat_n(&[0, 0, 0, 255], pixel_count)
.flatten()
.cloned()
.collect(),
))
}
}
pub struct VideoProducer {
rx_old: Receiver<VideoBuffer>,
sx_new: Sender<VideoBuffer>,
sx_info: Sender<String>,
pub rx_window_message: Receiver<WindowMessage>,
}
impl VideoProducer {
pub fn grab_old_buffer(&self) -> Option<VideoBuffer> {
self.rx_old.try_recv().ok()
}
pub fn send(&self, buffer: VideoBuffer) -> Result<(), SendError<String>> {
if self.sx_new.send(buffer).is_err() {
Err(SendError("cannot send filled buffer".to_string()))
} else {
Ok(())
}
}
pub fn set_info(&self, info: String) {
self.sx_info.send(info).unwrap();
}
}
pub struct VideoConsumer {
pub name: String,
pub resolution: Resolution,
pub rx_new: Receiver<VideoBuffer>,
pub sx_old: Sender<VideoBuffer>,
pub rx_info: Receiver<String>,
pub sx_window_message: Sender<WindowMessage>,
}
const POOL_SIZE: usize = 3;
pub fn new(name: &str, width: u32, height: u32) -> (VideoProducer, VideoConsumer) {
let (sx_new, rx_new) = channel();
let (sx_old, rx_old) = channel();
let (sx_info, rx_info) = channel();
let (sx_window_message, rx_window_message) = channel();
for _ in 0..POOL_SIZE {
sx_old
.send(VideoBuffer::new((width * height) as usize))
.unwrap();
}
(
VideoProducer {
rx_old,
sx_new,
sx_info,
rx_window_message,
},
VideoConsumer {
name: name.to_string(),
resolution: Resolution::new(width, height),
rx_new,
sx_old,
rx_info,
sx_window_message,
},
)
}
type CameraHandle = Option<JoinHandle<Result<(), String>>>;
struct App<'a> {
window: Arc<Window>,
pixels: Pixels<'a>,
consumer: VideoConsumer,
camera_handle: CameraHandle,
}
impl ApplicationHandler for App<'_> {
fn resumed(&mut self, _event_loop: &ActiveEventLoop) {}
fn window_event(
&mut self,
_event_loop: &ActiveEventLoop,
_window_id: WindowId,
event: WindowEvent,
) {
match event {
WindowEvent::CloseRequested => {
println!("stopping camera thread...");
self.consumer
.sx_window_message
.send(WindowMessage::Exit)
.ok();
}
WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Left,
..
} => {
self.consumer
.sx_window_message
.send(WindowMessage::MouseClick)
.ok();
}
_ => (),
}
}
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
if let Some(handle) = &self.camera_handle {
if handle.is_finished() {
if let Some(handle) = self.camera_handle.take() {
if let Ok(Err(e)) = handle.join() {
eprintln!("camera thread finished: {e}");
}
}
event_loop.exit();
}
}
let mut new_frame = None;
while let Ok(intermediate_frame) = self.consumer.rx_new.try_recv() {
if let Some(frame) = new_frame {
self.consumer.sx_old.send(frame).expect("couldn't drain");
}
new_frame = Some(intermediate_frame);
}
if let Some(frame) = new_frame {
self.pixels.frame_mut().copy_from_slice(&frame.0);
self.consumer
.sx_old
.send(frame)
.expect("couldn't send old buffer");
if let Err(err) = self.pixels.render() {
eprintln!("pixels render failed {err}");
}
}
if let Some(info) = self.consumer.rx_info.try_iter().last() {
self.window.set_title(&(self.consumer.name.clone() + &info));
}
}
}
pub fn run(
camera_handle: CameraHandle,
consumer: VideoConsumer,
) -> Result<(), Box<dyn std::error::Error>> {
let event_loop = EventLoop::new()?;
event_loop.set_control_flow(ControlFlow::Poll);
let (width, height) = consumer.resolution.to_tuple();
#[allow(deprecated)]
let window = Arc::new(
event_loop.create_window(
WindowAttributes::default()
.with_title(consumer.name.clone())
.with_inner_size(LogicalSize::new(width, height))
.with_resizable(false),
)?,
);
let surface_texture = SurfaceTexture::new(width, height, window.clone());
let pixels = Pixels::new(width, height, surface_texture)?;
let mut app = App {
window,
pixels,
consumer,
camera_handle,
};
event_loop.run_app(&mut app)?;
Ok(())
}