Browse Source

fix DrawSpritesHiAS

notaz 6 years ago
parent
commit
ee3c39efd2
3 changed files with 111 additions and 94 deletions
  1. 110 88
      pico/draw.c
  2. 0 1
      pico/pico.h
  3. 1 5
      platform/psp/emu.c

+ 110 - 88
pico/draw.c

@@ -13,20 +13,19 @@
  * - "sonic mode" for midline palette changes (8bit mode only)
  * - accurate sprites (AS) [+ s/h]
  *
- * AS and s/h both use upper bits for both priority and shadow/hilight flags.
+ * s/h uses upper bits for both priority and shadow/hilight flags.
  * "sonic mode" is autodetected, shadow/hilight is enabled by emulated game.
  * AS is enabled by user and takes priority over "sonic mode".
  *
  * since renderer always draws line in 8bit mode, there are 2 spare bits:
- * b \ mode: s/h             as        sonic
- * 00        normal          -         pal index
- * 01        shadow          -         pal index
- * 10        hilight+op spr  spr       pal index
- * 11        shadow +op spr  -         pal index
+ * b \ mode: s/h             sonic
+ * 00        normal          pal index
+ * 01        shadow          pal index
+ * 10        hilight+op spr  pal index
+ * 11        shadow +op spr  pal index
  *
  * not handled properly:
  * - hilight op on shadow tile
- * - AS + s/h (s/h sprite flag interferes with and cleared by AS code)
  */
 
 #include "pico_int.h"
@@ -95,11 +94,8 @@ void blockcpy_or(void *dst, void *src, size_t n, int pat)
 #define blockcpy memcpy
 #endif
 
-
-#define TileNormMaker(funcname,pix_func)                     \
-static void funcname(int sx, unsigned int pack, int pal)     \
+#define TileNormMaker_(pix_func)                             \
 {                                                            \
-  unsigned char *pd = Pico.est.HighCol + sx;                 \
   unsigned int t;                                            \
                                                              \
   t = (pack&0x0000f000)>>12; pix_func(0);                    \
@@ -112,10 +108,8 @@ static void funcname(int sx, unsigned int pack, int pal)     \
   t = (pack&0x000f0000)>>16; pix_func(7);                    \
 }
 
-#define TileFlipMaker(funcname,pix_func)                     \
-static void funcname(int sx, unsigned int pack, int pal)     \
+#define TileFlipMaker_(pix_func)                             \
 {                                                            \
-  unsigned char *pd = Pico.est.HighCol + sx;                 \
   unsigned int t;                                            \
                                                              \
   t = (pack&0x000f0000)>>16; pix_func(0);                    \
@@ -128,6 +122,21 @@ static void funcname(int sx, unsigned int pack, int pal)     \
   t = (pack&0x0000f000)>>12; pix_func(7);                    \
 }
 
+#define TileNormMaker(funcname, pix_func) \
+static void funcname(unsigned char *pd, unsigned int pack, int pal) \
+TileNormMaker_(pix_func)
+
+#define TileFlipMaker(funcname, pix_func) \
+static void funcname(unsigned char *pd, unsigned int pack, int pal) \
+TileFlipMaker_(pix_func)
+
+#define TileNormMakerAS(funcname, pix_func) \
+static void funcname(unsigned char *pd, unsigned char *mb, unsigned int pack, int pal) \
+TileNormMaker_(pix_func)
+
+#define TileFlipMakerAS(funcname, pix_func) \
+static void funcname(unsigned char *pd, unsigned char *mb, unsigned int pack, int pal) \
+TileFlipMaker_(pix_func)
 
 #define pix_just_write(x) \
   if (t) pd[x]=pal|t
@@ -155,11 +164,15 @@ TileFlipMaker(TileFlipSH, pix_sh)
 TileNormMaker(TileNormSH_markop, pix_sh_markop)
 TileFlipMaker(TileFlipSH_markop, pix_sh_markop)
 
+#endif
+
 // process operator pixels only, apply only on low pri tiles and other op pixels
 #define pix_sh_onlyop(x) \
   if (t>=0xe && (pd[x]&0xc0)) \
     pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \
 
+#ifndef _ASM_DRAW_C
+
 TileNormMaker(TileNormSH_onlyop_lp, pix_sh_onlyop)
 TileFlipMaker(TileFlipSH_onlyop_lp, pix_sh_onlyop)
 
