X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=Pico%2FDraw.c;h=20a18de1b47ae7ba785e5e96e7bb0e1851cf7d19;hb=7d4906bfc93ced40a544534f433f06b00add52b0;hp=2eed289f069538cb62008c26f1a99ec8ed351fb0;hpb=cc68a136aa179a5f32fe40208371eb9c2b0aadae;p=picodrive.git diff --git a/Pico/Draw.c b/Pico/Draw.c index 2eed289..20a18de 100644 --- a/Pico/Draw.c +++ b/Pico/Draw.c @@ -8,24 +8,27 @@ #include "PicoInt.h" -#ifndef __GNUC__ -#pragma warning (disable:4706) // Disable assignment within conditional -#endif int (*PicoScan)(unsigned int num, void *data)=NULL; -unsigned short DefOutBuff[320*2]; +#if OVERRIDE_HIGHCOL +static unsigned char DefHighCol[8+320+8]; +unsigned char *HighCol=DefHighCol; +#else unsigned char HighCol[8+320+8]; +#endif +unsigned short DefOutBuff[320*2]; +void *DrawLineDest=DefOutBuff; // pointer to dest buffer where to draw this line to + static int HighCacheA[41+1]; // caches for high layers static int HighCacheB[41+1]; static int HighCacheS[80+1]; // and sprites static int HighPreSpr[80*2+1]; // slightly preprocessed sprites char HighSprZ[320+8+8]; // Z-buffer for accurate sprites and shadow/hilight mode // (if bit 7 == 0, sh caused by tile; if bit 6 == 0 pixel must be shadowed, else hilighted, if bit5 == 1) -// lsb->msb: moved sprites, all window tiles don't use same priority, accurate sprites (copied from PicoOpt), interlace -// dirty sprites, sonic mode +// lsb->msb: moved sprites, not all window tiles use same priority, accurate sprites (copied from PicoOpt), interlace +// dirty sprites, sonic mode, have layer with all hi prio tiles (mk3), layer sh/hi already processed int rendstatus; -void *DrawLineDest=DefOutBuff; // pointer to dest buffer where to draw this line to int Scanline=0; // Scanline static int SpriteBlocks; @@ -34,7 +37,7 @@ static int SpriteBlocks; struct TileStrip { int nametab; // Position in VRAM of name table (for this tile line) - int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap + int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap int hscroll; // Horizontal scroll value in pixels for the line int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap int *hc; // cache for high tile codes and their positions @@ -46,9 +49,9 @@ struct TileStrip void DrawWindow(int tstart, int tend, int prio, int sh); void BackFill(int reg7, int sh); void DrawSprite(int *sprite, int **hc, int sh); -void DrawTilesFromCache(int *hc, int sh); +void DrawTilesFromCache(int *hc, int sh, int rlim); void DrawSpritesFromCache(int *hc, int sh); -void DrawLayer(int plane, int *hcache, int maxcells, int sh); +void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells); void FinalizeLineBGR444(int sh); void FinalizeLineRGB555(int sh); void blockcpy_or(void *dst, void *src, size_t n, int pat); @@ -271,20 +274,22 @@ static int TileFlipZSH(int sx,int addr,int pal,int zval) // -------------------------------------------- #ifndef _ASM_DRAW_C -static void DrawStrip(struct TileStrip *ts, int sh) +static void DrawStrip(struct TileStrip *ts, int plane_sh, int cellskip) { - int tilex=0,dx=0,ty=0,code=0,addr=0,cells; + int tilex,dx,ty,code=0,addr=0,cells; int oldcode=-1,blank=-1; // The tile we know is blank - int pal=0; + int pal=0,sh; // Draw tiles across screen: - tilex=(-ts->hscroll)>>3; + sh=(plane_sh<<5)&0x40; + tilex=((-ts->hscroll)>>3)+cellskip; ty=(ts->line&7)<<1; // Y-Offset into tile dx=((ts->hscroll-1)&7)+1; - cells = ts->cells; + cells = ts->cells - cellskip; if(dx != 8) cells++; // have hscroll, need to draw 1 cell more + dx+=cellskip<<3; - for (; cells; dx+=8,tilex++,cells--) + for (; cells > 0; dx+=8,tilex++,cells--) { int zero=0; @@ -304,8 +309,7 @@ static void DrawStrip(struct TileStrip *ts, int sh) addr+=ty; if (code&0x1000) addr^=0xe; // Y-flip -// pal=Pico.cram+((code>>9)&0x30); - pal=((code>>9)&0x30)|(sh<<6); + pal=((code>>9)&0x30)|sh; } if (code&0x0800) zero=TileFlip(dx,addr,pal); @@ -316,41 +320,33 @@ static void DrawStrip(struct TileStrip *ts, int sh) // terminate the cache list *ts->hc = 0; + // if oldcode wasn't changed, it means all layer is hi priority + if (oldcode == -1) rendstatus|=0x40; } -#endif // this is messy -#ifndef _ASM_DRAW_C -static -#endif -void DrawStripVSRam(struct TileStrip *ts, int plane) +void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip) { - int tilex=0,dx=0,ty=0,code=0,addr=0,cell=0,nametabadd=0; + int tilex,dx,code=0,addr=0,cell=0; int oldcode=-1,blank=-1; // The tile we know is blank int pal=0,scan=Scanline; // Draw tiles across screen: tilex=(-ts->hscroll)>>3; dx=((ts->hscroll-1)&7)+1; - if(dx != 8) { - int vscroll, line; - cell--; // have hscroll, start with negative cell - // also calculate intial VS stuff - vscroll=Pico.vsram[plane]; - - // Find the line in the name table - line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. - nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] - ty=(line&7)<<1; // Y-Offset into tile - } + if(dx != 8) cell--; // have hscroll, start with negative cell + cell+=cellskip; + tilex+=cellskip; + dx+=cellskip<<3; for (; cell < ts->cells; dx+=8,tilex++,cell++) { - int zero=0; + int zero=0,nametabadd,ty; - if((cell&1)==0) { + //if((cell&1)==0) + { int line,vscroll; - vscroll=Pico.vsram[plane+(cell&~1)]; + vscroll=Pico.vsram[(plane_sh&1)+(cell&~1)]; // Find the line in the name table line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. @@ -373,8 +369,7 @@ void DrawStripVSRam(struct TileStrip *ts, int plane) addr=(code&0x7ff)<<4; if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip -// pal=Pico.cram+((code>>9)&0x30); - pal=((code>>9)&0x30); + pal=((code>>9)&0x30)|((plane_sh<<5)&0x40); } if (code&0x0800) zero=TileFlip(dx,addr,pal); @@ -385,7 +380,9 @@ void DrawStripVSRam(struct TileStrip *ts, int plane) // terminate the cache list *ts->hc = 0; + if (oldcode == -1) rendstatus|=0x40; } +#endif #ifndef _ASM_DRAW_C static @@ -440,7 +437,7 @@ void DrawStripInterlace(struct TileStrip *ts) // -------------------------------------------- #ifndef _ASM_DRAW_C -static void DrawLayer(int plane, int *hcache, int maxcells, int sh) +static void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells) { struct PicoVideo *pvid=&Pico.video; const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid) @@ -463,20 +460,20 @@ static void DrawLayer(int plane, int *hcache, int maxcells, int sh) else if(width>1) ymask =0x0ff; // Find name table: - if (plane==0) ts.nametab=(pvid->reg[2]&0x38)<< 9; // A - else ts.nametab=(pvid->reg[4]&0x07)<<12; // B + if (plane_sh&1) ts.nametab=(pvid->reg[4]&0x07)<<12; // B + else ts.nametab=(pvid->reg[2]&0x38)<< 9; // A htab=pvid->reg[13]<<9; // Horizontal scroll table address if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile - htab+=plane; // A or B + htab+=plane_sh&1; // A or B // Get horizontal scroll value, will be masked later ts.hscroll=Pico.vram[htab&0x7fff]; if((pvid->reg[12]&6) == 6) { // interlace mode 2 - vscroll=Pico.vsram[plane]; // Get vertical scroll value + vscroll=Pico.vsram[plane_sh&1]; // Get vertical scroll value // Find the line in the name table ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1); @@ -487,15 +484,15 @@ static void DrawLayer(int plane, int *hcache, int maxcells, int sh) // shit, we have 2-cell column based vscroll // luckily this doesn't happen too often ts.line=ymask|(shift[width]<<24); // save some stuff instead of line - DrawStripVSRam(&ts, plane); + DrawStripVSRam(&ts, plane_sh, cellskip); } else { - vscroll=Pico.vsram[plane]; // Get vertical scroll value + vscroll=Pico.vsram[plane_sh&1]; // Get vertical scroll value // Find the line in the name table ts.line=(vscroll+Scanline)&ymask; ts.nametab+=(ts.line>>3)<hc++ = code | (dx<<16) | (ty<<25); // cache it - while((code=*hc++)) { - if(!sh && (short)code == blank) continue; + if (sh && (rendstatus&0xc0)) + { + if (!(rendstatus&0x80)) + { + // as some layer has covered whole line with hi priority tiles, + // we can process whole line and then act as if sh/hi mode was off. + rendstatus|=0x80; + int c = 320/4, *zb = (int *)(HighCol+8); + while (c--) + { + int tmp = *zb; + if (!(tmp & 0x80808080)) *zb=tmp&0x3f3f3f3f; + else { + if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; + if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; + *zb=tmp; + } + zb++; + } + } + sh = 0; + } - // Get tile address/2: - addr=(code&0x7ff)<<4; - addr+=(unsigned int)code>>25; // y offset into tile - dx=(code>>16)&0x1ff; - if(sh) { - unsigned char *zb = HighCol+dx; + if (sh) + { + while ((code=*hc++)) { + unsigned char *zb; + // Get tile address/2: + addr=(code&0x7ff)<<4; + addr+=(unsigned int)code>>25; // y offset into tile + dx=(code>>16)&0x1ff; + zb = HighCol+dx; if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + + pal=((code>>9)&0x30); + if (rlim-dx < 0) goto last_cut_tile; + + if (code&0x0800) TileFlip(dx,addr,pal); + else TileNorm(dx,addr,pal); } + } + else + { + short blank=-1; // The tile we know is blank + while ((code=*hc++)) { + int zero; + if((short)code == blank) continue; + // Get tile address/2: + addr=(code&0x7ff)<<4; + addr+=(unsigned int)code>>25; // y offset into tile + dx=(code>>16)&0x1ff; - pal=((code>>9)&0x30); + pal=((code>>9)&0x30); + if (rlim-dx < 0) goto last_cut_tile; - if (code&0x0800) zero=TileFlip(dx,addr,pal); - else zero=TileNorm(dx,addr,pal); + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); - if(zero) blank=(short)code; + if (zero) blank=(short)code; + } + } + return; + +last_cut_tile: + { + unsigned int t, pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + unsigned char *pd = HighCol+dx; + if (!pack) return; + if (code&0x0800) + { + switch (rlim-dx+8) + { + case 7: t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8)); // "break" is left out intentionally + case 6: t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4)); + case 5: t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t )); + case 4: t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28)); + case 3: t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24)); + case 2: t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20)); + case 1: t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16)); + default: break; + } + } + else + { + switch (rlim-dx+8) + { + case 7: t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20)); + case 6: t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24)); + case 5: t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28)); + case 4: t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t )); + case 3: t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4)); + case 2: t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8)); + case 1: t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12)); + default: break; + } + } } } @@ -921,13 +995,13 @@ static void PrepareSprites(int full) height = (hv&3)+1; if(sy > 240 || sy + (height<<3) <= 0) skip|=1<<22; - + width = (hv>>2)+1; code2 = sprite[1]; sx = (code2>>16)&0x1ff; sx -= 0x78; // Get X coordinate + 8 sx_min = 8-(width<<3); - + if((sx <= sx_min && sx >= -0x76) || sx >= 328) skip|=1<<23; else if (sx > sx_min && !skip) { int sbl = (2<>16)&0x7f; if(!link) break; // End of sprites @@ -1182,7 +1256,7 @@ static void FinalizeLine8bit(int sh) } } -void (*FinalizeLine)(int sh) = FinalizeLineBGR444; +static void (*FinalizeLine)(int sh) = FinalizeLineBGR444; // -------------------------------------------- @@ -1192,6 +1266,8 @@ static int DrawDisplay(int sh) int win=0,edge=0,hvwind=0; int maxw, maxcells; + rendstatus&=~0xc0; + if(pvid->reg[12]&1) { maxw = 328; maxcells = 40; } else { @@ -1205,47 +1281,56 @@ static int DrawDisplay(int sh) if (win&0x80) { if (Scanline>=edge) hvwind=1; } else { if (Scanline< edge) hvwind=1; } - if(!hvwind) { // we might have a vertical window here + if (!hvwind) { // we might have a vertical window here win=pvid->reg[0x11]; edge=win&0x1f; - if(win&0x80) { - if(!edge) hvwind=1; + if (win&0x80) { + if (!edge) hvwind=1; else if(edge < (maxcells>>1)) hvwind=2; } else { - if(!edge); + if (!edge); else if(edge < (maxcells>>1)) hvwind=2; else hvwind=1; } } - DrawLayer(1, HighCacheB, maxcells, sh); - if(hvwind == 1) - DrawWindow(0, maxcells>>1, 0, sh); // HighCacheAW - else if(hvwind == 2) { + DrawLayer(1|(sh<<1), HighCacheB, 0, maxcells); + if (hvwind == 1) + DrawWindow(0, maxcells>>1, 0, sh); + else if (hvwind == 2) { // ahh, we have vertical window - DrawLayer(0, HighCacheA, (win&0x80) ? edge<<1 : maxcells, sh); - DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 0, sh); // HighCacheW + DrawLayer(0|(sh<<1), HighCacheA, (win&0x80) ? 0 : edge<<1, (win&0x80) ? edge<<1 : maxcells); + DrawWindow( (win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 0, sh); } else - DrawLayer(0, HighCacheA, maxcells, sh); + DrawLayer(0|(sh<<1), HighCacheA, 0, maxcells); DrawAllSprites(HighCacheS, maxw, 0, sh); - if(HighCacheB[0]) DrawTilesFromCache(HighCacheB, sh); - if(hvwind == 1) + if (HighCacheB[0]) DrawTilesFromCache(HighCacheB, sh, 328); + if (hvwind == 1) DrawWindow(0, maxcells>>1, 1, sh); - else if(hvwind == 2) { - if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh); + else if (hvwind == 2) { + if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : 328); DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh); } else - if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh); + if (HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh, 328); DrawAllSprites(HighCacheS, maxw, 1, sh); +#if 0 + { + int *c, a, b; + for (a = 0, c = HighCacheA; *c; c++, a++); + for (b = 0, c = HighCacheB; *c; c++, b++); + printf("%i:%03i: a=%i, b=%i\n", Pico.m.frame_count, Scanline, a, b); + } +#endif + return 0; } static int Skip=0; -void PicoFrameStart() +PICO_INTERNAL void PicoFrameStart(void) { // prepare to do this frame rendstatus = (PicoOpt&0x80)>>5; // accurate sprites @@ -1259,7 +1344,7 @@ void PicoFrameStart() Skip=0; } -int PicoLine(int scan) +PICO_INTERNAL int PicoLine(int scan) { int sh; if (Skip>0) { Skip--; return 0; } // Skip rendering lines @@ -1272,8 +1357,8 @@ int PicoLine(int scan) if (Pico.video.reg[1]&0x40) DrawDisplay(sh); - FinalizeLine(sh); - //if (SpriteBlocks & (1<<(scan>>3))) for (sh=0; sh < 30; sh++) DrawLineDest[sh] = 0xf; + if (FinalizeLine != NULL) + FinalizeLine(sh); Skip=PicoScan(Scanline,DrawLineDest); @@ -1283,9 +1368,15 @@ int PicoLine(int scan) void PicoDrawSetColorFormat(int which) { - if (which == 2) - FinalizeLine = FinalizeLine8bit; - else if (which == 1) - FinalizeLine = FinalizeLineRGB555; - else FinalizeLine = FinalizeLineBGR444; + switch (which) + { + case 2: FinalizeLine = FinalizeLine8bit; break; + case 1: FinalizeLine = FinalizeLineRGB555; break; + case 0: FinalizeLine = FinalizeLineBGR444; break; + default:FinalizeLine = NULL; break; + } +#if OVERRIDE_HIGHCOL + if (which) HighCol=DefHighCol; +#endif } +