tile window draws all tiles + is optional

This commit is contained in:
Alex Janka 2023-02-08 09:40:54 +11:00
parent 3b2a07c264
commit 0a75b58732
4 changed files with 114 additions and 64 deletions

View file

@ -57,6 +57,10 @@ struct Args {
#[arg(short, long)] #[arg(short, long)]
cycle_count: bool, cycle_count: bool,
/// Show tile window
#[arg(short, long)]
tile_window: bool,
/// Step emulation by... /// Step emulation by...
#[arg(long)] #[arg(long)]
step_by: Option<usize>, step_by: Option<usize>,
@ -117,7 +121,11 @@ fn main() {
window.topmost(true); window.topmost(true);
let mut cpu = CPU::new(Memory::init(bootrom, args.run_bootrom, rom), window); let mut cpu = CPU::new(
Memory::init(bootrom, args.run_bootrom, rom),
window,
args.tile_window,
);
if !args.run_bootrom { if !args.run_bootrom {
cpu.reg.pc = 0x0100; cpu.reg.pc = 0x0100;

View file

@ -1,3 +1,4 @@
use self::tile_window::TileWindow;
use crate::{ use crate::{
processor::{as_signed, get_bit, set_bit, set_or_clear_bit, CPU}, processor::{as_signed, get_bit, set_bit, set_or_clear_bit, CPU},
FACTOR, HEIGHT, WIDTH, FACTOR, HEIGHT, WIDTH,
@ -117,8 +118,10 @@ struct Object {
flags: ObjectFlags, flags: ObjectFlags,
} }
const TILE_WINDOW_EDGE_LENGTH: usize = 16 * 8; const TILE_WINDOW_WIDTH: usize = 16 * 8;
const TILE_WINDOW_EDGE_LENGTH_SCALED: usize = TILE_WINDOW_EDGE_LENGTH * FACTOR; const TILE_WINDOW_HEIGHT: usize = 24 * 8;
const TILE_WINDOW_WIDTH_SCALED: usize = TILE_WINDOW_WIDTH * FACTOR;
const TILE_WINDOW_HEIGHT_SCALED: usize = TILE_WINDOW_HEIGHT * FACTOR;
pub struct GPU { pub struct GPU {
pub buffer: Vec<u32>, pub buffer: Vec<u32>,
@ -126,39 +129,36 @@ pub struct GPU {
mode: DrawMode, mode: DrawMode,
mode_clock: usize, mode_clock: usize,
scanline: u8, scanline: u8,
sprite_buffer: Vec<u32>, tile_window: Option<TileWindow>,
sprite_buffer_scaled: Vec<u32>,
sprite_window: Window,
} }
impl Default for GPU { impl GPU {
fn default() -> Self { pub(super) fn new(enable_tile_window: bool) -> Self {
let mut window = Window::new( let tile_window = if enable_tile_window {
"Tiles", let mut window = Window::new(
TILE_WINDOW_EDGE_LENGTH_SCALED, "Tiles",
TILE_WINDOW_EDGE_LENGTH_SCALED, TILE_WINDOW_WIDTH_SCALED,
WindowOptions::default(), TILE_WINDOW_HEIGHT_SCALED,
) WindowOptions::default(),
.unwrap_or_else(|e| { )
panic!("{}", e); .unwrap_or_else(|e| {
}); panic!("{}", e);
});
window.set_position((550 + (WIDTH * FACTOR)) as isize, 50); window.set_position((550 + (WIDTH * FACTOR)) as isize, 50);
window.topmost(true);
Some(TileWindow::new(window))
} else {
None
};
window.topmost(true);
Self { Self {
buffer: vec![0; WIDTH * HEIGHT], buffer: vec![0; WIDTH * HEIGHT],
scaled_buffer: vec![0; WIDTH * HEIGHT * 4], scaled_buffer: vec![0; WIDTH * HEIGHT * 4],
mode: DrawMode::Mode2, mode: DrawMode::Mode2,
mode_clock: 0, mode_clock: 0,
scanline: 0, scanline: 0,
sprite_buffer: vec![0; TILE_WINDOW_EDGE_LENGTH * TILE_WINDOW_EDGE_LENGTH], tile_window,
sprite_buffer_scaled: vec![
0;
TILE_WINDOW_EDGE_LENGTH_SCALED
* TILE_WINDOW_EDGE_LENGTH_SCALED
],
sprite_window: window,
} }
} }
} }
@ -259,10 +259,9 @@ impl CPU {
fn exit_vblank(&mut self) { fn exit_vblank(&mut self) {
self.gpu.mode = DrawMode::Mode2; self.gpu.mode = DrawMode::Mode2;
self.gpu.scanline = 0; self.gpu.scanline = 0;
self.draw_sprite_window( if let Some(tile_window) = &mut self.gpu.tile_window {
TiledataArea::D8000, tile_window.draw_sprite_window(byte_to_palette(self.memory.get(0xFF47)), &self.memory);
byte_to_palette(self.memory.get(0xFF47)), }
);
} }
fn set_lcd_status(&mut self) { fn set_lcd_status(&mut self) {

View file

@ -1,51 +1,94 @@
use minifb::Window;
use crate::{ use crate::{
processor::{ processor::{
get_bit, get_bit,
gpu::{ gpu::{
bits_to_mapped_colour, scale_buffer, Palette, TiledataArea, TILE_WINDOW_EDGE_LENGTH, bits_to_mapped_colour, scale_buffer, Palette, TiledataArea, TILE_WINDOW_HEIGHT,
TILE_WINDOW_EDGE_LENGTH_SCALED, TILE_WINDOW_HEIGHT_SCALED, TILE_WINDOW_WIDTH, TILE_WINDOW_WIDTH_SCALED,
}, },
CPU, memory::Memory,
}, },
FACTOR, FACTOR,
}; };
impl CPU { pub(super) struct TileWindow {
pub(super) fn draw_sprite_window(&mut self, area: TiledataArea, palette: Palette) { sprite_buffer: Vec<u32>,
for tile_y in 0..16 { sprite_buffer_scaled: Vec<u32>,
for tile_x in 0..16 { sprite_window: Window,
let tile_num = (tile_y * 16) + tile_x; }
let data_begin = area.get_addr(tile_num);
for px_y in 0..8 {
let lsbs = self.memory.get((px_y * 2) + data_begin);
let msbs = self.memory.get((px_y * 2) + data_begin + 1);
for px_x in 0..8 {
let real_px_y = (tile_y as usize * 8) + px_y as usize;
let real_px_x = (tile_x as usize * 8) + px_x as usize;
let lsb = get_bit(lsbs, 7 - px_x);
let msb = get_bit(msbs, 7 - px_x);
let colour = bits_to_mapped_colour(lsb, msb, palette);
self.gpu.sprite_buffer[real_px_x + (real_px_y * TILE_WINDOW_EDGE_LENGTH)] = impl TileWindow {
colour.to_rgb(); pub(super) fn new(window: Window) -> Self {
} Self {
} sprite_buffer: vec![0; TILE_WINDOW_WIDTH * TILE_WINDOW_HEIGHT],
} sprite_buffer_scaled: vec![0; TILE_WINDOW_WIDTH_SCALED * TILE_WINDOW_HEIGHT_SCALED],
sprite_window: window,
}
}
}
impl TileWindow {
pub(super) fn draw_sprite_window(&mut self, palette: Palette, memory: &Memory) {
for tile_y in 0..16 {
self.draw_row(
tile_y,
tile_y as usize,
TiledataArea::D8000,
palette,
memory,
);
}
for tile_y in 0..8 {
self.draw_row(
tile_y,
(tile_y as usize) + 16,
TiledataArea::D9000,
palette,
memory,
);
} }
self.gpu.sprite_buffer_scaled = scale_buffer( self.sprite_buffer_scaled = scale_buffer(
&self.gpu.sprite_buffer, &self.sprite_buffer,
TILE_WINDOW_EDGE_LENGTH, TILE_WINDOW_WIDTH,
TILE_WINDOW_EDGE_LENGTH, TILE_WINDOW_HEIGHT,
FACTOR, FACTOR,
); );
self.gpu self.sprite_window
.sprite_window
.update_with_buffer( .update_with_buffer(
&self.gpu.sprite_buffer_scaled, &self.sprite_buffer_scaled,
TILE_WINDOW_EDGE_LENGTH_SCALED, TILE_WINDOW_WIDTH_SCALED,
TILE_WINDOW_EDGE_LENGTH_SCALED, TILE_WINDOW_HEIGHT_SCALED,
) )
.unwrap(); .unwrap();
} }
fn draw_row(
&mut self,
tile_y: u8,
display_y: usize,
area: TiledataArea,
palette: Palette,
memory: &Memory,
) {
for tile_x in 0..16 {
let tile_num = (tile_y * 16) + tile_x;
let data_begin = area.get_addr(tile_num);
for px_y in 0..8 {
let lsbs = memory.get((px_y * 2) + data_begin);
let msbs = memory.get((px_y * 2) + data_begin + 1);
for px_x in 0..8 {
let real_px_y = (display_y * 8) + px_y as usize;
let real_px_x = (tile_x as usize * 8) + px_x as usize;
let lsb = get_bit(lsbs, 7 - px_x);
let msb = get_bit(msbs, 7 - px_x);
let colour = bits_to_mapped_colour(lsb, msb, palette);
self.sprite_buffer[real_px_x + (real_px_y * TILE_WINDOW_WIDTH)] =
colour.to_rgb();
}
}
}
}
} }

View file

@ -38,14 +38,14 @@ const SPEEDUP: f64 = 1.;
const FF04_SPEED: f64 = 16384.; const FF04_SPEED: f64 = 16384.;
impl CPU { impl CPU {
pub fn new(memory: Memory, window: Window) -> Self { pub fn new(memory: Memory, window: Window, enable_tile_window: bool) -> Self {
Self { Self {
memory, memory,
reg: Registers::default(), reg: Registers::default(),
last_instruction: 0x0, last_instruction: 0x0,
last_instruction_addr: 0x0, last_instruction_addr: 0x0,
window, window,
gpu: GPU::default(), gpu: GPU::new(enable_tile_window),
halted: false, halted: false,
} }
} }