From b0a5373ff645bec2d7c42e08e7ae0228d5f14ce9 Mon Sep 17 00:00:00 2001 From: Alex Janka Date: Mon, 17 Jul 2023 19:21:58 +1000 Subject: [PATCH] add layer window --- gb-emu/src/main.rs | 14 ++++- gb-emu/src/window.rs | 1 + lib/src/connect/mod.rs | 7 +++ lib/src/lib.rs | 1 + lib/src/processor/memory.rs | 5 +- lib/src/processor/memory/mmio/gpu.rs | 79 ++++++++++++++++++++-------- 6 files changed, 82 insertions(+), 25 deletions(-) diff --git a/gb-emu/src/main.rs b/gb-emu/src/main.rs index 2e36c6c..75dcf54 100644 --- a/gb-emu/src/main.rs +++ b/gb-emu/src/main.rs @@ -54,9 +54,13 @@ struct Args { hex: bool, /// Show tile window - #[arg(short, long)] + #[arg(long)] tile_window: bool, + /// Show layer window + #[arg(long)] + layer_window: bool, + /// Scale display by... #[arg(short, long)] scale_factor: Option, @@ -122,12 +126,19 @@ impl EmulatorHandler { let mut window_manager = WindowManager::new(sender); let window = window_manager.add(factor, Some(Gilrs::new().unwrap())); + let tile_window: Option = if args.tile_window { Some(window_manager.add(factor, None)) } else { None }; + let layer_window: Option = if args.layer_window { + Some(window_manager.add(1, None)) + } else { + None + }; + let options = EmulatorOptions::new(window, rom, output) .with_save_path(args.save) .with_serial_target(if args.ascii { @@ -149,6 +160,7 @@ impl EmulatorHandler { ) .with_no_save(args.no_save) .with_tile_window(tile_window) + .with_layer_window(layer_window) .with_cgb_mode(!args.dmg); // let core: Box = if args.camera { diff --git a/gb-emu/src/window.rs b/gb-emu/src/window.rs index 20318a0..24a5e14 100644 --- a/gb-emu/src/window.rs +++ b/gb-emu/src/window.rs @@ -116,6 +116,7 @@ impl WindowRenderer { ) -> (Self, WindowInfo) { let window = WindowBuilder::new() .with_title("Gameboy") + .with_resizable(false) .build(event_loop) .unwrap(); diff --git a/lib/src/connect/mod.rs b/lib/src/connect/mod.rs index acd265e..507279c 100644 --- a/lib/src/connect/mod.rs +++ b/lib/src/connect/mod.rs @@ -164,6 +164,7 @@ where { pub(crate) window: R, pub(crate) tile_window: Option, + pub(crate) layer_window: Option, pub(crate) rom: RomFile, pub(crate) output: AudioOutput, pub(crate) save: Option, @@ -185,6 +186,7 @@ where Self { window, tile_window: None, + layer_window: None, rom, output, save: None, @@ -238,6 +240,11 @@ where self } + pub fn with_layer_window(mut self, window: Option) -> Self { + self.layer_window = window; + self + } + pub fn with_cgb_mode(mut self, cgb_mode: bool) -> Self { self.cgb_mode = cgb_mode; self diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 361bdb5..06e26a9 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -130,6 +130,7 @@ where options.output, options.serial_target, options.tile_window, + options.layer_window, camera, ), ), diff --git a/lib/src/processor/memory.rs b/lib/src/processor/memory.rs index 65d94e9..1275497 100644 --- a/lib/src/processor/memory.rs +++ b/lib/src/processor/memory.rs @@ -119,6 +119,7 @@ where audio: AudioOutput, serial_target: SerialTarget, tile_window: Option, + layer_window: Option, camera: CameraWrapperRef, _phantom: PhantomData, } @@ -134,6 +135,7 @@ where audio: AudioOutput, serial_target: SerialTarget, tile_window: Option, + layer_window: Option, camera: CameraWrapperRef, ) -> Self { Self { @@ -141,6 +143,7 @@ where audio, serial_target, tile_window, + layer_window, camera, _phantom: PhantomData, } @@ -170,7 +173,7 @@ where user_mode: false, oam_dma: OamDma::default(), joypad: Joypad::default(), - gpu: Gpu::new(cgb, output.window, output.tile_window), + gpu: Gpu::new(cgb, output.window, output.tile_window, output.layer_window), apu: Apu::new(output.audio), serial: Serial::new(output.serial_target), timers: Timer::init(), diff --git a/lib/src/processor/memory/mmio/gpu.rs b/lib/src/processor/memory/mmio/gpu.rs index 6f66a94..c0f5414 100644 --- a/lib/src/processor/memory/mmio/gpu.rs +++ b/lib/src/processor/memory/mmio/gpu.rs @@ -40,6 +40,7 @@ where scanline: u8, lyc: u8, tile_window: Option>, + layer_window: Option<(R, Vec)>, window_lc: u8, has_window_been_enabled: bool, bg_palette: Palette, @@ -58,17 +59,30 @@ where ColourFormat: From + Clone, R: Renderer, { - pub fn new(cgb: bool, window: R, tile_window_renderer: Option) -> Self { + pub fn new( + cgb: bool, + window: R, + tile_window_renderer: Option, + layer_window_renderer: Option, + ) -> Self { let tile_window = tile_window_renderer .map(|tile_window_renderer| TileWindow::new(tile_window_renderer, cgb)); - let buffer = vec![ - if cgb { - rgb_from_bytes(0xFFFF).into() - } else { - ColourInner::Error.rgb_bytes(None).into() - }; - WIDTH * HEIGHT - ]; + + let blank_colour: ColourFormat = if cgb { + rgb_from_bytes(0xFFFF).into() + } else { + ColourInner::Error.rgb_bytes(None).into() + }; + + let buffer = vec![blank_colour.clone(); WIDTH * HEIGHT]; + + let layer_window = layer_window_renderer.map(|mut layer_window_renderer| { + layer_window_renderer.prepare(WIDTH, HEIGHT * 3); + ( + layer_window_renderer, + vec![blank_colour; WIDTH * HEIGHT * 3], + ) + }); Self { buffer, @@ -83,6 +97,7 @@ where scanline: 0, lyc: 0xFF, tile_window, + layer_window, window_lc: 0, has_window_been_enabled: false, bg_palette: Palette::from_byte(0xFC), @@ -361,25 +376,28 @@ where } let x_coord = x_coord_uncorrected - 8; if x_coord < WIDTH { + let cgb_data = self.cgb_data.as_ref().map(|v| { + ( + &v.palettes.obj, + if self.is_cgb_mode() { + object.flags.cgb_palette + } else { + 0 + }, + ) + }); + let buffer_index = (scanline as usize * WIDTH) + x_coord; if (!object.flags.behind_bg_and_window && !self.is_bg_priority[x_coord]) || self.is_bg_zero[x_coord] || (self.is_cgb_mode() && !self.lcdc.bg_window_enable) || obj_priority { - let cgb_data = self.cgb_data.as_ref().map(|v| { - ( - &v.palettes.obj, - if self.is_cgb_mode() { - object.flags.cgb_palette - } else { - 0 - }, - ) - }); - self.buffer[buffer_index] = colour.rgb_bytes(cgb_data).into(); } + if let Some((_, ref mut buffer)) = self.layer_window { + buffer[buffer_index + (2 * HEIGHT * WIDTH)] = colour.rgb_bytes(cgb_data).into(); + } } } } @@ -391,17 +409,17 @@ where tilemap: TilemapArea, offset_x: u8, offset_y: u8, - wrap: bool, + is_bg: bool, ) { let (tile_line_y, did_wrap_y) = draw_from.overflowing_sub(offset_y); - if did_wrap_y && !wrap { + if did_wrap_y && !is_bg { return; } let tilemap_row = tile_line_y / 8; let row_addr = ((tilemap_row as usize * 32) % 0x400) as u16; for x in 0..WIDTH { let (tile_line_x, did_wrap_x) = (x as u8).overflowing_sub(offset_x); - if did_wrap_x && !wrap { + if did_wrap_x && !is_bg { continue; } @@ -460,10 +478,25 @@ where .map(|v| (&v.palettes.bg, attributes.palette)); self.buffer[(scanline as usize * WIDTH) + x] = colour.rgb_bytes(cgb_data).into(); + if let Some((_, ref mut buffer)) = self.layer_window { + buffer[(scanline as usize * WIDTH) + x + if is_bg { 0 } else { HEIGHT * WIDTH }] = + colour.rgb_bytes(cgb_data).into(); + } } } fn render_window(&mut self) { self.window.display(&self.buffer); + if let Some((ref mut window, ref mut buffer)) = self.layer_window { + window.display(buffer); + let blank_colour: ColourFormat = if self.cgb_data.is_some() { + rgb_from_bytes(0xFFFF).into() + } else { + ColourInner::Error.rgb_bytes(None).into() + }; + for val in buffer { + *val = blank_colour.clone(); + } + } } }