diff options
-rw-r--r-- | Cargo.lock | 87 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/image.rs | 72 | ||||
-rw-r--r-- | src/main.rs | 143 |
4 files changed, 267 insertions, 36 deletions
diff --git a/Cargo.lock b/Cargo.lock index b48c529..4693496 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] name = "ahash" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -299,6 +305,15 @@ dependencies = [ ] [[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -403,6 +418,7 @@ name = "etch" version = "0.1.0" dependencies = [ "gilrs", + "neam", "softbuffer", "tracing", "tracing-subscriber", @@ -416,6 +432,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] +name = "fdeflate" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -470,6 +505,14 @@ dependencies = [ ] [[package]] +name = "gifed" +version = "0.1.0" +source = "git+https://github.com/gennyble/gifed?rev=0dd0a6c2d910437d040b14994c80468f3bd6fbc7#0dd0a6c2d910437d040b14994c80468f3bd6fbc7" +dependencies = [ + "weezl", +] + +[[package]] name = "gilrs" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -690,6 +733,16 @@ dependencies = [ ] [[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] name = "ndk" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -720,6 +773,15 @@ dependencies = [ ] [[package]] +name = "neam" +version = "0.1.0" +source = "git+https://github.com/gennyble/neam?rev=5efc1761866283537fd254a8fb3582f50631cf0f#5efc1761866283537fd254a8fb3582f50631cf0f" +dependencies = [ + "gifed", + "png", +] + +[[package]] name = "nix" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1034,6 +1096,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] +name = "png" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] name = "polling" version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1229,6 +1304,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1727,6 +1808,12 @@ dependencies = [ ] [[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index e2217f9..16cbc4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] gilrs = "0.11.0" +neam = { git = "https://github.com/gennyble/neam", rev = "5efc1761866283537fd254a8fb3582f50631cf0f" } softbuffer = "0.4.6" tracing = "0.1.41" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/src/image.rs b/src/image.rs new file mode 100644 index 0000000..66ca858 --- /dev/null +++ b/src/image.rs @@ -0,0 +1,72 @@ +#[allow(dead_code)] +pub struct Image { + width: u32, + height: u32, + data: Vec<u32>, +} + +impl Image { + pub fn new(width: u32, height: u32, fill: Option<Color>) -> Self { + let size = width as usize * height as usize; + let data = match fill { + None => vec![0; size], + Some(color) => vec![color.into(); size], + }; + + Self { + width, + height, + data, + } + } + + pub fn data(&self) -> &[u32] { + &self.data + } + + pub fn data_mut(&mut self) -> &mut [u32] { + &mut self.data + } + + pub fn width(&self) -> u32 { + self.width + } + + pub fn height(&self) -> u32 { + self.height + } + + pub fn rect(&mut self, x: u32, y: u32, width: u32, height: u32) { + todo!() + } +} + +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl Color { + pub fn new(r: u8, g: u8, b: u8) -> Self { + Color { r, g, b } + } +} + +impl Into<u32> for Color { + fn into(self) -> u32 { + ((self.r as u32) << 16) | ((self.g as u32) << 8) | (self.b as u32) + } +} + +impl Into<Color> for u32 { + fn into(self) -> Color { + let bytes = self.to_be_bytes(); + + Color { + r: bytes[1], + g: bytes[2], + b: bytes[3], + } + } +} diff --git a/src/main.rs b/src/main.rs index cdcb23d..9aed460 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,25 @@ use std::{ num::NonZeroU32, + ops::DerefMut, rc::Rc, time::{Duration, Instant}, }; -use gilrs::{Axis, GamepadId, Gilrs}; -use softbuffer::{Buffer, Context, Surface}; +use gilrs::{Axis, Gilrs}; +use image::Image; +use softbuffer::{Context, Surface}; use tracing::level_filters::LevelFilter; use tracing_subscriber::EnvFilter; use winit::{ application::ApplicationHandler, dpi::LogicalSize, - event::{DeviceEvent, WindowEvent}, + event::WindowEvent, event_loop::{ControlFlow, EventLoop}, window::Window, }; +mod image; + fn main() { setup_logging(); @@ -26,9 +30,20 @@ fn main() { let mut etch = Etch { window: None, gilrs: Gilrs::new().unwrap(), + img: Image::new(WIDTH as u32, HEIGHT as u32, Some(BACKGROUND_COLOUR.into())), + stylus: Vec2 { + x: 10.0, + y: HEIGHT / 2.0, + }, - dial: DialState::default(), + dial: DialState { + left_x: 0.0, + left_y: 0.0, + right_x: 0.0, + right_y: 0.0, + }, left_angle: 0.0, + right_angle: 0.0, next_check: Instant::now(), }; @@ -59,16 +74,52 @@ struct SurfacedWindow { struct Etch { window: Option<SurfacedWindow>, gilrs: Gilrs, + img: Image, + stylus: Vec2, dial: DialState, left_angle: f32, + right_angle: f32, next_check: Instant, } +impl Etch { + pub fn process_gamepad_events(&mut self) { + while let Some(gilrs::Event { + id, event, time, .. + }) = self.gilrs.next_event() + { + match event { + gilrs::EventType::AxisChanged(axis, value, _code) => { + tracing::trace!("{axis:?} value={value}"); + + if value.is_nan() { + continue; + } + + match axis { + Axis::LeftStickX => self.dial.left_x = value * 100.0, + Axis::LeftStickY => self.dial.left_y = value * 100.0, + Axis::RightStickX => self.dial.right_x = value * 100.0, + Axis::RightStickY => self.dial.right_y = value * 100.0, + _ => (), + } + } + _ => (), + } + } + } +} + +// Why are my consts HERE of all places const DIAL_SENSETIVITY: f32 = 2.0; const WIDTH: f32 = 640.0; const HEIGHT: f32 = 480.0; +// a very sublte gentle, dark-and-dull green +const BACKGROUND_COLOUR: u32 = 0x00868886; +const LINE_COLOUR: u32 = 0x00303230; + impl ApplicationHandler for Etch { fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { let window = Rc::new(event_loop.create_window(Window::default_attributes()).unwrap()); @@ -92,37 +143,45 @@ impl ApplicationHandler for Etch { event_loop.exit(); } WindowEvent::RedrawRequested => { - let previous_dial = self.dial; - - // Process gamepad events - while let Some(gilrs::Event { - id, event, time, .. - }) = self.gilrs.next_event() - { - match event { - gilrs::EventType::AxisChanged(axis, value, _code) => { - tracing::trace!("{axis:?} value={value}"); - - match axis { - Axis::LeftStickX => self.dial.left_x = value * 100.0, - Axis::LeftStickY => self.dial.left_y = value * 100.0, - Axis::RightStickX => self.dial.right_x = value * 100.0, - Axis::RightStickY => self.dial.right_y = value * 100.0, - _ => (), - } - } - _ => (), - } - } + self.process_gamepad_events(); - // We check the state of the joystick at 20fps - if self.next_check.elapsed() > Duration::from_millis(50) { + // We check the state of the joystick at 40fps + if self.next_check.elapsed() > Duration::from_millis(25) { let left_angle = xy_to_deg(self.dial.left_x, self.dial.left_y); + let left_delta = if !left_angle.is_nan() { + let delta = angle_delta(left_angle, self.left_angle); + self.left_angle = left_angle; + delta + } else { + 0.0 + }; + + let right_angle = xy_to_deg(self.dial.right_x, self.dial.right_y); + let right_delta = if !right_angle.is_nan() { + let delta = angle_delta(right_angle, self.right_angle); + self.right_angle = right_angle; + delta + } else { + 0.0 + }; + + tracing::info!( + "ANGLE {left_angle} // {left_delta}v -=- {right_angle} // {right_delta}v" + ); - let left_delta = angle_delta(left_angle, self.left_angle); - self.left_angle = left_angle; + let movement_x = left_delta / 10.0; + let movement_y = right_delta / 10.0; + self.stylus.x = + (self.stylus.x + movement_x).clamp(0.0, self.img.width() as f32); + self.stylus.y = + (self.stylus.y - movement_y).clamp(0.0, self.img.height() as f32); + + let w = self.img.width(); + self.img.data_mut() + [w as usize * self.stylus.y as usize + self.stylus.x as usize] = LINE_COLOUR; + + tracing::info!("STYLUS: ({},{})", self.stylus.x, self.stylus.y); - tracing::info!("ANGLE {left_angle} // {left_delta}v"); self.next_check = Instant::now(); } @@ -131,18 +190,25 @@ impl ApplicationHandler for Etch { return; }; - let (width, height) = { + let (window_width, window_height) = { let phys = surfaced.window.inner_size(); (phys.width as usize, phys.height as usize) }; let mut buffer = surfaced.surface.buffer_mut().unwrap(); - for idx in 0..width { - buffer[idx + (height / 2) * width] = 0xFF00FF00; - } + neam::nearest_buffer( + self.img.data(), + 1, + self.img.width(), + self.img.height(), + buffer.deref_mut(), + window_width as u32, + window_height as u32, + ); + surfaced.window.pre_present_notify(); buffer.present().unwrap(); - //surfaced.window.request_redraw(); + surfaced.window.request_redraw(); } WindowEvent::Resized(phys) => { tracing::trace!("resized window: {phys:?}"); @@ -190,3 +256,8 @@ fn angle_delta(lhs: f32, rhs: f32) -> f32 { lhs - rhs } } + +pub struct Vec2 { + x: f32, + y: f32, +} |