From af5aad126e4d9cb2aa7e64eace50ef1b51d47773 Mon Sep 17 00:00:00 2001 From: Determinant Date: Sun, 21 Jan 2018 20:41:44 -0500 Subject: support gamepad --- Cargo.lock | 89 ++++++++++++++++++------------------ Cargo.toml | 2 +- src/bin.rs | 149 +++++++++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 145 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2ef605..7098de0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,13 +5,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "atty" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -31,11 +30,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clap" -version = "2.29.0" +version = "2.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -45,28 +44,17 @@ dependencies = [ [[package]] name = "fuchsia-zircon" -version = "0.2.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-zircon-sys" -version = "0.2.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "lazy_static" @@ -75,7 +63,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.34" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -112,16 +100,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.3.18" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.32" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -129,14 +117,14 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "runes" -version = "0.1.7" +version = "0.1.8" dependencies = [ - "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.29.2 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -147,9 +135,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -171,8 +159,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -196,32 +184,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.2.8" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "winapi-build" -version = "0.1.1" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" -"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860" +"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f" -"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" -"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum clap 2.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4151c5790817c7d21bbdc6c3530811f798172915f93258244948b93ba19604a6" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" +"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" "checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" -"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" -"checksum redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ab105df655884ede59d45b7070c8a65002d921461ee813a024558ca16030eea0" +"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" +"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" @@ -230,5 +226,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 6b90d64..27a5d3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "runes" -version = "0.1.8" +version = "0.1.9" authors = ["Determinant "] description = "No-std NES emulator library and minimal emulator written purely in Rust." repository = "https://github.com/Determinant/runes" diff --git a/src/bin.rs b/src/bin.rs index 08f2f59..4e0a550 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -10,12 +10,9 @@ use std::cell::{Cell, RefCell}; extern crate sdl2; #[macro_use] extern crate clap; -use sdl2::event::Event; -use sdl2::keyboard::Keycode; -use sdl2::rect::Rect; use clap::{Arg, App}; - mod utils; +mod utils; mod memory; #[macro_use] mod mos6502; mod ppu; @@ -48,7 +45,7 @@ const PIX_HEIGHT: u32 = 240; const FB_PITCH: usize = PIX_WIDTH as usize * 3; const FB_SIZE: usize = PIX_HEIGHT as usize * FB_PITCH; const AUDIO_SAMPLES: u16 = 4410; -const AUDIO_EXTRA_SAMPLES: u16 = 20; +const AUDIO_EXTRA_SAMPLES: u16 = 1000; const AUDIO_ALL_SAMPLES: u16 = AUDIO_SAMPLES + AUDIO_EXTRA_SAMPLES; pub struct SimpleCart { @@ -155,46 +152,54 @@ impl utils::Write for FileIO { } } - -macro_rules! gen_keymap { - ($tab: ident, [$($x: expr, $y: expr), *]) => { - {$($tab[($x as usize) & 0xff] = $y;)*} - }; -} - struct SDLEventPoller { events: RefCell, p1_button_state: Cell, - keymap: [u8; 256], - exit_flag: Cell + exit_flag: Cell, +} + +fn keyboard_mapping(code: sdl2::keyboard::Keycode) -> u8 { + use sdl2::keyboard::Keycode::*; + match code { + I => stdctl::UP, + K => stdctl::DOWN, + J => stdctl::LEFT, + L => stdctl::RIGHT, + Z => stdctl::A, + X => stdctl::B, + Return => stdctl::START, + S => stdctl::SELECT, + Up => stdctl::UP, + Down => stdctl::DOWN, + Left => stdctl::LEFT, + Right => stdctl::RIGHT, + _ => 0, + } +} + +fn joystick_mapping(button: sdl2::controller::Button) -> u8 { + use sdl2::controller::Button::*; + match button { + DPadUp => stdctl::UP, + DPadDown => stdctl::DOWN, + DPadLeft => stdctl::LEFT, + DPadRight => stdctl::RIGHT, + A => stdctl::A, + B => stdctl::B, + X => stdctl::A, + Y => stdctl::B, + Start => stdctl::START, + _ => stdctl::SELECT + } } impl SDLEventPoller { fn new(_events: sdl2::EventPump) -> Self { - let mut res = SDLEventPoller { + SDLEventPoller { events: RefCell::new(_events), p1_button_state: Cell::new(0), - exit_flag: Cell::new(false), - keymap: [stdctl::NULL; 256] - }; - use Keycode::*; - { - let keymap = &mut res.keymap; - gen_keymap!(keymap, [I, stdctl::UP, - K, stdctl::DOWN, - J, stdctl::LEFT, - L, stdctl::RIGHT, - Z, stdctl::A, - X, stdctl::B, - Return, stdctl::START, - S, stdctl::SELECT, - Up, stdctl::UP, - Down, stdctl::DOWN, - Left, stdctl::LEFT, - Right, stdctl::RIGHT - ]); + exit_flag: Cell::new(false) } - res } #[inline] @@ -206,20 +211,38 @@ impl SDLEventPoller { impl InputPoller for SDLEventPoller { #[inline] fn poll(&self) -> u8 { - use Keycode::*; - let keymap = &self.keymap; + use sdl2::keyboard::Keycode::Escape; + use sdl2::event::Event; let mut ns = self.p1_button_state.get(); for event in self.events.borrow_mut().poll_iter() { match event { Event::Quit {..} | Event::KeyDown { keycode: Some(Escape), .. } => { self.exit_flag.set(true) }, - Event::KeyDown { keycode: Some(c), .. } => { - ns |= keymap[(c as usize) & 0xff] - }, - Event::KeyUp { keycode: Some(c), .. } => { - ns &= !keymap[(c as usize) & 0xff] + Event::KeyDown { keycode: Some(c), .. } => + ns |= keyboard_mapping(c), + Event::KeyUp { keycode: Some(c), .. } => + ns &= !keyboard_mapping(c), + Event::ControllerButtonDown { button, .. } => + ns |= joystick_mapping(button), + Event::ControllerButtonUp { button, .. } => + ns &= !joystick_mapping(button), + /* TODO: support axis motion + Event::ControllerAxisMotion { axis: LeftX, value: val, .. } => { + let threshold = 10_000; + if val > threshold { + println!("{}", val); + ns |= stdctl::RIGHT; + ns &= !stdctl::LEFT; + } else if val < -threshold { + println!("{}", val); + ns |= stdctl::LEFT; + ns &= !stdctl::RIGHT; + } else { + ns &= !(stdctl::RIGHT | stdctl::LEFT); + } }, + */ _ => () } } @@ -232,7 +255,7 @@ struct SDLWindow<'a> { canvas: sdl2::render::WindowCanvas, frame_buffer: [u8; FB_SIZE], texture: sdl2::render::Texture, - copy_area: Option, + copy_area: Option, event: &'a SDLEventPoller } @@ -246,7 +269,7 @@ impl<'a> SDLWindow<'a> { let mut copy_area = None; if !full_screen { actual_height -= 16 * pixel_scale; - copy_area = Some(Rect::new(0, 8, PIX_WIDTH, PIX_HEIGHT - 16)); + copy_area = Some(sdl2::rect::Rect::new(0, 8, PIX_WIDTH, PIX_HEIGHT - 16)); } let window = video_subsystem.window("RuNES", actual_width, actual_height) .position_centered() @@ -525,11 +548,13 @@ fn main() { println!("read prg {}", file.read(&mut prg_rom[..]).unwrap()); println!("read chr {}", file.read(&mut chr_rom[..]).unwrap()); - /* SDL setup */ + /* setup SDL */ let sdl_context = sdl2::init().unwrap(); - let event = SDLEventPoller::new(sdl_context.event_pump().unwrap()); + let controller_subsystem = sdl_context.game_controller().unwrap(); let video_subsystem = sdl_context.video().unwrap(); let audio_subsystem = sdl_context.audio().unwrap(); + + /* audio */ let audio_sync = AudioSync { time_barrier: Condvar::new(), buffer: Mutex::new((CircularBuffer::new(), AUDIO_ALL_SAMPLES))}; @@ -542,7 +567,33 @@ fn main() { let device = audio_subsystem.open_playback(None, &desired_spec, |_| { SDLAudioPlayback(&audio_sync) }).unwrap(); - let mut win = SDLWindow::new(&video_subsystem, &event, /*&p1ctl, */ scale, full); + + /* joysticks */ + let njoysticks = match controller_subsystem.num_joysticks() { + Ok(n) => n, + Err(e) => { + println!("can't enumerate joysticks: {}", e); + 0 + }, + }; + println!("detected {} joysticks", njoysticks); + let mut _sdl_joystick = None; + for id in 0..njoysticks { + if controller_subsystem.is_game_controller(id) { + match controller_subsystem.open(id) { + Ok(ctl) => { + println!("opened controller {}", ctl.name()); + println!("controller mapping: {}", ctl.mapping()); + _sdl_joystick = Some(ctl); + break; + }, + Err(e) => println!("failed to open {}: {}", id, e) + } + } + } + + let event = SDLEventPoller::new(sdl_context.event_pump().unwrap()); + let mut win = SDLWindow::new(&video_subsystem, &event, scale, full); /* construct mapper from cartridge data */ let cart = SimpleCart::new(chr_rom, prg_rom, sram, mirror); @@ -553,15 +604,17 @@ fn main() { _ => panic!("unsupported mapper {}", mapper_id) }; - /* P1 controller */ + /* controller for player 1 */ let p1ctl = stdctl::Joystick::new(&event); + /* setup the emulated machine */ let mapper = mapper::RefMapper::new(&mut (*m) as &mut mapper::Mapper); let mut cpu = CPU::new(CPUMemory::new(&mapper, Some(&p1ctl), None)); let mut ppu = PPU::new(PPUMemory::new(&mapper), &mut win); let mut apu = APU::new(&mut spkr); let cpu_ptr = &mut cpu as *mut CPU; cpu.mem.bus.attach(cpu_ptr, &mut ppu, &mut apu); + let load_state = !no_state && match match load_state_name { Some(s) => Some(File::open(s).unwrap()), None => match File::open(&default_state_name) { -- cgit v1.2.3