chip8/src/main.rs

172 lines
4.8 KiB
Rust
Raw Normal View History

// I used: http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#00E0
// and https://en.wikipedia.org/wiki/CHIP-8#Opcode_table
// for information about how to implement a CHIP-8 Emulator
2020-06-25 18:13:09 +00:00
use chip8::emu::Chip8;
use std::path::Path;
use pixels::{wgpu::Surface, Pixels, SurfaceTexture};
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;
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 rom_path = Path::new("./games/c8games/INVADERS");
chip8.load_rom(rom_path).expect("Unable to load ROM");
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);
}
chip8.execute_cycle();
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;
}
if input.key_pressed(VirtualKeyCode::Key1) {
chip8.key.set_key(0x1);
} else {
chip8.key.unset_key(0x1);
}
if input.key_pressed(VirtualKeyCode::Key2) {
chip8.key.set_key(0x2);
} else {
chip8.key.set_key(0x2);
}
if input.key_pressed(VirtualKeyCode::Key3) {
chip8.key.set_key(0x3);
} else {
chip8.key.set_key(0x3);
}
if input.key_pressed(VirtualKeyCode::Key4) {
chip8.key.set_key(0xC);
} else {
chip8.key.set_key(0xC);
}
if input.key_pressed(VirtualKeyCode::Q) {
chip8.key.set_key(0x4);
} else {
chip8.key.set_key(0x4);
}
if input.key_pressed(VirtualKeyCode::W) {
chip8.key.set_key(0x5);
} else {
chip8.key.set_key(0x5);
}
if input.key_pressed(VirtualKeyCode::E) {
chip8.key.set_key(0x6);
} else {
chip8.key.set_key(0x6);
}
if input.key_pressed(VirtualKeyCode::R) {
chip8.key.set_key(0xD);
} else {
chip8.key.set_key(0xD);
}
if input.key_pressed(VirtualKeyCode::A) {
chip8.key.set_key(0x7);
} else {
chip8.key.set_key(0x7);
}
if input.key_pressed(VirtualKeyCode::S) {
chip8.key.set_key(0x8);
} else {
chip8.key.set_key(0x8);
}
if input.key_pressed(VirtualKeyCode::D) {
chip8.key.set_key(0x9);
} else {
chip8.key.set_key(0x9);
}
if input.key_pressed(VirtualKeyCode::F) {
chip8.key.set_key(0x5);
} else {
chip8.key.set_key(0x5);
}
if input.key_pressed(VirtualKeyCode::Z) {
chip8.key.set_key(0xA);
} else {
chip8.key.set_key(0xA);
}
if input.key_pressed(VirtualKeyCode::X) {
chip8.key.set_key(0x0);
} else {
chip8.key.set_key(0x0);
}
if input.key_pressed(VirtualKeyCode::C) {
chip8.key.set_key(0xB);
} else {
chip8.key.set_key(0xB);
}
if input.key_pressed(VirtualKeyCode::V) {
chip8.key.set_key(0xF);
} else {
chip8.key.set_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 {
2020-07-14 04:04:58 +00:00
[0xFF; 4]
} else {
2020-07-14 04:04:58 +00:00
[0x00; 4]
};
pixel.copy_from_slice(&rgba);
}
}