@@ -167,26 +180,39 @@ TileFlipMaker(TileFlipSH_onlyop_lp, pix_sh_onlyop)
 
 // draw a sprite pixel (AS)
 #define pix_as(x) \
-  if (t && !(pd[x]&0x80)) pd[x]=pal|t
+  if (t & mb[x]) mb[x] = 0, pd[x] = pal | t
 
-TileNormMaker(TileNormAS, pix_as)
-TileFlipMaker(TileFlipAS, pix_as)
+TileNormMakerAS(TileNormAS, pix_as)
+TileFlipMakerAS(TileFlipAS, pix_as)
 
-// draw a sprite pixel, skip operator colors (AS)
-#define pix_sh_as_noop(x) \
-  if (t && t < 0xe && !(pd[x]&0x80)) pd[x]=pal|t
+// draw a sprite pixel, process operator colors (AS)
+#define pix_sh_as(x) \
+  if (t & mb[x]) { \
+    mb[x] = 0; \
+    if (t>=0xe) pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \
+    else pd[x] = pal | t; \
+  }
+
+TileNormMakerAS(TileNormSH_AS, pix_sh_as)
+TileFlipMakerAS(TileFlipSH_AS, pix_sh_as)
+
+#define pix_sh_as_onlyop(x) \
+  if (t & mb[x]) { \
+    mb[x] = 0; \
+    pix_sh_onlyop(x); \
+  }
 
-TileNormMaker(TileNormAS_noop, pix_sh_as_noop)
-TileFlipMaker(TileFlipAS_noop, pix_sh_as_noop)
+TileNormMakerAS(TileNormSH_AS_onlyop_lp, pix_sh_as_onlyop)
+TileFlipMakerAS(TileFlipSH_AS_onlyop_lp, pix_sh_as_onlyop)
 
 // mark pixel as sprite pixel (AS)
 #define pix_sh_as_onlymark(x) \
-  if (t) pd[x]|=0x80
+  if (t) mb[x] = 0
 
-TileNormMaker(TileNormAS_onlymark, pix_sh_as_onlymark)
-TileFlipMaker(TileFlipAS_onlymark, pix_sh_as_onlymark)
+TileNormMakerAS(TileNormAS_onlymark, pix_sh_as_onlymark)
+TileFlipMakerAS(TileFlipAS_onlymark, pix_sh_as_onlymark)
 
-// mark pixel as sprite pixel (AS)
+// forced both layer draw (through debug reg)
 #define pix_and(x) \
   pd[x] = (pd[x] & 0xc0) | (pd[x] & (pal | t))
 
@@ -198,6 +224,7 @@ TileFlipMaker(TileFlip_and, pix_and)
 #ifndef _ASM_DRAW_C
 static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)
 {
+  unsigned char *pd = Pico.est.HighCol;
   int tilex,dx,ty,code=0,addr=0,cells;
   int oldcode=-1,blank=-1; // The tile we know is blank
   int pal=0,sh;
@@ -241,8 +268,8 @@ static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)
       continue;
     }
 
-    if (code & 0x0800) TileFlip(dx, pack, pal);
-    else               TileNorm(dx, pack, pal);
+    if (code & 0x0800) TileFlip(pd + dx, pack, pal);
+    else               TileNorm(pd + dx, pack, pal);
   }
 
   // terminate the cache list
@@ -254,6 +281,7 @@ static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)
 // this is messy
 static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
 {
+  unsigned char *pd = Pico.est.HighCol;
   int tilex,dx,code=0,addr=0,cell=0;
   int oldcode=-1,blank=-1; // The tile we know is blank
   int pal=0,scan=Pico.est.DrawScanline;
@@ -310,8 +338,8 @@ static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
       continue;
     }
 
-    if (code & 0x0800) TileFlip(dx, pack, pal);
-    else               TileNorm(dx, pack, pal);
+    if (code & 0x0800) TileFlip(pd + dx, pack, pal);
+    else               TileNorm(pd + dx, pack, pal);
   }
 
   // terminate the cache list
@@ -325,6 +353,7 @@ static
 #endif
 void DrawStripInterlace(struct TileStrip *ts)
 {
+  unsigned char *pd = Pico.est.HighCol;
   int tilex=0,dx=0,ty=0,code=0,addr=0,cells;
   int oldcode=-1,blank=-1; // The tile we know is blank
   int pal=0;
@@ -366,8 +395,8 @@ void DrawStripInterlace(struct TileStrip *ts)
       continue;
     }
 
