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)]
cycle_count: bool,
/// Show tile window
#[arg(short, long)]
tile_window: bool,
/// Step emulation by...
#[arg(long)]
step_by: Option<usize>,
@ -117,7 +121,11 @@ fn main() {
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 {
cpu.reg.pc = 0x0100;

View file

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

View file

@ -1,51 +1,94 @@
use minifb::Window;
use crate::{
processor::{
get_bit,
gpu::{
bits_to_mapped_colour, scale_buffer, Palette, TiledataArea, TILE_WINDOW_EDGE_LENGTH,
TILE_WINDOW_EDGE_LENGTH_SCALED,
bits_to_mapped_colour, scale_buffer, Palette, TiledataArea, TILE_WINDOW_HEIGHT,
TILE_WINDOW_HEIGHT_SCALED, TILE_WINDOW_WIDTH, TILE_WINDOW_WIDTH_SCALED,
},
CPU,
memory::Memory,
},
FACTOR,
};
impl CPU {
pub(super) fn draw_sprite_window(&mut self, area: TiledataArea, palette: Palette) {
for tile_y in 0..16 {
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 = 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);
pub(super) struct TileWindow {
sprite_buffer: Vec<u32>,
sprite_buffer_scaled: Vec<u32>,
sprite_window: Window,
}
self.gpu.sprite_buffer[real_px_x + (real_px_y * TILE_WINDOW_EDGE_LENGTH)] =
colour.to_rgb();
}
}
}
impl TileWindow {
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.gpu.sprite_buffer,
TILE_WINDOW_EDGE_LENGTH,
TILE_WINDOW_EDGE_LENGTH,
self.sprite_buffer_scaled = scale_buffer(
&self.sprite_buffer,
TILE_WINDOW_WIDTH,
TILE_WINDOW_HEIGHT,
FACTOR,
);
self.gpu
.sprite_window
self.sprite_window
.update_with_buffer(
&self.gpu.sprite_buffer_scaled,
TILE_WINDOW_EDGE_LENGTH_SCALED,
TILE_WINDOW_EDGE_LENGTH_SCALED,
&self.sprite_buffer_scaled,
TILE_WINDOW_WIDTH_SCALED,
TILE_WINDOW_HEIGHT_SCALED,
)
.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.;
impl CPU {
pub fn new(memory: Memory, window: Window) -> Self {
pub fn new(memory: Memory, window: Window, enable_tile_window: bool) -> Self {
Self {
memory,
reg: Registers::default(),
last_instruction: 0x0,
last_instruction_addr: 0x0,
window,
gpu: GPU::default(),
gpu: GPU::new(enable_tile_window),
halted: false,
}
}