diff --git a/src/input.rs b/src/input.rs deleted file mode 100644 index eb92e71..0000000 --- a/src/input.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::collections::HashSet; - -use evdev::{AbsoluteAxisCode, Device, EventSummary, InputEvent, KeyCode}; - -struct InputState { - x: i32, - y: i32, - keys_down: HashSet, - keys_pressed_this_update: HashSet, - keys_released_this_update: HashSet, - clear_before_next_event: bool, -} - -impl InputState { - pub fn new() -> Self { - Self { - x: 0, - y: 0, - keys_down: HashSet::new(), - keys_pressed_this_update: HashSet::new(), - keys_released_this_update: HashSet::new(), - clear_before_next_event: true, - } - } - - pub fn handle_event(&mut self, event: &InputEvent) { - match event.destructure() { - EventSummary::AbsoluteAxis(_, AbsoluteAxisCode::ABS_X, value) => { - self.x = (((value - 13) as f32 / 882.) * (screen.width() as f32)) as i32; - } - EventSummary::AbsoluteAxis(_, AbsoluteAxisCode::ABS_Y, value) => { - self.y = (((value - 13) as f32 / 624.) * (screen.height() as f32)) as i32; - } - EventSummary::Key(_, KeyCode::BTN_TOUCH, value) => { - // if value is 1, touch is started - // if value is 0, touch ended - println!("touch: {}", value) - } - _ => {} - } - } -} diff --git a/src/main.rs b/src/main.rs index e745db3..fc321b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,76 +1,70 @@ mod rgba; -mod screen; -mod input; +mod trekstor; -use embedded_graphics::{prelude::*, primitives::{PrimitiveStyle, Rectangle}}; -use evdev::{AbsoluteAxisCode, Device, EventSummary, KeyCode}; -use screen::Screen; -use rgba::Rgba; +use evdev::KeyCode; +use crate::trekstor::Trekstor; fn main() { - let mut screen = Screen::new(); + let mut trekstor = Trekstor::new(30); - let red = (255, 0, 0, 255); - let green = (0, 255, 0, 255); - let blue = (0, 0, 255, 255); + trekstor.update(|screen, input| { + // retuyrningf false will exit loop + if input.is_just_pressed(KeyCode::BTN_TOUCH) { + println!("Touched {}x{}", input.x, input.y); + } + true + }); - // /dev/input/event4: silead_ts + // let red = (255, 0, 0, 255); + // let green = (0, 255, 0, 255); + // let blue = (0, 0, 255, 255); + // // /dev/input/event4: silead_ts - Rectangle::new(Point::new(0, 0), Size::new(screen.width(), 1)) - .into_styled(PrimitiveStyle::with_fill(Rgba::from(red))) - .draw(&mut screen) - .ok(); + // Rectangle::new(Point::new(0, 0), Size::new(trekstor.screen.width(), 1)) + // .into_styled(PrimitiveStyle::with_fill(Rgba::from(red))) + // .draw(&mut trekstor.screen) + // .ok(); - Rectangle::new(Point::new(0, 1), Size::new(screen.width(), 1)) - .into_styled(PrimitiveStyle::with_fill(Rgba::from(green))) - .draw(&mut screen) - .ok(); + // Rectangle::new(Point::new(0, 1), Size::new(trekstor.screen.width(), 1)) + // .into_styled(PrimitiveStyle::with_fill(Rgba::from(green))) + // .draw(&mut trekstor.screen) + // .ok(); - Rectangle::new(Point::new(0, 2), Size::new(screen.width(), 1)) - .into_styled(PrimitiveStyle::with_fill(Rgba::from(blue))) - .draw(&mut screen) - .ok(); - - let Ok(mut device) = Device::open("/dev/input/event4") else { - panic!("No TS"); - }; + // Rectangle::new(Point::new(0, 2), Size::new(trekstor.screen.width(), 1)) + // .into_styled(PrimitiveStyle::with_fill(Rgba::from(blue))) + // .draw(&mut trekstor.screen) + // .ok(); // device.set_nonblocking(true).unwrap(); - let mut x = -1; - let mut y = -1; + // loop { + // // println!("dont block"); - loop { - // println!("dont block"); - let Ok(events) = device.fetch_events() else { - continue; - }; + // for event in events { + // match event.destructure() { + // EventSummary::AbsoluteAxis(_, AbsoluteAxisCode::ABS_X, value) => { + // x = (((value - 13) as f32 / 882.) * (trekstor.width() as f32)) as i32; + // } + // EventSummary::AbsoluteAxis(_, AbsoluteAxisCode::ABS_Y, value) => { + // y = (((value - 13) as f32 / 624.) * (trekstor.height() as f32)) as i32; + // } + // EventSummary::Key(_, KeyCode::BTN_TOUCH, value) => { + // // if value is 1, touch is started + // // if value is 0, touch ended + // println!("touch: {}", value) + // } + // _ => {} + // } + // } - for event in events { - match event.destructure(){ - EventSummary::AbsoluteAxis(_, AbsoluteAxisCode::ABS_X, value) => { - x = (((value - 13) as f32 / 882.) * (screen.width() as f32)) as i32; - }, - EventSummary::AbsoluteAxis(_, AbsoluteAxisCode::ABS_Y, value) => { - y = (((value - 13) as f32 / 624.) * (screen.height() as f32)) as i32; - }, - EventSummary::Key(_, KeyCode::BTN_TOUCH, value) => { - // if value is 1, touch is started - // if value is 0, touch ended - println!("touch: {}", value) - }, - _ => {} - } - } + // println!("{}x{}", x, y); - println!("{}x{}", x, y); - - screen.clear(Rgba::from((0,0,0,255))).ok(); - Rectangle::new(Point::new(x - 50, y - 50), Size::new(100, 100)) - .into_styled(PrimitiveStyle::with_fill(Rgba::from(blue))) - .draw(&mut screen) - .ok(); - } + // trekstor.clear(Rgba::from((0, 0, 0, 255))).ok(); + // Rectangle::new(Point::new(x - 50, y - 50), Size::new(100, 100)) + // .into_styled(PrimitiveStyle::with_fill(Rgba::from(blue))) + // .draw(&mut trekstor) + // .ok(); + // } } diff --git a/src/trekstor.rs b/src/trekstor.rs new file mode 100644 index 0000000..37a5438 --- /dev/null +++ b/src/trekstor.rs @@ -0,0 +1,63 @@ +use std::time::{Duration, Instant}; + +use self::input::InputState; +use self::screen::Screen; + +type UpdateFn = fn(&mut Screen, &InputState) -> bool; + +mod input; +mod screen; + +pub struct Trekstor { + pub screen: Screen, + pub input: InputState, + accumulator: Duration, + last_time: Instant, + current_time: Instant, + update_timestep: Duration, +} + +impl Trekstor { + pub fn new(update_fps: i32) -> Self { + let screen = Screen::new(); + let input = InputState::new(&screen); + + Self { + screen, + input, + accumulator: Duration::default(), + current_time: Instant::now(), + last_time: Instant::now(), + update_timestep: Duration::from_nanos( + (1_000_000_000f64 / update_fps as f64).round() as u64 + ), + } + } + + pub fn update(&mut self, update: UpdateFn) { + loop { + self.input.handle_event(); + + self.last_time = self.current_time; + self.current_time = Instant::now(); + let mut dt = self.current_time - self.last_time; + + if dt > Duration::from_millis(100) { + dt = Duration::from_millis(100); + } + + while self.accumulator > self.update_timestep { + self.input.next_loop(); + + if !update(&mut self.screen, &self.input) { + return; + } + self.accumulator -= self.update_timestep; + } + + self.screen.flush(); + + self.accumulator += dt; + } + } +} diff --git a/src/trekstor/input.rs b/src/trekstor/input.rs new file mode 100644 index 0000000..ce55b45 --- /dev/null +++ b/src/trekstor/input.rs @@ -0,0 +1,100 @@ +use super::screen::Screen; +use std::collections::HashSet; + +use evdev::{AbsoluteAxisCode, Device, EventSummary, KeyCode}; + +pub struct InputState { + device: Device, + pub x: i32, + pub y: i32, + width: i32, + height: i32, + keys_down: HashSet, + keys_pressed_this_update: HashSet, + keys_released_this_update: HashSet, + clear_before_next_event: bool, +} + +impl InputState { + pub fn new(screen: &Screen) -> Self { + let Ok(device) = Device::open("/dev/input/event4") else { + panic!("No TS"); + }; + + device.set_nonblocking(true).unwrap(); + + Self { + device, + x: 0, + y: 0, + width: screen.width() as i32, + height: screen.height() as i32, + keys_down: HashSet::new(), + keys_pressed_this_update: HashSet::new(), + keys_released_this_update: HashSet::new(), + clear_before_next_event: true, + } + } + + pub(super) fn next_loop(&mut self) { + self.clear_before_next_event = true; + } + + pub(super) fn handle_event(&mut self) { + let Ok(events) = self.device.fetch_events() else { + return; + }; + + if self.clear_before_next_event { + self.keys_pressed_this_update.clear(); + self.keys_released_this_update.clear(); + self.clear_before_next_event = false; + } + + for event in events { + match event.destructure() { + EventSummary::AbsoluteAxis(_, AbsoluteAxisCode::ABS_X, value) => { + self.x = (((value - 13) as f32 / 882.) * (self.width as f32)) as i32; + } + EventSummary::AbsoluteAxis(_, AbsoluteAxisCode::ABS_Y, value) => { + self.y = (((value - 13) as f32 / 624.) * (self.height as f32)) as i32; + } + EventSummary::Key(_, key, value) => match value { + 1 => { + if !self.keys_down.contains(&key) { + self.keys_pressed_this_update.insert(key); + } + self.keys_down.insert(key); + } + 0 => { + if self.keys_down.contains(&key) { + self.keys_released_this_update.insert(key); + } + self.keys_down.remove(&key); + } + _ => {} + }, + _ => {} + } + } + } +} + +#[allow(unused)] +impl InputState { + pub fn is_just_pressed(&self, key: KeyCode) -> bool { + self.keys_pressed_this_update.contains(&key) + } + + pub fn is_down(&self, key: KeyCode) -> bool { + self.keys_down.contains(&key) + } + + pub fn is_just_released(&self, key: KeyCode) -> bool { + self.keys_released_this_update.contains(&key) + } + + pub fn is_up(&self, key: KeyCode) -> bool { + !self.is_down(key) + } +} diff --git a/src/screen.rs b/src/trekstor/screen.rs similarity index 86% rename from src/screen.rs rename to src/trekstor/screen.rs index 63eeca7..54c0fe3 100644 --- a/src/screen.rs +++ b/src/trekstor/screen.rs @@ -3,7 +3,6 @@ use linfb::{Framebuffer, shape::Color}; use crate::rgba::Rgba; - pub struct Screen { framebuffer: Framebuffer, width: u32, @@ -12,8 +11,7 @@ pub struct Screen { impl Screen { pub fn new() -> Self { - let framebuffer = Framebuffer::open() - .expect("Failed to open framebuffer"); + let framebuffer = Framebuffer::open().expect("Failed to open framebuffer"); let width = framebuffer.screen_info.xres; let height = framebuffer.screen_info.yres; @@ -21,10 +19,14 @@ impl Screen { Self { framebuffer, width, - height + height, } } + pub fn flush(&mut self) { + self.framebuffer.flush(); + } + pub fn width(&self) -> u32 { self.width } @@ -36,10 +38,7 @@ impl Screen { impl Dimensions for Screen { fn bounding_box(&self) -> Rectangle { - Rectangle::new( - Point::new(0, 0), - Size::new(self.width, self.height), - ) + Rectangle::new(Point::new(0, 0), Size::new(self.width, self.height)) } } @@ -71,7 +70,6 @@ impl DrawTarget for Screen { self.framebuffer.set_pixel(x, y, color); } - self.framebuffer.flush(); Ok(()) }