-    if (code & 0x0800) TileFlip(dx, pack, pal);
-    else               TileNorm(dx, pack, pal);
+    if (code & 0x0800) TileFlip(pd + dx, pack, pal);
+    else               TileNorm(pd + dx, pack, pal);
   }
 
   // terminate the cache list
@@ -447,7 +476,8 @@ static void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells,
 static void DrawWindow(int tstart, int tend, int prio, int sh,
                        struct PicoEState *est)
 {
-  struct PicoVideo *pvid=&Pico.video;
+  unsigned char *pd = Pico.est.HighCol;
+  struct PicoVideo *pvid = &Pico.video;
   int tilex,ty,nametab,code=0;
   int blank=-1; // The tile we know is blank
 
@@ -504,8 +534,8 @@ static void DrawWindow(int tstart, int tend, int prio, int sh,
       pal = ((code >> 9) & 0x30);
       dx = 8 + (tilex << 3);
 
-      if (code & 0x0800) TileFlip(dx, pack, pal);
-      else               TileNorm(dx, pack, pal);
+      if (code & 0x0800) TileFlip(pd + dx, pack, pal);
+      else               TileNorm(pd + dx, pack, pal);
     }
   }
   else
@@ -545,8 +575,8 @@ static void DrawWindow(int tstart, int tend, int prio, int sh,
 
       dx = 8 + (tilex << 3);
 
-      if (code & 0x0800) TileFlip(dx, pack, pal);
-      else               TileNorm(dx, pack, pal);
+      if (code & 0x0800) TileFlip(pd + dx, pack, pal);
+      else               TileNorm(pd + dx, pack, pal);
     }
   }
 }
@@ -568,6 +598,7 @@ static void DrawTilesFromCacheShPrep(void)
 
 static void DrawTilesFromCache(int *hc, int sh, int rlim, struct PicoEState *est)
 {
+  unsigned char *pd = Pico.est.HighCol;
   int code, addr, dx;
   unsigned int pack;
   int pal;
@@ -602,8 +633,8 @@ static void DrawTilesFromCache(int *hc, int sh, int rlim, struct PicoEState *est
       if (rlim-dx < 0)
         goto last_cut_tile;
 
-      if (code & 0x0800) TileFlip(dx, pack, pal);
-      else               TileNorm(dx, pack, pal);
+      if (code & 0x0800) TileFlip(pd + dx, pack, pal);
+      else               TileNorm(pd + dx, pack, pal);
     }
   }
   else
@@ -627,8 +658,8 @@ static void DrawTilesFromCache(int *hc, int sh, int rlim, struct PicoEState *est
       if (rlim - dx < 0)
         goto last_cut_tile;
 
-      if (code & 0x0800) TileFlip(dx, pack, pal);
-      else               TileNorm(dx, pack, pal);
+      if (code & 0x0800) TileFlip(pd + dx, pack, pal);
+      else               TileNorm(pd + dx, pack, pal);
     }
   }
   return;
