From 3db5b5e0940677f2848135c2999721faa305c98e Mon Sep 17 00:00:00 2001 From: Avii Date: Thu, 12 Feb 2026 17:14:50 +0100 Subject: [PATCH] input and text and stuff --- Cargo.lock | 1 + g13-os/Cargo.toml | 8 +- g13-os/src/main.rs | 177 ++++++++++++++++++++++++++++++++++++++++++--- scripts/main.luau | 35 +++++---- 4 files changed, 197 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d06d34d..7be8306 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2783,6 +2783,7 @@ dependencies = [ name = "g13-os" version = "0.1.0" dependencies = [ + "ctrlc", "embedded-graphics", "g13-driver", "mlua", diff --git a/g13-os/Cargo.toml b/g13-os/Cargo.toml index 73447ea..f120b1a 100644 --- a/g13-os/Cargo.toml +++ b/g13-os/Cargo.toml @@ -6,4 +6,10 @@ edition.workspace = true [dependencies] g13-driver.workspace = true embedded-graphics = "0.8" -mlua = { version = "0.11.6", features = ["luau-jit", "async", "macros", "serde"] } +mlua = { version = "0.11.6", features = [ + "luau-jit", + "async", + "macros", + "serde", +] } +ctrlc = "3.5" diff --git a/g13-os/src/main.rs b/g13-os/src/main.rs index 0d20ede..fc18955 100644 --- a/g13-os/src/main.rs +++ b/g13-os/src/main.rs @@ -1,23 +1,48 @@ +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 g13_driver::{G13, G13_LCD_COLUMNS, G13_LCD_ROWS}; -use mlua::{ExternalResult, Lua}; - fn main() -> Result<(), Box> { + let running = Arc::new(AtomicBool::new(true)); + + let _running = running.clone(); + ctrlc::set_handler(move || _running.store(false, Ordering::SeqCst)) + .expect("Error setting Ctrl-C handler"); + let g13 = G13::new()?; let lua = Lua::new(); let globals = lua.globals(); - let g13_table = lua.create_table()?; + 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)| _g13.set_lcd_color(r, g, b).into_lua_err())?, + 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, + ) + .into_lua_err() + })?, )?; let _g13 = g13.clone(); @@ -31,8 +56,8 @@ fn main() -> Result<(), Box> { BinaryColor::Off }; _g13.clear(color).into_lua_err() - }); - g13_table.set("clear", fn_clear?)?; + })?; + g13_table.set("clear", fn_clear)?; let mut _g13 = g13.clone(); let fn_set_pixel = lua.create_function_mut(move |_, (x, y, on)| { @@ -46,14 +71,107 @@ fn main() -> Result<(), Box> { Pixel(Point::new(x, y), color) .draw(&mut _g13) .into_lua_err() - }); - g13_table.set("set_pixel", fn_set_pixel?)?; + })?; + 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.luau")?; @@ -67,10 +185,46 @@ fn main() -> Result<(), Box> { if lua.load("update ~= nil").eval()? { let mut _g13 = g13.clone(); let mut delta: f32 = 0.0; - loop { + 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; @@ -79,9 +233,12 @@ fn main() -> Result<(), Box> { if duration < Duration::from_millis(33) { sleep(Duration::from_millis(33) - duration); } + delta = (Instant::now() - start).as_secs_f32(); } } + running.store(false, Ordering::SeqCst); + Ok(()) } diff --git a/scripts/main.luau b/scripts/main.luau index cc116cf..cec1b65 100644 --- a/scripts/main.luau +++ b/scripts/main.luau @@ -15,27 +15,23 @@ local speed = 20 local size = 3 +function setup() + joy.deadzone = 40 +end + function update(delta: number) - x = x + speed * delta * x_direction - y = y + speed * delta * y_direction - - if x <= size or x >= width - size then - x_direction = -x_direction - end - - if y <= size or y >= height - size then - y_direction = -y_direction - end + x = x + speed * delta * joy.x * 1.2 + y = y + speed * delta * joy.y local color_x = (x / width) * 255 local color_y = (y / height) * 255 local color_z = 255 - (color_x + color_y) / 2 - g13.set_color(color_x/2, color_y/2, color_z/2) - g13.clear() - print(x, y) + g13.set_color(color_x/2, color_y/2, color_z/2) + + g13.text("Hello World!", 1, 1, true, 0, 0, 1) for sy = -size,size do for sx = -size,size do @@ -43,3 +39,16 @@ function update(delta: number) end end end + +function dump(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. dump(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end