*/\r
\r
#include "pico_int.h"\r
+#define FORCE // layer forcing via debug register?\r
\r
int (*PicoScanBegin)(unsigned int num) = NULL;\r
int (*PicoScanEnd) (unsigned int num) = NULL;\r
TileNormMakerAS(TileNormAS_onlymark, pix_sh_as_onlymark)\r
TileFlipMakerAS(TileFlipAS_onlymark, pix_sh_as_onlymark)\r
\r
+#ifdef FORCE\r
// forced both layer draw (through debug reg)\r
#define pix_and(x) \\r
pd[x] = (pd[x] & 0xc0) | (pd[x] & (pal | t))\r
TileFlipMaker(TileFlip_and, pix_and)\r
\r
// forced sprite draw (through debug reg)\r
-#define pix_sh_and(x) /* XXX is there S/H with forced draw? */ \\r
- if (t>=0xe) pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \\r
- else pd[x] = (pd[x] & 0xc0) | (pd[x] & (pal | t))\r
+#define pix_sh_as_and(x) /* XXX is there S/H with forced draw? */ \\r
+ if (m & (1<<(x+8))) { \\r
+ m &= ~(1<<(x+8)); \\r
+ if (t>=0xe) pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \\r
+ else pd[x] = (pd[x] & 0xc0) | (pd[x] & (pal | t)); \\r
+ }\r
\r
-TileNormMaker(TileNormSH_and, pix_sh_and)\r
-TileFlipMaker(TileFlipSH_and, pix_sh_and)\r
+TileNormMakerAS(TileNormSH_AS_and, pix_sh_as_and)\r
+TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and)\r
+#endif\r
\r
// --------------------------------------------\r
\r
int adj = ((ts->hscroll ^ dx) >> 3) & 1;\r
cell -= adj + 1;\r
ts->cells -= adj;\r
+ PicoMem.vsram[0x3e] = PicoMem.vsram[0x3f] = plane_sh >> 16;\r
}\r
cell+=cellskip;\r
tilex+=cellskip;\r
// shit, we have 2-cell column based vscroll\r
// luckily this doesn't happen too often\r
ts.line=ymask|(shift[width]<<24); // save some stuff instead of line\r
- PicoMem.vsram[(plane_sh & 1)+0x3e] = PicoMem.vsram[0x27]; // XXX really?\r
+ plane_sh |= PicoMem.vsram[0x26+(~plane_sh&1)] << 16;\r
DrawStripVSRam(&ts, plane_sh, cellskip);\r
} else {\r
vscroll = PicoMem.vsram[plane_sh & 1]; // Get vertical scroll value\r
}\r
#endif\r
\r
-static NOINLINE void DrawTilesFromCacheForced(const int *hc)\r
-{\r
- unsigned char *pd = Pico.est.HighCol;\r
- int code, addr, dx;\r
- unsigned int pack;\r
- int pal;\r
-\r
- // *ts->hc++ = code | (dx<<16) | (ty<<25);\r
- while ((code = *hc++)) {\r
- // Get tile address/2:\r
- addr = (code & 0x7ff) << 4;\r
- addr += (code >> 25) & 0x0e; // y offset into tile\r
-\r
- dx = (code >> 16) & 0x1ff;\r
- pal = ((code >> 9) & 0x30);\r
- pack = *(unsigned int *)(PicoMem.vram + addr);\r
-\r
- if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);\r
- else TileNorm_and(pd + dx, pack, pal);\r
- }\r
-}\r
-\r
static void DrawSpriteInterlace(unsigned int *sprite)\r
{\r
unsigned char *pd = Pico.est.HighCol;\r
}\r
}\r
\r
+#ifdef FORCE\r
+static void DrawStripForced(struct TileStrip *ts, int lflags, int cellskip)\r
+{\r
+ unsigned char *pd = Pico.est.HighCol;\r
+ int tilex,dx,ty,code=0,addr=0,cells;\r
+ int oldcode=-1;\r
+ int pal=0,sh;\r
+\r
+ // Draw tiles across screen:\r
+ sh = (lflags & LF_SH) << 5; // 0x40\r
+ tilex=((-ts->hscroll)>>3)+cellskip;\r
+ ty=(ts->line&7)<<1; // Y-Offset into tile\r
+ dx=((ts->hscroll-1)&7)+1;\r
+ cells = ts->cells - cellskip;\r
+ if(dx != 8) cells++; // have hscroll, need to draw 1 cell more\r
+ dx+=cellskip<<3;\r
+\r
+ for (; cells > 0; dx+=8, tilex++, cells--)\r
+ {\r
+ unsigned int pack;\r
+\r
+ code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
+\r
+ if (code!=oldcode) {\r
+ oldcode = code;\r
+ // Get tile address/2:\r
+ addr=(code&0x7ff)<<4;\r
+ addr+=ty;\r
+ if (code&0x1000) addr^=0xe; // Y-flip\r
+\r
+ pal=((code>>9)&0x30)|sh;\r
+ }\r
+\r
+ pack = *(unsigned int *)(PicoMem.vram + addr);\r
+\r
+ if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);\r
+ else TileNorm_and(pd + dx, pack, pal);\r
+ }\r
+}\r
+\r
+// this is messy\r
+static void DrawStripVSRamForced(struct TileStrip *ts, int plane_sh, int cellskip)\r
+{\r
+ unsigned char *pd = Pico.est.HighCol;\r
+ int tilex,dx,code=0,addr=0,cell=0;\r
+ int oldcode=-1;\r
+ int pal=0,scan=Pico.est.DrawScanline;\r
+\r
+ // Draw tiles across screen:\r
+ tilex=(-ts->hscroll)>>3;\r
+ dx=((ts->hscroll-1)&7)+1;\r
+ if (ts->hscroll & 0x0f) {\r
+ int adj = ((ts->hscroll ^ dx) >> 3) & 1;\r
+ cell -= adj + 1;\r
+ ts->cells -= adj;\r
+ PicoMem.vsram[0x3e] = PicoMem.vsram[0x3f] = plane_sh >> 16;\r
+ }\r
+ cell+=cellskip;\r
+ tilex+=cellskip;\r
+ dx+=cellskip<<3;\r
+\r
+ for (; cell < ts->cells; dx+=8,tilex++,cell++)\r
+ {\r
+ int nametabadd, ty;\r
+ unsigned int pack;\r
+\r
+ //if((cell&1)==0)\r
+ {\r
+ int line,vscroll;\r
+ vscroll=PicoMem.vsram[(plane_sh&1)+(cell&0x3e)];\r
+\r
+ // Find the line in the name table\r
+ line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..\r
+ nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width]\r
+ ty=(line&7)<<1; // Y-Offset into tile\r
+ }\r
+\r
+ code=PicoMem.vram[ts->nametab+nametabadd+(tilex&ts->xmask)];\r
+\r
+ if (code!=oldcode) {\r
+ oldcode = code;\r
+ // Get tile address/2:\r
+ addr=(code&0x7ff)<<4;\r
+\r
+ pal=((code>>9)&0x30)|((plane_sh<<5)&0x40);\r
+ }\r
+\r
+ if (code & 0x1000) ty ^= 0xe; // Y-flip\r
+ pack = *(unsigned int *)(PicoMem.vram + addr+ty);\r
+\r
+ if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);\r
+ else TileNorm_and(pd + dx, pack, pal);\r
+ }\r
+}\r
+\r
+static void DrawLayerForced(int plane_sh, int cellskip, int maxcells,\r
+ struct PicoEState *est)\r
+{\r
+ struct PicoVideo *pvid=&Pico.video;\r
+ const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid)\r
+ struct TileStrip ts;\r
+ int width, height, ymask;\r
+ int vscroll, htab;\r
+\r
+ ts.cells=maxcells;\r
+\r
+ // Work out the TileStrip to draw\r
+\r
+ // Work out the name table size: 32 64 or 128 tiles (0-3)\r
+ width=pvid->reg[16];\r
+ height=(width>>4)&3; width&=3;\r
+\r
+ ts.xmask=(1<<shift[width])-1; // X Mask in tiles (0x1f-0x7f)\r
+ ymask=(height<<8)|0xff; // Y Mask in pixels\r
+ switch (width) {\r
+ case 1: ymask &= 0x1ff; break;\r
+ case 2: ymask = 0x007; break;\r
+ case 3: ymask = 0x0ff; break;\r
+ }\r
+\r
+ // Find name table:\r
+ if (plane_sh&1) ts.nametab=(pvid->reg[4]&0x07)<<12; // B\r
+ else ts.nametab=(pvid->reg[2]&0x38)<< 9; // A\r
+\r
+ htab=pvid->reg[13]<<9; // Horizontal scroll table address\r
+ switch (pvid->reg[11]&3) {\r
+ case 1: htab += (est->DrawScanline<<1) & 0x0f; break;\r
+ case 2: htab += (est->DrawScanline<<1) & ~0x0f; break; // Offset by tile\r
+ case 3: htab += (est->DrawScanline<<1); break; // Offset by line\r
+ }\r
+ htab+=plane_sh&1; // A or B\r
+\r
+ // Get horizontal scroll value, will be masked later\r
+ ts.hscroll = PicoMem.vram[htab & 0x7fff];\r
+\r
+ if((pvid->reg[12]&6) == 6) {\r
+ // interlace mode 2\r
+ vscroll = PicoMem.vsram[plane_sh & 1]; // Get vertical scroll value\r
+\r
+ // Find the line in the name table\r
+ ts.line=(vscroll+(est->DrawScanline<<1))&((ymask<<1)|1);\r
+ ts.nametab+=(ts.line>>4)<<shift[width];\r
+\r
+ DrawStripInterlace(&ts);\r
+ } else if( pvid->reg[11]&4) {\r
+ // shit, we have 2-cell column based vscroll\r
+ // luckily this doesn't happen too often\r
+ ts.line=ymask|(shift[width]<<24); // save some stuff instead of line\r
+ plane_sh |= PicoMem.vsram[0x26+(~plane_sh&1)] << 16;\r
+ DrawStripVSRamForced(&ts, plane_sh, cellskip);\r
+ } else {\r
+ vscroll = PicoMem.vsram[plane_sh & 1]; // Get vertical scroll value\r
+\r
+ // Find the line in the name table\r
+ ts.line=(vscroll+est->DrawScanline)&ymask;\r
+ ts.nametab+=(ts.line>>3)<<shift[width];\r
+\r
+ DrawStripForced(&ts, plane_sh, cellskip);\r
+ }\r
+}\r
+\r
+// rather messy (XXX revisit layer compositing)\r
static void DrawSpritesForced(unsigned char *sprited)\r
{\r
- void (*fTileFunc)(unsigned char *pd, unsigned int pack, int pal);\r
+ unsigned (*fTileFunc)(unsigned char *pd, unsigned m, unsigned int pack, int pal);\r
unsigned char *pd = Pico.est.HighCol;\r
- unsigned char *p;\r
+ unsigned char mb[1+320+1];\r
+ unsigned char *p, *mp;\r
+ unsigned m;\r
int entry, cnt;\r
\r
cnt = sprited[0] & 0x7f;\r
- if (cnt == 0) return;\r
-\r
+ if (cnt == 0) { memset(pd, 0, sizeof(DefHighCol)); return; }\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
return; // masking effective due to tile overflow\r
code = sprite[1];\r
pal = (code>>9)&0x30;\r
\r
- if (code&0x800) fTileFunc = TileFlipSH_and;\r
- else fTileFunc = TileNormSH_and;\r
+ if (code&0x800) fTileFunc = TileFlipSH_AS_and;\r
+ else fTileFunc = TileNormSH_AS_and;\r
\r
// parse remaining sprite data\r
sy=sprite[0];\r
delta<<=4; // Delta of address\r
\r
if (entry+1 == cnt) width = p[entry+1]; // last sprite width limited?\r
- for (; width; width--,sx+=8,tile+=delta)\r
+ mp = mb+(sx>>3);\r
+ for (m = *mp; width; width--, sx+=8, *mp++ = m, m >>= 8, tile+=delta)\r
{\r
unsigned int pack;\r
\r
if(sx>=328) break; // Offscreen\r
\r
pack = *(unsigned int *)(PicoMem.vram + (tile & 0x7fff));\r
- fTileFunc(pd + sx, pack, pal);\r
- }\r
+\r
+ m |= mp[1] << 8; // next mask byte\r
+ // shift mask bits to bits 8-15 for easier load/store handling\r
+ m = fTileFunc(pd + sx, m << (8-(sx&0x7)), pack, pal) >> (8-(sx&0x7));\r
+ } \r
+ *mp = m; // write last mask byte\r
}\r
+\r
+ // anything not covered by a sprite is off (XXX or bg?)\r
+ for (cnt = 1; cnt < sizeof(mb)-1; cnt++)\r
+ if (mb[cnt] == 0xff)\r
+ for (m = 0; m < 8; m++)\r
+ pd[8*cnt+m] = 0;\r
+ else if (mb[cnt])\r
+ for (m = 0; m < 8; m++)\r
+ if (mb[cnt] & (1<<m))\r
+ pd[8*cnt+m] = 0;\r
}\r
+#endif\r
\r
\r
// Index + 0 : ----hhvv -lllllll -------y yyyyyyyy\r
/* - layer B low - */\r
if (!(pvid->debug_p & PVD_KILL_B)) {\r
lflags = LF_PLANE_1 | (sh << 1);\r
- if (pvid->debug_p & PVD_FORCE_B)\r
- lflags |= LF_FORCE;\r
DrawLayer(lflags, HighCacheB, 0, maxcells, est);\r
}\r
/* - layer A low - */\r
lflags = 0 | (sh << 1);\r
- if (pvid->debug_p & PVD_FORCE_A)\r
- lflags |= LF_FORCE;\r
if (pvid->debug_p & PVD_KILL_A)\r
;\r
else if (hvwind == 1)\r
else if (sprited[1] & SPRL_HAVE_HI)\r
DrawAllSprites(sprited, 1, 0, est);\r
\r
- if (pvid->debug_p & PVD_FORCE_B)\r
- DrawTilesFromCacheForced(HighCacheB);\r
- else if (pvid->debug_p & PVD_FORCE_A)\r
- DrawTilesFromCacheForced(HighCacheA);\r
- else if (pvid->debug_p & PVD_FORCE_S)\r
+#ifdef FORCE\r
+ if (pvid->debug_p & PVD_FORCE_B) {\r
+ lflags = LF_PLANE_1 | (sh << 1);\r
+ DrawLayerForced(lflags, 0, maxcells, est);\r
+ } else if (pvid->debug_p & PVD_FORCE_A) {\r
+ lflags = (sh << 1);\r
+ DrawLayerForced(lflags, 0, maxcells, est);\r
+ } else if (pvid->debug_p & PVD_FORCE_S)\r
DrawSpritesForced(sprited);\r
+#endif\r
\r
#if 0\r
{\r