X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=pico%2Fdraw.c;h=e474168cf0d416240a3fa1f8c4f5ed736fefad4f;hb=b60b8745c02ebe6fb6584161b4ee5feae1716000;hp=551b3d645f44e642ab181ef3caf20187eecdc808;hpb=1cfc5cc4ce06642b9bc45ca3b9d32793718e9455;p=picodrive.git diff --git a/pico/draw.c b/pico/draw.c index 551b3d6..e474168 100644 --- a/pico/draw.c +++ b/pico/draw.c @@ -10,12 +10,23 @@ * The renderer has 4 modes now: * - normal * - shadow/hilight (s/h) - * - "sonic mode" for midline palette changes - * - accurate sprites (AS) + * - "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. * "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 - - + * 01 shadow - pal index + * 10 hilight+op spr 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" @@ -29,7 +40,7 @@ unsigned char *HighCol=DefHighCol; #else unsigned char HighCol[8+320+8]; #endif -unsigned short DefOutBuff[320*2]; +static unsigned int DefOutBuff[320*2/2]; void *DrawLineDest=DefOutBuff; // pointer to dest buffer where to draw this line to static int HighCacheA[41+1]; // caches for high layers @@ -42,8 +53,9 @@ int HighPreSpr[80*2+1]; // slightly preprocessed sprites #define SPRL_LO_ABOVE_HI 0x10 // low priority sprites may be on top of hi unsigned char HighLnSpr[240][3 + MAX_LINE_SPRITES]; // sprite_count, ^flags, tile_count, [spritep]... -int rendstatus = 0; -int DrawScanline = 0; +int rendstatus, rendstatus_old; +int rendlines; +int DrawScanline; int PicoDrawMask = -1; static int skip_next_line=0; @@ -63,13 +75,11 @@ struct TileStrip // stuff available in asm: #ifdef _ASM_DRAW_C void DrawWindow(int tstart, int tend, int prio, int sh); -void BackFill(int reg7, int sh); void DrawAllSprites(unsigned char *sprited, int prio, int sh); void DrawTilesFromCache(int *hc, int sh, int rlim); void DrawSpritesSHi(unsigned char *sprited); void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells); -void FinalizeLineBGR444(int sh); -void FinalizeLineRGB555(int sh); +void FinalizeLineBGR444(int sh, int line); void *blockcpy(void *dst, const void *src, size_t n); void blockcpy_or(void *dst, void *src, size_t n, int pat); #else @@ -150,25 +160,25 @@ TileFlipMaker(TileFlip,pix_just_write) // draw a sprite pixel, process operator colors #define pix_sh(x) \ if (!t); \ - else if (t==0xe) pd[x]=(pd[x]&0x3f)|0x80; /* hilight */ \ - else if (t==0xf) pd[x]= pd[x] |0xc0; /* shadow */ \ + else if (t>=0xe) pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \ else pd[x]=pal|t TileNormMaker(TileNormSH, pix_sh) TileFlipMaker(TileFlipSH, pix_sh) -// draw a sprite pixel ignoring operator colors -#define pix_sh_noop(x) \ - if (t && t < 0xe) \ - pd[x]=pal|t +// draw a sprite pixel, mark operator colors +#define pix_sh_markop(x) \ + if (!t); \ + else if (t>=0xe) pd[x]|=0x80; \ + else pd[x]=pal|t -TileNormMaker(TileNormSH_noop, pix_sh_noop) -TileFlipMaker(TileFlipSH_noop, pix_sh_noop) +TileNormMaker(TileNormSH_markop, pix_sh_markop) +TileFlipMaker(TileFlipSH_markop, pix_sh_markop) -// process operator pixels only, apply only on low pri tiles +// process operator pixels only, apply only on low pri tiles and other op pixels #define pix_sh_onlyop(x) \ - if (t==0xe && (pd[x]&0x40)) pd[x]=(pd[x]&0x3f)|0x80; /* hilight */ \ - else if (t==0xf && (pd[x]&0x40)) pd[x]= pd[x] |0xc0; /* shadow */ + if (t>=0xe && (pd[x]&0xc0)) \ + pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \ TileNormMaker(TileNormSH_onlyop_lp, pix_sh_onlyop) TileFlipMaker(TileFlipSH_onlyop_lp, pix_sh_onlyop) @@ -501,8 +511,8 @@ static void DrawWindow(int tstart, int tend, int prio, int sh) // int *hcache if (prio) { int *zb = (int *)(HighCol+8+(tilex<<3)); - *zb++ &= 0x3f3f3f3f; - *zb &= 0x3f3f3f3f; + *zb++ &= 0xbfbfbfbf; + *zb &= 0xbfbfbfbf; } else { pal |= 0x40; } @@ -524,12 +534,13 @@ static void DrawWindow(int tstart, int tend, int prio, int sh) // int *hcache static void DrawTilesFromCacheShPrep(void) { // 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. + // we can process whole line and then act as if sh/hi mode was off, + // but leave lo pri op sprite markers alone int c = 320/4, *zb = (int *)(HighCol+8); rendstatus |= PDRAW_SHHI_DONE; while (c--) { - *zb++ &= 0x3f3f3f3f; + *zb++ &= 0xbfbfbfbf; } } @@ -576,8 +587,8 @@ static void DrawTilesFromCache(int *hc, int sh, int rlim) addr+=(unsigned int)code>>25; // y offset into tile dx=(code>>16)&0x1ff; zb = HighCol+dx; - *zb++ &= 0x3f; *zb++ &= 0x3f; *zb++ &= 0x3f; *zb++ &= 0x3f; - *zb++ &= 0x3f; *zb++ &= 0x3f; *zb++ &= 0x3f; *zb++ &= 0x3f; + *zb++ &= 0xbf; *zb++ &= 0xbf; *zb++ &= 0xbf; *zb++ &= 0xbf; + *zb++ &= 0xbf; *zb++ &= 0xbf; *zb++ &= 0xbf; *zb++ &= 0xbf; pal=((code>>9)&0x30); if (rlim-dx < 0) goto last_cut_tile; @@ -661,8 +672,8 @@ static void DrawSprite(int *sprite, int sh) pal|=sh<<6; if (sh && (code&0x6000) == 0x6000) { - if(code&0x0800) fTileFunc=TileFlipSH_noop; - else fTileFunc=TileNormSH_noop; + if(code&0x0800) fTileFunc=TileFlipSH_markop; + else fTileFunc=TileNormSH_markop; } else { if(code&0x0800) fTileFunc=TileFlip; else fTileFunc=TileNorm; @@ -771,8 +782,13 @@ static void DrawAllSpritesInterlace(int pri, int sh) #ifndef _ASM_DRAW_C -// Index + 0 : hhhhvvvv ----hhvv yyyyyyyy yyyyyyyy // v, h: vert./horiz. size -// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 +/* + * s/h drawing: lo_layers|40, lo_sprites|40 && mark_op, + * hi_layers&=~40, hi_sprites + * + * Index + 0 : hhhhvvvv ----hhvv yyyyyyyy yyyyyyyy // v, h: vert./horiz. size + * Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + */ static void DrawSpritesSHi(unsigned char *sprited) { int (*fTileFunc)(int sx,int addr,int pal); @@ -915,10 +931,11 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh) /* nasty 1: remove 'sprite' flags */ { - int c = 320/4, *zb = (int *)(HighCol+8); + int c = 320/4/4, *zb = (int *)(HighCol+8); while (c--) { - *zb++ &= 0x7f7f7f7f; + *zb++ &= 0x7f7f7f7f; *zb++ &= 0x7f7f7f7f; + *zb++ &= 0x7f7f7f7f; *zb++ &= 0x7f7f7f7f; } } @@ -1122,7 +1139,7 @@ static void DrawAllSprites(unsigned char *sprited, int prio, int sh) // -------------------------------------------- -static void BackFill(int reg7, int sh) +void BackFill(int reg7, int sh) { unsigned int back; @@ -1143,20 +1160,24 @@ unsigned short HighPal[0x100]; #ifndef _ASM_DRAW_C void PicoDoHighPal555(int sh) { + unsigned int *spal, *dpal; unsigned short *pal=HighPal; int i, t; Pico.m.dirtyPal = 0; - { - unsigned int *spal=(void *)Pico.cram; - unsigned int *dpal=(void *)HighPal; - for (i = 0x3f/2; i >= 0; i--) + spal = (void *)Pico.cram; + dpal = (void *)HighPal; + + for (i = 0; i < 0x40; i++) { + unsigned int t = spal[i]; #ifdef USE_BGR555 - dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4); + t = ((t & 0x000e000e)<< 1) | ((t & 0x00e000e0)<<3) | ((t & 0x0e000e00)<<4); #else - dpal[i] = ((spal[i]&0x000f000f)<<12)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)>>7); + t = ((t & 0x000e000e)<<12) | ((t & 0x00e000e0)<<3) | ((t & 0x0e000e00)>>7); #endif + t |= (t >> 3) & 0x18e318e3; + dpal[i] = t; } if (sh) @@ -1172,7 +1193,7 @@ void PicoDoHighPal555(int sh) } } -static void FinalizeLineBGR444(int sh) +static void FinalizeLineBGR444(int sh, int line) { unsigned short *pd=DrawLineDest; unsigned char *ps=HighCol+8; @@ -1210,7 +1231,7 @@ static void FinalizeLineBGR444(int sh) } -static void FinalizeLineRGB555(int sh) +void FinalizeLineRGB555(int sh, int line) { unsigned short *pd=DrawLineDest; unsigned char *ps=HighCol+8; @@ -1246,13 +1267,13 @@ static void FinalizeLineRGB555(int sh) } #endif -static void FinalizeLine8bit(int sh) +static void FinalizeLine8bit(int sh, int line) { - unsigned char *pd=DrawLineDest; + unsigned char *pd = DrawLineDest; int len, rs = rendstatus; static int dirty_count; - if (!sh && Pico.m.dirtyPal == 1 && DrawScanline < 222) + if (!sh && Pico.m.dirtyPal == 1) { // a hack for mid-frame palette changes if (!(rs & PDRAW_SONIC_MODE)) @@ -1270,7 +1291,8 @@ static void FinalizeLine8bit(int sh) if (Pico.video.reg[12]&1) { len = 320; } else { - if (!(PicoOpt&POPT_DIS_32C_BORDER)) pd+=32; + if (!(PicoOpt & POPT_DIS_32C_BORDER)) + pd += 32; len = 256; } @@ -1285,26 +1307,10 @@ static void FinalizeLine8bit(int sh) } } -static void (*FinalizeLine)(int sh) = FinalizeLineBGR444; +static void (*FinalizeLine)(int sh, int line); // -------------------------------------------- -static void DrawBlankedLine(void) -{ - int sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight? - - if (PicoScanBegin != NULL) - PicoScanBegin(DrawScanline); - - BackFill(Pico.video.reg[7], sh); - - if (FinalizeLine != NULL) - FinalizeLine(sh); - - if (PicoScanEnd != NULL) - PicoScanEnd(DrawScanline); -} - static int DrawDisplay(int sh) { unsigned char *sprited = &HighLnSpr[DrawScanline][0]; @@ -1399,62 +1405,117 @@ static int DrawDisplay(int sh) // MUST be called every frame PICO_INTERNAL void PicoFrameStart(void) { + int lines = 224; + // prepare to do this frame rendstatus = 0; - if ((Pico.video.reg[12]&6) == 6) + if ((Pico.video.reg[12] & 6) == 6) rendstatus |= PDRAW_INTERLACE; // interlace mode + if (!(Pico.video.reg[12] & 1)) + rendstatus |= PDRAW_32_COLS; + if (Pico.video.reg[1] & 8) + lines = 240; + + DrawScanline = 0; + skip_next_line = 0; + + if (rendstatus != rendstatus_old || lines != rendlines) { + rendlines = lines; + // mode_change() might reset rendstatus_old by calling SetColorFormat + emu_video_mode_change((lines == 240) ? 0 : 8, + lines, (Pico.video.reg[12] & 1) ? 0 : 1); + rendstatus_old = rendstatus; + } - if (Pico.m.dirtyPal) Pico.m.dirtyPal = 2; // reset dirty if needed + if (PicoOpt & POPT_ALT_RENDERER) + return; - DrawScanline=0; + if (Pico.m.dirtyPal) + Pico.m.dirtyPal = 2; // reset dirty if needed PrepareSprites(1); - skip_next_line=0; } -static void PicoLine(void) +static void DrawBlankedLine(int line, int offs, int sh, int bgc) +{ + if (PicoScanBegin != NULL) + PicoScanBegin(line + offs); + + BackFill(bgc, sh); + + if (FinalizeLine != NULL) + FinalizeLine(sh, line); + + if (PicoScanEnd != NULL) + PicoScanEnd(line + offs); +} + +static void PicoLine(int line, int offs, int sh, int bgc) { - int sh; - if (skip_next_line>0) { skip_next_line--; return; } // skip rendering lines + int skip = 0; - sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight? + if (skip_next_line > 0) { + skip_next_line--; + return; + } + DrawScanline = line; if (PicoScanBegin != NULL) - skip_next_line = PicoScanBegin(DrawScanline); + skip = PicoScanBegin(line + offs); + + if (skip) { + skip_next_line = skip - 1; + return; + } // Draw screen: - BackFill(Pico.video.reg[7], sh); + BackFill(bgc, sh); if (Pico.video.reg[1]&0x40) DrawDisplay(sh); if (FinalizeLine != NULL) - FinalizeLine(sh); + FinalizeLine(sh, line); if (PicoScanEnd != NULL) - skip_next_line = PicoScanEnd(DrawScanline); + skip_next_line = PicoScanEnd(line + offs); } void PicoDrawSync(int to, int blank_last_line) { - for (; DrawScanline < to; DrawScanline++) + int line, offs = 0; + int sh = (Pico.video.reg[0xC] & 8) >> 3; // shadow/hilight? + int bgc = Pico.video.reg[7]; + + if (rendlines != 240) + offs = 8; + + // need to know which pixels are bg for 32x + if (PicoAHW & PAHW_32X) + bgc = 0; + + for (line = DrawScanline; line < to; line++) { #if !CAN_HANDLE_240_LINES - if (DrawScanline >= 224) break; + if (line >= 224) break; #endif - PicoLine(); + PicoLine(line, offs, sh, bgc); } #if !CAN_HANDLE_240_LINES - if (DrawScanline >= 224) { DrawScanline = 240; return; } + if (line >= 224) { + DrawScanline = 240; + return; + } #endif // last line - if (DrawScanline <= to) + if (line <= to) { if (blank_last_line) - DrawBlankedLine(); - else PicoLine(); - DrawScanline++; + DrawBlankedLine(line, offs, sh, bgc); + else PicoLine(line, offs, sh, bgc); + line++; } + DrawScanline = line; } void PicoDrawSetColorFormat(int which) @@ -1462,12 +1523,15 @@ void PicoDrawSetColorFormat(int which) switch (which) { case 2: FinalizeLine = FinalizeLine8bit; break; - case 1: FinalizeLine = FinalizeLineRGB555; break; + case 1: FinalizeLine = (PicoAHW & PAHW_32X) ? FinalizeLine32xRGB555 : FinalizeLineRGB555; break; case 0: FinalizeLine = FinalizeLineBGR444; break; default:FinalizeLine = NULL; break; } + PicoDrawSetColorFormatMode4(which); + rendstatus_old = -1; #if OVERRIDE_HIGHCOL - if (which) HighCol=DefHighCol; + if (which) + HighCol=DefHighCol; #endif }