core vdp, improve sprite rendering
authorkub <derkub@gmail.com>
Wed, 12 Apr 2023 18:11:29 +0000 (18:11 +0000)
committerkub <derkub@gmail.com>
Wed, 12 Apr 2023 18:11:29 +0000 (18:11 +0000)
implements kabuto's phase 2, fixes rotating 3D blocks in Overdrive 2

pico/draw.c
pico/videoport.c

index 0e43fb9..b9d23ac 100644 (file)
@@ -61,7 +61,8 @@ int DrawLineDestIncrement;
 \r
 static u32 HighCacheA[41*2+1]; // caches for high layers\r
 static u32 HighCacheB[41*2+1];\r
-static s32 HighPreSpr[80*2+1]; // slightly preprocessed sprites\r
+static s32 HighPreSpr[128*2*2]; // slightly preprocessed sprites (2 banks a 128)\r
+static int HighPreSprBank;\r
 \r
 u32 VdpSATCache[2*128];  // VDP sprite cache (1st 32 sprite attr bits)\r
 \r
@@ -295,7 +296,7 @@ TileFlipMaker(TileFlip_and, pix_and)
     /* if (!t) pd[x] |= 0x40; as per titan hw notes? */ \\r
     pd[x] &= pal|t; \\r
   }\r
\r
+\r
 TileNormMakerAS(TileNormSH_AS_and, pix_sh_as_and)\r
 TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and)\r
 #endif\r
@@ -825,7 +826,7 @@ static void DrawSprite(s32 *sprite, int sh, int w)
   sx=code>>16; // X\r
   width=sy>>28;\r
   height=(sy>>24)&7; // Width and height in tiles\r
-  sy=(sy<<16)>>16; // Y\r
+  sy=(s16)sy; // Y\r
 \r
   row=Pico.est.DrawScanline-sy; // Row of the sprite we are on\r
 \r
@@ -980,7 +981,7 @@ static void DrawSpritesSHi(unsigned char *sprited, const struct PicoEState *est)
   unsigned char *p;\r
   int cnt, w;\r
 \r
-  cnt = sprited[0];\r
+  cnt = sprited[0] & 0x7f;\r
   if (cnt == 0) return;\r
 \r
   p = &sprited[4];\r
@@ -1008,7 +1009,7 @@ static void DrawSpritesSHi(unsigned char *sprited, const struct PicoEState *est)
     sx=code>>16; // X\r
     width=sy>>28;\r
     height=(sy>>24)&7; // Width and height in tiles\r
-    sy=(sy<<16)>>16; // Y\r
+    sy=(s16)sy; // Y\r
 \r
     row=est->DrawScanline-sy; // Row of the sprite we are on\r
 \r
@@ -1049,7 +1050,7 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh)
   unsigned m;\r
   int entry, cnt;\r
 \r
-  cnt = sprited[0];\r
+  cnt = sprited[0] & 0x7f;\r
   if (cnt == 0) return;\r
 \r
   memset(mb, 0xff, sizeof(mb));\r
@@ -1065,7 +1066,7 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh)
     int offs, delta, width, height, row;\r
 \r
     offs = (p[entry] & 0x7f) * 2;\r
-    sprite = HighPreSpr + offs;\r
+    sprite = Pico.est.HighPreSpr + offs;\r
     code = sprite[1];\r
     pal = (code>>9)&0x30;\r
 \r
@@ -1076,7 +1077,7 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh)
     sx=code>>16; // X\r
     width=sy>>28;\r
     height=(sy>>24)&7; // Width and height in tiles\r
-    sy=(sy<<16)>>16; // Y\r
+    sy=(s16)sy; // Y\r
 \r
     row=Pico.est.DrawScanline-sy; // Row of the sprite we are on\r
 \r
@@ -1326,9 +1327,9 @@ static void DrawSpritesForced(unsigned char *sprited)
   unsigned m;\r
   int entry, cnt;\r
 \r
-  cnt = sprited[0];\r
+  cnt = sprited[0] & 0x7f;\r
   if (cnt == 0) { memset(pd, 0, sizeof(DefHighCol)); return; }\r
-  \r
+\r
   memset(mb, 0xff, sizeof(mb));\r
   p = &sprited[4];\r
   if ((sprited[1] & (SPRL_TILE_OVFL|SPRL_HAVE_MASK0)) == (SPRL_TILE_OVFL|SPRL_HAVE_MASK0))\r
@@ -1342,7 +1343,7 @@ static void DrawSpritesForced(unsigned char *sprited)
     int offs, delta, width, height, row;\r
 \r
     offs = (p[entry] & 0x7f) * 2;\r
-    sprite = HighPreSpr + offs;\r
+    sprite = Pico.est.HighPreSpr + offs;\r
     code = sprite[1];\r
     pal = (code>>9)&0x30;\r
 \r
