WIP
Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu>
This commit is contained in:
parent
6b3a2cfbfc
commit
f5d307e5bc
6 changed files with 231 additions and 75 deletions
25
Cargo.lock
generated
25
Cargo.lock
generated
|
@ -71,12 +71,14 @@ name = "beonew-5"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"evdev",
|
||||
"evdev-rs",
|
||||
"femtovg",
|
||||
"gilrs",
|
||||
"glutin",
|
||||
"glutin-winit",
|
||||
"image",
|
||||
"instant",
|
||||
"nix 0.28.0",
|
||||
"raw-window-handle",
|
||||
"resource",
|
||||
"winit",
|
||||
|
@ -284,6 +286,29 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "evdev-rs"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9812d5790fb6fcce449333eb6713dad335e8c979225ed98755c84a3987e06dba"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"evdev-sys",
|
||||
"libc",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "evdev-sys"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14ead42b547b15d47089c1243d907bcf0eb94e457046d3b315a26ac9c9e9ea6d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.4"
|
||||
|
|
|
@ -18,3 +18,5 @@ image = { version = "0.24.0", default-features = false, features = [
|
|||
"jpeg",
|
||||
"png",
|
||||
] }
|
||||
evdev-rs = "0.6.1"
|
||||
nix = { version = "0.28.0", features = ["fs"] }
|
||||
|
|
|
@ -22,10 +22,9 @@ mod perf_graph;
|
|||
pub use perf_graph::PerfGraph;
|
||||
|
||||
pub fn start(
|
||||
#[cfg(not(target_arch = "wasm32"))] width: u32,
|
||||
#[cfg(not(target_arch = "wasm32"))] height: u32,
|
||||
#[cfg(not(target_arch = "wasm32"))] title: &'static str,
|
||||
#[cfg(not(target_arch = "wasm32"))] resizeable: bool,
|
||||
width: u32,
|
||||
height: u32,
|
||||
title: &'static str,
|
||||
) {
|
||||
// This provides better error messages in debug mode.
|
||||
// It's disabled in release mode so it doesn't bloat up the file size.
|
||||
|
@ -34,11 +33,10 @@ pub fn start(
|
|||
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let (canvas, window, context, surface) = {
|
||||
let window_builder = WindowBuilder::new()
|
||||
.with_inner_size(winit::dpi::PhysicalSize::new(width, height))
|
||||
.with_resizable(resizeable)
|
||||
.with_resizable(false)
|
||||
.with_title(title);
|
||||
|
||||
let template = ConfigTemplateBuilder::new().with_alpha_size(8);
|
||||
|
@ -116,39 +114,11 @@ pub fn start(
|
|||
(canvas, window, gl_context, surface)
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let (canvas, window) = {
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
let canvas = web_sys::window()
|
||||
.unwrap()
|
||||
.document()
|
||||
.unwrap()
|
||||
.get_element_by_id("canvas")
|
||||
.unwrap()
|
||||
.dyn_into::<web_sys::HtmlCanvasElement>()
|
||||
.unwrap();
|
||||
|
||||
use winit::platform::web::WindowBuilderExtWebSys;
|
||||
|
||||
let renderer = OpenGl::new_from_html_canvas(&canvas).expect("Cannot create renderer");
|
||||
|
||||
let window = WindowBuilder::new()
|
||||
.with_canvas(Some(canvas))
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
|
||||
let canvas = Canvas::new(renderer).expect("Cannot create canvas");
|
||||
|
||||
(canvas, window)
|
||||
};
|
||||
|
||||
run(
|
||||
canvas,
|
||||
event_loop,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
context,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
surface,
|
||||
window,
|
||||
);
|
||||
|
|
160
src/hid.rs
Normal file
160
src/hid.rs
Normal file
|
@ -0,0 +1,160 @@
|
|||
use core::panic;
|
||||
use gilrs::ev;
|
||||
use nix::{
|
||||
fcntl::{FcntlArg, OFlag},
|
||||
sys::epoll,
|
||||
};
|
||||
use std::{
|
||||
io,
|
||||
os::fd::{AsRawFd, FromRawFd, OwnedFd},
|
||||
};
|
||||
|
||||
use evdev;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Beo5Event {
|
||||
LaserPosition(f32),
|
||||
SelectionWheelRel(i32),
|
||||
VolumeWheelRel(i32),
|
||||
RightButtonPressed,
|
||||
RightButtonReleased,
|
||||
LeftButtonPressed,
|
||||
LeftButtonReleased,
|
||||
GoButtonPressed,
|
||||
GoButtonReleased,
|
||||
PowerButtonPressed,
|
||||
PowerButtonReleased,
|
||||
}
|
||||
|
||||
pub struct Beo5Device {
|
||||
device: evdev::Device,
|
||||
}
|
||||
|
||||
pub struct Beo5DeviceEvents<'a> {
|
||||
events: Option<evdev::FetchEventsSynced<'a>>,
|
||||
}
|
||||
|
||||
impl Beo5Device {
|
||||
pub fn new_autodiscover() -> Option<Beo5Device> {
|
||||
let devices = evdev::enumerate().map(|t| t.1).collect::<Vec<_>>();
|
||||
for (i, d) in devices.iter().enumerate() {
|
||||
if d.name().unwrap_or("Unnamed device").contains("BeoSound 5") {
|
||||
println!(
|
||||
"Found BeoSound 5 device at index {}: {}",
|
||||
i,
|
||||
d.name().unwrap()
|
||||
);
|
||||
// XXX Is there a better way than this into_iter.nth.unwrap ?
|
||||
let mut d = devices.into_iter().nth(i).unwrap();
|
||||
|
||||
// From evdev's example
|
||||
let raw_fd = d.as_raw_fd();
|
||||
// Set nonblocking
|
||||
nix::fcntl::fcntl(raw_fd, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)); //("Couldn't set nonblocking");
|
||||
|
||||
// Create epoll handle and attach raw_fd
|
||||
//let epoll_fd = epoll::epoll_create1(epoll::EpollCreateFlags::EPOLL_CLOEXEC)?;
|
||||
let epoll_fd = epoll::epoll_create1(epoll::EpollCreateFlags::EPOLL_CLOEXEC).ok()?;
|
||||
let epoll_fd = unsafe { OwnedFd::from_raw_fd(epoll_fd) };
|
||||
let mut event = epoll::EpollEvent::new(epoll::EpollFlags::EPOLLIN, 0);
|
||||
epoll::epoll_ctl(
|
||||
epoll_fd.as_raw_fd(),
|
||||
epoll::EpollOp::EpollCtlAdd,
|
||||
raw_fd,
|
||||
Some(&mut event),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
//let events = d.fetch_events().unwrap();
|
||||
|
||||
return Some(Beo5Device { device: d });
|
||||
}
|
||||
}
|
||||
println!("Couldn't find a Beosound 5 device! Is the Beosound 5 kernel module loaded + device connected?");
|
||||
None
|
||||
}
|
||||
|
||||
pub fn fetch_events(&self) -> io::Result<Beo5DeviceEvents> {
|
||||
let events = &mut self.device.fetch_events()?;
|
||||
Ok(Beo5DeviceEvents {
|
||||
events: Some(events),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_event_nonblocking(&mut self) -> Option<Beo5Event> {
|
||||
if self.events.is_none() {
|
||||
self.events = Some(self.device.fetch_events().unwrap());
|
||||
}
|
||||
|
||||
for ev in self.events.unwrap().into_iter() {
|
||||
println!("Beosound event: {ev:?}");
|
||||
// XXX What happens with the other events in the iterator?
|
||||
match ev.kind() {
|
||||
// Look at the beosound 5 kernel module for the correct event codes
|
||||
evdev::InputEventKind::RelAxis(axis) => {
|
||||
match axis {
|
||||
evdev::RelativeAxisType::REL_Y => {
|
||||
return Some(Beo5Event::SelectionWheelRel(ev.value()));
|
||||
}
|
||||
evdev::RelativeAxisType::REL_Z => {
|
||||
return Some(Beo5Event::VolumeWheelRel(ev.value()));
|
||||
}
|
||||
// Shouldn't be any more relative axe
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
evdev::InputEventKind::AbsAxis(axis) => {
|
||||
match axis {
|
||||
evdev::AbsoluteAxisType::ABS_X => {
|
||||
let pos_pct = ev.value() as f32 / 255.0;
|
||||
return Some(Beo5Event::LaserPosition(pos_pct));
|
||||
}
|
||||
// Shouldn't be any other absolute axe
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
evdev::InputEventKind::Switch(switch) => {
|
||||
/*
|
||||
match switch {
|
||||
evdev::SwitchType::LE=> {
|
||||
if ev.value() == 1 {
|
||||
return Beo5Event::RightButtonPressed;
|
||||
} else {
|
||||
return Beo5Event::RightButtonReleased;
|
||||
}
|
||||
}
|
||||
evdev::Switch::SW_LEFT => {
|
||||
if ev.value() == 1 {
|
||||
return Beo5Event::LeftButtonPressed;
|
||||
} else {
|
||||
return Beo5Event::LeftButtonReleased;
|
||||
}
|
||||
}
|
||||
evdev::Switch::SW_GO => {
|
||||
if ev.value() == 1 {
|
||||
return Beo5Event::GoButtonPressed;
|
||||
} else {
|
||||
return Beo5Event::GoButtonReleased;
|
||||
}
|
||||
}
|
||||
evdev::Switch::SW_POWER => {
|
||||
if ev.value() == 1 {
|
||||
return Beo5Event::PowerButtonPressed;
|
||||
} else {
|
||||
return Beo5Event::PowerButtonReleased;
|
||||
}
|
||||
}
|
||||
// Shouldn't be any other switches
|
||||
_ => {
|
||||
panic!("Unknown switch event: {ev:?}")
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
_ => {} //SYN et al
|
||||
}
|
||||
return None;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
64
src/main.rs
64
src/main.rs
|
@ -1,5 +1,3 @@
|
|||
use core::panic;
|
||||
|
||||
use femtovg::{
|
||||
renderer::OpenGl, Align, Baseline, Canvas, Color, FontId, ImageFlags, ImageId, Paint, Path,
|
||||
Renderer,
|
||||
|
@ -21,14 +19,20 @@ struct Fonts {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
helpers::start(1024, 768, "Text demo", false);
|
||||
helpers::start(1024, 768, "Text demo");
|
||||
}
|
||||
|
||||
use glutin::prelude::*;
|
||||
|
||||
mod hid;
|
||||
mod roundy_math;
|
||||
mod ui;
|
||||
|
||||
enum UiEvent<'e> {
|
||||
WinitEvent(winit::event::Event<'e, ()>),
|
||||
HardwareEvent(evdev::InputEvent),
|
||||
}
|
||||
|
||||
fn run(
|
||||
mut canvas: Canvas<OpenGl>,
|
||||
el: EventLoop<()>,
|
||||
|
@ -50,11 +54,6 @@ fn run(
|
|||
println!("{}", app.name());
|
||||
}
|
||||
|
||||
let flags = ImageFlags::GENERATE_MIPMAPS | ImageFlags::REPEAT_X | ImageFlags::REPEAT_Y;
|
||||
let image_id = canvas
|
||||
.load_image_mem(&resource!("assets/pattern.jpg"), flags)
|
||||
.expect("Cannot create image");
|
||||
|
||||
let start = Instant::now();
|
||||
let mut prevt = start;
|
||||
|
||||
|
@ -65,12 +64,26 @@ fn run(
|
|||
#[cfg(feature = "debug_inspector")]
|
||||
let mut font_texture_to_show: Option<usize> = None;
|
||||
|
||||
let mut x = 5.0;
|
||||
let mut y = 380.0;
|
||||
let mut beo_device = hid::Beo5Device::new_autodiscover().expect("Couldn't find Beo5 device");
|
||||
loop {
|
||||
if let Some(ev) = beo_device.get_event_nonblocking() {
|
||||
println!("HW Event: {:?}", ev);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
el.run(move |event, _, control_flow| {
|
||||
*control_flow = ControlFlow::Poll;
|
||||
|
||||
let hw_event = beo_device.get_event_nonblocking();
|
||||
match hw_event {
|
||||
Some(ev) => {
|
||||
println!("HW Event: {:?}", ev);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
match event {
|
||||
Event::LoopDestroyed => *control_flow = ControlFlow::Exit,
|
||||
Event::WindowEvent { ref event, .. } => match event {
|
||||
|
@ -91,22 +104,13 @@ fn run(
|
|||
},
|
||||
..
|
||||
} => {
|
||||
println!("INput");
|
||||
if *keycode == VirtualKeyCode::W {
|
||||
y -= 0.1;
|
||||
}
|
||||
|
||||
if *keycode == VirtualKeyCode::S {
|
||||
y += 0.1;
|
||||
}
|
||||
|
||||
if *keycode == VirtualKeyCode::A {
|
||||
x -= 0.1;
|
||||
}
|
||||
|
||||
if *keycode == VirtualKeyCode::D {
|
||||
x += 0.1;
|
||||
if keycode == &VirtualKeyCode::Escape {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
println!("INput {:?}", keycode);
|
||||
//if *keycode == VirtualKeyCode::W {
|
||||
// y -= 0.1;
|
||||
//}
|
||||
|
||||
if *keycode == VirtualKeyCode::NumpadAdd || *keycode == VirtualKeyCode::B {
|
||||
println!("Add");
|
||||
|
@ -136,10 +140,13 @@ fn run(
|
|||
delta: winit::event::MouseScrollDelta::LineDelta(_, y),
|
||||
..
|
||||
} => {
|
||||
println!("Scroll {:?}", y);
|
||||
font_size += *y / 2.0;
|
||||
font_size = font_size.max(2.0);
|
||||
}
|
||||
_ => (),
|
||||
_ => {
|
||||
println!("{:?}", event);
|
||||
}
|
||||
},
|
||||
Event::RedrawRequested(_) => {
|
||||
let dpi_factor = window.scale_factor();
|
||||
|
@ -186,6 +193,7 @@ fn run(
|
|||
);
|
||||
*/
|
||||
|
||||
// XXX Why the save/reset/restore ?
|
||||
canvas.save();
|
||||
canvas.reset();
|
||||
perf.render(&mut canvas, 500.0, 5.0);
|
||||
|
@ -225,8 +233,6 @@ fn draw_main_menu<T: Renderer>(canvas: &mut Canvas<T>, fonts: &Fonts, beo: &ui::
|
|||
radius: 400.0,
|
||||
};
|
||||
|
||||
println!("Canvas width: {}, height: {}", canvas_width, canvas_height);
|
||||
|
||||
let canvas_size = roundy_math::Point {
|
||||
x: canvas_width as f64,
|
||||
y: canvas_height as f64,
|
||||
|
@ -234,7 +240,7 @@ fn draw_main_menu<T: Renderer>(canvas: &mut Canvas<T>, fonts: &Fonts, beo: &ui::
|
|||
|
||||
let pts = main_menu_circle.get_equidistant_points(8, canvas_size);
|
||||
for i in 0..pts.len() {
|
||||
println!(">>> {:?}", pts[i]);
|
||||
//println!(">>> {:?}", pts[i]);
|
||||
let mut paint = Paint::color(Color::hex("B7410E"));
|
||||
paint.set_font(&[fonts.bold]);
|
||||
paint.set_text_baseline(Baseline::Top);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::f64::consts::PI;
|
||||
//use std::f64;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Point {
|
||||
|
@ -19,10 +17,6 @@ impl VirtualCircle {
|
|||
// because I'm not clever enough to figure out how to calculate the intersection points
|
||||
// in the general case.
|
||||
|
||||
println!(
|
||||
"center: {:?}, radius: {}, viewport_size: {:?}",
|
||||
self.center, self.radius, viewport_size
|
||||
);
|
||||
// Calculate the angles at which the circle intersects with the viewport
|
||||
let upper_x = self.center.x - (self.radius.powf(2.) - (0. - self.center.y).powf(2.)).sqrt();
|
||||
let lower_x = self.center.x
|
||||
|
@ -35,27 +29,26 @@ impl VirtualCircle {
|
|||
y: viewport_size.y,
|
||||
};
|
||||
|
||||
println!("up/low: {:?} {:?}", upper_point, lower_point);
|
||||
//println!("up/low: {:?} {:?}", upper_point, lower_point);
|
||||
|
||||
let intersection_angles = (
|
||||
(upper_point.x - self.center.x).atan2(upper_point.y - self.center.y),
|
||||
(lower_point.x - self.center.x).atan2(lower_point.y - self.center.y),
|
||||
);
|
||||
println!("int angles: {:?}", intersection_angles);
|
||||
//println!("int angles: {:?}", intersection_angles);
|
||||
|
||||
let mut points = Vec::new();
|
||||
|
||||
// Calculate the angle step to distribute points evenly
|
||||
let angle_step = (intersection_angles.1 - intersection_angles.0) / (n as f64);
|
||||
println!("angle step: {}", angle_step);
|
||||
//println!("angle step: {}", angle_step);
|
||||
|
||||
// Generate the points
|
||||
for i in 0..n {
|
||||
let theta = intersection_angles.0 + angle_step * (i as f64 + 0.5);
|
||||
let x = theta.sin() * self.radius + viewport_size.x;
|
||||
let y = theta.cos() * self.radius + viewport_size.y - self.center.y;
|
||||
println!("x: {}, y: {}", x, y);
|
||||
points.push(Point { x: x, y: y });
|
||||
points.push(Point { x, y });
|
||||
}
|
||||
|
||||
points
|
||||
|
|
Loading…
Reference in a new issue