aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArisotura <thetotalworm@gmail.com>2019-09-15 01:31:09 +0200
committerArisotura <thetotalworm@gmail.com>2019-09-15 01:31:09 +0200
commitcb90475b60dc329d902b866aeef1caff0ac3d9c1 (patch)
tree7f0813de5bab0ecb8b718facf9b96b6599163927
parentb8f55623c1330d5aa957448d2f3b29b4bad17708 (diff)
begin work on mosaic
OBJ Y mosaic emulated correctly, there's atleast that.
-rw-r--r--src/GPU2D.cpp587
-rw-r--r--src/GPU2D.h16
2 files changed, 272 insertions, 331 deletions
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index 9297643..bd6e758 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -74,7 +74,9 @@
// mosaic:
// * mosaic grid starts at 0,0 regardless of the BG/sprite position
// * when changing it midframe: new X setting is applied immediately, new Y setting is applied only
-// after the end of the current mosaic row
+// after the end of the current mosaic row (when Y counter needs reloaded)
+// * for rotscaled sprites: coordinates that are inside the sprite are clamped to the sprite region
+// after being transformed for mosaic
// TODO: find which parts of DISPCNT are latched. for example, not possible to change video mode midframe.
@@ -82,6 +84,16 @@
GPU2D::GPU2D(u32 num)
{
Num = num;
+
+ // initialize mosaic table
+ for (int m = 0; m < 16; m++)
+ {
+ for (int x = 0; x < 256; x++)
+ {
+ int offset = x % (m+1);
+ MosaicTable[m][x] = offset;
+ }
+ }
}
GPU2D::~GPU2D()
@@ -118,6 +130,8 @@ void GPU2D::Reset()
BGMosaicYMax = 0;
OBJMosaicY = 0;
OBJMosaicYMax = 0;
+ CurBGXMosaicTable = MosaicTable[0];
+ CurOBJXMosaicTable = MosaicTable[0];
BlendCnt = 0;
EVA = 16;
@@ -207,6 +221,9 @@ void GPU2D::DoSavestate(Savestate* file)
BGExtPalStatus[2] = 0;
BGExtPalStatus[3] = 0;
OBJExtPalStatus = 0;
+
+ CurBGXMosaicTable = MosaicTable[BGMosaicSize[0]];
+ CurOBJXMosaicTable = MosaicTable[OBJMosaicSize[0]];
}
}
@@ -365,10 +382,12 @@ void GPU2D::Write8(u32 addr, u8 val)
case 0x04C:
BGMosaicSize[0] = val & 0xF;
BGMosaicSize[1] = val >> 4;
+ CurBGXMosaicTable = MosaicTable[BGMosaicSize[0]];
return;
case 0x04D:
OBJMosaicSize[0] = val & 0xF;
OBJMosaicSize[1] = val >> 4;
+ CurOBJXMosaicTable = MosaicTable[OBJMosaicSize[0]];
return;
case 0x050: BlendCnt = (BlendCnt & 0x3F00) | val; return;
@@ -497,8 +516,10 @@ void GPU2D::Write16(u32 addr, u16 val)
case 0x04C:
BGMosaicSize[0] = val & 0xF;
BGMosaicSize[1] = (val >> 4) & 0xF;
+ CurBGXMosaicTable = MosaicTable[BGMosaicSize[0]];
OBJMosaicSize[0] = (val >> 8) & 0xF;
OBJMosaicSize[1] = val >> 12;
+ CurOBJXMosaicTable = MosaicTable[OBJMosaicSize[0]];
return;
case 0x050: BlendCnt = val & 0x3FFF; return;
@@ -710,6 +731,24 @@ u32 GPU2D::ColorComposite(int i, u32 val1, u32 val2)
}
+void GPU2D::UpdateMosaicCounters(u32 line)
+{
+ // Y mosaic uses incrementing 4-bit counters
+ // the transformed Y position is updated every time the counter matches the MOSAIC register
+
+ if (OBJMosaicYCount == OBJMosaicSize[1])
+ {
+ OBJMosaicYCount = 0;
+ OBJMosaicY = line + 1;
+ }
+ else
+ {
+ OBJMosaicYCount++;
+ OBJMosaicYCount &= 0xF;
+ }
+}
+
+
void GPU2D::DrawScanline(u32 line)
{
int stride = Accelerated ? (256*3 + 1) : 256;
@@ -756,6 +795,7 @@ void GPU2D::DrawScanline(u32 line)
// always render regular graphics
DrawScanline_BGOBJ(line);
+ UpdateMosaicCounters(line);
switch (dispmode)
{
@@ -901,8 +941,10 @@ void GPU2D::VBlankEnd()
BGMosaicY = 0;
BGMosaicYMax = BGMosaicSize[1];
+ //OBJMosaicY = 0;
+ //OBJMosaicYMax = OBJMosaicSize[1];
OBJMosaicY = 0;
- OBJMosaicYMax = OBJMosaicSize[1];
+ OBJMosaicYCount = 0;
if (Accelerated)
{
@@ -1282,6 +1324,12 @@ void GPU2D::CalculateWindowMask(u32 line)
}
+#define DoDrawBG(type, line, num) \
+ { if ((BGCnt[num] & 0x0040) && (BGMosaicSize[0] > 0)) DrawBG_##type<true>(line, num); else DrawBG_##type<false>(line, num); }
+
+#define DoDrawBG_Large(line) \
+ { if ((BGCnt[2] & 0x0040) && (BGMosaicSize[0] > 0)) DrawBG_Large<true>(line); else DrawBG_Large<false>(line); }
+
template<u32 bgmode>
void GPU2D::DrawScanlineBGMode(u32 line)
{
@@ -1292,11 +1340,11 @@ void GPU2D::DrawScanlineBGMode(u32 line)
if (DispCnt & 0x0800)
{
if (bgmode >= 3)
- DrawBG_Extended(line, 3);
+ DoDrawBG(Extended, line, 3)
else if (bgmode >= 1)
- DrawBG_Affine(line, 3);
+ DoDrawBG(Affine, line, 3)
else
- DrawBG_Text(line, 3);
+ DoDrawBG(Text, line, 3)
}
}
if ((BGCnt[2] & 0x3) == i)
@@ -1304,18 +1352,18 @@ void GPU2D::DrawScanlineBGMode(u32 line)
if (DispCnt & 0x0400)
{
if (bgmode == 5)
- DrawBG_Extended(line, 2);
+ DoDrawBG(Extended, line, 2)
else if (bgmode == 4 || bgmode == 2)
- DrawBG_Affine(line, 2);
+ DoDrawBG(Affine, line, 2)
else
- DrawBG_Text(line, 2);
+ DoDrawBG(Text, line, 2)
}
}
if ((BGCnt[1] & 0x3) == i)
{
if (DispCnt & 0x0200)
{
- DrawBG_Text(line, 1);
+ DoDrawBG(Text, line, 1)
}
}
if ((BGCnt[0] & 0x3) == i)
@@ -1325,7 +1373,7 @@ void GPU2D::DrawScanlineBGMode(u32 line)
if ((!Num) && (DispCnt & 0x8))
DrawBG_3D();
else
- DrawBG_Text(line, 0);
+ DoDrawBG(Text, line, 0)
}
}
if ((DispCnt & 0x1000) && NumSprites)
@@ -1341,7 +1389,7 @@ void GPU2D::DrawScanlineBGMode6(u32 line)
{
if (DispCnt & 0x0400)
{
- DrawBG_Large(line);
+ DoDrawBG_Large(line)
}
}
if ((BGCnt[0] & 0x3) == i)
@@ -1367,7 +1415,7 @@ void GPU2D::DrawScanlineBGMode7(u32 line)
{
if (DispCnt & 0x0200)
{
- DrawBG_Text(line, 1);
+ DoDrawBG(Text, line, 1)
}
}
if ((BGCnt[0] & 0x3) == i)
@@ -1377,7 +1425,7 @@ void GPU2D::DrawScanlineBGMode7(u32 line)
if ((!Num) && (DispCnt & 0x8))
DrawBG_3D();
else
- DrawBG_Text(line, 0);
+ DoDrawBG(Text, line, 0)
}
}
if ((DispCnt & 0x1000) && NumSprites)
@@ -1542,13 +1590,13 @@ void GPU2D::DrawScanline_BGOBJ(u32 line)
else
BGMosaicY++;
- if (OBJMosaicY >= OBJMosaicYMax)
+ /*if (OBJMosaicY >= OBJMosaicYMax)
{
OBJMosaicY = 0;
OBJMosaicYMax = OBJMosaicSize[1];
}
else
- OBJMosaicY++;
+ OBJMosaicY++;*/
}
@@ -1557,6 +1605,7 @@ void GPU2D::DrawPixel_Normal(u32* dst, u16 color, u32 flag)
u8 r = (color & 0x001F) << 1;
u8 g = (color & 0x03E0) >> 4;
u8 b = (color & 0x7C00) >> 9;
+ //g |= ((color & 0x8000) >> 15);
*(dst+256) = *dst;
*dst = r | (g << 8) | (b << 16) | flag;
@@ -1618,10 +1667,10 @@ void GPU2D::DrawBG_3D()
}
}
+template<bool mosaic>
void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
{
u16 bgcnt = BGCnt[bgnum];
- u32 xmos = 0, xmossize = 0;
u32 tilesetaddr, tilemapaddr;
u16* pal;
@@ -1632,9 +1681,8 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
if (bgcnt & 0x0040)
{
- // mosaic
+ // vertical mosaic
yoff -= BGMosaicY;
- xmossize = BGMosaicSize[0];
}
u32 widexmask = (bgcnt & 0x4000) ? 0x100 : 0;
@@ -1671,15 +1719,15 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
u16* curpal;
u32 pixelsaddr;
u8 color;
+ u32 lastxpos;
if (bgcnt & 0x0080)
{
// 256-color
// preload shit as needed
- if (xoff & 0x7)
+ if ((xoff & 0x7) || mosaic)
{
- // load a new tile
curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xoff & 0xF8) >> 2) + ((xoff & widexmask) << 3));
if (extpal) curpal = GetBGExtPal(extpalslot, curtile>>12);
@@ -1689,31 +1737,34 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
+ (((curtile & 0x0800) ? (7-(yoff&0x7)) : (yoff&0x7)) << 3);
}
+ if (mosaic) lastxpos = xoff;
+
for (int i = 0; i < 256; i++)
{
- if (!(xoff & 0x7))
+ u32 xpos;
+ if (mosaic) xpos = xoff - CurBGXMosaicTable[i];
+ else xpos = xoff;
+
+ if ((!mosaic && (!(xpos & 0x7))) ||
+ (mosaic && ((xpos >> 3) != (lastxpos >> 3))))
{
// load a new tile
- curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xoff & 0xF8) >> 2) + ((xoff & widexmask) << 3));
+ curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xpos & 0xF8) >> 2) + ((xpos & widexmask) << 3));
if (extpal) curpal = GetBGExtPal(extpalslot, curtile>>12);
else curpal = pal;
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 6)
+ (((curtile & 0x0800) ? (7-(yoff&0x7)) : (yoff&0x7)) << 3);
+
+ if (mosaic) lastxpos = xpos;
}
// draw pixel
if (WindowMask[i] & (1<<bgnum))
{
- if (xmos == 0)
- {
- u32 tilexoff = (curtile & 0x0400) ? (7-(xoff&0x7)) : (xoff&0x7);
- color = GPU::ReadVRAM_BG<u8>(pixelsaddr + tilexoff);
- xmos = xmossize;
- }
- else
- xmos--;
+ u32 tilexoff = (curtile & 0x0400) ? (7-(xpos&0x7)) : (xpos&0x7);
+ color = GPU::ReadVRAM_BG<u8>(pixelsaddr + tilexoff);
if (color)
DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
@@ -1727,45 +1778,46 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
// 16-color
// preload shit as needed
- if (xoff & 0x7)
+ if ((xoff & 0x7) || mosaic)
{
- // load a new tile
curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xoff & 0xF8) >> 2) + ((xoff & widexmask) << 3));
curpal = pal + ((curtile & 0xF000) >> 8);
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 5)
+ (((curtile & 0x0800) ? (7-(yoff&0x7)) : (yoff&0x7)) << 2);
}
+ if (mosaic) lastxpos = xoff;
+
for (int i = 0; i < 256; i++)
{
- if (!(xoff & 0x7))
+ u32 xpos;
+ if (mosaic) xpos = xoff - CurBGXMosaicTable[i];
+ else xpos = xoff;
+
+ if ((!mosaic && (!(xpos & 0x7))) ||
+ (mosaic && ((xpos >> 3) != (lastxpos >> 3))))
{
// load a new tile
- curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xoff & 0xF8) >> 2) + ((xoff & widexmask) << 3));
+ curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xpos & 0xF8) >> 2) + ((xpos & widexmask) << 3));
curpal = pal + ((curtile & 0xF000) >> 8);
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 5)
+ (((curtile & 0x0800) ? (7-(yoff&0x7)) : (yoff&0x7)) << 2);
+
+ if (mosaic) lastxpos = xpos;
}
// draw pixel
- // TODO: optimize VRAM access
if (WindowMask[i] & (1<<bgnum))
{
- if (xmos == 0)
+ u32 tilexoff = (curtile & 0x0400) ? (7-(xpos&0x7)) : (xpos&0x7);
+ if (tilexoff & 0x1)
{
- u32 tilexoff = (curtile & 0x0400) ? (7-(xoff&0x7)) : (xoff&0x7);
- if (tilexoff & 0x1)
- {
- color = GPU::ReadVRAM_BG<u8>(pixelsaddr + (tilexoff >> 1)) >> 4;
- }
- else
- {
- color = GPU::ReadVRAM_BG<u8>(pixelsaddr + (tilexoff >> 1)) & 0x0F;
- }
- xmos = xmossize;
+ color = GPU::ReadVRAM_BG<u8>(pixelsaddr + (tilexoff >> 1)) >> 4;
}
else
- xmos--;
+ {
+ color = GPU::ReadVRAM_BG<u8>(pixelsaddr + (tilexoff >> 1)) & 0x0F;
+ }
if (color)
DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
@@ -1776,10 +1828,10 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
}
}
+template<bool mosaic>
void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
{
u16 bgcnt = BGCnt[bgnum];
- u32 xmos = 0, xmossize = 0;
u32 tilesetaddr, tilemapaddr;
u16* pal;
@@ -1808,10 +1860,9 @@ void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
if (bgcnt & 0x0040)
{
- // mosaic
+ // vertical mosaic
rotX -= (BGMosaicY * rotB);
rotY -= (BGMosaicY * rotD);
- xmossize = BGMosaicSize[0];
}
if (Num)
@@ -1838,28 +1889,31 @@ void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
{
if (WindowMask[i] & (1<<bgnum))
{
- if (xmos > 0)
+ s32 finalX, finalY;
+ if (mosaic)
{
- if (color)
- DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum);
-
- xmos--;
+ int im = CurBGXMosaicTable[i];
+ finalX = rotX - (im * rotA);
+ finalY = rotY - (im * rotC);
}
else
- if ((!((rotX|rotY) & overflowmask)))
{
- curtile = GPU::ReadVRAM_BG<u8>(tilemapaddr + ((((rotY & coordmask) >> 11) << yshift) + ((rotX & coordmask) >> 11)));
+ finalX = rotX;
+ finalY = rotY;
+ }
+
+ if ((!((finalX|finalY) & overflowmask)))
+ {
+ curtile = GPU::ReadVRAM_BG<u8>(tilemapaddr + ((((finalY & coordmask) >> 11) << yshift) + ((finalX & coordmask) >> 11)));
// draw pixel
- u32 tilexoff = (rotX >> 8) & 0x7;
- u32 tileyoff = (rotY >> 8) & 0x7;
+ u32 tilexoff = (finalX >> 8) & 0x7;
+ u32 tileyoff = (finalY >> 8) & 0x7;
color = GPU::ReadVRAM_BG<u8>(tilesetaddr + (curtile << 6) + (tileyoff << 3) + tilexoff);
if (color)
DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum);
-
- xmos = xmossize;
}
}
@@ -1871,10 +1925,10 @@ void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
BGYRefInternal[bgnum-2] += rotD;
}
+template<bool mosaic>
void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
{
u16 bgcnt = BGCnt[bgnum];
- u32 xmos = 0, xmossize = 0;
u32 tilesetaddr, tilemapaddr;
u16* pal;
@@ -1892,10 +1946,9 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
if (bgcnt & 0x0040)
{
- // mosaic
+ // vertical mosaic
rotX -= (BGMosaicY * rotB);
rotY -= (BGMosaicY * rotD);
- xmossize = BGMosaicSize[0];
}
if (bgcnt & 0x0080)
@@ -1937,22 +1990,25 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
{
if (WindowMask[i] & (1<<bgnum))
{
- if (xmos > 0)
+ s32 finalX, finalY;
+ if (mosaic)
{
- if (color & 0x8000)
- DrawPixel(&BGOBJLine[i], color, 0x01000000<<bgnum);
-
- xmos--;
+ int im = CurBGXMosaicTable[i];
+ finalX = rotX - (im * rotA);
+ finalY = rotY - (im * rotC);
}
else
- if (!(rotX & ofxmask) && !(rotY & ofymask))
{
- color = GPU::ReadVRAM_BG<u16>(tilemapaddr + (((((rotY & ymask) >> 8) << yshift) + ((rotX & xmask) >> 8)) << 1));
+ finalX = rotX;
+ finalY = rotY;
+ }
+
+ if (!(finalX & ofxmask) && !(finalY & ofymask))
+ {
+ color = GPU::ReadVRAM_BG<u16>(tilemapaddr + (((((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8)) << 1));
if (color & 0x8000)
DrawPixel(&BGOBJLine[i], color, 0x01000000<<bgnum);
-
- xmos = xmossize;
}
}
@@ -1973,22 +2029,25 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
{
if (WindowMask[i] & (1<<bgnum))
{
- if (xmos > 0)
+ s32 finalX, finalY;
+ if (mosaic)
{
- if (color)
- DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum);
-
- xmos--;
+ int im = CurBGXMosaicTable[i];
+ finalX = rotX - (im * rotA);
+ finalY = rotY - (im * rotC);
}
else
- if (!(rotX & ofxmask) && !(rotY & ofymask))
{
- color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((rotY & ymask) >> 8) << yshift) + ((rotX & xmask) >> 8));
+ finalX = rotX;
+ finalY = rotY;
+ }
+
+ if (!(finalX & ofxmask) && !(finalY & ofymask))
+ {
+ color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8));
if (color)
DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum);
-
- xmos = xmossize;
}
}
@@ -2040,24 +2099,29 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
{
if (WindowMask[i] & (1<<bgnum))
{
- if (xmos > 0)
+ s32 finalX, finalY;
+ if (mosaic)
{
- if (color)
- DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
-
- xmos--;
+ int im = CurBGXMosaicTable[i];
+ finalX = rotX - (im * rotA);
+ finalY = rotY - (im * rotC);
}
else
- if ((!((rotX|rotY) & overflowmask)))
{
- curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + (((((rotY & coordmask) >> 11) << yshift) + ((rotX & coordmask) >> 11)) << 1));
+ finalX = rotX;
+ finalY = rotY;
+ }
+
+ if ((!((finalX|finalY) & overflowmask)))
+ {
+ curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + (((((finalY & coordmask) >> 11) << yshift) + ((finalX & coordmask) >> 11)) << 1));
if (extpal) curpal = GetBGExtPal(bgnum, curtile>>12);
else curpal = pal;
// draw pixel
- u32 tilexoff = (rotX >> 8) & 0x7;
- u32 tileyoff = (rotY >> 8) & 0x7;
+ u32 tilexoff = (finalX >> 8) & 0x7;
+ u32 tileyoff = (finalY >> 8) & 0x7;
if (curtile & 0x0400) tilexoff = 7-tilexoff;
if (curtile & 0x0800) tileyoff = 7-tileyoff;
@@ -2066,8 +2130,6 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
if (color)
DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
-
- xmos = xmossize;
}
}
@@ -2080,10 +2142,10 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
BGYRefInternal[bgnum-2] += rotD;
}
+template<bool mosaic>
void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
{
u16 bgcnt = BGCnt[2];
- u32 xmos = 0, xmossize = 0;
u32 tilesetaddr, tilemapaddr;
u16* pal;
@@ -2125,10 +2187,9 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
if (bgcnt & 0x0040)
{
- // mosaic
+ // vertical mosaic
rotX -= (BGMosaicY * rotB);
rotY -= (BGMosaicY * rotD);
- xmossize = BGMosaicSize[0];
}
if (Num) tilemapaddr = 0x06200000;
@@ -2145,17 +2206,22 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
{
if (WindowMask[i] & (1<<2))
{
- if (xmos > 0)
+ s32 finalX, finalY;
+ if (mosaic)
{
- if (color)
- DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<2);
-
- xmos--;
+ int im = CurBGXMosaicTable[i];
+ finalX = rotX - (im * rotA);
+ finalY = rotY - (im * rotC);
}
else
- if (!(rotX & ofxmask) && !(rotY & ofymask))
{
- color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((rotY & ymask) >> 8) << yshift) + ((rotX & xmask) >> 8));
+ finalX = rotX;
+ finalY = rotY;
+ }
+
+ if (!(finalX & ofxmask) && !(finalY & ofymask))
+ {
+ color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8));
if (color)
DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<2);
@@ -2218,6 +2284,16 @@ void GPU2D::InterleaveSprites(u32 prio)
}
}
+#define DoDrawSprite(type, ...) \
+ if (iswin) \
+ { \
+ DrawSprite_##type<true>(__VA_ARGS__); \
+ } \
+ else \
+ { \
+ DrawSprite_##type<false>(__VA_ARGS__); \
+ }
+
void GPU2D::DrawSprites(u32 line)
{
NumSprites = 0;
@@ -2278,10 +2354,7 @@ void GPU2D::DrawSprites(u32 line)
u32 rotparamgroup = (attrib[1] >> 9) & 0x1F;
- if (iswin)
- DrawSprite_Rotscale<true>(attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos);
- else
- DrawSprite_Rotscale<false>(attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos);
+ DoDrawSprite(Rotscale, attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos);
NumSprites++;
}
@@ -2307,10 +2380,7 @@ void GPU2D::DrawSprites(u32 line)
if (attrib[1] & 0x2000)
ypos = height-1 - ypos;
- if (iswin)
- DrawSprite_Normal<true>(attrib, width, xpos, ypos);
- else
- DrawSprite_Normal<false>(attrib, width, xpos, ypos);
+ DoDrawSprite(Normal, attrib, width, xpos, ypos);
NumSprites++;
}
@@ -2324,22 +2394,20 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
u32 pixelattr = ((attrib[2] & 0x0C00) << 6) | 0x40000;
u32 tilenum = attrib[2] & 0x03FF;
u32 spritemode = window ? 0 : ((attrib[0] >> 10) & 0x3);
- u32 xmos = 0, xmossize = 0;
u32 ytilefactor;
s32 centerX = boundwidth >> 1;
s32 centerY = boundheight >> 1;
+ s32 limitX = 0;//(boundwidth - width) << 7;
+ s32 limitY = 0;//(boundheight - height) << 7;
+
if (attrib[0] & 0x1000)
{
- // mosaic
- ypos -= OBJMosaicY;
+ // apply Y mosaic
+ ypos = OBJMosaicY - (attrib[0] & 0xFF);
if (ypos < 0) ypos = 0;
- xmossize = OBJMosaicSize[0];
-
- if (xpos > 0)
- xmos = (xmossize+1) - (xpos % (xmossize+1));
}
u32 xoff;
@@ -2406,20 +2474,12 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
}
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
- if (xmos && !(attrib[0]&0x0200))
- color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr + ((rotY >> 8) * ytilefactor) + ((rotX >> 8) << 1));
for (; xoff < boundwidth;)
{
if ((u32)rotX < width && (u32)rotY < height)
{
- if (xmos == 0)
- {
- color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr + ((rotY >> 8) * ytilefactor) + ((rotX >> 8) << 1));
- xmos = xmossize;
- }
- else
- xmos--;
+ color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr + ((rotY >> 8) * ytilefactor) + ((rotX >> 8) << 1));
if (color & 0x8000)
{
@@ -2427,11 +2487,6 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
else OBJLine[xpos] = color | pixelattr;
}
}
- else
- {
- if (xmos == 0) xmos = xmossize;
- else xmos--;
- }
rotX += rotA;
rotY += rotC;
@@ -2469,20 +2524,11 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
pixelattr |= ((attrib[2] & 0xF000) >> 4);
}
- if (xmos && !(attrib[0]&0x0200))
- color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>5) + ((rotX>>11)*64) + ((rotX&0x700)>>8));
-
for (; xoff < boundwidth;)
{
if ((u32)rotX < width && (u32)rotY < height)
{
- if (xmos == 0)
- {
- color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>5) + ((rotX>>11)*64) + ((rotX&0x700)>>8));
- xmos = xmossize;
- }
- else
- xmos--;
+ color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>5) + ((rotX>>11)*64) + ((rotX&0x700)>>8));
if (color)
{
@@ -2490,11 +2536,6 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
else OBJLine[xpos] = color | pixelattr;
}
}
- else
- {
- if (xmos == 0) xmos = xmossize;
- else xmos--;
- }
rotX += rotA;
rotY += rotC;
@@ -2515,31 +2556,15 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
pixelattr |= ((attrib[2] & 0xF000) >> 8);
}
- if (xmos && !(attrib[0]&0x0200))
- {
- color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>6) + ((rotX>>11)*32) + ((rotX&0x700)>>9));
- if (rotX & 0x100)
- color >>= 4;
- else
- color &= 0x0F;
- }
-
for (; xoff < boundwidth;)
{
if ((u32)rotX < width && (u32)rotY < height)
{
- if (xmos == 0)
- {
- color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>6) + ((rotX>>11)*32) + ((rotX&0x700)>>9));
- if (rotX & 0x100)
- color >>= 4;
- else
- color &= 0x0F;
-
- xmos = xmossize;
- }
+ color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>6) + ((rotX>>11)*32) + ((rotX&0x700)>>9));
+ if (rotX & 0x100)
+ color >>= 4;
else
- xmos--;
+ color &= 0x0F;
if (color)
{
@@ -2547,11 +2572,6 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
else OBJLine[xpos] = color | pixelattr;
}
}
- else
- {
- if (xmos == 0) xmos = xmossize;
- else xmos--;
- }
rotX += rotA;
rotY += rotC;
@@ -2568,19 +2588,14 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
u32 pixelattr = ((attrib[2] & 0x0C00) << 6) | 0x40000;
u32 tilenum = attrib[2] & 0x03FF;
u32 spritemode = window ? 0 : ((attrib[0] >> 10) & 0x3);
- u32 xmos = 0, xmossize = 0;
u32 wmask = width - 8; // really ((width - 1) & ~0x7)
if (attrib[0] & 0x1000)
{
- // mosaic
- ypos -= OBJMosaicY;
+ // apply Y mosaic
+ ypos = OBJMosaicY - (attrib[0] & 0xFF);
if (ypos < 0) ypos = 0;
- xmossize = OBJMosaicSize[0];
-
- if (xpos > 0)
- xmos = (xmossize+1) - (xpos % (xmossize+1));
}
u32 xoff;
@@ -2639,60 +2654,34 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
}
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
+ s32 pixelstride;
- if (attrib[1] & 0x1000)
+ if (attrib[1] & 0x1000) // xflip
{
- pixelsaddr += ((width-1 - xoff) << 1);
- if (xmos) color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr);
-
- for (; xoff < xend;)
- {
- if (xmos == 0)
- {
- color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr);
- xmos = xmossize;
- }
- else
- xmos--;
-
- pixelsaddr -= 2;
-
- if (color & 0x8000)
- {
- if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
- }
-
- xoff++;
- xpos++;
- }
+ pixelsaddr += (width-1 << 1);
+ pixelsaddr -= (xoff << 1);
+ pixelstride = -2;
}
else
{
pixelsaddr += (xoff << 1);
- if (xmos) color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr);
-
- for (; xoff < xend;)
- {
- if (xmos == 0)
- {
- color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr);
- xmos = xmossize;
- }
- else
- xmos--;
+ pixelstride = 2;
+ }
- pixelsaddr += 2;
+ for (; xoff < xend;)
+ {
+ color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr);
- if (color & 0x8000)
- {
- if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
- }
+ pixelsaddr += pixelstride;
- xoff++;
- xpos++;
+ if (color & 0x8000)
+ {
+ if (window) OBJWindow[xpos] = 1;
+ else OBJLine[xpos] = color | pixelattr;
}
+
+ xoff++;
+ xpos++;
}
}
else
@@ -2716,6 +2705,7 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
tilenum <<= 5;
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
pixelsaddr += ((ypos & 0x7) << 3);
+ s32 pixelstride;
if (!window)
{
@@ -2725,63 +2715,36 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
pixelattr |= ((attrib[2] & 0xF000) >> 4);
}
- if (attrib[1] & 0x1000) // xflip. TODO: do better? oh well for now this works
+ if (attrib[1] & 0x1000) // xflip
{
- pixelsaddr += (((width-1 - xoff) & wmask) << 3);
- pixelsaddr += ((width-1 - xoff) & 0x7);
- if (xmos) color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr);
-
- for (; xoff < xend;)
- {
- if (xmos == 0)
- {
- color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr);
- xmos = xmossize;
- }
- else
- xmos--;
-
- pixelsaddr--;
-
- if (color)
- {
- if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
- }
-
- xoff++;
- xpos++;
- if (!(xoff & 0x7)) pixelsaddr -= 56;
- }
+ pixelsaddr += (((width-1) & wmask) << 3);
+ pixelsaddr += ((width-1) & 0x7);
+ pixelsaddr -= ((xoff & wmask) << 3);
+ pixelsaddr -= (xoff & 0x7);
+ pixelstride = -1;
}
else
{
pixelsaddr += ((xoff & wmask) << 3);
pixelsaddr += (xoff & 0x7);
- if (xmos) color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr);
-
- for (; xoff < xend;)
- {
- if (xmos == 0)
- {
- color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr);
- xmos = xmossize;
- }
- else
- xmos--;
+ pixelstride = 1;
+ }
- pixelsaddr++;
+ for (; xoff < xend;)
+ {
+ color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr);
- if (color)
- {
- if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
- }
+ pixelsaddr += pixelstride;
- xoff++;
- xpos++;
- if (!(xoff & 0x7)) pixelsaddr += 56;
+ if (color)
+ {
+ if (window) OBJWindow[xpos] = 1;
+ else OBJLine[xpos] = color | pixelattr;
}
+
+ xoff++;
+ xpos++;
+ if (!(xoff & 0x7)) pixelsaddr += (56 * pixelstride);
}
}
else
@@ -2790,6 +2753,7 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
tilenum <<= 5;
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
pixelsaddr += ((ypos & 0x7) << 2);
+ s32 pixelstride;
if (!window)
{
@@ -2798,74 +2762,45 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
}
// TODO: optimize VRAM access!!
+ // TODO: do xflip better? the 'two pixels per byte' thing makes it a bit shitty
- if (attrib[1] & 0x1000) // xflip. TODO: do better? oh well for now this works
+ if (attrib[1] & 0x1000) // xflip
{
- pixelsaddr += (((width-1 - xoff) & wmask) << 2);
- pixelsaddr += (((width-1 - xoff) & 0x7) >> 1);
- if (xmos)
- {
- if (xoff & 0x1) color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F;
- else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4;
- }
-
- for (; xoff < xend;)
- {
- if (xmos == 0)
- {
- if (xoff & 0x1) color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F;
- else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4;
- xmos = xmossize;
- }
- else
- xmos--;
-
- if (xoff & 0x1) pixelsaddr--;
-
- if (color)
- {
- if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
- }
-
- xoff++;
- xpos++;
- if (!(xoff & 0x7)) pixelsaddr -= 28;
- }
+ pixelsaddr += (((width-1) & wmask) << 2);
+ pixelsaddr += (((width-1) & 0x7) >> 1);
+ pixelsaddr -= ((xoff & wmask) << 2);
+ pixelsaddr -= ((xoff & 0x7) >> 1);
+ pixelstride = -1;
}
else
{
pixelsaddr += ((xoff & wmask) << 2);
pixelsaddr += ((xoff & 0x7) >> 1);
- if (xmos)
+ pixelstride = 1;
+ }
+
+ for (; xoff < xend;)
+ {
+ if (attrib[1] & 0x1000)
{
- if (xoff & 0x1) color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4;
- else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F;
+ if (xoff & 0x1) { color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F; pixelsaddr--; }
+ else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4;
}
-
- for (; xoff < xend;)
+ else
{
- if (xmos == 0)
- {
- if (xoff & 0x1) color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4;
- else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F;
- xmos = xmossize;
- }
- else
- xmos--;
-
- if (xoff & 0x1) pixelsaddr++;
-
- if (color)
- {
- if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
- }
+ if (xoff & 0x1) { color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4; pixelsaddr++; }
+ else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F;
+ }
- xoff++;
- xpos++;
- if (!(xoff & 0x7)) pixelsaddr += 28;
+ if (color)
+ {
+ if (window) OBJWindow[xpos] = 1;
+ else OBJLine[xpos] = color | pixelattr;
}
+
+ xoff++;
+ xpos++;
+ if (!(xoff & 0x7)) pixelsaddr += ((attrib[1] & 0x1000) ? -28 : 28);
}
}
}
diff --git a/src/GPU2D.h b/src/GPU2D.h
index 9184215..1e5e6e0 100644
--- a/src/GPU2D.h
+++ b/src/GPU2D.h
@@ -111,7 +111,11 @@ private:
u8 BGMosaicSize[2];
u8 OBJMosaicSize[2];
u8 BGMosaicY, BGMosaicYMax;
- u8 OBJMosaicY, OBJMosaicYMax;
+ u8 OBJMosaicYCount, OBJMosaicY, OBJMosaicYMax;
+
+ u8 MosaicTable[16][256];
+ u8* CurBGXMosaicTable;
+ u8* CurOBJXMosaicTable;
u16 BlendCnt;
u16 BlendAlpha;
@@ -133,6 +137,8 @@ private:
u32 ColorBrightnessDown(u32 val, u32 factor);
u32 ColorComposite(int i, u32 val1, u32 val2);
+ void UpdateMosaicCounters(u32 line);
+
template<u32 bgmode> void DrawScanlineBGMode(u32 line);
void DrawScanlineBGMode6(u32 line);
void DrawScanlineBGMode7(u32 line);
@@ -143,10 +149,10 @@ private:
void (*DrawPixel)(u32* dst, u16 color, u32 flag);
void DrawBG_3D();
- void DrawBG_Text(u32 line, u32 bgnum);
- void DrawBG_Affine(u32 line, u32 bgnum);
- void DrawBG_Extended(u32 line, u32 bgnum);
- void DrawBG_Large(u32 line);
+ template<bool mosaic> void DrawBG_Text(u32 line, u32 bgnum);
+ template<bool mosaic> void DrawBG_Affine(u32 line, u32 bgnum);
+ template<bool mosaic> void DrawBG_Extended(u32 line, u32 bgnum);
+ template<bool mosaic> void DrawBG_Large(u32 line);
void InterleaveSprites(u32 prio);
template<bool window> void DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos);