2D: implement large BG, fix non-large bitmap BG. fixes #61

This commit is contained in:
StapleButter 2017-07-05 19:31:13 +02:00
parent 678ae00e0a
commit 93ab7064b2
2 changed files with 106 additions and 21 deletions

View File

@ -934,7 +934,7 @@ void GPU2D::DrawScanlineBGMode6(u32 line, u32* spritebuf, u32* dst)
{
if (DispCnt & 0x0400)
{
printf("GPU2D: MODE6 LARGE BG TODO\n");
DrawBG_Large(line, dst);
}
}
if ((BGCnt[0] & 0x3) == i)
@ -1387,20 +1387,6 @@ void GPU2D::DrawBG_Extended(u32 line, u32* dst, u32 bgnum)
u16* pal;
u32 extpal;
u32 coordmask;
u32 yshift;
switch (bgcnt & 0xC000)
{
case 0x0000: coordmask = 0x07800; yshift = 7; break;
case 0x4000: coordmask = 0x0F800; yshift = 8; break;
case 0x8000: coordmask = 0x1F800; yshift = 9; break;
case 0xC000: coordmask = 0x3F800; yshift = 10; break;
}
u32 overflowmask;
if (bgcnt & 0x2000) overflowmask = 0;
else overflowmask = ~(coordmask | 0x7FF);
extpal = (DispCnt & 0x40000000);
s16 rotA = BGRotA[bgnum-2];
@ -1415,20 +1401,40 @@ void GPU2D::DrawBG_Extended(u32 line, u32* dst, u32 bgnum)
{
// bitmap modes
u32 xmask, ymask;
u32 yshift;
switch (bgcnt & 0xC000)
{
case 0x0000: xmask = 0x07FFF; ymask = 0x07FFF; yshift = 7; break;
case 0x4000: xmask = 0x0FFFF; ymask = 0x0FFFF; yshift = 8; break;
case 0x8000: xmask = 0x1FFFF; ymask = 0x0FFFF; yshift = 9; break;
case 0xC000: xmask = 0x1FFFF; ymask = 0x1FFFF; yshift = 9; break;
}
u32 ofxmask, ofymask;
if (bgcnt & 0x2000)
{
ofxmask = 0;
ofymask = 0;
}
else
{
ofxmask = ~xmask;
ofymask = ~ymask;
}
if (Num) tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 6);
else tilemapaddr = 0x06000000 + ((bgcnt & 0x1F00) << 6);
coordmask |= 0x7FF;
if (bgcnt & 0x0004)
{
// direct color bitmap
for (int i = 0; i < 256; i++)
{
if ((!((rotX|rotY) & overflowmask)) && (windowmask[i] & (1<<bgnum)))
if (!(rotX & ofxmask) && !(rotY & ofymask) && (windowmask[i] & (1<<bgnum)))
{
u16 color = GPU::ReadVRAM_BG<u16>(tilemapaddr + (((((rotY & coordmask) >> 8) << yshift) + ((rotX & coordmask) >> 8)) << 1));
u16 color = GPU::ReadVRAM_BG<u16>(tilemapaddr + (((((rotY & ymask) >> 8) << yshift) + ((rotX & xmask) >> 8)) << 1));
if (color & 0x8000)
DrawPixel(&dst[i], color, 0x01000000<<bgnum);
@ -1447,9 +1453,9 @@ void GPU2D::DrawBG_Extended(u32 line, u32* dst, u32 bgnum)
for (int i = 0; i < 256; i++)
{
if ((!((rotX|rotY) & overflowmask)) && (windowmask[i] & (1<<bgnum)))
if (!(rotX & ofxmask) && !(rotY & ofymask) && (windowmask[i] & (1<<bgnum)))
{
u8 color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((rotY & coordmask) >> 8) << yshift) + ((rotX & coordmask) >> 8));
u8 color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((rotY & ymask) >> 8) << yshift) + ((rotX & xmask) >> 8));
if (color)
DrawPixel(&dst[i], pal[color], 0x01000000<<bgnum);
@ -1464,6 +1470,20 @@ void GPU2D::DrawBG_Extended(u32 line, u32* dst, u32 bgnum)
{
// mixed affine/text mode
u32 coordmask;
u32 yshift;
switch (bgcnt & 0xC000)
{
case 0x0000: coordmask = 0x07800; yshift = 7; break;
case 0x4000: coordmask = 0x0F800; yshift = 8; break;
case 0x8000: coordmask = 0x1F800; yshift = 9; break;
case 0xC000: coordmask = 0x3F800; yshift = 10; break;
}
u32 overflowmask;
if (bgcnt & 0x2000) overflowmask = 0;
else overflowmask = ~(coordmask | 0x7FF);
if (Num)
{
tilesetaddr = 0x06200000 + ((bgcnt & 0x003C) << 12);
@ -1516,6 +1536,70 @@ void GPU2D::DrawBG_Extended(u32 line, u32* dst, u32 bgnum)
BGYRefInternal[bgnum-2] += rotD;
}
void GPU2D::DrawBG_Large(u32 line, u32* dst) // BG is always BG2
{
u8* windowmask = (u8*)&dst[256*2];
u16 bgcnt = BGCnt[2];
u32 tilesetaddr, tilemapaddr;
u16* pal;
u32 xmask, ymask;
u32 yshift;
switch (bgcnt & 0xC000)
{
case 0x0000: xmask = 0x1FFFF; ymask = 0x3FFFF; yshift = 9; break;
case 0x4000: xmask = 0x3FFFF; ymask = 0x1FFFF; yshift = 10; break;
case 0x8000: // TODO (most likely the second size bit is just ignored)
case 0xC000: printf("bad BG size for large BG: %04X\n", bgcnt); return;
}
u32 ofxmask, ofymask;
if (bgcnt & 0x2000)
{
ofxmask = 0;
ofymask = 0;
}
else
{
ofxmask = ~xmask;
ofymask = ~ymask;
}
s16 rotA = BGRotA[0];
s16 rotB = BGRotB[0];
s16 rotC = BGRotC[0];
s16 rotD = BGRotD[0];
s32 rotX = BGXRefInternal[0];
s32 rotY = BGYRefInternal[0];
if (Num) tilemapaddr = 0x06200000;
else tilemapaddr = 0x06000000;
// 256-color bitmap
if (Num) pal = (u16*)&GPU::Palette[0x400];
else pal = (u16*)&GPU::Palette[0];
for (int i = 0; i < 256; i++)
{
if (!(rotX & ofxmask) && !(rotY & ofymask) && (windowmask[i] & (1<<2)))
{
u8 color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((rotY & ymask) >> 8) << yshift) + ((rotX & xmask) >> 8));
if (color)
DrawPixel(&dst[i], pal[color], 0x01000000<<2);
}
rotX += rotA;
rotY += rotC;
}
BGXRefInternal[0] += rotB;
BGYRefInternal[0] += rotD;
}
void GPU2D::InterleaveSprites(u32* buf, u32 prio, u32* dst)
{
u8* windowmask = (u8*)&dst[256*2];

View File

@ -114,6 +114,7 @@ private:
void DrawBG_Text(u32 line, u32* dst, u32 bgnum);
void DrawBG_Affine(u32 line, u32* dst, u32 bgnum);
void DrawBG_Extended(u32 line, u32* dst, u32 bgnum);
void DrawBG_Large(u32 line, u32* dst);
void InterleaveSprites(u32* buf, u32 prio, u32* dst);
void DrawSprites(u32 line, u32* dst);