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);  |