refactor display struct

This commit is contained in:
Denis-Cosmin Nutiu 2024-12-04 23:48:59 +02:00
parent 2f4e615ab3
commit f47228bf8c
2 changed files with 52 additions and 28 deletions

View file

@ -9,22 +9,16 @@ pub trait Display {
/// Re-draws the display.
fn clear(&self);
/// Renders the display data on screen.
fn render(&mut self);
/// Draws the pixels at x and y coordinates
fn draw(&mut self, x: u8, y: u8, pixels: u8) -> bool;
fn render(&mut self, display_data: &[bool; DISPLAY_WIDTH * DISPLAY_HEIGHT]);
}
/// Display models the Chip8's display.
pub struct TerminalDisplay {
/// Holds the display data, each bit corresponds to a pixel.
display_data: [bool; DISPLAY_WIDTH * DISPLAY_HEIGHT],
}
impl TerminalDisplay {
pub fn new() -> TerminalDisplay {
TerminalDisplay {
display_data: [false; DISPLAY_WIDTH * DISPLAY_HEIGHT],
}
TerminalDisplay {}
}
}
@ -36,11 +30,11 @@ impl Display for TerminalDisplay {
print!("{esc}[2J{esc}[1;1H", esc = 27 as char);
}
/// Renders the display data on screen.
fn render(&mut self) {
fn render(&mut self, display_data: &[bool; DISPLAY_WIDTH * DISPLAY_HEIGHT]) {
for row in 0..32 {
for column in 0..64 {
if self.display_data[row * DISPLAY_WIDTH + column] {
print!("")
if display_data[row * DISPLAY_WIDTH + column] {
print!("#")
} else {
print!(" ")
}
@ -48,15 +42,4 @@ impl Display for TerminalDisplay {
print!("\n")
}
}
/// Draws the pixels at x and y coordinates
fn draw(&mut self, x: u8, y: u8, pixels: u8) -> bool {
let row = y as usize;
let column = x as usize;
for pixel in 0..=pixels {
self.display_data[row * DISPLAY_WIDTH + column + pixel as usize] = true;
}
self.render();
true
}
}

View file

@ -8,6 +8,12 @@ use std::io::Read;
use std::path::Path;
use std::{thread, time};
/// Represents the display's width in pixels.
const DISPLAY_WIDTH: usize = 64;
/// Represents the display's height pixels.
const DISPLAY_HEIGHT: usize = 32;
const MEMORY_SIZE: usize = 4096;
const NUMBER_OF_REGISTERS: usize = 16;
const FONT_SPRITES: [u8; 80] = [
@ -51,7 +57,10 @@ where
stack_pointer: u8,
/// The display_data holds all the data associated with the display
display: D,
/// The stack of the emulator.
stack: Stack<u16>,
/// Holds the display data, each bit corresponds to a pixel.
display_data: [bool; DISPLAY_WIDTH * DISPLAY_HEIGHT],
}
impl<D> Emulator<D>
@ -71,6 +80,7 @@ where
sound_timer: 0,
stack_pointer: 0,
stack: Stack::new(),
display_data: [false; DISPLAY_WIDTH * DISPLAY_HEIGHT],
};
emulator.load_font_data();
@ -136,12 +146,43 @@ where
trace!("Add to register {} data {:04x}", register, data);
self.registers[register as usize] += data
}
ProcessorInstruction::Draw(vx_register, vy_register, pixels) => {
trace!("Draw vx_register={vx_register} vy_register={vy_register} pixels={pixels}");
let x_coordinate = self.registers[vx_register as usize] & 63;
let y_coordinate = self.registers[vy_register as usize] & 31;
self.registers[0xF] = 0;
self.display.draw(x_coordinate, y_coordinate, pixels);
ProcessorInstruction::Draw(vx_register, vy_register, num_rows) => {
trace!("Draw vx_register={vx_register} vy_register={vy_register} pixels={num_rows}");
let x_coordinate = self.registers[vx_register as usize];
let y_coordinate = self.registers[vy_register as usize];
// Keep track if any pixels were flipped
let mut flipped = false;
// Iterate over each row of our sprite
for y_line in 0..num_rows {
// Determine which memory address our row's data is stored
let addr = self.index_register + y_line as u16;
let pixels = self.memory[0xf0 + addr as usize];
// Iterate over each column in our row
for x_line in 0..8 {
// Use a mask to fetch current pixel's bit. Only flip if a 1
if (pixels & (0b1000_0000 >> x_line)) != 0 {
// Sprites should wrap around screen, so apply modulo
let x = (x_coordinate + x_line) as usize % DISPLAY_WIDTH;
let y = (y_coordinate + y_line) as usize % DISPLAY_HEIGHT;
// Get our pixel's index for our 1D screen array
let index = x + DISPLAY_WIDTH * y;
// Check if we're about to flip the pixel and set
flipped |= self.display_data[index];
self.display_data[index] ^= true;
}
}
}
if flipped {
self.registers[0xF] = 1;
} else {
self.registers[0xF] = 0;
}
self.display.render(&self.display_data);
}
ProcessorInstruction::UnknownInstruction => {
warn!("Unknown instruction: {:04x}, skipping.", instruction);