@@ -636,9 +667,9 @@ static void DrawTilesFromCache(int *hc, int sh, int rlim, struct PicoEState *est
 last_cut_tile:
   // for vertical window cutoff
   {
-    unsigned char *pd = est->HighCol + dx;
     unsigned int t;
 
+    pd += dx;
     if (code&0x0800)
     {
       switch (rlim-dx+8)
@@ -677,12 +708,13 @@ last_cut_tile:
 
 static void DrawSprite(int *sprite, int sh)
 {
+  void (*fTileFunc)(unsigned char *pd, unsigned int pack, int pal);
+  unsigned char *pd = Pico.est.HighCol;
   int width=0,height=0;
   int row=0,code=0;
   int pal;
   int tile=0,delta=0;
   int sx, sy;
-  void (*fTileFunc)(int sx, unsigned int pack, int pal);
 
   // parse the sprite data
   sy=sprite[0];
@@ -722,13 +754,14 @@ static void DrawSprite(int *sprite, int sh)
     if(sx>=328) break; // Offscreen
 
     pack = *(unsigned int *)(PicoMem.vram + (tile & 0x7fff));
-    fTileFunc(sx, pack, pal);
+    fTileFunc(pd + sx, pack, pal);
   }
 }
 #endif
 
 static NOINLINE void DrawTilesFromCacheForced(const int *hc)
 {
+  unsigned char *pd = Pico.est.HighCol;
   int code, addr, dx;
   unsigned int pack;
   int pal;
@@ -743,13 +776,14 @@ static NOINLINE void DrawTilesFromCacheForced(const int *hc)
     pal = ((code >> 9) & 0x30);
     pack = *(unsigned int *)(PicoMem.vram + addr);
 
-    if (code & 0x0800) TileFlip_and(dx, pack, pal);
-    else               TileNorm_and(dx, pack, pal);
+    if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);
+    else               TileNorm_and(pd + dx, pack, pal);
   }
 }
 
 static void DrawSpriteInterlace(unsigned int *sprite)
 {
+  unsigned char *pd = Pico.est.HighCol;
   int width=0,height=0;
   int row=0,code=0;
   int pal;
@@ -788,8 +822,8 @@ static void DrawSpriteInterlace(unsigned int *sprite)
     if(sx>=328) break; // Offscreen
 
     pack = *(unsigned int *)(PicoMem.vram + (tile & 0x7fff));
-    if (code & 0x0800) TileFlip(sx, pack, pal);
-    else               TileNorm(sx, pack, pal);
+    if (code & 0x0800) TileFlip(pd + sx, pack, pal);
+    else               TileNorm(pd + sx, pack, pal);
   }
 }
 
@@ -851,7 +885,8 @@ static NOINLINE void DrawAllSpritesInterlace(int pri, int sh)
  */
 static void DrawSpritesSHi(unsigned char *sprited, const struct PicoEState *est)
 {
-  void (*fTileFunc)(int sx, unsigned int pack, int pal);
+  void (*fTileFunc)(unsigned char *pd, unsigned int pack, int pal);
+  unsigned char *pd = Pico.est.HighCol;
   unsigned char *p;
   int cnt;
 
@@ -913,7 +948,7 @@ static void DrawSpritesSHi(unsigned char *sprited, const struct PicoEState *est)
       if(sx>=328) break; // Offscreen
 
       pack = *(unsigned int *)(PicoMem.vram + (tile & 0x7fff));
-      fTileFunc(sx, pack, pal);
+      fTileFunc(pd + sx, pack, pal);
     }
   }
 }
@@ -921,15 +956,17 @@ static void DrawSpritesSHi(unsigned char *sprited, const struct PicoEState *est)
 
 static void DrawSpritesHiAS(unsigned char *sprited, int sh)
 {
-  void (*fTileFunc)(int sx, unsigned int pack, int pal);
+  void (*fTileFunc)(unsigned char *pd, unsigned char *mb,
+                    unsigned int pack, int pal);
+  unsigned char *pd = Pico.est.HighCol;
+  unsigned char mb[8+320+8];
   unsigned char *p;
-  int entry, cnt, sh_cnt = 0;
+  int entry, cnt;
 
   cnt = sprited[0] & 0x7f;
   if (cnt == 0) return;
 
-  Pico.est.rendstatus |= PDRAW_SPR_LO_ON_HI;
-
+  memset(mb, 0xff, sizeof(mb));
   p = &sprited[3];
 
   // Go through sprites:
@@ -943,22 +980,26 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh)
     code = sprite[1];
     pal = (code>>9)&0x30;
 
-    if (code & 0x8000) // hi priority
+    if (sh && pal == 0x30)
     {
-      if (sh && pal == 0x30)
+      if (code & 0x8000) // hi priority
       {
-        if (code&0x800) fTileFunc=TileFlipAS_noop;
-        else            fTileFunc=TileNormAS_noop;
+        if (code&0x800) fTileFunc = TileFlipSH_AS;
+        else            fTileFunc = TileNormSH_AS;
       } else {
-        if (code&0x800) fTileFunc=TileFlipAS;
-        else            fTileFunc=TileNormAS;
+        if (code&0x800) fTileFunc = TileFlipSH_AS_onlyop_lp;
+        else            fTileFunc = TileNormSH_AS_onlyop_lp;
       }
     } else {
-      if (code&0x800) fTileFunc=TileFlipAS_onlymark;
-      else            fTileFunc=TileNormAS_onlymark;
+      if (code & 0x8000) // hi priority
+      {
+        if (code&0x800) fTileFunc = TileFlipAS;
+        else            fTileFunc = TileNormAS;
+      } else {
+        if (code&0x800) fTileFunc = TileFlipAS_onlymark;
+        else            fTileFunc = TileNormAS_onlymark;
+      }
     }
