diff options
author | Arisotura <thetotalworm@gmail.com> | 2019-09-15 01:31:09 +0200 |
---|---|---|
committer | Arisotura <thetotalworm@gmail.com> | 2019-09-15 01:31:09 +0200 |
commit | cb90475b60dc329d902b866aeef1caff0ac3d9c1 (patch) | |
tree | 7f0813de5bab0ecb8b718facf9b96b6599163927 | |
parent | b8f55623c1330d5aa957448d2f3b29b4bad17708 (diff) |
begin work on mosaic
OBJ Y mosaic emulated correctly, there's atleast that.
-rw-r--r-- | src/GPU2D.cpp | 587 | ||||
-rw-r--r-- | src/GPU2D.h | 16 |
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); |