diff --git a/src/ppu.c b/src/ppu.c index 97c9a9c..5912669 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -61,7 +61,12 @@ void nes_ppu_render_line(nes_PPU* ppu, nes_PPU_Memory* mem) { uint8_t* ptr = ppu->line_data; if (!(mem->mask & ppu_Mask_Back)) { - memset(ptr, 0, nes_ppu_render_w); + // Emulate the happy part of the backdrop override quirk + int pal_idx = ((mem->addr & 0x3F00U) == 0x3F00U) ? + (mem->addr & 0x1FU) : 0; + // Don't use the rendering palette (masked transparency) + memset(ptr, mem->pal_bank[0x300 + pal_idx], + nes_ppu_render_w); } else { int back_bank = nes_PPU_Nametable_Bank_Index + ((mem->addr >> 10) & 3); @@ -75,32 +80,33 @@ void nes_ppu_render_line(nes_PPU* ppu, nes_PPU_Memory* mem) { const uint8_t* nametable = mem->bank[back_bank] + (y_coarse * 32) + x_coarse; const uint8_t* attrs = mem->bank[back_bank] + 0x3C0U + ((y_coarse >> 2) << 3); + // Partial left column ptr += 8 - mem->x; - // TODO: Omit if left column is masked? - { - const uint8_t* pal = mem->palette + - (((attrs[x_coarse >> 2] >> - ( (x_coarse & 2) + - ((y_coarse & 2) << 1))) & 3) << 2); - const int ch = *nametable; - const int bank = (ch >> 6) + bank_off; - const int addr_off = ((ch & 0x3F) << 4) + y_fine; - const uint8_t* data = mem->bank[bank] + addr_off; - const uint8_t pl0 = data[0]; - const uint8_t pl1 = data[8]; - const int pat0 = (pl0 & 0x55) | ((pl1 << 1) & 0xAA); - const int pat1 = ((pl0 >> 1) & 0x55) | (pl1 & 0xAA); - switch (mem->x) { - case 0: ptr[-8] = pal[(pat1 >> 6) & 3]; - case 1: ptr[-7] = pal[(pat0 >> 6) & 3]; - case 2: ptr[-6] = pal[(pat1 >> 4) & 3]; - case 3: ptr[-5] = pal[(pat0 >> 4) & 3]; - case 4: ptr[-4] = pal[(pat1 >> 2) & 3]; - case 5: ptr[-3] = pal[(pat0 >> 2) & 3]; - case 6: ptr[-2] = pal[(pat1 >> 0) & 3]; - case 7: ptr[-1] = pal[(pat0 >> 0) & 3]; - } + // Omit if left column is masked + if (mem->mask & ppu_Mask_Left_Back) { + const uint8_t* pal = mem->palette + + (((attrs[x_coarse >> 2] >> + ( (x_coarse & 2) + + ((y_coarse & 2) << 1))) & 3) << 2); + const int ch = *nametable; + const int bank = (ch >> 6) + bank_off; + const int addr_off = ((ch & 0x3F) << 4) + y_fine; + const uint8_t* data = mem->bank[bank] + addr_off; + const uint8_t pl0 = data[0]; + const uint8_t pl1 = data[8]; + const int pat0 = (pl0 & 0x55) | ((pl1 << 1) & 0xAA); + const int pat1 = ((pl0 >> 1) & 0x55) | (pl1 & 0xAA); + switch (mem->x) { + case 0: ptr[-8] = pal[(pat1 >> 6) & 3]; + case 1: ptr[-7] = pal[(pat0 >> 6) & 3]; + case 2: ptr[-6] = pal[(pat1 >> 4) & 3]; + case 3: ptr[-5] = pal[(pat0 >> 4) & 3]; + case 4: ptr[-4] = pal[(pat1 >> 2) & 3]; + case 5: ptr[-3] = pal[(pat0 >> 2) & 3]; + case 6: ptr[-2] = pal[(pat1 >> 0) & 3]; + case 7: ptr[-1] = pal[(pat0 >> 0) & 3]; + } } // TODO: Mapper ppu_bus @@ -119,8 +125,6 @@ void nes_ppu_render_line(nes_PPU* ppu, nes_PPU_Memory* mem) { const uint8_t* data = mem->bank[bank] + addr_off; const uint8_t pl0 = data[0]; const uint8_t pl1 = data[8]; - //const int pat0 = ((pl0 & 0x55) << 1) | ((pl1 & 0x55) << 2); - //const int pat1 = ((pl0 & 0xAA) << 0) | ((pl1 & 0xAA) << 1); const int pat0 = (pl0 & 0x55) | ((pl1 << 1) & 0xAA); const int pat1 = ((pl0 >> 1) & 0x55) | (pl1 & 0xAA); @@ -135,12 +139,14 @@ void nes_ppu_render_line(nes_PPU* ppu, nes_PPU_Memory* mem) { ptr += 8; } + // Left Nametable for (; x_coarse < 32; ++x_coarse) { render_bg(); // TODO: Mapper ppu_bus ++nametable; } + // Right Nametable back_bank ^= 0b01; nametable = mem->bank[back_bank] + (y_coarse * 32); attrs = mem->bank[back_bank] + 0x3C0U + ((y_coarse >> 2) << 3); @@ -150,6 +156,38 @@ void nes_ppu_render_line(nes_PPU* ppu, nes_PPU_Memory* mem) { // TODO: Mapper ppu_bus ++nametable; } + + // Partial right column + { + const uint8_t* pal = mem->palette + + (((attrs[x_coarse >> 2] >> + ( (x_coarse & 2) + + ((y_coarse & 2) << 1))) & 3) << 2); + const int ch = *nametable; + const int bank = (ch >> 6) + bank_off; + const int addr_off = ((ch & 0x3F) << 4) + y_fine; + const uint8_t* data = mem->bank[bank] + addr_off; + const uint8_t pl0 = data[0]; + const uint8_t pl1 = data[8]; + const int pat0 = (pl0 & 0x55) | ((pl1 << 1) & 0xAA); + const int pat1 = ((pl0 >> 1) & 0x55) | (pl1 & 0xAA); + switch (mem->x) { + case 8: ptr[7] = pal[(pat0 >> 0) & 3]; + case 7: ptr[6] = pal[(pat1 >> 0) & 3]; + case 6: ptr[5] = pal[(pat0 >> 2) & 3]; + case 5: ptr[4] = pal[(pat1 >> 2) & 3]; + case 4: ptr[3] = pal[(pat0 >> 4) & 3]; + case 3: ptr[2] = pal[(pat1 >> 4) & 3]; + case 2: ptr[1] = pal[(pat0 >> 6) & 3]; + case 1: ptr[0] = pal[(pat1 >> 6) & 3]; + } + } + } + + // TODO: Mapper ppu_bus + + if (!(mem->mask & ppu_Mask_Left_Back)) { + memset(ppu->line_data, mem->palette[0], 8); } // TODO: Draw Sprites