#define SPRL_HAVE_LO 0x40 // *lo*\r
#define SPRL_MAY_HAVE_OP 0x20 // may have operator sprites on the line\r
#define SPRL_LO_ABOVE_HI 0x10 // low priority sprites may be on top of hi\r
-unsigned char HighLnSpr[240][3 + MAX_LINE_SPRITES]; // sprite_count, ^flags, tile_count, [spritep]...\r
+#define SPRL_HAVE_X 0x08 // have sprites with x != 0\r
+#define SPRL_TILE_OVFL 0x04 // tile limit exceeded on previous line\r
+#define SPRL_HAVE_MASK0 0x02 // have sprite with x == 0 in 1st slot\r
+#define SPRL_MASKED 0x01 // lo prio masking by sprite with x == 0 active\r
+unsigned char HighLnSpr[240][4+MAX_LINE_SPRITES+1]; // sprite_count, ^flags, tile_count, sprites_total, [spritep]..., last_width\r
\r
int rendstatus_old;\r
int rendlines;\r
// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size\r
// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8\r
\r
-static void DrawSprite(int *sprite, int sh)\r
+static void DrawSprite(int *sprite, int sh, int w)\r
{\r
void (*fTileFunc)(unsigned char *pd, unsigned int pack, int pal);\r
unsigned char *pd = Pico.est.HighCol;\r
else fTileFunc=TileNorm;\r
}\r
\r
+ if (w) width = w; // tile limit\r
for (; width; width--,sx+=8,tile+=delta)\r
{\r
unsigned int pack;\r
struct PicoVideo *pvid=&Pico.video;\r
int i,u,table,link=0,sline=Pico.est.DrawScanline<<1;\r
unsigned int *sprites[80]; // Sprite index\r
+ int max_sprites = Pico.video.reg[12]&1 ? 80 : 64;\r
\r
table=pvid->reg[5]&0x7f;\r
if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode\r
table<<=8; // Get sprite table address/2\r
\r
- for (i=u=0; u < 80 && i < 21; u++)\r
+ for (i = u = 0; u < max_sprites && link < max_sprites; u++)\r
{\r
unsigned int *sprite;\r
int code, sx, sy, height;\r
void (*fTileFunc)(unsigned char *pd, unsigned int pack, int pal);\r
unsigned char *pd = Pico.est.HighCol;\r
unsigned char *p;\r
- int cnt;\r
+ int cnt, w;\r
\r
cnt = sprited[0] & 0x7f;\r
if (cnt == 0) return;\r
\r
- p = &sprited[3];\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
\r
// Go through sprites backwards:\r
- for (cnt--; cnt >= 0; cnt--)\r
+ w = p[cnt]; // possibly clipped width of last sprite\r
+ for (cnt--; cnt >= 0; cnt--, w = 0)\r
{\r
int *sprite, code, pal, tile, sx, sy;\r
int offs, delta, width, height, row;\r
tile &= 0x7ff; tile<<=4; tile+=(row&7)<<1; // Tile address\r
delta<<=4; // Delta of address\r
\r
+ if (w) width = w; // tile limit\r
for (; width; width--,sx+=8,tile+=delta)\r
{\r
unsigned int pack;\r
if (cnt == 0) return;\r
\r
memset(mb, 0xff, sizeof(mb));\r
- p = &sprited[3];\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
\r
// Go through sprites:\r
for (entry = 0; entry < cnt; entry++)\r
tile &= 0x7ff; tile<<=4; tile+=(row&7)<<1; // Tile address\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
{\r
unsigned int pack;\r
{\r
int pack;\r
// updates: tilecode, sx\r
- for (u=0; u < max_sprites && (pack = *pd); u++, pd+=2)\r
+ for (u=0; u < max_sprites && link < max_sprites && (pack = *pd); u++, pd+=2)\r
{\r
unsigned int *sprite;\r
- int code2, sx, sy, height;\r
+ int code2, sx, sy, height, width;\r
\r
sprite=(unsigned int *)(PicoMem.vram+((table+(link<<2))&0x7ffc)); // Find sprite\r
\r
sx -= 0x78; // Get X coordinate + 8\r
sy = (pack << 16) >> 16;\r
height = (pack >> 24) & 0xf;\r
+ width = (pack >> 28);\r
\r
if (sy < max_lines &&\r
- sy + (height<<3) > est->DrawScanline && // sprite onscreen (y)?\r
- (sx > -24 || sx < max_width)) // onscreen x\r
+ sy + (height<<3) > est->DrawScanline) // sprite onscreen (y)?\r
{\r
int y = (sy >= est->DrawScanline) ? sy : est->DrawScanline;\r
int entry = ((pd - HighPreSpr) / 2) | ((code2>>8)&0x80);\r
for (; y < sy + (height<<3) && y < max_lines; y++)\r
{\r
int i, cnt;\r
- cnt = HighLnSpr[y][0] & 0x7f;\r
- if (cnt >= max_line_sprites) continue; // sprite limit?\r
+ cnt = HighLnSpr[y][0];\r
+ if (HighLnSpr[y][3] >= max_line_sprites) continue; // sprite limit?\r
\r
for (i = 0; i < cnt; i++)\r
- if (((HighLnSpr[y][3+i] ^ entry) & 0x7f) == 0) goto found;\r
+ if (((HighLnSpr[y][4+i] ^ entry) & 0x7f) == 0) goto found;\r
\r
// this sprite was previously missing\r
- HighLnSpr[y][3+cnt] = entry;\r
- HighLnSpr[y][0] = cnt + 1;\r
+ HighLnSpr[y][3] ++;\r
+ if (sx > -24 && sx < max_width) { // onscreen x\r
+ HighLnSpr[y][4+cnt] = entry; // XXX wrong sequence?\r
+ HighLnSpr[y][5+cnt] = width; // XXX should count tiles for limit\r
+ HighLnSpr[y][0] = cnt + 1;\r
+ }\r
found:;\r
if (entry & 0x80)\r
HighLnSpr[y][1] |= SPRL_HAVE_HI;\r
for (u = 0; u < max_lines; u++)\r
*((int *)&HighLnSpr[u][0]) = 0;\r
\r
- for (u = 0; u < max_sprites; u++)\r
+ for (u = 0; u < max_sprites && link < max_sprites; u++)\r
{\r
unsigned int *sprite;\r
int code, code2, sx, sy, hv, height, width;\r
\r
if (sy < max_lines && sy + (height<<3) > est->DrawScanline) // sprite onscreen (y)?\r
{\r
- int entry, y, sx_min, onscr_x, maybe_op = 0;\r
+ int entry, y, w, sx_min, onscr_x, maybe_op = 0;\r
\r
sx_min = 8-(width<<3);\r
onscr_x = sx_min < sx && sx < max_width;\r
y = (sy >= est->DrawScanline) ? sy : est->DrawScanline;\r
for (; y < sy + (height<<3) && y < max_lines; y++)\r
{\r
- unsigned char *p = &HighLnSpr[y][0];\r
+ unsigned char *p = &HighLnSpr[y][0];\r
int cnt = p[0];\r
- if (cnt >= max_line_sprites) continue; // sprite limit?\r
-\r
- if (p[2] >= max_line_sprites*2) { // tile limit?\r
- p[0] |= 0x80;\r
- continue;\r
+ if (p[3] >= max_line_sprites) continue; // sprite limit?\r
+ if ((p[1] & SPRL_MASKED) && !(entry & 0x80)) continue; // masked?\r
+\r
+ w = width;\r
+ if (p[2] + width > max_line_sprites*2) { // tile limit?\r
+ if (y+1 < 240) HighLnSpr[y+1][1] |= SPRL_TILE_OVFL;\r
+ if (p[2] >= max_line_sprites*2) continue;\r
+ w = max_line_sprites*2 - p[2];\r
}\r
- p[2] += width;\r
+ p[2] += w;\r
+ p[3] ++;\r
\r
if (sx == -0x78) {\r
- if (cnt > 0)\r
- p[0] |= 0x80; // masked, no more sprites for this line\r
- continue;\r
- }\r
- // must keep the first sprite even if it's offscreen, for masking\r
- if (cnt > 0 && !onscr_x) continue; // offscreen x\r
+ if (p[1] & (SPRL_HAVE_X|SPRL_TILE_OVFL))\r
+ p[1] |= SPRL_MASKED; // masked, no more low sprites for this line\r
+ if (!(p[1] & SPRL_HAVE_X) && cnt == 0)\r
+ p[1] |= SPRL_HAVE_MASK0; // 1st sprite is masking\r
+ } else\r
+ p[1] |= SPRL_HAVE_X;\r
+\r
+ if (!onscr_x) continue; // offscreen x\r
\r
- p[3+cnt] = entry;\r
+ p[4+cnt] = entry;\r
+ p[5+cnt] = w; // width clipped by tile limit for sprite renderer\r
p[0] = cnt + 1;\r
p[1] |= (entry & 0x80) ? SPRL_HAVE_HI : SPRL_HAVE_LO;\r
p[1] |= maybe_op; // there might be op sprites on this line\r
- if (cnt > 0 && (code2 & 0x8000) && !(p[3+cnt-1]&0x80))\r
+ if (cnt > 0 && (code2 & 0x8000) && !(p[4+cnt-1]&0x80))\r
p[1] |= SPRL_LO_ABOVE_HI;\r
}\r
}\r
for (u = 0; u < max_lines; u++)\r
{\r
int y;\r
- printf("c%03i: %2i, %2i: ", u, HighLnSpr[u][0] & 0x7f, HighLnSpr[u][2]);\r
- for (y = 0; y < HighLnSpr[u][0] & 0x7f; y++)\r
- printf(" %i", HighLnSpr[u][y+3]);\r
+ printf("c%03i: f %x c %2i/%2i w %2i: ", u, HighLnSpr[u][1],\r
+ HighLnSpr[u][0], HighLnSpr[u][3], HighLnSpr[u][2]);\r
+ for (y = 0; y < HighLnSpr[u][0]; y++)\r
+ printf(" %i", HighLnSpr[u][y+4]);\r
printf("\n");\r
}\r
#endif\r
struct PicoEState *est)\r
{\r
unsigned char *p;\r
- int cnt;\r
+ int cnt, w = sprited[2];\r
\r
cnt = sprited[0] & 0x7f;\r
if (cnt == 0) return;\r
\r
- p = &sprited[3];\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
\r
// Go through sprites backwards:\r
- for (cnt--; cnt >= 0; cnt--)\r
+ w = p[cnt]; // possibly clipped width of last sprite\r
+ for (cnt--; cnt >= 0; cnt--, w = 0)\r
{\r
- int offs;\r
+ int *sp = HighPreSpr + (p[cnt]&0x7f) * 2;\r
if ((p[cnt] >> 7) != prio) continue;\r
- offs = (p[cnt]&0x7f) * 2;\r
- DrawSprite(HighPreSpr + offs, sh);\r
+ DrawSprite(sp, sh, w);\r
}\r
}\r
\r
.global DrawSpritesSHi\r
\r
DrawSpritesSHi:\r
- ldr r3, [r0]\r
+ ldrb r3, [r0]\r
mov r12,#0xff\r
ands r3, r3, #0x7f\r
bxeq lr\r
\r
- stmfd sp!, {r1,r4-r11,lr} @ +est\r
- strb r12,[r0,#2] @ set end marker\r
- add r10,r0, #3 @ r10=HighLnSpr end\r
+ stmfd sp!, {r1,r3-r11,lr} @ +est\r
+ strb r12,[r0,#3] @ set end marker\r
+ ldrb r12,[r0,#1]\r
+ add r10,r0, #4 @ r10=HighLnSpr end\r
+ mvn r12,r12\r
+ tst r12,#0x6 @ masking in slot 1 and tile ovfl?\r
+ ldmeqfd sp!, {r1,r3-r11,pc}\r
add r10,r10,r3 @ r10=HighLnSpr end\r
\r
+ ldrb r12,[r10,#0] @ width of last sprite\r
ldr r11,[r1, #OFS_EST_HighCol]\r
+ str r12,[sp, #4]\r
mov r12,#0xf\r
ldr lr, [r1, #OFS_EST_PicoMem_vram]\r
\r
ldr r7, [sp] @ est\r
ldr r1, [r7, #OFS_EST_HighPreSpr]\r
cmp r0, #0xff\r
- ldmeqfd sp!, {r1,r4-r11,pc} @ end of list\r
+ ldmeqfd sp!, {r1,r3-r11,pc} @ end of list\r
and r0, r0, #0x7f\r
add r0, r1, r0, lsl #3\r
\r
and r7, r7, #7\r
add r8, r8, r7, lsl #1 @ tile+=(row&7)<<1; // Tile address\r
\r
+ ldr r0, [sp, #4]\r
+ add r6, r6, #1 @ inc now\r
+ cmp r0, #0 @ check width of last sprite\r
+ movne r6, r0\r
+ movne r0, #0\r
+ strne r0, [sp, #4]\r
+\r
mov r5, r5, lsl #4 @ delta<<=4; // Delta of address\r
mov r3, r4, lsr #9 @ r3=pal=((code>>9)&0x30);\r
\r
- add r6, r6, #1 @ inc now\r
adds r0, r2, #0 @ mov sx to r0 and set ZV flags\r
b .dsprShi_loop_enter\r
\r
@ time to do some real work\r
stmfd sp!, {r1,r3-r11,lr} @ +sh|prio<<1 +est\r
mov r12,#0xff\r
- strb r12,[r0,#2] @ set end marker\r
- add r10,r0, #3\r
+ strb r12,[r0,#3] @ set end marker\r
+ ldrb r12,[r0,#1]\r
+ add r10,r0 ,#4\r
+ mvn r12,r12\r
+ tst r12,#0x6 @ masking in slot 1 and tile ovfl?\r
+ ldmeqfd sp!, {r1,r3-r11,pc}\r
add r10,r10,r2 @ r10=HighLnSpr end\r
\r
+ ldrb r12,[r10,#0] @ width of last sprite\r
ldr r11,[r3, #OFS_EST_HighCol]\r
+ orr r1 ,r1 ,r12,lsl #24\r
+ str r1, [sp]\r
mov r12,#0xf\r
ldr lr, [r3, #OFS_EST_PicoMem_vram]\r
\r
DrawSprite:\r
@ draw next sprite\r
ldrb r0, [r10,#-1]!\r
- ldr r8, [sp] @ sh|prio<<1\r
+ ldr r4, [sp] @ sh|prio<<1|lastw<<24\r
ldr r7, [sp, #4] @ est\r
- mov r2, r0, lsr #7\r
+ mov r2, r0, lsl #24\r
cmp r0, #0xff\r
ldmeqfd sp!, {r1,r3-r11,pc} @ end of list\r
- cmp r2, r8, lsr #1\r
- bne DrawSprite @ wrong priority\r
+ eor r2, r2, r4, lsl #30\r
+ bmi DrawSprite @ wrong priority\r
ldr r1, [r7, #OFS_EST_HighPreSpr]\r
and r0, r0, #0x7f\r
add r0, r1, r0, lsl #3\r
mov r5, r3, lsr #24\r
and r5, r5, #7 @ r5=height\r
\r
- mov r4, r3, lsl #16 @ r4=sy<<16 (tmp)\r
+ mov r8, r3, lsl #16 @ r8=sy<<16 (tmp)\r
\r
ldr r9, [r0, #4]\r
- sub r7, r7, r4, asr #16 @ r7=row=DrawScanline-sy\r
+ sub r7, r7, r8, asr #16 @ r7=row=DrawScanline-sy\r
\r
mov r2, r9, asr #16 @ r2=sx\r
mov r9, r9, lsl #16\r
mov r9, r9, lsr #16\r
- orr r9, r9, r8, lsl #31 @ r9=code|sh[31]\r
+ orr r9, r9, r4, lsl #31 @ r9=code|sh[31]\r
\r
tst r9, #0x1000\r
- movne r4, r5, lsl #3\r
- subne r4, r4, #1\r
- subne r7, r4, r7 @ if (code&0x1000) row=(height<<3)-1-row; // Flip Y\r
+ movne r8, r5, lsl #3\r
+ subne r8, r8, #1\r
+ subne r7, r8, r7 @ if (code&0x1000) row=(height<<3)-1-row; // Flip Y\r
\r
add r8, r9, r7, lsr #3 @ tile+=row>>3; // Tile number increases going down\r
tst r9, #0x0800\r
and r7, r7, #7\r
add r8, r8, r7, lsl #1 @ tile+=(row&7)<<1; // Tile address\r
\r
-.dspr_continue:\r
+ add r6, r6, #1 @ inc now\r
+ cmp r4, #0x1000000 @ check width of last sprite\r
+ movhs r6, r4, lsr #24\r
+ bichs r4, r4, #0xff000000\r
+ strhs r4, [sp]\r
+\r
@ cache some stuff to avoid mem access\r
mov r5, r5, lsl #4 @ delta<<=4; // Delta of address\r
and r4, r9, #0x6000\r
mov r3, r4, lsr #9 @ r3=pal=((code>>9)&0x30);\r
orrmi r3, r3, #0x40 @ for sh/hi\r
\r
- add r6, r6, #1 @ inc now\r
adds r0, r2, #0 @ mov sx to r0 and set ZV flags\r
b .dspr_loop_enter\r
\r