add layer window

This commit is contained in:
Alex Janka 2023-07-17 19:21:58 +10:00
parent 2685bc06e6
commit b0a5373ff6
6 changed files with 82 additions and 25 deletions

View file

@ -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<usize>,
@ -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<WindowRenderer> = if args.tile_window {
Some(window_manager.add(factor, None))
} else {
None
};
let layer_window: Option<WindowRenderer> = 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<dyn EmulatorCoreTrait> = if args.camera {

View file

@ -116,6 +116,7 @@ impl WindowRenderer {
) -> (Self, WindowInfo) {
let window = WindowBuilder::new()
.with_title("Gameboy")
.with_resizable(false)
.build(event_loop)
.unwrap();

View file

@ -164,6 +164,7 @@ where
{
pub(crate) window: R,
pub(crate) tile_window: Option<R>,
pub(crate) layer_window: Option<R>,
pub(crate) rom: RomFile,
pub(crate) output: AudioOutput,
pub(crate) save: Option<SramType>,
@ -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<R>) -> Self {
self.layer_window = window;
self
}
pub fn with_cgb_mode(mut self, cgb_mode: bool) -> Self {
self.cgb_mode = cgb_mode;
self

View file

@ -130,6 +130,7 @@ where
options.output,
options.serial_target,
options.tile_window,
options.layer_window,
camera,
),
),

View file

@ -119,6 +119,7 @@ where
audio: AudioOutput,
serial_target: SerialTarget,
tile_window: Option<R>,
layer_window: Option<R>,
camera: CameraWrapperRef<C>,
_phantom: PhantomData<ColourFormat>,
}
@ -134,6 +135,7 @@ where
audio: AudioOutput,
serial_target: SerialTarget,
tile_window: Option<R>,
layer_window: Option<R>,
camera: CameraWrapperRef<C>,
) -> 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(),

View file

@ -40,6 +40,7 @@ where
scanline: u8,
lyc: u8,
tile_window: Option<TileWindow<ColourFormat, R>>,
layer_window: Option<(R, Vec<ColourFormat>)>,
window_lc: u8,
has_window_been_enabled: bool,
bg_palette: Palette,
@ -58,17 +59,30 @@ where
ColourFormat: From<Colour> + Clone,
R: Renderer<ColourFormat>,
{
pub fn new(cgb: bool, window: R, tile_window_renderer: Option<R>) -> Self {
pub fn new(
cgb: bool,
window: R,
tile_window_renderer: Option<R>,
layer_window_renderer: Option<R>,
) -> 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();
}
}
}
}