aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStapleButter <thetotalworm@gmail.com>2017-07-05 19:31:13 +0200
committerStapleButter <thetotalworm@gmail.com>2017-07-05 19:31:13 +0200
commit93ab7064b203c463607258cb3bc94f5da9729959 (patch)
tree0f59c3a4c428b227a9c67c8d2dfaf70467b79596 /src
parent678ae00e0a4dc7fbe7b4027a1ed7bc3bcd253cec (diff)
2D: implement large BG, fix non-large bitmap BG. fixes #61
Diffstat (limited to 'src')
-rw-r--r--src/GPU2D.cpp126
-rw-r--r--src/GPU2D.h1
2 files changed, 106 insertions, 21 deletions
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index a9bd498..ee1fbc1 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -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];
diff --git a/src/GPU2D.h b/src/GPU2D.h
index 289f1fe..4c68cdb 100644
--- a/src/GPU2D.h
+++ b/src/GPU2D.h
@@ -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);