Add pixels-rs and winit as dependencies

This commit is contained in:
paoda 2020-06-25 14:22:37 -05:00
parent be4be99c92
commit 4acffdfb6b
5 changed files with 1543 additions and 16 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target
/games
/.vscode

1431
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,3 +8,6 @@ edition = "2018"
[dependencies]
rand = "0.7.3"
pixels = "0.0.4"
winit = "0.22.2"
winit_input_helper = "0.7.0"

View File

@ -15,12 +15,12 @@ pub struct Chip8 {
memory: [u8; 4096],
delay: Timer,
sound: Timer,
display: Display,
pub display: Display,
}
impl Default for Chip8 {
fn default() -> Self {
Chip8 {
let mut chip8 = Chip8 {
opcode: 0,
i: 0,
pc: 0x200, // Progrm counter starts at 0x200
@ -32,11 +32,33 @@ impl Default for Chip8 {
delay: Default::default(),
sound: Default::default(),
display: Display::default(),
}
};
chip8.load_font_set();
chip8
}
}
impl Chip8 {
const FONT_SET: [u8; 80] = [
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
0x20, 0x60, 0x20, 0x20, 0x70, // 1
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];
pub fn execute_cycle(&mut self) {
self.opcode = self.get_opcode();
println!("{:#x}", self.opcode);
@ -46,6 +68,12 @@ impl Chip8 {
self.sound.tick();
}
pub fn load_font_set(&mut self) {
for (i, byte) in Self::FONT_SET.iter().enumerate() {
self.memory[i] = *byte;
}
}
pub fn load_rom<P: AsRef<Path>>(&mut self, path: P) -> Result<(), io::Error> {
let mut file = File::open(path.as_ref())?;
let mut rom_buf: Vec<u8> = vec![];
@ -157,6 +185,7 @@ impl Chip8 {
fn jmp_addr(&mut self, n_1: u16, n_2: u16, n_3: u16) {
// sets the program counter to addr (nnn)
self.pc = Self::convert_to_addr(n_1, n_2, n_3);
println!("{:#x}", self.pc);
}
fn ret(&mut self) {
@ -203,7 +232,7 @@ impl Chip8 {
fn add_vx_byte(&mut self, x: u16, k_1: u16, k_2: u16) {
// calculate Vx + kk, then store it in Vx
let x = x as usize;
self.v[x] = self.v[x] + Self::convert_to_byte(k_1, k_2);
self.v[x] = self.v[x].wrapping_add(Self::convert_to_byte(k_1, k_2));
}
fn ld_vx_vy(&mut self, x: u16, y: u16) {
@ -247,7 +276,7 @@ impl Chip8 {
let vy = self.v[y as usize];
self.v[0xF as usize] = if vx > vy { 1 } else { 0 };
self.v[x as usize] = vx - vy;
self.v[x as usize] = vx.wrapping_sub(vy);
}
fn shr_vx(&mut self, x: u16) {
@ -390,8 +419,9 @@ impl Chip8 {
self.i = self.i + self.v[x as usize] as u16;
}
fn ld_f_vx(&mut self, _x: u16) {
todo!("Implement 0xF_29");
fn ld_f_vx(&mut self, x: u16) {
// set I to location of hex sprite related to Vx
self.i = self.v[x as usize] as u16 * 5;
}
fn ld_b_vx(&mut self, x: u16) {
@ -399,15 +429,15 @@ impl Chip8 {
// take tens digit and place it at I + 1
// take ones digit and place it at I + 2
let i = self.i as usize;
let mut iter = Self::digits(self.v[x as usize]);
let mut iter = Self::digits(self.v[x as usize] as usize);
let ones = iter.next().unwrap(); // Ther has to at least be a ones lol
let tens = iter.next().unwrap_or(0);
let hundreds = iter.next().unwrap_or(0);
self.memory[i] = hundreds;
self.memory[i + 1] = tens;
self.memory[i + 2] = ones;
self.memory[i] = hundreds as u8;
self.memory[i + 1] = tens as u8;
self.memory[i + 2] = ones as u8;
}
fn ld_i_vx(&mut self, x: u16) {
@ -436,7 +466,7 @@ impl Chip8 {
}
// https://stackoverflow.com/questions/41536479/how-do-i-split-an-integer-into-individual-digits
fn digits(mut num: u8) -> impl Iterator<Item = u8> {
fn digits(mut num: usize) -> impl Iterator<Item = usize> {
let mut divisor = 1;
while num >= divisor * 10 {
divisor *= 10;

View File

@ -4,16 +4,78 @@
use chip8::emu::Chip8;
use std::path::Path;
use std::time::Duration;
use pixels::{wgpu::Surface, Error, Pixels, SurfaceTexture};
use winit::dpi::LogicalSize;
use winit::event::{Event, VirtualKeyCode};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use winit_input_helper::WinitInputHelper;
static WIDTH: u32 = 64;
static HEIGHT: u32 = 32;
fn main() {
let event_loop = EventLoop::new();
let mut input = WinitInputHelper::new();
let window = {
let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
WindowBuilder::new()
.with_title("Chip8 Emulator")
.with_inner_size(size)
.with_min_inner_size(size)
.build(&event_loop)
.unwrap()
};
let mut hidpi_factor = window.scale_factor();
let mut pixels = {
let surface = Surface::create(&window);
let surface_texture = SurfaceTexture::new(WIDTH, HEIGHT, surface);
Pixels::new(WIDTH, HEIGHT, surface_texture).unwrap()
};
let mut chip8: Chip8 = Default::default();
chip8
.load_rom(Path::new("./games/c8games/TICTAC"))
.load_rom(Path::new("./games/test_opcode.ch8"))
.expect("Unable to load ROM");
loop {
event_loop.run(move |event, _, control_flow| {
chip8.execute_cycle();
std::thread::sleep(Duration::from_millis(300));
draw(&chip8.display.buf, pixels.get_frame());
pixels.render().unwrap();
window.request_redraw();
if input.update(&event) {
if let Some(factor) = input.scale_factor_changed() {
hidpi_factor = factor;
};
if input.key_pressed(VirtualKeyCode::Escape) || input.quit() {
*control_flow = ControlFlow::Exit;
return;
}
if let Some(size) = input.window_resized() {
pixels.resize(size.width, size.height);
}
}
// std::thread::sleep(Duration::from_millis(1000));
});
}
fn draw(chip8_gfx: &[u8], frame: &mut [u8]) {
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
let rgba = if chip8_gfx[i] != 0 {
[0xFF, 0xFF, 0xFF, 0xFF]
} else {
[0x00, 0x00, 0x00, 0xFF]
};
pixel.copy_from_slice(&rgba);
}
}