X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=picodrive.git;a=blobdiff_plain;f=pico%2Fmode4.c;h=bda1188802a8bf9cf7eb40c8f0a52af0d3b51381;hp=7062a1775b36720c62c4a71bb486a4cf773e725a;hb=e0bcb7a90d06b295b1ca989b6ad70412912cca5b;hpb=200772b7904a4851c1beff5ea90b233274639ef4 diff --git a/pico/mode4.c b/pico/mode4.c index 7062a17..bda1188 100644 --- a/pico/mode4.c +++ b/pico/mode4.c @@ -1,7 +1,23 @@ +/* + * mode4/SMS renderer + * (C) notaz, 2009-2010 + * + * This work is licensed under the terms of MAME license. + * See COPYING file in the top-level directory. + */ +/* + * TODO: + * - TMS9918 modes? + * - gg mode? + * - column scroll (reg 0 bit7) + * - 224/240 line modes + * - doubled sprites + */ #include "pico_int.h" -static void (*FinalizeLineM4)(void); +static void (*FinalizeLineM4)(int line); static int skip_next_line; +static int screen_offset; #define PLANAR_PIXEL(x,p) \ t = pack & (0x80808080 >> p); \ @@ -12,7 +28,7 @@ static int skip_next_line; static int TileNormM4(int sx, int addr, int pal) { - unsigned char *pd = HighCol + sx; + unsigned char *pd = Pico.est.HighCol + sx; unsigned int pack, t; pack = *(unsigned int *)(Pico.vram + addr); /* Get 4 bitplanes / 8 pixels */ @@ -34,7 +50,7 @@ static int TileNormM4(int sx, int addr, int pal) static int TileFlipM4(int sx,int addr,int pal) { - unsigned char *pd = HighCol + sx; + unsigned char *pd = Pico.est.HighCol + sx; unsigned int pack, t; pack = *(unsigned int *)(Pico.vram + addr); /* Get 4 bitplanes / 8 pixels */ @@ -54,85 +70,156 @@ static int TileFlipM4(int sx,int addr,int pal) return 1; /* Tile blank */ } -struct TileStrip +static void draw_sprites(int scanline) { - 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 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 - int cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320) -}; - -static void DrawStrip(struct TileStrip *ts, int cellskip) + struct PicoVideo *pv = &Pico.video; + unsigned int sprites_addr[8]; + unsigned int sprites_x[8]; + unsigned char *sat; + int xoff = 8; // relative to HighCol, which is (screen - 8) + int sprite_base, addr_mask; + int i, s, h; + + if (pv->reg[0] & 8) + xoff = 0; + + sat = (unsigned char *)Pico.vram + ((pv->reg[5] & 0x7e) << 7); + if (pv->reg[1] & 2) { + addr_mask = 0xfe; h = 16; + } else { + addr_mask = 0xff; h = 8; + } + sprite_base = (pv->reg[6] & 4) << (13-2-1); + + for (i = s = 0; i < 64 && s < 8; i++) + { + int y; + y = sat[i] + 1; + if (y == 0xd1) + break; + if (y + h <= scanline || scanline < y) + continue; // not on this line + + sprites_x[s] = xoff + sat[0x80 + i*2]; + sprites_addr[s] = sprite_base + ((sat[0x80 + i*2 + 1] & addr_mask) << (5-1)) + + ((scanline - y) << (2-1)); + s++; + } + + // now draw all sprites backwards + for (--s; s >= 0; s--) + TileNormM4(sprites_x[s], sprites_addr[s], 0x10); +} + +// tilex_ty_prio merged to reduce register pressure +static void draw_strip(const unsigned short *nametab, int dx, int cells, int tilex_ty_prio) { - int tilex,dx,ty,code=0,addr=0,cells; - int oldcode=-1,blank=-1; // The tile we know is blank - int pal=0; + int oldcode = -1, blank = -1; // The tile we know is blank + int addr = 0, pal = 0; // Draw tiles across screen: - tilex=((-ts->hscroll)>>3)+cellskip; - ty=(ts->line&7)<<1; // Y-Offset into tile - dx=((ts->hscroll-1)&7)+1; - cells = ts->cells - cellskip; - if (dx != 8) cells++; // have hscroll, need to draw 1 cell more - dx+=cellskip<<3; - - for (; cells > 0; dx+=8,tilex++,cells--) + for (; cells > 0; dx += 8, tilex_ty_prio++, cells--) { - int zero; + int code, zero; - code=Pico.vram[ts->nametab + (tilex & 0x1f)]; - if (code==blank) continue; + code = nametab[tilex_ty_prio & 0x1f]; + if (code == blank) + continue; + if ((code ^ tilex_ty_prio) & 0x1000) // priority differs? + continue; - if (code!=oldcode) { + if (code != oldcode) { oldcode = code; // Get tile address/2: - addr=(code&0x1ff)<<4; - addr+=ty; - if (code&0x0400) addr^=0xe; // Y-flip + addr = (code & 0x1ff) << 4; + addr += tilex_ty_prio >> 16; + if (code & 0x0400) + addr ^= 0xe; // Y-flip - pal=((code>>7)&0x10); + pal = (code>>7) & 0x10; } - if (code&0x0200) zero=TileFlipM4(dx,addr,pal); - else zero=TileNormM4(dx,addr,pal); + if (code&0x0200) zero = TileFlipM4(dx, addr, pal); + else zero = TileNormM4(dx, addr, pal); - if (zero) blank=code; // We know this tile is blank now + if (zero) + blank = code; // We know this tile is blank now } } -static void DrawLayer(int cellskip, int maxcells) +static void DrawDisplayM4(int scanline) { - struct PicoVideo *pvid=&Pico.video; - struct TileStrip ts; - int vscroll; - - ts.cells=maxcells; - - // Find name table: - ts.nametab=(pvid->reg[2]&0x0e) << (10-1); - - // Get horizontal scroll value, will be masked later - ts.hscroll=0;//pvid->reg[8]; - vscroll=0;//pvid->reg[9]; // Get vertical scroll value + struct PicoVideo *pv = &Pico.video; + unsigned short *nametab; + int line, tilex, dx, ty, cells; + int cellskip = 0; // XXX + int maxcells = 32; // Find the line in the name table - ts.line=(vscroll+DrawScanline)&0xff; - ts.nametab+=(ts.line>>3) << (6-1); - - DrawStrip(&ts, cellskip); -} + line = pv->reg[9] + scanline; // vscroll + scanline + if (line >= 224) + line -= 224; -static void DrawDisplayM4(void) -{ - DrawLayer(0, 32); + // Find name table: + nametab = Pico.vram; + nametab += (pv->reg[2] & 0x0e) << (10-1); + nametab += (line>>3) << (6-1); + + dx = pv->reg[8]; // hscroll + if (scanline < 16 && (pv->reg[0] & 0x40)) + dx = 0; // hscroll disabled for top 2 rows + + tilex = ((-dx >> 3) + cellskip) & 0x1f; + ty = (line & 7) << 1; // Y-Offset into tile + cells = maxcells - cellskip; + + dx = ((dx - 1) & 7) + 1; + if (dx != 8) + cells++; // have hscroll, need to draw 1 cell more + dx += cellskip << 3; + + // low priority tiles + if (!(pv->debug_p & PVD_KILL_B)) + draw_strip(nametab, dx, cells, tilex | 0x0000 | (ty << 16)); + + // sprites + if (!(pv->debug_p & PVD_KILL_S_LO)) + draw_sprites(scanline); + + // high priority tiles (use virtual layer switch just for fun) + if (!(pv->debug_p & PVD_KILL_A)) + draw_strip(nametab, dx, cells, tilex | 0x1000 | (ty << 16)); + + if (pv->reg[0] & 0x20) + // first column masked + ((int *)Pico.est.HighCol)[2] = ((int *)Pico.est.HighCol)[3] = 0xe0e0e0e0; } void PicoFrameStartMode4(void) { - DrawScanline = 0; + int lines = 192; skip_next_line = 0; + screen_offset = 24; + Pico.est.rendstatus = PDRAW_32_COLS; + + if ((Pico.video.reg[0] & 6) == 6 && (Pico.video.reg[1] & 0x18)) { + if (Pico.video.reg[1] & 0x08) { + screen_offset = 0; + lines = 240; + } + else { + screen_offset = 8; + lines = 224; + } + } + + if (Pico.est.rendstatus != rendstatus_old || lines != rendlines) { + emu_video_mode_change(screen_offset, lines, 1); + rendstatus_old = Pico.est.rendstatus; + rendlines = lines; + } + + Pico.est.DrawLineDest = (char *)DrawLineDestBase + screen_offset * DrawLineDestIncrement; } void PicoLineMode4(int line) @@ -142,27 +229,27 @@ void PicoLineMode4(int line) return; } - DrawScanline = line; - if (PicoScanBegin != NULL) - skip_next_line = PicoScanBegin(DrawScanline); + skip_next_line = PicoScanBegin(line + screen_offset); // Draw screen: - BackFill((Pico.video.reg[7] & 0x0f) | 0x10, 0); + BackFill(Pico.video.reg[7] & 0x0f, 0, &Pico.est); if (Pico.video.reg[1] & 0x40) - DrawDisplayM4(); + DrawDisplayM4(line); if (FinalizeLineM4 != NULL) - FinalizeLineM4(); + FinalizeLineM4(line); if (PicoScanEnd != NULL) - skip_next_line = PicoScanEnd(DrawScanline); + skip_next_line = PicoScanEnd(line + screen_offset); + + Pico.est.DrawLineDest = (char *)Pico.est.DrawLineDest + DrawLineDestIncrement; } void PicoDoHighPal555M4(void) { unsigned int *spal=(void *)Pico.cram; - unsigned int *dpal=(void *)HighPal; + unsigned int *dpal=(void *)Pico.est.HighPal; unsigned int t; int i; @@ -180,39 +267,36 @@ void PicoDoHighPal555M4(void) t |= (t >> 4) & 0x08610861; *dpal = t; } + Pico.est.HighPal[0xe0] = 0; } -static void FinalizeLineRGB555M4(void) +static void FinalizeLineRGB555M4(int line) { - unsigned short *pd=DrawLineDest; - unsigned char *ps=HighCol+8; - unsigned short *pal=HighPal; - int i; - if (Pico.m.dirtyPal) PicoDoHighPal555M4(); + // standard FinalizeLine can finish it for us, + // with features like scaling and such + FinalizeLine555(0, line, &Pico.est); +} + +static void FinalizeLine8bitM4(int line) +{ + unsigned char *pd = Pico.est.DrawLineDest; + if (!(PicoOpt & POPT_DIS_32C_BORDER)) pd += 32; - for (i = 256/4; i > 0; i--) { - *pd++ = pal[*ps++]; - *pd++ = pal[*ps++]; - *pd++ = pal[*ps++]; - *pd++ = pal[*ps++]; - } + memcpy32((int *)pd, (int *)(Pico.est.HighCol+8), 256/4); } -void PicoDrawSetColorFormatMode4(int which) +void PicoDrawSetOutputMode4(pdso_t which) { switch (which) { - case 1: FinalizeLineM4 = FinalizeLineRGB555M4; break; - default:FinalizeLineM4 = NULL; break; + case PDF_8BIT: FinalizeLineM4 = FinalizeLine8bitM4; break; + case PDF_RGB555: FinalizeLineM4 = FinalizeLineRGB555M4; break; + default: FinalizeLineM4 = NULL; break; } -#if OVERRIDE_HIGHCOL - if (which) - HighCol = DefHighCol; -#endif }