sprite binning wip

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@514 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2008-07-02 19:34:34 +00:00
parent 48dc74f20a
commit d9fc2fe1ac
3 changed files with 110 additions and 91 deletions

View file

@ -38,10 +38,12 @@ static int HighCacheS[80+1]; // and sprites
static int HighPreSpr[80*2+1]; // slightly preprocessed sprites
int *HighCacheS_ptr;
#define MAX_LINE_SPRITES 30
static unsigned char HighLnSpr[240][2 + MAX_LINE_SPRITES]; // sprite_count, tile_count, [spritep]...
int rendstatus = 0;
int DrawScanline = 0;
static int SpriteBlocks;
static int skip_next_line=0;
//unsigned short ppt[] = { 0x0f11, 0x0ff1, 0x01f1, 0x011f, 0x01ff, 0x0f1f, 0x0f0e, 0x0e7c };
@ -924,15 +926,24 @@ static void DrawSpritesFromCacheAS(int *hc, int maxwidth, int prio, int sh)
// Index + 0 : ----hhvv -lllllll -------y yyyyyyyy
// Index + 4 : -------x xxxxxxxx pccvhnnn nnnnnnnn
// v
// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size
// Index + 0 : hhhhvvvv ----hhvv yyyyyyyy yyyyyyyy // v, h: vert./horiz. size
// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
static void PrepareSprites(int full)
{
struct PicoVideo *pvid=&Pico.video;
int u=0,link=0,sblocks=0;
int u,link=0;
int table=0;
int *pd = HighPreSpr;
int max_lines = 224, max_sprites = 80;
int max_line_sprites = 20; // 20 sprites, 40 tiles
if (!(Pico.video.reg[12]&1))
max_sprites = 64, max_line_sprites = 16;
if (PicoOpt & POPT_DIS_SPRITE_LIM)
max_line_sprites = MAX_LINE_SPRITES;
if (pvid->reg[1]&8) max_lines = 240;
table=pvid->reg[5]&0x7f;
if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
@ -942,41 +953,60 @@ static void PrepareSprites(int full)
{
int pack;
// updates: tilecode, sx
for (u=0; u < 80 && (pack = *pd); u++, pd+=2)
for (u=0; u < max_lines && (pack = *pd); u++, pd+=2)
{
unsigned int *sprite;
int code, code2, sx, sy, skip=0;
int code2, sx, sy, height;
sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
// parse sprite info
code = sprite[0];
code2 = sprite[1];
code2 &= ~0xfe000000;
code2 -= 0x00780000; // Get X coordinate + 8 in upper 16 bits
sx = code2>>16;
sx = (code2>>16)&0x1ff;
sx -= 0x78; // Get X coordinate + 8
sy = (pack << 16) >> 16;
height = pack >> 28;
if((sx <= 8-((pack>>28)<<3) && sx >= -0x76) || sx >= 328) skip=1<<23;
else if ((sy = (pack<<16)>>16) < 240 && sy > -32) {
int sbl = (2<<(pack>>28))-1;
sblocks |= sbl<<(sy>>3);
if (sy < max_lines && sy + (height<<3) > DrawScanline && // sprite onscreen (y)?
(sx > -24 || sx < 328)) // onscreen x
{
int y = (sy >= DrawScanline) ? sy : DrawScanline;
for (; y < sy + (height<<3) && y < max_lines; y++)
{
int i, cnt, offs;
cnt = HighLnSpr[y][0] & 0x7f;
if (cnt >= max_line_sprites) continue; // sprite limit?
offs = (pd - HighPreSpr) / 2;
for (i = 0; i < cnt; i++)
if (HighLnSpr[y][2+i] == offs) goto found;
// this sprite was previously missing
HighLnSpr[y][2+cnt] = offs;
HighLnSpr[y][0] = cnt + 1;
found:;
}
}
*pd = (pack&~(1<<23))|skip;
*(pd+1) = code2;
code2 &= ~0xfe000000;
code2 -= 0x00780000; // Get X coordinate + 8 in upper 16 bits
pd[1] = code2;
// Find next sprite
link=(code>>16)&0x7f;
if(!link) break; // End of sprites
link=(sprite[0]>>16)&0x7f;
if (!link) break; // End of sprites
}
SpriteBlocks |= sblocks;
}
else
{
for (; u < 80; u++)
for (u = 0; u < max_lines; u++)
*((int *)&HighLnSpr[u][0]) = 0;
for (u = 0; u < max_lines; u++)
{
unsigned int *sprite;
int code, code2, sx, sy, hv, height, width, skip=0, sx_min;
int code, code2, sx, sy, hv, height, width;
int sx_min, offscr_x;
sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
@ -986,103 +1016,92 @@ static void PrepareSprites(int full)
hv = (code>>24)&0xf;
height = (hv&3)+1;
if (sy > 240 || sy + (height<<3) <= 0) skip|=1<<22; // sprite offscreen (completely, y)
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; // offscreen x
else if (sx > sx_min && !skip) {
int sbl = (2<<height)-1;
int shi = sy>>3;
if(shi < 0) shi=0; // negative sy
sblocks |= sbl<<shi;
offscr_x = (sx <= sx_min) || sx >= 328;
if (sy < max_lines && sy + (height<<3) > DrawScanline) // sprite onscreen (y)?
{
int y = (sy >= DrawScanline) ? sy : DrawScanline;
for (; y < sy + (height<<3) && y < max_lines; y++)
{
int cnt = HighLnSpr[y][0];
if (cnt >= max_line_sprites) continue; // sprite limit?
if (HighLnSpr[y][1] >= max_line_sprites*2) { // tile limit?
HighLnSpr[y][0] |= 0x80;
continue;
}
HighLnSpr[y][1] += width;
if (sx == -0x78) {
if (cnt > 0)
HighLnSpr[y][0] |= 0x80; // masked, no more sprites for this line
continue;
}
// must keep the first sprite even if it's offscreen, for masking
if (cnt > 0 && (sx <= sx_min || sx >= 328)) continue; // offscreen x
HighLnSpr[y][2+cnt] = ((pd - HighPreSpr) / 2); // | prio;
HighLnSpr[y][0] = cnt + 1;
}
}
*pd++ = (width<<28)|(height<<24)|skip|(hv<<16)|((unsigned short)sy);
*pd++ = (width<<28)|(height<<24)|(hv<<16)|((unsigned short)sy);
*pd++ = (sx<<16)|((unsigned short)code2);
// Find next sprite
link=(code>>16)&0x7f;
if(!link) break; // End of sprites
if (!link) break; // End of sprites
}
SpriteBlocks = sblocks;
*pd = 0; // terminate
*pd = 0;
#if 0
for (u = 0; u < max_lines; u++)
{
int y;
printf("c%03i: %2i, %2i: ", u, HighLnSpr[u][0] & 0x7f, HighLnSpr[u][1]);
for (y = 0; y < HighLnSpr[u][0] & 0x7f; y++)
printf(" %i", HighLnSpr[u][y+2]);
printf("\n");
}
#endif
}
}
static void DrawAllSprites(int *hcache, int maxwidth, int prio, int sh)
{
int i,u,n;
int sx1seen = 0; // sprite with x coord 1 or 0 seen
int ntiles = 0; // tile counter for sprite limit emulation
int *sprites[40]; // Sprites to draw in fast mode
int max_line_sprites = 20; // 20 sprites, 40 tiles
int *ps, pack, rs = rendstatus, scan = DrawScanline;
int rs = rendstatus, scan = DrawScanline;
unsigned char *p;
int cnt, as;
if (rs & (PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES)) {
//dprintf("PrepareSprites(%i) [%i]", (rs>>4)&1, scan);
//elprintf(EL_STATUS, "PrepareSprites(%i)", (rs>>4)&1);
PrepareSprites(rs & PDRAW_DIRTY_SPRITES);
rendstatus = rs & ~(PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES);
}
if (!(SpriteBlocks & (1<<(scan>>3)))) { *hcache = 0; return; }
if (PicoOpt & POPT_DIS_SPRITE_LIM)
max_line_sprites = 80;
HighCacheS_ptr = hcache;
ps = HighPreSpr;
cnt = HighLnSpr[scan][0] & 0x7f;
// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size
// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
for (i=u=n=0; (pack = *ps) && n < max_line_sprites; ps+=2, u++)
if (cnt != 0)
{
int sx, sy, row, pack2;
p = &HighLnSpr[scan][2];
as = (rs & PDRAW_ACC_SPRITES) ? 1 : 0;
if (pack & 0x00400000) continue;
// get sprite info
pack2 = *(ps+1);
sx = pack2>>16;
sy = (pack <<16)>>16;
row = scan-sy;
// elprintf(EL_ANOMALY, "x: %4i y: %4i p %i %ix%i", sx, sy, (pack2>>15)&1, (pack>>28)<<3, (pack>>21)&0x38);
if (sx == -0x77) sx1seen|=1; // for masking mode 2
// check if it is on this line
if (row < 0 || row >= ((pack>>21)&0x38)) continue; // no
// masking sprite?
if (sx == -0x78) {
if (n > 0) break; // masked
continue;
// Go through sprites backwards:
for (cnt--; cnt >= 0; cnt--)
{
int offs = p[cnt] * 2;
//if ((p[cnt] & 0x80) && !as) continue;
DrawSprite(HighPreSpr + offs, sh, as);
}
n++; // number of sprites on this line (both visible and hidden, except of x=0)
// sprite limit
ntiles += pack>>28;
if (ntiles > max_line_sprites*2) break;
if (pack & 0x00800000) continue;
// sprite is good, save it's pointer
sprites[i++]=ps;
}
n = (rs & PDRAW_ACC_SPRITES) ? 1 : 0;
// Go through sprites backwards:
for (i--; i>=0; i--)
DrawSprite(sprites[i],sh,n);
// terminate cache list
*HighCacheS_ptr = 0;
}
@ -1351,9 +1370,9 @@ PICO_INTERNAL void PicoFrameStart(void)
if (Pico.m.dirtyPal) Pico.m.dirtyPal = 2; // reset dirty if needed
DrawScanline=0;
PrepareSprites(1);
skip_next_line=0;
DrawScanline=0;
}
static void PicoLine(void)