diff --git a/src/chip_8/chip_8.rs b/src/chip_8/chip_8.rs index 24dd71b..fa6d0da 100644 --- a/src/chip_8/chip_8.rs +++ b/src/chip_8/chip_8.rs @@ -13,7 +13,7 @@ pub fn run() { ); let sdl_context = sdl2::init().unwrap(); - let mut display = Display::init(&sdl_context, cpu.get_display_scale()); + let mut display = Display::init(&sdl_context); let mut event_pump = sdl_context.event_pump().unwrap(); 'runner: loop { @@ -68,7 +68,7 @@ pub fn run() { cpu.fetch(); cpu.decode(); if cpu.should_redraw { - display.draw(&cpu.get_display_buffer()); + display.draw(&cpu.get_frame_buffer()); cpu.should_redraw = false; } } diff --git a/src/chip_8/cpu.rs b/src/chip_8/cpu.rs index 5526b90..e956535 100644 --- a/src/chip_8/cpu.rs +++ b/src/chip_8/cpu.rs @@ -1,7 +1,7 @@ pub mod cpu; mod clock; -mod display_buffer; +mod frame_buffer; mod keypad; mod opcodes; mod ram; diff --git a/src/chip_8/cpu/cpu.rs b/src/chip_8/cpu/cpu.rs index 2e4a5a2..5eb8bdf 100644 --- a/src/chip_8/cpu/cpu.rs +++ b/src/chip_8/cpu/cpu.rs @@ -1,5 +1,5 @@ use super::clock::Clock; -use super::display_buffer::{DisplayBuffer, DISPLAY_HEIGHT, DISPLAY_WIDTH}; +use super::frame_buffer::{FrameBuffer, HEIGHT, WIDTH, PITCH_BYTES}; use super::keypad::Keypad; use super::opcodes::OpCodes; use super::ram::RAM; @@ -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 + frame_buffer: FrameBuffer, // Frame Buffer + op: OpCodes, // Operation Code, + pub should_redraw: bool, // Boolean indicating Display Buffer update } impl CPU { @@ -35,7 +35,7 @@ impl CPU { regs: Registers::new(), ram: ram, keypad: Keypad::new(), - db: DisplayBuffer::new(10), + frame_buffer: FrameBuffer::new(), op: OpCodes::new(0000), should_redraw: false, } @@ -211,17 +211,13 @@ impl CPU { self.ram.load_rom(rom); } - pub fn get_display_scale(&self) -> u32 { - self.db.scale - } - - pub fn get_display_buffer(&self) -> [[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH] { - self.db.db + pub fn get_frame_buffer(&self) -> [u8; WIDTH * HEIGHT * PITCH_BYTES] { + self.frame_buffer.frame_buffer } } fn op_00e0(cpu: &mut CPU) { - cpu.db.clear(); + cpu.frame_buffer.clear(); } fn op_1nnn(cpu: &mut CPU) { @@ -349,26 +345,27 @@ fn op_cxnn(cpu: &mut CPU) { fn op_dxyn(cpu: &mut CPU) { let mut vf: bool = false; let value = cpu.op.n as usize; - let ori_x = cpu.regs.get(cpu.op.x) as usize % DISPLAY_WIDTH; - let ori_y = cpu.regs.get(cpu.op.y) as usize % DISPLAY_HEIGHT; + let ori_x = cpu.regs.get(cpu.op.x) as usize % WIDTH; + let ori_y = cpu.regs.get(cpu.op.y) as usize % HEIGHT; for row in 0..value { let y = ori_y + row; - if y >= DISPLAY_HEIGHT { + if y >= HEIGHT { break; } let sprite = cpu.ram.read8(cpu.regs.i + row); for pixel_position in 0..8 { let x = ori_x + pixel_position; - if x >= DISPLAY_WIDTH { + if x >= WIDTH { break; } let memory_pixel: bool = (sprite & (1 << (7 - pixel_position))) > 0; - let display_pixel: bool = cpu.db.db[x][y]; - cpu.db.db[x][y] = memory_pixel ^ display_pixel; - vf = (memory_pixel && display_pixel) || vf; + let frame_pixel: bool = cpu.frame_buffer.toggle_buffer[x][y]; + cpu.frame_buffer.toggle_buffer[x][y] = memory_pixel ^ frame_pixel; + cpu.frame_buffer.update_frame_buffer(x, y); + vf = (memory_pixel && frame_pixel) || vf; } } cpu.regs.set(0xF, if vf { 1 } else { 0 }); diff --git a/src/chip_8/cpu/display_buffer.rs b/src/chip_8/cpu/display_buffer.rs deleted file mode 100644 index 026cfb3..0000000 --- a/src/chip_8/cpu/display_buffer.rs +++ /dev/null @@ -1,20 +0,0 @@ -pub const DISPLAY_WIDTH: usize = 64; -pub const DISPLAY_HEIGHT: usize = 32; - -pub struct DisplayBuffer { - pub db: [[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH], - pub scale: u32, -} - -impl DisplayBuffer { - pub fn new(scale: u32) -> DisplayBuffer { - DisplayBuffer { - db: [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH], - scale: scale, - } - } - - pub fn clear(&mut self) { - self.db = [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH]; - } -} diff --git a/src/chip_8/cpu/frame_buffer.rs b/src/chip_8/cpu/frame_buffer.rs new file mode 100644 index 0000000..13a3753 --- /dev/null +++ b/src/chip_8/cpu/frame_buffer.rs @@ -0,0 +1,45 @@ +use sdl2::pixels::Color; +use crate::chip_8::display; + +pub const WIDTH: usize = display::WIDTH; +pub const HEIGHT: usize = display::HEIGHT; +pub const PITCH_BYTES: usize = display::PITCH_BYTES; + +pub struct FrameBuffer { + pub frame_buffer: [u8; WIDTH * HEIGHT * PITCH_BYTES], + pub toggle_buffer: [[bool; HEIGHT]; WIDTH], + off_color: Color, + on_color: Color, +} + +impl FrameBuffer { + pub fn new() -> FrameBuffer { + FrameBuffer { + frame_buffer: [0; WIDTH * HEIGHT * PITCH_BYTES], + toggle_buffer: [[false; HEIGHT]; WIDTH], + off_color: Color::RGBA(0, 0, 0, 255), + on_color: Color::RGBA(255, 255, 255, 255), + } + } + + pub fn clear(&mut self) { + for (x, col) in self.toggle_buffer.iter().enumerate() { + for (y, _) in col.iter().enumerate() { + let offset = x * PITCH_BYTES + y * WIDTH * PITCH_BYTES; + for i in offset..(offset + PITCH_BYTES) { self.frame_buffer[i] = self.color_to_array(&self.off_color)[i - offset]; } + } + } + + self.toggle_buffer = [[false; HEIGHT]; WIDTH]; + } + + pub fn update_frame_buffer(&mut self, x: usize, y: usize) { + let offset = x * PITCH_BYTES + y * WIDTH * PITCH_BYTES; + let color: Color = if self.toggle_buffer[x][y] { self.on_color } else { self.off_color }; + for i in offset..(offset + PITCH_BYTES) { self.frame_buffer[i] = self.color_to_array(&color)[i - offset]; } + } + + fn color_to_array(&self, color: &Color) -> [u8; PITCH_BYTES] { + [color.r, color.g, color.b, color.a] + } +} diff --git a/src/chip_8/display.rs b/src/chip_8/display.rs index a4635b0..49d471a 100644 --- a/src/chip_8/display.rs +++ b/src/chip_8/display.rs @@ -1,56 +1,35 @@ -use sdl2::pixels::Color; 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 const WIDTH: usize = 64; +pub const HEIGHT: usize = 32; +pub const PITCH_BYTES: usize = std::mem::size_of::(); // 4 bytes: R G B A, from colors pub struct Display { - canvas: Canvas, - off_color: [u8; PITCH_BYTES], - on_color: [u8; PITCH_BYTES], + canvas: Canvas } impl Display { - pub fn init(sdl_context: &sdl2::Sdl, scale: u32) -> Display { + pub fn init(sdl_context: &sdl2::Sdl) -> Display { + let scale = 10; let canvas = sdl_context.video().unwrap() .window("Chip-8", WIDTH as u32 * scale, HEIGHT as u32 * scale) .resizable().position_centered().build().unwrap() .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, - 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], + canvas: canvas } } - pub fn draw(self: &mut Display, buffer: &[[bool; HEIGHT]; WIDTH]) { - self.apply_texture(buffer); - self.canvas.present(); - } - - 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() { - 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]; } - } - } - + pub fn draw(self: &mut Display, frame_buffer: &[u8; HEIGHT * WIDTH * PITCH_BYTES]) { 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(); + texture.update(None, frame_buffer, WIDTH * PITCH_BYTES).unwrap(); self.canvas.copy(&texture, None, None).unwrap(); + self.canvas.present(); } }