sm64pc/gamebridge/src/main.rs

204 lines
6.2 KiB
Rust
Raw Normal View History

#[macro_use]
extern crate bitflags;
2020-05-09 13:16:19 +00:00
pub(crate) mod au;
pub(crate) mod controller;
2020-05-09 00:47:36 +00:00
pub(crate) mod twitch;
2020-05-09 13:16:19 +00:00
use crate::au::Lerper;
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,
2020-05-08 21:54:57 +00:00
};
pub(crate) struct State {
2020-05-09 03:44:03 +00:00
frame: u64,
2020-05-09 13:16:19 +00:00
stickx: Lerper,
sticky: Lerper,
a_button: Lerper,
b_button: Lerper,
z_button: Lerper,
r_button: Lerper,
start: Lerper,
c_left: Lerper,
c_right: Lerper,
c_up: Lerper,
c_down: Lerper,
}
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")?;
2020-05-09 14:12:13 +00:00
const STICK_LERP_TIME: f64 = 270.0; // 270 frames to lerp stick positions down to 0
2020-05-09 13:16:19 +00:00
const BUTTON_LERP_TIME: f64 = 20.0; // 20 frames to lerp button inputs down to 0
let st = {
let st = State {
2020-05-09 03:44:03 +00:00
frame: 0,
2020-05-09 13:16:19 +00:00
stickx: Lerper::init(STICK_LERP_TIME, 127, -128, 0),
sticky: Lerper::init(STICK_LERP_TIME, 127, -128, 0),
a_button: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
b_button: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
2020-05-09 14:12:13 +00:00
z_button: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
2020-05-09 13:16:19 +00:00
r_button: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
start: Lerper::init(BUTTON_LERP_TIME / 4.0, 64, -1, 0), // z button is special
c_left: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
c_right: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
c_up: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
c_down: Lerper::init(BUTTON_LERP_TIME, 64, -1, 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-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
2020-05-09 13:16:19 +00:00
let mut controller = [0; 4];
2020-05-08 22:32:29 +00:00
match str {
"OK\n" => {
2020-05-09 13:16:19 +00:00
{
let mut data = st.write().unwrap();
data.frame += 1;
}
let mut data = st.write().unwrap();
2020-05-09 13:16:19 +00:00
let frame = data.frame + 1;
2020-05-09 03:44:03 +00:00
2020-05-09 13:16:19 +00:00
//data.stickx.update(data.controller[2] as i64);
//data.sticky.update(data.controller[3] as i64);
2020-05-09 14:12:13 +00:00
debug!("x before: {}", data.stickx.scalar);
2020-05-09 13:16:19 +00:00
let mut stickx_scalar = data.stickx.apply(frame) as i8;
2020-05-09 14:12:13 +00:00
debug!("x after: {}", data.stickx.scalar);
debug!("y before: {}", data.sticky.scalar);
2020-05-09 13:16:19 +00:00
let mut sticky_scalar = data.sticky.apply(frame) as i8;
2020-05-09 14:12:13 +00:00
debug!("y after: {}", data.sticky.scalar);
2020-05-09 03:44:03 +00:00
2020-05-09 13:16:19 +00:00
let dist = stick_distance(stickx_scalar, sticky_scalar);
2020-05-09 03:44:03 +00:00
if dist <= 10 {
2020-05-09 13:16:19 +00:00
stickx_scalar = 0;
sticky_scalar = 0;
2020-05-09 03:44:03 +00:00
}
2020-05-09 13:16:19 +00:00
use controller::{HiButtons, LoButtons};
let mut hi = HiButtons::NONE;
let mut lo = LoButtons::NONE;
2020-05-09 14:12:13 +00:00
const BUTTON_PUSH_THRESHOLD: i64 = 2;
2020-05-09 13:16:19 +00:00
// high buttons
data.a_button.apply(frame);
2020-05-09 14:12:13 +00:00
if data.a_button.pressed(BUTTON_PUSH_THRESHOLD) {
hi = hi | HiButtons::A_BUTTON;
}
2020-05-09 13:16:19 +00:00
data.b_button.apply(frame);
2020-05-09 14:12:13 +00:00
if data.b_button.pressed(BUTTON_PUSH_THRESHOLD) {
hi = hi | HiButtons::B_BUTTON;
}
2020-05-09 13:16:19 +00:00
data.z_button.apply(frame);
2020-05-09 14:12:13 +00:00
if data.z_button.pressed(BUTTON_PUSH_THRESHOLD) {
hi = hi | HiButtons::Z_BUTTON;
}
2020-05-09 13:16:19 +00:00
data.start.apply(frame);
2020-05-09 14:12:13 +00:00
if data.start.pressed(BUTTON_PUSH_THRESHOLD) {
hi = hi | HiButtons::START;
}
2020-05-09 13:16:19 +00:00
data.r_button.apply(frame);
2020-05-09 14:12:13 +00:00
if data.r_button.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::R_BUTTON;
}
2020-05-09 13:16:19 +00:00
data.c_up.apply(frame);
2020-05-09 14:12:13 +00:00
if data.c_up.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::C_UP;
}
2020-05-09 13:16:19 +00:00
data.c_down.apply(frame);
2020-05-09 14:12:13 +00:00
if data.c_down.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::C_DOWN;
}
2020-05-09 13:16:19 +00:00
data.c_left.apply(frame);
2020-05-09 14:12:13 +00:00
if data.c_left.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::C_LEFT;
}
2020-05-09 13:16:19 +00:00
data.c_right.apply(frame);
2020-05-09 14:12:13 +00:00
if data.c_right.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::C_RIGHT;
}
2020-05-09 13:16:19 +00:00
2020-05-09 15:00:46 +00:00
debug!(
2020-05-09 14:12:13 +00:00
"[ rust] {:02x}{:02x} {:02x}{:02x}",
hi.bits(),
lo.bits(),
stickx_scalar as u8,
sticky_scalar as u8
);
2020-05-09 13:16:19 +00:00
controller[0] = hi.bits() as u8;
controller[1] = lo.bits() as u8;
controller[2] = stickx_scalar as u8;
controller[3] = sticky_scalar as u8;
input.write(&controller)?;
}
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 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 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);
}
}
}