@@ -1354,7 +1355,7 @@ static void DrawSpritesForced(unsigned char *sprited)
     sx=code>>16; // X\r
     width=sy>>28;\r
     height=(sy>>24)&7; // Width and height in tiles\r
-    sy=(sy<<16)>>16; // Y\r
+    sy=(s16)sy; // Y\r
 \r
     row=Pico.est.DrawScanline-sy; // Row of the sprite we are on\r
 \r
@@ -1400,19 +1401,21 @@ static void DrawSpritesForced(unsigned char *sprited)
 #endif\r
 \r
 \r
+// sprite info in SAT:\r
 // Index + 0  :    ----hhvv -lllllll -------y yyyyyyyy\r
 // Index + 4  :    -------x xxxxxxxx pccvhnnn nnnnnnnn\r
-// v\r
-// Index + 0  :    hhhhvvvv ----hhvv yyyyyyyy yyyyyyyy // v, h: vert./horiz. size\r
-// Index + 4  :    xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8\r
+// sprite info in HighPreSpr:\r
+// Index + 0  :    hhhhvvvv -lllllll yyyyyyyy yyyyyyyy // v/h size, link, y\r
+// Index + 4  :    xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x+8, prio, palette, flip, tile\r
 \r
+// Sprite parsing 1 line in advance: determine sprites on line by Y pos\r
 static NOINLINE void ParseSprites(int max_lines, int limit)\r
 {\r
   const struct PicoVideo *pvid=&Pico.video;\r
   const struct PicoEState *est=&Pico.est;\r
   int u,link=0,sh;\r
   int table=0;\r
-  s32 *pd = HighPreSpr;\r
+  s32 *pd = HighPreSpr + HighPreSprBank*2;\r
   int max_sprites = 80, max_width = 328;\r
   int max_line_sprites = 20; // 20 sprites, 40 tiles\r
 \r
@@ -1470,12 +1473,12 @@ static NOINLINE void ParseSprites(int max_lines, int limit)
       if (sh && (code2 & 0x6000) == 0x6000)\r
         maybe_op = SPRL_MAY_HAVE_OP;\r
 \r
-      entry = ((pd - HighPreSpr) / 2) | ((code2>>8)&0x80);\r
+      entry = (((pd - HighPreSpr) / 2) & 0x7f) | ((code2>>8)&0x80);\r
       y = (sy >= first_line) ? sy : first_line;\r
       for (; y < sy + (height<<3) && y <= last_line; y++)\r
       {\r
         unsigned char *p = &HighLnSpr[y][0];\r
-        int cnt = p[0];\r
+        int cnt = p[0] & 0x7f;\r
         if (p[1] & SPRL_MASKED) continue;               // masked?\r
 \r
         if (p[3] >= max_line_sprites) continue;         // sprite limit?\r
@@ -1507,12 +1510,12 @@ static NOINLINE void ParseSprites(int max_lines, int limit)
 \r
         p[4+cnt] = entry;\r
         p[5+cnt] = w; // width clipped by tile limit for sprite renderer\r
-        p[0] = cnt + 1;\r
+        p[0] = (cnt + 1) | HighPreSprBank;\r
       }\r
     }\r
 \r
-    *pd++ = (width<<28)|(height<<24)|(hv<<16)|((unsigned short)sy);\r
-    *pd++ = (sx<<16)|((unsigned short)code2);\r
+    *pd++ = (width<<28)|(height<<24)|(link<<16)|((u16)sy);\r
+    *pd++ = (sx<<16)|((u16)code2);\r
 \r
     // Find next sprite\r
     link=(code>>16)&0x7f;\r
@@ -1525,11 +1528,11 @@ static NOINLINE void ParseSprites(int max_lines, int limit)
     int w = 0;\r
     unsigned char *sprited = &HighLnSpr[max_lines-1][0]; // current render line\r
 \r
