diff --git a/Cargo.lock b/Cargo.lock index d0f1234..8eb6d0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "aligned" version = "0.4.3" @@ -2376,6 +2382,19 @@ dependencies = [ "byteorder", ] +[[package]] +name = "embedded-graphics-simulator" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31606a4fb7d9d3a79a38d27bc2954cfa98682c8fea4b22c09a442785a80424e" +dependencies = [ + "base64", + "embedded-graphics", + "image", + "ouroboros", + "sdl2", +] + [[package]] name = "encase" version = "0.12.0" @@ -2785,6 +2804,7 @@ version = "0.1.0" dependencies = [ "ctrlc", "embedded-graphics", + "embedded-graphics-simulator", "g13-driver", "mlua", "time", @@ -3076,6 +3096,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.5.2" @@ -4196,6 +4222,30 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ouroboros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" +dependencies = [ + "heck", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + [[package]] name = "owned_ttf_parser" version = "0.25.1" @@ -4426,6 +4476,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + [[package]] name = "profiling" version = "1.0.17" @@ -4847,6 +4910,29 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "sdl2" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b498da7d14d1ad6c839729bd4ad6fc11d90a57583605f3b4df2cd709a9cd380" +dependencies = [ + "bitflags 1.3.2", + "lazy_static", + "libc", + "sdl2-sys", +] + +[[package]] +name = "sdl2-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951deab27af08ed9c6068b7b0d05a93c91f0a8eb16b6b816a5e73452a43521d3" +dependencies = [ + "cfg-if", + "libc", + "version-compare", +] + [[package]] name = "self_cell" version = "1.2.2" @@ -5549,6 +5635,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + [[package]] name = "version_check" version = "0.9.5" @@ -6625,6 +6717,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yazi" version = "0.2.1" diff --git a/driver/src/lib.rs b/driver/src/lib.rs index 08853d6..ffd6f2c 100644 --- a/driver/src/lib.rs +++ b/driver/src/lib.rs @@ -1,6 +1,7 @@ pub mod joystick; use std::{ + collections::{HashMap, hash_map::Entry}, io::{Read, Write}, sync::{Arc, RwLock}, time::Duration, @@ -16,62 +17,78 @@ use nusb::{ transfer::{ControlOut, ControlType, In, Interrupt, Out, Recipient}, }; +use crate::joystick::Button; + pub const G13_LCD_COLUMNS: i32 = 160; pub const G13_LCD_ROWS: i32 = 43; pub const G13_LCD_BYTES_PER_ROW: i32 = G13_LCD_COLUMNS / 8; pub const G13_LCD_BUF_SIZE: i32 = (G13_LCD_ROWS + 5) * G13_LCD_BYTES_PER_ROW; +const BUTTON_MAP: &[(Button, usize, u8)] = &[ + // buf[6] + (Button::Action, 6, 0b00000001), + (Button::Screen1, 6, 0b00000010), + (Button::Screen2, 6, 0b00000100), + (Button::Screen3, 6, 0b00001000), + (Button::Screen4, 6, 0b00010000), + (Button::M1, 6, 0b00100000), + (Button::M2, 6, 0b01000000), + (Button::M3, 6, 0b10000000), + // buf[7] + (Button::Light, 7, 0b01000000), + (Button::MR, 7, 0b00000001), + (Button::Stick1, 7, 0b00000010), + (Button::Stick2, 7, 0b00000100), + (Button::Stick3, 7, 0b00001000), + // buf[3] + (Button::G1, 3, 0b00000001), + (Button::G2, 3, 0b00000010), + (Button::G3, 3, 0b00000100), + (Button::G4, 3, 0b00001000), + (Button::G5, 3, 0b00010000), + (Button::G6, 3, 0b00100000), + (Button::G7, 3, 0b01000000), + (Button::G8, 3, 0b10000000), + // buf[4] + (Button::G9, 4, 0b00000001), + (Button::G10, 4, 0b00000010), + (Button::G11, 4, 0b00000100), + (Button::G12, 4, 0b00001000), + (Button::G13, 4, 0b00010000), + (Button::G14, 4, 0b00100000), + (Button::G15, 4, 0b01000000), + (Button::G16, 4, 0b10000000), + // buf[5] + (Button::G17, 5, 0b00000001), + (Button::G18, 5, 0b00000010), + (Button::G19, 5, 0b00000100), + (Button::G20, 5, 0b00001000), + (Button::G21, 5, 0b00010000), + (Button::G22, 5, 0b00100000), +]; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Vec2 +where + T: Copy, +{ + pub x: T, + pub y: T, +} + +impl Vec2 +where + T: Copy, +{ + pub fn new(x: T, y: T) -> Self { + Self { x, y } + } +} + #[derive(Clone)] pub struct G13 { - interface: Interface, - img_buffer: Arc>, - state: Arc>, -} - -#[derive(Debug, Clone, Copy, Default)] -pub struct State { - pub x: i32, - pub y: i32, - pub buttons: Buttons, -} - -#[derive(Debug, Clone, Copy, Default)] -pub struct Buttons { - pub action: bool, - pub screen1: bool, - pub screen2: bool, - pub screen3: bool, - pub screen4: bool, - pub light: bool, - pub m1: bool, - pub m2: bool, - pub m3: bool, - pub mr: bool, - pub g1: bool, - pub g2: bool, - pub g3: bool, - pub g4: bool, - pub g5: bool, - pub g6: bool, - pub g7: bool, - pub g8: bool, - pub g9: bool, - pub g10: bool, - pub g11: bool, - pub g12: bool, - pub g13: bool, - pub g14: bool, - pub g15: bool, - pub g16: bool, - pub g17: bool, - pub g18: bool, - pub g19: bool, - pub g20: bool, - pub g21: bool, - pub g22: bool, - pub stick1: bool, - pub stick2: bool, - pub stick3: bool, + display: G13Display, + input: G13Input, } impl G13 { @@ -96,80 +113,142 @@ impl G13 { Err(e) => return Err(format!("Unable to claim interface: {:#?}", e).into()), }; - let img_buffer = [0u8; G13_LCD_BUF_SIZE as usize + 8]; - let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8]; - buffer[0] = 0x03; - buffer[32..G13_LCD_BUF_SIZE as usize + 32 + 8].copy_from_slice(&img_buffer); - - let mut w = interface.endpoint::(0x02)?.writer(64); - w.write_all(&buffer)?; - w.flush()?; - Ok(Self { - interface, - img_buffer: Arc::new(RwLock::new(img_buffer)), - state: Arc::new(RwLock::new(Default::default())), + input: G13Input::new(interface.clone()), + display: G13Display::new(interface), }) } - pub fn state(&self) -> State { - *self.state.read().expect("Poisoned") + pub fn split(self) -> (G13Display, G13Input) { + (self.display, self.input) + } +} + +#[derive(Debug)] +pub enum G13Event { + Axis(u8, u8), + Button(Button, (bool, bool)), // (old, new) +} + +#[derive(Clone)] +pub struct G13Input { + interface: Interface, + buttons: HashMap, + axis: Vec2, + calibrated_axis: (Vec2, Vec2), // this needs to be saved/loaded + calibrating: bool, +} + +impl G13Input { + pub fn new(interface: Interface) -> Self { + Self { + interface, + buttons: HashMap::new(), + axis: Default::default(), + calibrated_axis: (Vec2::new(127, 127), Vec2::new(127, 127)), + calibrating: false, + } + } + pub fn calibrate(mut self) -> Self { + self.calibrating = true; + self } - pub fn read(&self) -> Result> { - let mut state = self.state(); + pub fn with_calibration_axis(mut self, min: Vec2, max: Vec2) -> Self { + self.calibrated_axis.0 = min; + self.calibrated_axis.1 = max; + self.calibrating = false; + self + } - let mut reader = self.interface.endpoint::(0x81)?.reader(8); + pub fn get_calibration_axis(&self) -> (Vec2, Vec2) { + self.calibrated_axis + } + + fn handle_button(&mut self, button: Button, value: bool) -> Option { + if let Entry::Vacant(e) = self.buttons.entry(button) { + e.insert(value); + if value { + return Some(G13Event::Button(button, (!value, value))); + } + } + + let prev = self.buttons[&button]; + if self.buttons[&button] == value { + return None; + } + + self.buttons.insert(button, value); + Some(G13Event::Button(button, (prev, value))) + } +} + +impl Iterator for G13Input { + type Item = Option; + + fn next(&mut self) -> Option { + let mut reader = self + .interface + .endpoint::(0x81) + .ok()? + .reader(8); let mut buf = [0; 8]; - reader.read_exact(&mut buf)?; + reader.read_exact(&mut buf).ok()?; - state.x = (((buf[1] as f64) / 256.0 * 1024.0) - 512.0) as i32; - state.y = (((buf[2] as f64) / 256.0 * 1024.0) - 512.0) as i32; + for &(button, index, mask) in BUTTON_MAP { + if let Some(event) = self.handle_button(button, buf[index] & mask != 0) { + self.calibrating = false; + return Some(Some(event)); + } + } - state.buttons.action = buf[6] & 0b00000001 != 0; - state.buttons.screen1 = buf[6] & 0b00000010 != 0; - state.buttons.screen2 = buf[6] & 0b00000100 != 0; - state.buttons.screen3 = buf[6] & 0b00001000 != 0; - state.buttons.screen4 = buf[6] & 0b00010000 != 0; - state.buttons.light = buf[7] & 0b0100000 != 0; + let axis = Vec2::new(buf[1], buf[2]); - state.buttons.m1 = buf[6] & 0b00100000 != 0; - state.buttons.m2 = buf[6] & 0b01000000 != 0; - state.buttons.m3 = buf[6] & 0b10000000 != 0; - state.buttons.mr = buf[7] & 0b00000001 != 0; + if self.axis == axis { + return Some(None); + } - state.buttons.g1 = buf[3] & 0b00000001 != 0; - state.buttons.g2 = buf[3] & 0b00000010 != 0; - state.buttons.g3 = buf[3] & 0b00000100 != 0; - state.buttons.g4 = buf[3] & 0b00001000 != 0; - state.buttons.g5 = buf[3] & 0b00010000 != 0; - state.buttons.g6 = buf[3] & 0b00100000 != 0; - state.buttons.g7 = buf[3] & 0b01000000 != 0; - state.buttons.g8 = buf[3] & 0b10000000 != 0; + self.axis = axis; - state.buttons.g9 = buf[4] & 0b00000001 != 0; - state.buttons.g10 = buf[4] & 0b00000010 != 0; - state.buttons.g11 = buf[4] & 0b00000100 != 0; - state.buttons.g12 = buf[4] & 0b00001000 != 0; - state.buttons.g13 = buf[4] & 0b00010000 != 0; - state.buttons.g14 = buf[4] & 0b00100000 != 0; - state.buttons.g15 = buf[4] & 0b01000000 != 0; - state.buttons.g16 = buf[4] & 0b10000000 != 0; + self.calibrated_axis.0.x = self.calibrated_axis.0.x.min(axis.x); + self.calibrated_axis.1.x = self.calibrated_axis.1.x.max(axis.x); + self.calibrated_axis.0.y = self.calibrated_axis.0.y.min(axis.y); + self.calibrated_axis.1.y = self.calibrated_axis.1.y.max(axis.y); - state.buttons.g17 = buf[5] & 0b00000001 != 0; - state.buttons.g18 = buf[5] & 0b00000010 != 0; - state.buttons.g19 = buf[5] & 0b00000100 != 0; - state.buttons.g20 = buf[5] & 0b00001000 != 0; - state.buttons.g21 = buf[5] & 0b00010000 != 0; - state.buttons.g22 = buf[5] & 0b00100000 != 0; + let (xmin, xmax) = (self.calibrated_axis.0.x, self.calibrated_axis.1.x); + let (ymin, ymax) = (self.calibrated_axis.0.y, self.calibrated_axis.1.y); - state.buttons.stick1 = buf[7] & 0b00000010 != 0; - state.buttons.stick2 = buf[7] & 0b00000100 != 0; - state.buttons.stick3 = buf[7] & 0b00001000 != 0; + let x_output = map_range(self.axis.x, xmin, xmax); + let y_output = map_range(self.axis.y, ymin, ymax); - *self.state.write().expect("Poisoned") = state; + Some(Some(G13Event::Axis(x_output as u8, y_output as u8))) + } +} - Ok(state) +fn map_range(v: u8, in_min: u8, in_max: u8) -> f64 { + if in_min == in_max { + return 0.0; + } + 255.0 * (v as f64 - in_min as f64) / (in_max as f64 - in_min as f64) +} + +#[derive(Clone)] +pub struct G13Display { + interface: Interface, + img_buffer: Arc>, +} + +impl G13Display { + pub fn new(interface: Interface) -> Self { + let img_buffer = [0u8; G13_LCD_BUF_SIZE as usize + 8]; + // let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8]; + // buffer[0] = 0x03; + // buffer[32..G13_LCD_BUF_SIZE as usize + 32 + 8].copy_from_slice(&img_buffer); + + Self { + interface, + img_buffer: Arc::new(RwLock::new(img_buffer)), + } } pub fn set_lcd_color(&self, r: u8, g: u8, b: u8) -> Result<(), Box> { @@ -202,9 +281,13 @@ impl G13 { w.flush()?; Ok(()) } + + pub fn size(&self) -> Size { + Size::new(G13_LCD_COLUMNS as u32, G13_LCD_ROWS as u32) + } } -impl Dimensions for G13 { +impl Dimensions for G13Display { fn bounding_box(&self) -> Rectangle { Rectangle::new( Point::new(0, 0), @@ -213,7 +296,7 @@ impl Dimensions for G13 { } } -impl DrawTarget for G13 { +impl DrawTarget for G13Display { type Color = BinaryColor; type Error = Box; diff --git a/g13-os/Cargo.toml b/g13-os/Cargo.toml index f8de538..8b4caf7 100644 --- a/g13-os/Cargo.toml +++ b/g13-os/Cargo.toml @@ -4,8 +4,11 @@ version.workspace = true edition.workspace = true [dependencies] +# buoyant = "0.6.1" ctrlc = "3.5" embedded-graphics = "0.8" g13-driver.workspace = true mlua = { version = "0.11.6", features = ["lua54", "async", "macros", "serde"] } time = { version = "0.3.47", features = ["formatting", "macros"] } + +embedded-graphics-simulator = "0.7.0" diff --git a/g13-os/src/main.rs b/g13-os/src/main.rs index a686aa9..18f2a46 100644 --- a/g13-os/src/main.rs +++ b/g13-os/src/main.rs @@ -1,251 +1,73 @@ -pub mod mouse; -mod os; +// pub mod mouse; +// mod os; -use g13_driver::{G13, G13_LCD_COLUMNS, G13_LCD_ROWS}; -use mlua::{Error, ExternalResult, Lua}; -use std::{ - fs, - sync::{ - Arc, - atomic::{AtomicBool, Ordering}, - }, - thread::sleep, - time::{Duration, Instant}, +// use embedded_graphics::prelude::{Dimensions, DrawTarget}; +// use embedded_graphics::{pixelcolor::BinaryColor, prelude::Size}; +// use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window}; +// use mlua::{Error, ExternalResult, Lua}; +// use rsact_ui::prelude::*; +// use rsact_ui::{ +// col, +// event::simulator::simulator_single_encoder, +// render::{AntiAliasing, RendererOptions}, +// row, +// style::accent::AccentStyler, +// ui::UI, +// }; +// use std::fmt::Binary; +// use std::{ +// fs, +// sync::{ +// Arc, +// atomic::{AtomicBool, Ordering}, +// }, +// thread::sleep, +// time::{Duration, Instant}, +// }; + +// use crate::os::G13Os; + +use embedded_graphics::{ + Drawable, + pixelcolor::BinaryColor, + prelude::{DrawTarget, Point}, }; - -use crate::os::G13Os; +use g13_driver::{G13, G13Event}; fn main() -> Result<(), Box> { - let running = Arc::new(AtomicBool::new(true)); + let g13 = G13::new()?; + let (mut display, input) = g13.split(); - let _running = running.clone(); + let character_style = embedded_graphics::mono_font::MonoTextStyle::new( + &embedded_graphics::mono_font::ascii::FONT_10X20, + embedded_graphics::pixelcolor::BinaryColor::On, + ); + let textstyle = embedded_graphics::text::TextStyleBuilder::new() + .alignment(embedded_graphics::text::Alignment::Left) + .baseline(embedded_graphics::text::Baseline::Top) + .build(); - let os = G13Os::new(); + for event in input { + let Some(event) = event else { + continue; + }; - os.run(); + println!("{:?}", event); - /* - let lua = Lua::new(); - let globals = lua.globals(); - let g13_table = lua.create_table()?; + display.clear(BinaryColor::Off)?; - let _running = running.clone(); - let _g13 = g13.clone(); - std::thread::spawn(move || { - while _running.load(Ordering::SeqCst) { - if _g13.read().is_err() { - _running.store(false, Ordering::SeqCst); - } - } - }); - - let _g13 = g13.clone(); - g13_table.set( - "set_color", - lua.create_function(move |_, (r, g, b): (i32, i32, i32)| { - _g13.set_lcd_color( - r.clamp(0, 255) as u8, - g.clamp(0, 255) as u8, - b.clamp(0, 255) as u8, + if let G13Event::Axis(x, y) = event { + embedded_graphics::text::Text::with_text_style( + &format!("{}x{}", x, y), + Point::new(5, 5), + character_style, + textstyle, ) - .into_lua_err() - })?, - )?; - - let _g13 = g13.clone(); - let fn_clear = lua.create_function(move |_, on| { - let mut _g13 = _g13.clone(); - use embedded_graphics::pixelcolor::BinaryColor; - use embedded_graphics::prelude::*; - let color = if on { - BinaryColor::On - } else { - BinaryColor::Off - }; - _g13.clear(color).into_lua_err() - })?; - g13_table.set("clear", fn_clear)?; - - let mut _g13 = g13.clone(); - let fn_set_pixel = lua.create_function_mut(move |_, (x, y, on)| { - use embedded_graphics::pixelcolor::BinaryColor; - use embedded_graphics::prelude::*; - let color = if on { - BinaryColor::On - } else { - BinaryColor::Off - }; - Pixel(Point::new(x, y), color) - .draw(&mut _g13) - .into_lua_err() - })?; - g13_table.set("set_pixel", fn_set_pixel)?; - - let mut _g13 = g13.clone(); - let fn_text = lua.create_function_mut( - move |_, - (text, x, y, color, alignment, baseline, size): ( - String, - i32, - i32, - bool, - i32, - i32, - i32, - )| { - use embedded_graphics::mono_font::ascii::*; - use embedded_graphics::pixelcolor::BinaryColor; - use embedded_graphics::prelude::*; - use embedded_graphics::text::*; - - let alignment = match alignment { - 0 => Alignment::Left, - 1 => Alignment::Center, - 2 => Alignment::Right, - _ => { - return Err(Error::RuntimeError( - "Invalid alignment, allowed values: 0, 1, 2".into(), - )); - } - }; - - let baseline = match baseline { - 0 => Baseline::Top, - 1 => Baseline::Middle, - 2 => Baseline::Bottom, - _ => { - return Err(Error::RuntimeError( - "Invalid baseline, allowed values: 0, 1, 2".into(), - )); - } - }; - - let color = if color { - BinaryColor::On - } else { - BinaryColor::Off - }; - - let size = match size { - 2 => FONT_5X7, - 3 => FONT_5X8, - 4 => FONT_6X9, - 5 => FONT_6X10, - 6 => FONT_6X12, - 7 => FONT_6X13, - 8 => FONT_6X13_BOLD, - 9 => FONT_6X13_ITALIC, - 10 => FONT_7X13, - 11 => FONT_7X13_BOLD, - 12 => FONT_7X13_ITALIC, - 13 => FONT_7X14, - 14 => FONT_7X14_BOLD, - 15 => FONT_8X13, - 16 => FONT_8X13_BOLD, - 17 => FONT_8X13_ITALIC, - 18 => FONT_9X15, - 19 => FONT_9X15_BOLD, - 20 => FONT_9X18, - 21 => FONT_9X18_BOLD, - 22 => FONT_10X20, - _ => FONT_4X6, - }; - - let character_style = embedded_graphics::mono_font::MonoTextStyle::new(&size, color); - - let textstyle = TextStyleBuilder::new() - .alignment(alignment) - .baseline(baseline) - .build(); - - let pos = Point::new(x, y); - - Text::with_text_style(&text, pos, character_style, textstyle) - .draw(&mut _g13) - .into_lua_err()?; - Ok(()) - }, - )?; - g13_table.set("text", fn_text)?; - - g13_table.set("display_width", G13_LCD_COLUMNS)?; - g13_table.set("display_height", G13_LCD_ROWS)?; - - globals.set("g13", g13_table)?; - - let joy = lua.create_table()?; - joy.set("x", 0.0f32)?; - joy.set("y", 0.0f32)?; - joy.set("deadzone", 40)?; - globals.set("joy", joy)?; - - // load all files from dir `./scripts` for now, user configurable later or ~/.config/g13-os/\*. - // for now, just main.luau - let main = fs::read_to_string("./scripts/main.lua")?; - - lua.load(main).set_name("main.lua").exec()?; - - if lua.load("setup ~= nil").eval()? { - lua.load("setup()").exec()?; - } - - if lua.load("update ~= nil").eval()? { - let mut _g13 = g13.clone(); - let mut delta: f32 = 0.0; - while running.load(std::sync::atomic::Ordering::SeqCst) { - let start = Instant::now(); - let state = g13.state(); - - let mut deadzone: i32 = lua.load("joy.deadzone").eval()?; - if deadzone > 512 { - deadzone = 0; - } - let offset: i32 = 512 - deadzone; - let mut x = state.x; - let mut y = state.y; - - x = if x.abs() < deadzone { - 0 - } else { - x - deadzone * x.signum() - }; - - y = if y.abs() < deadzone { - 0 - } else { - y - deadzone * y.signum() - }; - - lua.load(format!( - "joy.x = {}\njoy.y = {}", - x as f32 / offset as f32, - y as f32 / offset as f32 - )) - .exec()?; - - let buttons = lua.create_table()?; - buttons.set("t1", state.buttons.screen1)?; - buttons.set("t2", state.buttons.screen2)?; - buttons.set("t3", state.buttons.screen3)?; - buttons.set("t4", state.buttons.screen4)?; - globals.set("buttons", buttons)?; - - lua.load(format!("update({})", delta)).exec()?; - - _g13.render()?; - - let duration = Instant::now() - start; - - // 30 fps lock - if duration < Duration::from_millis(33) { - sleep(Duration::from_millis(33) - duration); - } - - delta = (Instant::now() - start).as_secs_f32(); + .draw(&mut display)?; } + + display.render()?; } - running.store(false, Ordering::SeqCst); - */ Ok(()) }