sm64pc/gamebridge/src/main.rs

168 lines
4.2 KiB
Rust
Raw Normal View History

#[macro_use]
extern crate bitflags;
pub(crate) mod controller;
2020-05-09 00:47:36 +00:00
pub(crate) mod twitch;
2020-05-08 22:32:29 +00:00
use anyhow::{anyhow, Result};
use log::{debug, error, info, warn};
2020-05-08 21:54:57 +00:00
use std::{
fs::{File, OpenOptions},
io::{Read, Write},
str::from_utf8,
sync::{Arc, RwLock},
thread::spawn,
time::Instant,
2020-05-08 21:54:57 +00:00
};
#[derive(Debug)]
pub(crate) struct State {
controller: [u8; 4],
last_got: Box<Instant>,
ok: bool,
2020-05-09 03:44:03 +00:00
frame: u64,
}
pub(crate) type MTState = Arc<RwLock<State>>;
2020-05-08 22:32:29 +00:00
fn main() -> Result<()> {
2020-05-08 21:54:57 +00:00
pretty_env_logger::try_init()?;
2020-05-09 00:47:36 +00:00
kankyo::init()?;
2020-05-08 21:54:57 +00:00
let mut vblank = File::open("vblank")?;
let mut input = OpenOptions::new().write(true).open("input")?;
let st = {
let st = State {
controller: [0; 4],
last_got: Box::new(Instant::now()),
ok: true,
2020-05-09 03:44:03 +00:00
frame: 0,
};
Arc::new(RwLock::new(st))
};
2020-05-08 22:00:20 +00:00
info!("ready");
2020-05-08 21:54:57 +00:00
{
let st = st.clone();
2020-05-09 00:47:36 +00:00
spawn(move || twitch::run(st));
}
2020-05-09 10:30:23 +00:00
const LERP_TIME: f64 = 330.0; // 330 frames to lerp stick positions down to 0
2020-05-09 03:44:03 +00:00
let mut xmax_frame: u64 = 0;
let mut ymax_frame: u64 = 0;
2020-05-08 21:54:57 +00:00
loop {
let mut data = [0; 3];
debug!("waiting for vblank");
2020-05-08 21:54:57 +00:00
vblank.read(&mut data)?;
let str = from_utf8(&data)?;
debug!("got data: {}", str);
2020-05-08 22:32:29 +00:00
match str {
"OK\n" => {
let mut data = st.write().unwrap();
2020-05-09 03:44:03 +00:00
data.frame += 1;
let mut stickx = data.controller[2] as i8;
let mut sticky = data.controller[3] as i8;
let dist = stick_distance(stickx, sticky);
if dist <= 10 {
stickx = 0;
sticky = 0;
xmax_frame = 0;
ymax_frame = 0;
}
stickx = match stickx {
0 => stickx,
127 => {
xmax_frame = data.frame;
stickx - 10
},
-128 => {
xmax_frame = data.frame;
stickx + 10
},
_ => {
let t = (data.frame - xmax_frame) as f64 / (LERP_TIME as f64);
lerp(stickx, 0, t)
},
};
2020-05-09 03:50:23 +00:00
sticky = match sticky {
2020-05-09 03:44:03 +00:00
0 => sticky,
127 => {
ymax_frame = data.frame;
sticky - 10
},
-128 => {
ymax_frame = data.frame;
sticky + 10
},
_ => {
let t = (data.frame - ymax_frame) as f64 / (LERP_TIME as f64);
lerp(sticky, 0, t)
},
};
input.write(&data.controller)?;
2020-05-09 00:47:36 +00:00
data.controller[0] = 0;
data.controller[1] = 0;
2020-05-09 03:44:03 +00:00
data.controller[2] = stickx as u8;
data.controller[3] = sticky as u8;
}
2020-05-08 22:32:29 +00:00
"BYE" => {
warn!("asked to exit by the game");
return Ok(());
}
2020-05-08 22:32:29 +00:00
_ => {
error!("got unknown FIFO data {}", str);
return Err(anyhow!("unknown FIFO data received"));
}
};
2020-05-08 21:54:57 +00:00
}
2020-05-08 20:30:43 +00:00
}
2020-05-09 03:44:03 +00:00
fn lerp(start: i8, end: i8, t: f64) -> i8 {
(start as f64 * (1.0 - t) + (end as f64) * t) as i8
}
fn stick_distance(x: i8, y: i8) -> i8 {
let x = (x as f64).powi(2);
let y = (y as f64).powi(2);
(x + y).sqrt() as i8
}
#[cfg(test)]
mod test {
#[test]
fn lerp_scale() {
for case in [(0.1, 10), (0.5, 31)].iter() {
let t = case.0;
let start = 127.0 * t;
assert_eq!(crate::lerp(start as i8, 0, t), case.1);
}
}
#[test]
fn stick_distance() {
for case in [
(0, 0, 0),
(127, 0, 127),
(64, 64, 90),
(-64, 64, 90),
(-64, -64, 90),
]
.iter()
{
let x = case.0;
let y = case.1;
assert_eq!(crate::stick_distance(x, y), case.2);
}
}
}