diff --git a/src/chip_8/chip_8.rs b/src/chip_8/chip_8.rs index 14718c5..24dd71b 100644 --- a/src/chip_8/chip_8.rs +++ b/src/chip_8/chip_8.rs @@ -1,43 +1,48 @@ use super::cpu::cpu::CPU; use super::display::Display; +use sdl2::event::Event; +use sdl2::keyboard::Keycode; use std::io::Read; pub fn run() { let mut cpu = CPU::new(); - load_rom("src/chip_8/roms/CAVE.ch8", &mut cpu); + load_rom( + "src/chip_8/roms/Trip8 Demo (2008) [Revival Studios].ch8", + &mut cpu, + ); let sdl_context = sdl2::init().unwrap(); let mut display = Display::init(&sdl_context, cpu.get_display_scale()); - let mut event_listener = sdl_context.event_pump().unwrap(); + let mut event_pump = sdl_context.event_pump().unwrap(); 'runner: loop { - for event in event_listener.poll_iter() { + for event in event_pump.poll_iter() { match event { - sdl2::event::Event::Quit { .. } => break 'runner, - sdl2::event::Event::KeyDown { - keycode: Some(sdl2::keyboard::Keycode::Escape), + Event::Quit { .. } => break 'runner, + Event::KeyDown { + keycode: Some(Keycode::Escape), .. } => break 'runner, - sdl2::event::Event::KeyDown { - keycode: Some(sdl2::keyboard::Keycode::RightBracket), + Event::KeyDown { + keycode: Some(Keycode::RightBracket), .. } => { cpu.increase_clock(true); } - sdl2::event::Event::KeyDown { - keycode: Some(sdl2::keyboard::Keycode::LeftBracket), + Event::KeyDown { + keycode: Some(Keycode::LeftBracket), .. } => { cpu.decrease_clock(true); } - sdl2::event::Event::KeyDown { - keycode: Some(sdl2::keyboard::Keycode::Backspace), + Event::KeyDown { + keycode: Some(Keycode::Backspace), .. } => { cpu.reset_rom(); } - sdl2::event::Event::KeyDown { + Event::KeyDown { keycode: Some(keycode), .. } => { @@ -45,7 +50,7 @@ pub fn run() { cpu.press_key(key_index); } } - sdl2::event::Event::KeyUp { + Event::KeyUp { keycode: Some(keycode), .. } => { diff --git a/src/chip_8/cpu/clock.rs b/src/chip_8/cpu/clock.rs index 5cc3d5d..4cedc19 100644 --- a/src/chip_8/cpu/clock.rs +++ b/src/chip_8/cpu/clock.rs @@ -16,22 +16,16 @@ impl Clock { } pub fn tick(&mut self) -> bool { - let mut res: bool = false; - match self.elapsed.elapsed() { - Ok(elapsed) => { - if elapsed.as_secs_f64() >= self.clock_hz_as_secs_f64() { - if self.tick > 0 { - self.tick -= 1; - } - self.reset_elapsed(); - res = true; + if let Ok(elapsed) = self.elapsed.elapsed() { + if elapsed.as_secs_f64() >= self.clock_hz_as_secs_f64() { + if self.tick > 0 { + self.tick -= 1; } - } - Err(e) => { - println!("Error: {:?}", e); + self.reset_elapsed(); + return true; } } - res + false } fn reset_elapsed(&mut self) { diff --git a/src/chip_8/cpu/cpu.rs b/src/chip_8/cpu/cpu.rs index 695e259..2e4a5a2 100644 --- a/src/chip_8/cpu/cpu.rs +++ b/src/chip_8/cpu/cpu.rs @@ -10,16 +10,16 @@ use sdl2::keyboard::Keycode; use rand::Rng; pub struct CPU { - stack: Vec, // Function Stack - dt: Clock, // Delay Timer - st: Clock, // Sound Timer - clock: Clock, // CPU Clock - regs: Registers, // Registers - ram: RAM, // RAM - keypad: Keypad, // Keypad - db: DisplayBuffer, // Display Buffer - op: OpCodes, // Operation Code, - pub should_redraw: bool // Boolean indicating Display Buffer update + stack: Vec, // Function Stack + dt: Clock, // Delay Timer + st: Clock, // Sound Timer + clock: Clock, // CPU Clock + regs: Registers, // Registers + ram: RAM, // RAM + keypad: Keypad, // Keypad + db: DisplayBuffer, // Display Buffer + op: OpCodes, // Operation Code, + pub should_redraw: bool, // Boolean indicating Display Buffer update } impl CPU { @@ -37,7 +37,7 @@ impl CPU { keypad: Keypad::new(), db: DisplayBuffer::new(10), op: OpCodes::new(0000), - should_redraw: false + should_redraw: false, } } @@ -189,7 +189,7 @@ impl CPU { pub fn set_delay_timer(&mut self, tick: u8) { self.dt.tick = tick; - } + } pub fn set_sound_timer(&mut self, tick: u8) { self.st.tick = tick; @@ -343,8 +343,7 @@ fn op_bnnn(cpu: &mut CPU) { fn op_cxnn(cpu: &mut CPU) { let mut rng = rand::thread_rng(); - cpu.regs - .set(cpu.op.x, rng.gen_range(0x0..0xFF) & cpu.op.nn); + cpu.regs.set(cpu.op.x, rng.gen_range(0x0..0xFF) & cpu.op.nn); } fn op_dxyn(cpu: &mut CPU) { @@ -438,4 +437,4 @@ fn op_fx65(cpu: &mut CPU) { for regs in 0x0..(cpu.op.x + 1) { cpu.regs.set(regs, cpu.ram.read8(i + regs)); } -} \ No newline at end of file +} diff --git a/src/chip_8/cpu/keypad.rs b/src/chip_8/cpu/keypad.rs index a1ae97c..b826bc8 100644 --- a/src/chip_8/cpu/keypad.rs +++ b/src/chip_8/cpu/keypad.rs @@ -35,10 +35,10 @@ impl Keypad { } pub fn compute_keycode(&self, keycode: Keycode) -> Option { - match self.keys.get(&keycode) { - Some(chip8_key) => Some(*chip8_key), - None => None, + if let Some(&chip8_key) = self.keys.get(&keycode) { + return Some(chip8_key); } + None } pub fn get_status(&mut self, pos: usize) -> bool { diff --git a/src/chip_8/cpu/registers.rs b/src/chip_8/cpu/registers.rs index ec3d57e..08eb7cf 100644 --- a/src/chip_8/cpu/registers.rs +++ b/src/chip_8/cpu/registers.rs @@ -16,9 +16,9 @@ pub struct Registers { x_c: u8, x_d: u8, x_e: u8, - x_f: u8, // Flag register - pub pc: usize, // Program Counter - pub i: usize // Index register + x_f: u8, // Flag register + pub pc: usize, // Program Counter + pub i: usize, // Index register } impl Registers { @@ -64,7 +64,7 @@ impl Registers { 0xD => self.x_d, 0xE => self.x_e, 0xF => self.x_f, - _ => 0, + _ => panic!("Trying to access non-existing register"), } } @@ -87,7 +87,7 @@ impl Registers { 0xD => self.x_d = value, 0xE => self.x_e = value, 0xF => self.x_f = value, - _ => {} + _ => panic!("Trying to access non-existing register"), } } diff --git a/src/chip_8/display.rs b/src/chip_8/display.rs index 1583be1..a4635b0 100644 --- a/src/chip_8/display.rs +++ b/src/chip_8/display.rs @@ -1,56 +1,56 @@ -use sdl2::render::Canvas; use sdl2::pixels::Color; -use sdl2::rect::Rect; +use sdl2::pixels::PixelFormatEnum; +use sdl2::render::Canvas; +use sdl2::video::Window; const WIDTH: usize = 64; const HEIGHT: usize = 32; +const PITCH_BYTES: usize = std::mem::size_of::(); // 4 bytes: R G B A, from colors +const PITCH: usize = WIDTH * PITCH_BYTES; pub struct Display { - canvas: Canvas, - scale: u32, - off_color: Color, - on_color: Color, + canvas: Canvas, + off_color: [u8; PITCH_BYTES], + on_color: [u8; PITCH_BYTES], } impl Display { pub fn init(sdl_context: &sdl2::Sdl, scale: u32) -> Display { - let video_subsystem = sdl_context.video().unwrap(); - - let window = video_subsystem + let canvas = sdl_context.video().unwrap() .window("Chip-8", WIDTH as u32 * scale, HEIGHT as u32 * scale) - .position_centered() - .build() - .unwrap(); + .resizable().position_centered().build().unwrap() + .into_canvas().build().unwrap(); - let canvas = window.into_canvas().build().unwrap(); + let off_color = Color::RGBA(0, 0, 0, 255); + let on_color = Color::RGBA(255, 255, 255, 255); Display { canvas: canvas, - scale: scale, - off_color: Color::RGB(0, 0, 0), - on_color: Color::RGB(255, 255, 255), + off_color: [off_color.r, off_color.g, off_color.b, off_color.a], + on_color: [on_color.r, on_color.g, on_color.b, on_color.a], } } pub fn draw(self: &mut Display, buffer: &[[bool; HEIGHT]; WIDTH]) { - self.canvas.set_draw_color(self.off_color); - self.canvas.clear(); + self.apply_texture(buffer); + self.canvas.present(); + } - self.canvas.set_draw_color(self.on_color); + fn apply_texture(&mut self, buffer: &[[bool; HEIGHT]; WIDTH]) { + let mut framebuffer: [u8; HEIGHT * PITCH] = [0; HEIGHT * PITCH]; for (x, col) in buffer.iter().enumerate() { for (y, pixel) in col.iter().enumerate() { - if *pixel { - let x = (x as u32 * self.scale) as i32; - let y = (y as u32 * self.scale) as i32; - let width = self.scale; - let height = self.scale; - self.canvas - .fill_rect(Rect::new(x, y, width, height)) - .expect("Failed to draw pixel"); - } + let offset = x * PITCH_BYTES + y * PITCH; + let color: &[u8; PITCH_BYTES] = if *pixel { &self.on_color } else { &self.off_color }; + for i in offset..(offset + PITCH_BYTES) { framebuffer[i] = color[i - offset]; } } } - self.canvas.present(); + let texture_creator = self.canvas.texture_creator(); + let mut texture = texture_creator + .create_texture_streaming(PixelFormatEnum::RGBA32, WIDTH as u32, HEIGHT as u32) + .unwrap(); + texture.update(None, &framebuffer, PITCH).unwrap(); + self.canvas.copy(&texture, None, None).unwrap(); } }