212 lines
5.9 KiB
Rust
212 lines
5.9 KiB
Rust
use chip8::{emu::Chip8, timer::Timer};
|
|
use pixels::{wgpu::Surface, Pixels, SurfaceTexture};
|
|
use std::path::Path;
|
|
use std::time::{Duration, Instant};
|
|
use winit::dpi::LogicalSize;
|
|
use winit::event::{Event, VirtualKeyCode};
|
|
use winit::event_loop::{ControlFlow, EventLoop};
|
|
use winit::window::{Window, WindowBuilder};
|
|
use winit_input_helper::WinitInputHelper;
|
|
|
|
static WIDTH: u32 = 64;
|
|
static HEIGHT: u32 = 32;
|
|
static OPCODES_PER_SECOND: u64 = 500;
|
|
|
|
fn main() {
|
|
let mut chip8: Chip8 = Default::default();
|
|
let mut input = WinitInputHelper::new();
|
|
let event_loop = EventLoop::new();
|
|
let window = init_window(&event_loop);
|
|
let mut pixels = init_pixels(&window);
|
|
|
|
let path = std::env::args().nth(1).expect("No Path Provided!");
|
|
let rom_path = Path::new(&path);
|
|
chip8.load_rom(rom_path).expect("Unable to load ROM");
|
|
|
|
Timer::start_thread();
|
|
|
|
let mut start = Instant::now();
|
|
let frametime = Duration::from_nanos(1e+9 as u64 / OPCODES_PER_SECOND);
|
|
|
|
event_loop.run(move |event, _, control_flow| {
|
|
if let Event::RedrawRequested(_) = event {
|
|
draw(&chip8.display.buf, pixels.get_frame());
|
|
if pixels
|
|
.render()
|
|
.map_err(|e| eprintln!("pixels.render() failed: {}", e))
|
|
.is_err()
|
|
{
|
|
*control_flow = ControlFlow::Exit;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if input.update(&event) {
|
|
handle_input(&mut chip8, &mut input, control_flow);
|
|
|
|
if let Some(size) = input.window_resized() {
|
|
pixels.resize(size.width, size.height);
|
|
}
|
|
|
|
if Instant::now().duration_since(start) > frametime {
|
|
chip8.execute_cycle();
|
|
start = Instant::now();
|
|
}
|
|
|
|
if chip8.request_redraw {
|
|
window.request_redraw();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
fn handle_input(chip8: &mut Chip8, input: &mut WinitInputHelper, control_flow: &mut ControlFlow) {
|
|
if input.key_pressed(VirtualKeyCode::Escape) || input.quit() {
|
|
*control_flow = ControlFlow::Exit;
|
|
return;
|
|
}
|
|
|
|
// 1 -> 1
|
|
if input.key_pressed(VirtualKeyCode::Key1) {
|
|
chip8.key.set_key(0x1);
|
|
}
|
|
if input.key_released(VirtualKeyCode::Key1) {
|
|
chip8.key.unset_key(0x1);
|
|
}
|
|
// 2 -> 2
|
|
if input.key_pressed(VirtualKeyCode::Key2) {
|
|
chip8.key.set_key(0x2);
|
|
}
|
|
if input.key_released(VirtualKeyCode::Key2) {
|
|
chip8.key.unset_key(0x2);
|
|
}
|
|
// 3 -> 3
|
|
if input.key_pressed(VirtualKeyCode::Key3) {
|
|
chip8.key.set_key(0x3);
|
|
}
|
|
if input.key_released(VirtualKeyCode::Key3) {
|
|
chip8.key.unset_key(0x3);
|
|
}
|
|
// 4 -> C
|
|
if input.key_pressed(VirtualKeyCode::Key4) {
|
|
chip8.key.set_key(0xC);
|
|
}
|
|
if input.key_released(VirtualKeyCode::Key4) {
|
|
chip8.key.unset_key(0xC);
|
|
}
|
|
// Q -> 4
|
|
if input.key_pressed(VirtualKeyCode::Q) {
|
|
chip8.key.set_key(0x4);
|
|
}
|
|
if input.key_released(VirtualKeyCode::Q) {
|
|
chip8.key.unset_key(0x4);
|
|
}
|
|
// W -> 5
|
|
if input.key_pressed(VirtualKeyCode::W) {
|
|
chip8.key.set_key(0x5);
|
|
}
|
|
if input.key_released(VirtualKeyCode::W) {
|
|
chip8.key.unset_key(0x5);
|
|
}
|
|
// E -> 6
|
|
if input.key_pressed(VirtualKeyCode::E) {
|
|
chip8.key.set_key(0x6);
|
|
}
|
|
if input.key_released(VirtualKeyCode::E) {
|
|
chip8.key.unset_key(0x6);
|
|
}
|
|
// R -> D
|
|
if input.key_pressed(VirtualKeyCode::R) {
|
|
chip8.key.set_key(0xD);
|
|
}
|
|
if input.key_released(VirtualKeyCode::R) {
|
|
chip8.key.unset_key(0xD);
|
|
}
|
|
// A -> 7
|
|
if input.key_pressed(VirtualKeyCode::A) {
|
|
chip8.key.set_key(0x7);
|
|
}
|
|
if input.key_released(VirtualKeyCode::A) {
|
|
chip8.key.unset_key(0x7);
|
|
}
|
|
// S -> 8
|
|
if input.key_pressed(VirtualKeyCode::S) {
|
|
chip8.key.set_key(0x8);
|
|
}
|
|
if input.key_released(VirtualKeyCode::S) {
|
|
chip8.key.unset_key(0x8);
|
|
}
|
|
// D -> 9
|
|
if input.key_pressed(VirtualKeyCode::D) {
|
|
chip8.key.set_key(0x9);
|
|
}
|
|
if input.key_released(VirtualKeyCode::D) {
|
|
chip8.key.unset_key(0x9);
|
|
}
|
|
// F -> A
|
|
if input.key_pressed(VirtualKeyCode::F) {
|
|
chip8.key.set_key(0xE);
|
|
}
|
|
if input.key_released(VirtualKeyCode::F) {
|
|
chip8.key.unset_key(0xE);
|
|
}
|
|
// Z -> A
|
|
if input.key_pressed(VirtualKeyCode::Z) {
|
|
chip8.key.set_key(0xA);
|
|
}
|
|
if input.key_released(VirtualKeyCode::Z) {
|
|
chip8.key.unset_key(0xA);
|
|
}
|
|
// X -> 0
|
|
if input.key_pressed(VirtualKeyCode::X) {
|
|
chip8.key.set_key(0x0);
|
|
}
|
|
if input.key_released(VirtualKeyCode::X) {
|
|
chip8.key.unset_key(0x0);
|
|
}
|
|
// C -> B
|
|
if input.key_pressed(VirtualKeyCode::C) {
|
|
chip8.key.set_key(0xB);
|
|
}
|
|
if input.key_released(VirtualKeyCode::C) {
|
|
chip8.key.unset_key(0xB);
|
|
}
|
|
// V -> F
|
|
if input.key_pressed(VirtualKeyCode::V) {
|
|
chip8.key.set_key(0xF);
|
|
}
|
|
if input.key_released(VirtualKeyCode::V) {
|
|
chip8.key.unset_key(0xF);
|
|
}
|
|
}
|
|
|
|
fn init_pixels(window: &Window) -> Pixels {
|
|
let surface = Surface::create(window);
|
|
let texture = SurfaceTexture::new(WIDTH, HEIGHT, surface);
|
|
Pixels::new(WIDTH, HEIGHT, texture).unwrap()
|
|
}
|
|
|
|
fn init_window(event_loop: &EventLoop<()>) -> Window {
|
|
const SCALE: u32 = 10;
|
|
let min_size = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
|
|
let size = LogicalSize::new((WIDTH * SCALE) as f64, (HEIGHT * SCALE) as f64);
|
|
WindowBuilder::new()
|
|
.with_title("Chip8 Emulator")
|
|
.with_inner_size(size)
|
|
.with_min_inner_size(min_size)
|
|
.build(event_loop)
|
|
.unwrap()
|
|
}
|
|
|
|
fn draw(chip8_gfx: &[u8], frame: &mut [u8]) {
|
|
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
|
let rgba = if chip8_gfx[i] == 1 {
|
|
[0xFF; 4]
|
|
} else {
|
|
[0x00; 4]
|
|
};
|
|
|
|
pixel.copy_from_slice(&rgba);
|
|
}
|
|
}
|