diff --git a/snes-core/src/ppu/registers.rs b/snes-core/src/ppu/registers.rs index f304674..0e5af73 100644 --- a/snes-core/src/ppu/registers.rs +++ b/snes-core/src/ppu/registers.rs @@ -111,7 +111,7 @@ pub enum BgSize { T32x32, T64x32, // V Mirror T32x64, // H Mirror - T64x64, // H Mirror + T64x64, // H/V Mirror } impl BgSize { @@ -266,10 +266,10 @@ impl PPURegisters { pub fn get_bg_tile_size(&self, background: Background) -> TileSize { let byte = self._read(BGMODE); let bit = match background { - Background::Bg1 => byte >> 3 & 0b1 == 1, // Bit 4 - Background::Bg2 => byte >> 4 & 0b1 == 1, // Bit 5 - Background::Bg3 => byte >> 5 & 0b1 == 1, // Bit 6 - Background::Bg4 => byte >> 6 & 0b1 == 1, // Bit 7 + Background::Bg1 => byte >> 4 & 0b1 == 1, // Bit 4 + Background::Bg2 => byte >> 5 & 0b1 == 1, // Bit 5 + Background::Bg3 => byte >> 6 & 0b1 == 1, // Bit 6 + Background::Bg4 => byte >> 7 & 0b1 == 1, // Bit 7 }; match bit { true => TileSize::P16x16, diff --git a/snes-frontend/src/emu_ui/debug/ppu_graphics.rs b/snes-frontend/src/emu_ui/debug/ppu_graphics.rs index f809af8..4d695b4 100644 --- a/snes-frontend/src/emu_ui/debug/ppu_graphics.rs +++ b/snes-frontend/src/emu_ui/debug/ppu_graphics.rs @@ -2,7 +2,7 @@ use eframe::epaint::{Vec2, TextureHandle}; use eframe::{egui::Context, epaint::ColorImage}; use eframe::egui::{self, TextureOptions, Ui}; -use snes_core::ppu::registers::{PPURegisters, Background}; +use snes_core::ppu::registers::{PPURegisters, Background, MAX_BG_WIDTH, MAX_BG_HEIGHT}; use crate::emu_state::debug_options::BgDebug; @@ -25,8 +25,9 @@ fn build_bg_preview_window(ctx: &Context, bgdebug: &mut BgDebug, registers: &PPU ui.label("Charset"); compute_2bpp_bg_char_framebuffer(bgdebug.background, &mut bgdebug.char_framebuffer, registers); paint_texture(ui, &mut bgdebug.char_texture, &bgdebug.char_framebuffer, 16 * 8, 8 * 8); - // ui.label("Background"); - // paint_texture(ui, &mut bgdebug.bg_texture, &mut bgdebug.bg_framebuffer, MAX_BG_WIDTH, MAX_BG_HEIGHT); + ui.label("Background"); + compute_2bpp_bg_background_framebuffer(bgdebug.background, &mut bgdebug.bg_framebuffer, registers); + paint_texture(ui, &mut bgdebug.bg_texture, &mut bgdebug.bg_framebuffer, MAX_BG_WIDTH, MAX_BG_HEIGHT); }); }); } @@ -122,6 +123,101 @@ fn compute_2bpp_bg_char_framebuffer(background: Background, framebuffer: &mut [u } } +fn compute_2bpp_bg_background_framebuffer(background: Background, framebuffer: &mut [u8], registers: &PPURegisters) { + let tileset_vram_base_address = registers.get_bg_tile_base_address(background) as usize; + let charset_vram_base_address = registers.get_bg_char_base_address(background) as usize; + let (bg_size_width, bg_size_height) = registers.get_bg_size(background).to_usize(); + let (tile_size_width, tile_size_height) = registers.get_bg_tile_size(background).to_usize(); + let vram = registers.vram(); + let width: usize = bg_size_width * tile_size_width; + let height: usize = bg_size_height * tile_size_height; + for y in 0..height { + for x in 0..width { + let current_tile = (x / tile_size_width) + ((y / tile_size_height) * bg_size_width); + let char_index = vram[(tileset_vram_base_address + current_tile) & 0x7FFF] & 0b11_11111111; + let current_char_column = x.rem_euclid(tile_size_width); + let current_char_row = y.rem_euclid(tile_size_height); + // 8x8 pixels, 2 bitplanes, each word (16bit) holds 8 pixels + // so 1 char is 8 bytes x 2 + let effective_vram_address = + charset_vram_base_address + + ((char_index as usize) * tile_size_width) + + current_char_row; + + let vram_word = vram[effective_vram_address]; + let lsb_bitplane= vram_word as u8; + let msb_bitplane= (vram_word >> 8) as u8; + let pixels = [ + ( + (lsb_bitplane >> 7) | + ((msb_bitplane >> 7) << 1) + ), + ( + ((lsb_bitplane >> 6) & 1) | + (((msb_bitplane >> 6) & 1) << 1) + ), + ( + ((lsb_bitplane >> 5) & 1) | + (((msb_bitplane >> 5) & 1) << 1) + ), + ( + ((lsb_bitplane >> 4) & 1) | + (((msb_bitplane >> 4) & 1) << 1) + ), + ( + ((lsb_bitplane >> 3) & 1) | + (((msb_bitplane >> 3) & 1) << 1) + ), + ( + ((lsb_bitplane >> 2) & 1) | + (((msb_bitplane >> 2) & 1) << 1) + ), + ( + ((lsb_bitplane >> 1) & 1) | + (((msb_bitplane >> 1) & 1) << 1) + ), + ( + (lsb_bitplane & 1) | + ((msb_bitplane & 1) << 1) + ), + ]; + let effective_pixel = pixels[current_char_column]; + + let current_fb_pixel = x + (y * MAX_BG_WIDTH); + let fb_index = current_fb_pixel * 4; + let r = fb_index; + let g = fb_index + 1; + let b = fb_index + 2; + let a = fb_index + 3; + + framebuffer[a] = 0xFF; + match effective_pixel { + 0b00 => { + framebuffer[r] = 0xFF; + framebuffer[g] = 0xFF; + framebuffer[b] = 0xFF; + }, + 0b01 => { + framebuffer[r] = 0xAC; + framebuffer[g] = 0xAC; + framebuffer[b] = 0xAC; + }, + 0b10 => { + framebuffer[r] = 0x56; + framebuffer[g] = 0x56; + framebuffer[b] = 0x56; + }, + 0b11 => { + framebuffer[r] = 0x00; + framebuffer[g] = 0x00; + framebuffer[b] = 0x00; + }, + _ => unreachable!(), + }; + } + } +} + fn paint_texture(ui: &mut Ui, texture: &mut Option, framebuffer: &[u8], width: usize, height: usize) { if let Some(txt) = texture { txt.set(