-    for (u = 0; u < sprited[0]; u++) {\r
-      s32 *sp = HighPreSpr + (sprited[4+u] & 0x7f) * 2;\r
+    for (u = 0; u < (sprited[0] & 0x7f); u++) {\r
+      s32 *sp = HighPreSpr + (sprited[4+u] & 0x7f) * 2 + HighPreSprBank*2;\r
       int sw = sp[0] >> 28;\r
       if (w + sw > limit) {\r
-        sprited[0] = u;\r
+        sprited[0] = u | HighPreSprBank;\r
         sprited[4+u] = limit-w;\r
         break;\r
       }\r
@@ -1541,15 +1544,17 @@ static NOINLINE void ParseSprites(int max_lines, int limit)
   for (u = first_line; u <= max_lines; u++)\r
   {\r
     int y;\r
-    printf("c%03i: f %x c %2i/%2i w %2i: ", u, HighLnSpr[u][1],\r
-           HighLnSpr[u][0], HighLnSpr[u][3], HighLnSpr[u][2]);\r
-    for (y = 0; y < HighLnSpr[u][0]; y++) {\r
-      s32 *sp = HighPreSpr + (HighLnSpr[u][y+4]&0x7f) * 2;\r
+    printf("c%03i b%d: f %x c %2i/%2i w %2i: ", u, !!HighPreSprBank, HighLnSpr[u][1],\r
+           HighLnSpr[u][0] & 0x7f, HighLnSpr[u][3], HighLnSpr[u][2]);\r
+    for (y = 0; y < (HighLnSpr[u][0] & 0x7f); y++) {\r
+      s32 *sp = HighPreSpr + (HighLnSpr[u][y+4]&0x7f) * 2 + HighPreSprBank*2;\r
       printf(" %i(%x/%x)", HighLnSpr[u][y+4],sp[0],sp[1]);\r
     }\r
     printf("\n");\r
   }\r
 #endif\r
+\r
+  HighPreSprBank ^= 0x80;\r
 }\r
 \r
 #ifndef _ASM_DRAW_C\r
@@ -1559,7 +1564,7 @@ static void DrawAllSprites(unsigned char *sprited, int prio, int sh,
   unsigned char *p;\r
   int cnt, w;\r
 \r
-  cnt = sprited[0];\r
+  cnt = sprited[0] & 0x7f;\r
   if (cnt == 0) return;\r
 \r
   p = &sprited[4];\r
@@ -1570,7 +1575,7 @@ static void DrawAllSprites(unsigned char *sprited, int prio, int sh,
   w = p[cnt]; // possibly clipped width of last sprite\r
   for (cnt--; cnt >= 0; cnt--, w = 0)\r
   {\r
-    s32 *sp = HighPreSpr + (p[cnt]&0x7f) * 2;\r
+    s32 *sp = est->HighPreSpr + (p[cnt]&0x7f) * 2;\r
     if ((p[cnt] >> 7) != prio) continue;\r
     DrawSprite(sp, sh, w);\r
   }\r
@@ -1793,6 +1798,7 @@ static int DrawDisplay(int sh)
   int maxw, maxcells;\r
 \r
   est->rendstatus &= ~(PDRAW_SHHI_DONE|PDRAW_PLANE_HI_PRIO|PDRAW_WND_DIFF_PRIO);\r
+  est->HighPreSpr = HighPreSpr + (sprited[0]&0x80)*2;\r
 \r
   if (pvid->reg[12]&1) {\r
     maxw = 328; maxcells = 40;\r
@@ -2039,6 +2045,29 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites)
   pprof_end(draw);\r
 }\r
 \r
+void PicoDrawRefreshSprites()\r
+{\r
+  unsigned char *sprited = &HighLnSpr[Pico.est.DrawScanline][0];\r
+  int i;\r
+\r
+  if (Pico.est.DrawScanline == 0 || Pico.est.DrawScanline >= rendlines) return;\r
+\r
+  // compute sprite row. The VDP does this by subtracting the sprite y pos from\r
+  // the current line and treating the lower 5 bits as the row number. Y pos\r
+  // is reread from SAT cache, which may have changed by now (Overdrive 2).\r
+  for (i = 0; i < (sprited[0] & 0x7f); i++) {\r
+    int num = sprited[4+i] & 0x7f;\r
+    s32 *sp = HighPreSpr + 2*num + (sprited[0] & 0x80)*2;\r
+    int link = (sp[0]>>16) & 0x7f;\r
+    int sy = (CPU_LE2(VdpSATCache[2*link]) & 0x1ff) - 0x80;\r
+    if (sy != (s16)sp[0]) {\r
+      // Y info in SAT cache has really changed\r
+      sy = Pico.est.DrawScanline - ((Pico.est.DrawScanline - sy) & 0x1f);\r
+      sp[0] = (sp[0] & 0xffff0000) | (u16)sy;\r
+    }\r
+  }\r
+}\r
+\r
 // also works for fast renderer\r
 void PicoDrawUpdateHighPal(void)\r
 {\r
@@ -2157,7 +2186,6 @@ void PicoDrawInit(void)
 {\r
   Pico.est.DrawLineDest = DefOutBuff;\r
   Pico.est.HighCol = HighColBase;\r
-  Pico.est.HighPreSpr = HighPreSpr;\r
   rendstatus_old = -1;\r
 }\r
 \r
index 1038515..a444cf3 100644 (file)
@@ -389,6 +389,8 @@ int PicoVideoFIFOHint(void)
 \r
   // reset slot to start of scanline\r
   vf->fifo_slot = 0;\r
+  if (Pico.est.DrawScanline == Pico.m.scanline)\r
+    PicoDrawRefreshSprites();\r
  \r
   // if CPU is waiting for the bus, advance CPU and FIFO until bus is free\r
   if (pv->status & PVS_CPUWR)\r