| @@ -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 | |||