-    if (sh && pal == 0x30)
-      p[sh_cnt++] = offs / 2; // re-save for sh/hi pass
 
     // parse remaining sprite data
     sy=sprite[0];
@@ -978,7 +1019,6 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh)
     tile &= 0x7ff; tile<<=4; tile+=(row&7)<<1; // Tile address
     delta<<=4; // Delta of address
 
-    pal |= 0x80;
     for (; width; width--,sx+=8,tile+=delta)
     {
       unsigned int pack;
@@ -987,25 +1027,9 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh)
       if(sx>=328) break; // Offscreen
 
       pack = *(unsigned int *)(PicoMem.vram + (tile & 0x7fff));
-      fTileFunc(sx, pack, pal);
+      fTileFunc(pd + sx, mb + sx, pack, pal);
     }
   }
-
-  if (!sh || !(sprited[1]&SPRL_MAY_HAVE_OP)) return;
-
-  /* nasty 1: remove 'sprite' flags */
-  {
-    int c = 320/4/4, *zb = (int *)(Pico.est.HighCol+8);
-    while (c--)
-    {
-      *zb++ &= 0x7f7f7f7f; *zb++ &= 0x7f7f7f7f;
-      *zb++ &= 0x7f7f7f7f; *zb++ &= 0x7f7f7f7f;
-    }
-  }
-
-  /* nasty 2: sh operator pass */
-  sprited[0] = sh_cnt;
-  DrawSpritesSHi(sprited, &Pico.est);
 }
 
 
@@ -1272,17 +1296,15 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est)
   }
 
   {
-#ifndef PSP
-    int i, mask=0xff;
-    if (!sh && (est->rendstatus & PDRAW_SPR_LO_ON_HI))
-      mask=0x3f; // accurate sprites, upper bits are priority stuff
+#if 1
+    int i;
 
     for (i = 0; i < len; i++)
-      pd[i] = pal[ps[i] & mask];
+      pd[i] = pal[ps[i]];
 #else
     extern void amips_clut(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);
     extern void amips_clut_6bit(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);
-    if (!sh && (est->rendstatus & PDRAW_SPR_LO_ON_HI))
+    if (!sh)
          amips_clut_6bit(pd, ps, pal, len);
     else amips_clut(pd, ps, pal, len);
 #endif

+ 0 - 1
pico/pico.h

@@ -197,7 +197,6 @@ void PicoDoHighPal555(int sh, int line, struct PicoEState *est);
 // internals
 #define PDRAW_SPRITES_MOVED (1<<0) // (asm)
 #define PDRAW_WND_DIFF_PRIO (1<<1) // not all window tiles use same priority
-#define PDRAW_SPR_LO_ON_HI  (1<<2) // seen sprites without layer pri bit ontop spr. with that bit
 #define PDRAW_INTERLACE     (1<<3)
 #define PDRAW_DIRTY_SPRITES (1<<4) // (asm)
 #define PDRAW_SONIC_MODE    (1<<5) // mid-frame palette changes for 8bit renderer

+ 1 - 5
platform/psp/emu.c

@@ -223,10 +223,6 @@ static void do_pal_update(int allow_sh, int allow_as)
 		localPal[0xe0] = 0;
 		localPal[0xf0] = 0x001f;
 	}
-	else if (allow_as && (Pico.est.rendstatus & PDRAW_SPR_LO_ON_HI))
-	{
-		memcpy(dpal + 0x80/2, localPal, 0x40*2);
-	}
 }
 
 static void do_slowmode_lines(int line_to)
@@ -250,7 +246,7 @@ static void EmuScanPrepare(void)
 
 	if (Pico.m.dirtyPal)
 		do_pal_update(1, 1);
-	if ((Pico.est.rendstatus & PDRAW_SPR_LO_ON_HI) && !(Pico.video.reg[0xC]&8))
+	if (!(Pico.video.reg[0xC] & 8))
 	     amips_clut_f = amips_clut_6bit;
 	else amips_clut_f = amips_clut;
 }