| 1 | // This is part of Pico Library |
| 2 | |
| 3 | // (c) Copyright 2004 Dave, All rights reserved. |
| 4 | // (c) Copyright 2006 notaz, All rights reserved. |
| 5 | // Free for non-commercial use. |
| 6 | |
| 7 | // For commercial use, separate licencing terms must be obtained. |
| 8 | |
| 9 | |
| 10 | #include "../../Pico/PicoInt.h" |
| 11 | #undef blockcpy |
| 12 | |
| 13 | extern unsigned short DefOutBuff[320*2]; |
| 14 | extern unsigned char HighCol[8+320+8]; |
| 15 | extern char HighSprZ[320+8+8]; // Z-buffer for accurate sprites and shadow/hilight mode |
| 16 | // (if bit 7 == 0, sh caused by tile; if bit 6 == 0 pixel must be shadowed, else hilighted, if bit5 == 1) |
| 17 | // lsb->msb: moved sprites, all window tiles don't use same priority, accurate sprites (copied from PicoOpt), interlace |
| 18 | // dirty sprites, sonic mode |
| 19 | extern int rendstatus; |
| 20 | extern int Scanline; // Scanline |
| 21 | |
| 22 | |
| 23 | struct TileStrip |
| 24 | { |
| 25 | int nametab; // Position in VRAM of name table (for this tile line) |
| 26 | int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap |
| 27 | int hscroll; // Horizontal scroll value in pixels for the line |
| 28 | int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap |
| 29 | int *hc; // cache for high tile codes and their positions |
| 30 | int cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320) |
| 31 | }; |
| 32 | |
| 33 | // utility |
| 34 | void *blockcpy(void *dst, const void *src, size_t n) |
| 35 | { |
| 36 | return memcpy(dst, src, n); |
| 37 | } |
| 38 | |
| 39 | void blockcpy_or(void *dst, void *src, size_t n, int pat) |
| 40 | { |
| 41 | unsigned char *pd = dst, *ps = src; |
| 42 | for (; n; n--) |
| 43 | *pd++ = (unsigned char) (*ps++ | pat); |
| 44 | } |
| 45 | |
| 46 | |
| 47 | static int TileNorm(int sx,int addr,int pal) |
| 48 | { |
| 49 | unsigned char *pd = HighCol+sx; |
| 50 | unsigned int pack=0; unsigned int t=0; |
| 51 | |
| 52 | pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels |
| 53 | if (pack) |
| 54 | { |
| 55 | t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12)); |
| 56 | t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8)); |
| 57 | t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4)); |
| 58 | t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t )); |
| 59 | t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28)); |
| 60 | t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24)); |
| 61 | t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20)); |
| 62 | t=pack&0x000f0000; if (t) pd[7]=(unsigned char)(pal|(t>>16)); |
| 63 | return 0; |
| 64 | } |
| 65 | |
| 66 | return 1; // Tile blank |
| 67 | } |
| 68 | |
| 69 | static int TileFlip(int sx,int addr,int pal) |
| 70 | { |
| 71 | unsigned char *pd = HighCol+sx; |
| 72 | unsigned int pack=0; unsigned int t=0; |
| 73 | |
| 74 | pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels |
| 75 | if (pack) |
| 76 | { |
| 77 | t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16)); |
| 78 | t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20)); |
| 79 | t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24)); |
| 80 | t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28)); |
| 81 | t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t )); |
| 82 | t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4)); |
| 83 | t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8)); |
| 84 | t=pack&0x0000f000; if (t) pd[7]=(unsigned char)(pal|(t>>12)); |
| 85 | return 0; |
| 86 | } |
| 87 | return 1; // Tile blank |
| 88 | } |
| 89 | |
| 90 | |
| 91 | // tile renderers for hacky operator sprite support |
| 92 | #define sh_pix(x) \ |
| 93 | if(!t); \ |
| 94 | else if(t==0xe) pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ \ |
| 95 | else if(t==0xf) pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ \ |
| 96 | else pd[x]=(unsigned char)(pal|t); |
| 97 | |
| 98 | static int TileNormSH(int sx,int addr,int pal) |
| 99 | { |
| 100 | unsigned int pack=0; unsigned int t=0; |
| 101 | unsigned char *pd = HighCol+sx; |
| 102 | |
| 103 | pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels |
| 104 | if (pack) |
| 105 | { |
| 106 | t=(pack&0x0000f000)>>12; sh_pix(0); |
| 107 | t=(pack&0x00000f00)>> 8; sh_pix(1); |
| 108 | t=(pack&0x000000f0)>> 4; sh_pix(2); |
| 109 | t=(pack&0x0000000f) ; sh_pix(3); |
| 110 | t=(pack&0xf0000000)>>28; sh_pix(4); |
| 111 | t=(pack&0x0f000000)>>24; sh_pix(5); |
| 112 | t=(pack&0x00f00000)>>20; sh_pix(6); |
| 113 | t=(pack&0x000f0000)>>16; sh_pix(7); |
| 114 | return 0; |
| 115 | } |
| 116 | |
| 117 | return 1; // Tile blank |
| 118 | } |
| 119 | |
| 120 | static int TileFlipSH(int sx,int addr,int pal) |
| 121 | { |
| 122 | unsigned int pack=0; unsigned int t=0; |
| 123 | unsigned char *pd = HighCol+sx; |
| 124 | |
| 125 | pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels |
| 126 | if (pack) |
| 127 | { |
| 128 | t=(pack&0x000f0000)>>16; sh_pix(0); |
| 129 | t=(pack&0x00f00000)>>20; sh_pix(1); |
| 130 | t=(pack&0x0f000000)>>24; sh_pix(2); |
| 131 | t=(pack&0xf0000000)>>28; sh_pix(3); |
| 132 | t=(pack&0x0000000f) ; sh_pix(4); |
| 133 | t=(pack&0x000000f0)>> 4; sh_pix(5); |
| 134 | t=(pack&0x00000f00)>> 8; sh_pix(6); |
| 135 | t=(pack&0x0000f000)>>12; sh_pix(7); |
| 136 | return 0; |
| 137 | } |
| 138 | return 1; // Tile blank |
| 139 | } |
| 140 | |
| 141 | |
| 142 | // -------------------------------------------- |
| 143 | |
| 144 | static void DrawStrip(struct TileStrip *ts, int sh) |
| 145 | { |
| 146 | int tilex=0,dx=0,ty=0,code=0,addr=0,cells; |
| 147 | int oldcode=-1,blank=-1; // The tile we know is blank |
| 148 | int pal=0; |
| 149 | |
| 150 | // Draw tiles across screen: |
| 151 | tilex=(-ts->hscroll)>>3; |
| 152 | ty=(ts->line&7)<<1; // Y-Offset into tile |
| 153 | dx=((ts->hscroll-1)&7)+1; |
| 154 | cells = ts->cells; |
| 155 | if(dx != 8) cells++; // have hscroll, need to draw 1 cell more |
| 156 | |
| 157 | for (; cells; dx+=8,tilex++,cells--) |
| 158 | { |
| 159 | int zero=0; |
| 160 | |
| 161 | code=Pico.vram[ts->nametab+(tilex&ts->xmask)]; |
| 162 | if (code==blank) continue; |
| 163 | if (code>>15) { // high priority tile |
| 164 | int cval = code | (dx<<16) | (ty<<25); |
| 165 | if(code&0x1000) cval^=7<<26; |
| 166 | *ts->hc++ = cval; // cache it |
| 167 | continue; |
| 168 | } |
| 169 | |
| 170 | if (code!=oldcode) { |
| 171 | oldcode = code; |
| 172 | // Get tile address/2: |
| 173 | addr=(code&0x7ff)<<4; |
| 174 | addr+=ty; |
| 175 | if (code&0x1000) addr^=0xe; // Y-flip |
| 176 | |
| 177 | // pal=Pico.cram+((code>>9)&0x30); |
| 178 | pal=((code>>9)&0x30)|(sh<<6); |
| 179 | } |
| 180 | |
| 181 | if (code&0x0800) zero=TileFlip(dx,addr,pal); |
| 182 | else zero=TileNorm(dx,addr,pal); |
| 183 | |
| 184 | if (zero) blank=code; // We know this tile is blank now |
| 185 | } |
| 186 | |
| 187 | // terminate the cache list |
| 188 | *ts->hc = 0; |
| 189 | } |
| 190 | |
| 191 | static void DrawStripVSRam(struct TileStrip *ts, int plane) |
| 192 | { |
| 193 | int tilex=0,dx=0,ty=0,code=0,addr=0,cell=0,nametabadd=0; |
| 194 | int oldcode=-1,blank=-1; // The tile we know is blank |
| 195 | int pal=0,scan=Scanline; |
| 196 | |
| 197 | // Draw tiles across screen: |
| 198 | tilex=(-ts->hscroll)>>3; |
| 199 | dx=((ts->hscroll-1)&7)+1; |
| 200 | if(dx != 8) { |
| 201 | int vscroll, line; |
| 202 | cell--; // have hscroll, start with negative cell |
| 203 | // also calculate intial VS stuff |
| 204 | vscroll=Pico.vsram[plane]; |
| 205 | |
| 206 | // Find the line in the name table |
| 207 | line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. |
| 208 | nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] |
| 209 | ty=(line&7)<<1; // Y-Offset into tile |
| 210 | } |
| 211 | |
| 212 | for (; cell < ts->cells; dx+=8,tilex++,cell++) |
| 213 | { |
| 214 | int zero=0; |
| 215 | |
| 216 | if((cell&1)==0) { |
| 217 | int line,vscroll; |
| 218 | vscroll=Pico.vsram[plane+(cell&~1)]; |
| 219 | |
| 220 | // Find the line in the name table |
| 221 | line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. |
| 222 | nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] |
| 223 | ty=(line&7)<<1; // Y-Offset into tile |
| 224 | } |
| 225 | |
| 226 | code=Pico.vram[ts->nametab+nametabadd+(tilex&ts->xmask)]; |
| 227 | if (code==blank) continue; |
| 228 | if (code>>15) { // high priority tile |
| 229 | int cval = code | (dx<<16) | (ty<<25); |
| 230 | if(code&0x1000) cval^=7<<26; |
| 231 | *ts->hc++ = cval; // cache it |
| 232 | continue; |
| 233 | } |
| 234 | |
| 235 | if (code!=oldcode) { |
| 236 | oldcode = code; |
| 237 | // Get tile address/2: |
| 238 | addr=(code&0x7ff)<<4; |
| 239 | if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip |
| 240 | |
| 241 | // pal=Pico.cram+((code>>9)&0x30); |
| 242 | pal=((code>>9)&0x30); |
| 243 | } |
| 244 | |
| 245 | if (code&0x0800) zero=TileFlip(dx,addr,pal); |
| 246 | else zero=TileNorm(dx,addr,pal); |
| 247 | |
| 248 | if (zero) blank=code; // We know this tile is blank now |
| 249 | } |
| 250 | |
| 251 | // terminate the cache list |
| 252 | *ts->hc = 0; |
| 253 | } |
| 254 | |
| 255 | static void DrawStripInterlace(struct TileStrip *ts) |
| 256 | { |
| 257 | int tilex=0,dx=0,ty=0,code=0,addr=0,cells; |
| 258 | int oldcode=-1,blank=-1; // The tile we know is blank |
| 259 | int pal=0; |
| 260 | |
| 261 | // Draw tiles across screen: |
| 262 | tilex=(-ts->hscroll)>>3; |
| 263 | ty=(ts->line&15)<<1; // Y-Offset into tile |
| 264 | dx=((ts->hscroll-1)&7)+1; |
| 265 | cells = ts->cells; |
| 266 | if(dx != 8) cells++; // have hscroll, need to draw 1 cell more |
| 267 | |
| 268 | for (; cells; dx+=8,tilex++,cells--) |
| 269 | { |
| 270 | int zero=0; |
| 271 | |
| 272 | code=Pico.vram[ts->nametab+(tilex&ts->xmask)]; |
| 273 | if (code==blank) continue; |
| 274 | if (code>>15) { // high priority tile |
| 275 | int cval = (code&0xfc00) | (dx<<16) | (ty<<25); |
| 276 | cval|=(code&0x3ff)<<1; |
| 277 | if(code&0x1000) cval^=0xf<<26; |
| 278 | *ts->hc++ = cval; // cache it |
| 279 | continue; |
| 280 | } |
| 281 | |
| 282 | if (code!=oldcode) { |
| 283 | oldcode = code; |
| 284 | // Get tile address/2: |
| 285 | addr=(code&0x7ff)<<5; |
| 286 | if (code&0x1000) addr+=30-ty; else addr+=ty; // Y-flip |
| 287 | |
| 288 | // pal=Pico.cram+((code>>9)&0x30); |
| 289 | pal=((code>>9)&0x30); |
| 290 | } |
| 291 | |
| 292 | if (code&0x0800) zero=TileFlip(dx,addr,pal); |
| 293 | else zero=TileNorm(dx,addr,pal); |
| 294 | |
| 295 | if (zero) blank=code; // We know this tile is blank now |
| 296 | } |
| 297 | |
| 298 | // terminate the cache list |
| 299 | *ts->hc = 0; |
| 300 | } |
| 301 | |
| 302 | // -------------------------------------------- |
| 303 | |
| 304 | void DrawLayer(int plane, int *hcache, int maxcells, int sh) |
| 305 | { |
| 306 | struct PicoVideo *pvid=&Pico.video; |
| 307 | const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid) |
| 308 | struct TileStrip ts; |
| 309 | int width, height, ymask; |
| 310 | int vscroll, htab; |
| 311 | |
| 312 | ts.hc=hcache; |
| 313 | ts.cells=maxcells; |
| 314 | |
| 315 | // Work out the TileStrip to draw |
| 316 | |
| 317 | // Work out the name table size: 32 64 or 128 tiles (0-3) |
| 318 | width=pvid->reg[16]; |
| 319 | height=(width>>4)&3; width&=3; |
| 320 | |
| 321 | ts.xmask=(1<<shift[width])-1; // X Mask in tiles (0x1f-0x7f) |
| 322 | ymask=(height<<8)|0xff; // Y Mask in pixels |
| 323 | if(width == 1) ymask&=0x1ff; |
| 324 | else if(width>1) ymask =0x0ff; |
| 325 | |
| 326 | // Find name table: |
| 327 | if (plane==0) ts.nametab=(pvid->reg[2]&0x38)<< 9; // A |
| 328 | else ts.nametab=(pvid->reg[4]&0x07)<<12; // B |
| 329 | |
| 330 | htab=pvid->reg[13]<<9; // Horizontal scroll table address |
| 331 | if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line |
| 332 | if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile |
| 333 | htab+=plane; // A or B |
| 334 | |
| 335 | // Get horizontal scroll value, will be masked later |
| 336 | ts.hscroll=Pico.vram[htab&0x7fff]; |
| 337 | |
| 338 | if((pvid->reg[12]&6) == 6) { |
| 339 | // interlace mode 2 |
| 340 | vscroll=Pico.vsram[plane]; // Get vertical scroll value |
| 341 | |
| 342 | // Find the line in the name table |
| 343 | ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1); |
| 344 | ts.nametab+=(ts.line>>4)<<shift[width]; |
| 345 | |
| 346 | DrawStripInterlace(&ts); |
| 347 | } else if( pvid->reg[11]&4) { |
| 348 | // shit, we have 2-cell column based vscroll |
| 349 | // luckily this doesn't happen too often |
| 350 | ts.line=ymask|(shift[width]<<24); // save some stuff instead of line |
| 351 | DrawStripVSRam(&ts, plane); |
| 352 | } else { |
| 353 | vscroll=Pico.vsram[plane]; // Get vertical scroll value |
| 354 | |
| 355 | // Find the line in the name table |
| 356 | ts.line=(vscroll+Scanline)&ymask; |
| 357 | ts.nametab+=(ts.line>>3)<<shift[width]; |
| 358 | |
| 359 | DrawStrip(&ts, sh); |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | |
| 364 | // -------------------------------------------- |
| 365 | |
| 366 | // tstart & tend are tile pair numbers |
| 367 | void DrawWindow(int tstart, int tend, int prio, int sh) // int *hcache |
| 368 | { |
| 369 | struct PicoVideo *pvid=&Pico.video; |
| 370 | int tilex=0,ty=0,nametab,code=0; |
| 371 | int blank=-1; // The tile we know is blank |
| 372 | |
| 373 | // Find name table line: |
| 374 | if (pvid->reg[12]&1) |
| 375 | { |
| 376 | nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode |
| 377 | nametab+=(Scanline>>3)<<6; |
| 378 | } |
| 379 | else |
| 380 | { |
| 381 | nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode |
| 382 | nametab+=(Scanline>>3)<<5; |
| 383 | } |
| 384 | |
| 385 | tilex=tstart<<1; |
| 386 | tend<<=1; |
| 387 | |
| 388 | ty=(Scanline&7)<<1; // Y-Offset into tile |
| 389 | |
| 390 | if(!(rendstatus&2)) { |
| 391 | // check the first tile code |
| 392 | code=Pico.vram[nametab+tilex]; |
| 393 | // if the whole window uses same priority (what is often the case), we may be able to skip this field |
| 394 | if((code>>15) != prio) return; |
| 395 | } |
| 396 | |
| 397 | // Draw tiles across screen: |
| 398 | for (; tilex < tend; tilex++) |
| 399 | { |
| 400 | int addr=0,zero=0; |
| 401 | int pal; |
| 402 | |
| 403 | code=Pico.vram[nametab+tilex]; |
| 404 | if(code==blank) continue; |
| 405 | if((code>>15) != prio) { |
| 406 | rendstatus|=2; |
| 407 | continue; |
| 408 | } |
| 409 | |
| 410 | pal=((code>>9)&0x30); |
| 411 | |
| 412 | if(sh) { |
| 413 | int tmp, *zb = (int *)(HighCol+8+(tilex<<3)); |
| 414 | if(prio) { |
| 415 | tmp = *zb; |
| 416 | if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; |
| 417 | if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; |
| 418 | *zb++=tmp; tmp = *zb; |
| 419 | if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; |
| 420 | if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; |
| 421 | *zb++=tmp; |
| 422 | } else { |
| 423 | pal |= 0x40; |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | // Get tile address/2: |
| 428 | addr=(code&0x7ff)<<4; |
| 429 | if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip |
| 430 | |
| 431 | if (code&0x0800) zero=TileFlip(8+(tilex<<3),addr,pal); |
| 432 | else zero=TileNorm(8+(tilex<<3),addr,pal); |
| 433 | |
| 434 | if (zero) blank=code; // We know this tile is blank now |
| 435 | } |
| 436 | |
| 437 | // terminate the cache list |
| 438 | //*hcache = 0; |
| 439 | } |
| 440 | |
| 441 | // -------------------------------------------- |
| 442 | |
| 443 | void DrawTilesFromCache(int *hc, int sh) |
| 444 | { |
| 445 | int code, addr, zero, dx; |
| 446 | int pal; |
| 447 | short blank=-1; // The tile we know is blank |
| 448 | |
| 449 | // *ts->hc++ = code | (dx<<16) | (ty<<25); // cache it |
| 450 | |
| 451 | while((code=*hc++)) { |
| 452 | if(!sh && (short)code == blank) continue; |
| 453 | |
| 454 | // Get tile address/2: |
| 455 | addr=(code&0x7ff)<<4; |
| 456 | addr+=(unsigned int)code>>25; // y offset into tile |
| 457 | dx=(code>>16)&0x1ff; |
| 458 | if(sh) { |
| 459 | unsigned char *zb = HighCol+dx; |
| 460 | if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; |
| 461 | if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; |
| 462 | if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; |
| 463 | if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; |
| 464 | } |
| 465 | |
| 466 | pal=((code>>9)&0x30); |
| 467 | |
| 468 | if (code&0x0800) zero=TileFlip(dx,addr,pal); |
| 469 | else zero=TileNorm(dx,addr,pal); |
| 470 | |
| 471 | if(zero) blank=(short)code; |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | // -------------------------------------------- |
| 476 | |
| 477 | // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size |
| 478 | // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 |
| 479 | |
| 480 | void DrawSprite(int *sprite, int **hc, int sh) |
| 481 | { |
| 482 | int width=0,height=0; |
| 483 | int row=0,code=0; |
| 484 | int pal; |
| 485 | int tile=0,delta=0; |
| 486 | int sx, sy; |
| 487 | int (*fTileFunc)(int sx,int addr,int pal); |
| 488 | |
| 489 | // parse the sprite data |
| 490 | sy=sprite[0]; |
| 491 | code=sprite[1]; |
| 492 | sx=code>>16; // X |
| 493 | width=sy>>28; |
| 494 | height=(sy>>24)&7; // Width and height in tiles |
| 495 | sy=(sy<<16)>>16; // Y |
| 496 | |
| 497 | row=Scanline-sy; // Row of the sprite we are on |
| 498 | |
| 499 | if (code&0x1000) row=(height<<3)-1-row; // Flip Y |
| 500 | |
| 501 | tile=code&0x7ff; // Tile number |
| 502 | tile+=row>>3; // Tile number increases going down |
| 503 | delta=height; // Delta to increase tile by going right |
| 504 | if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X |
| 505 | |
| 506 | tile<<=4; tile+=(row&7)<<1; // Tile address |
| 507 | |
| 508 | if(code&0x8000) { // high priority - cache it |
| 509 | *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>16)&0xf); |
| 510 | } else { |
| 511 | delta<<=4; // Delta of address |
| 512 | pal=((code>>9)&0x30)|(sh<<6); |
| 513 | |
| 514 | if(sh && (code&0x6000) == 0x6000) { |
| 515 | if(code&0x0800) fTileFunc=TileFlipSH; |
| 516 | else fTileFunc=TileNormSH; |
| 517 | } else { |
| 518 | if(code&0x0800) fTileFunc=TileFlip; |
| 519 | else fTileFunc=TileNorm; |
| 520 | } |
| 521 | |
| 522 | for (; width; width--,sx+=8,tile+=delta) |
| 523 | { |
| 524 | if(sx<=0) continue; |
| 525 | if(sx>=328) break; // Offscreen |
| 526 | |
| 527 | tile&=0x7fff; // Clip tile address |
| 528 | fTileFunc(sx,tile,pal); |
| 529 | } |
| 530 | } |
| 531 | } |
| 532 | |
| 533 | |
| 534 | void DrawSpritesFromCache(int *hc, int sh) |
| 535 | { |
| 536 | int code, tile, sx, delta, width; |
| 537 | int pal; |
| 538 | int (*fTileFunc)(int sx,int addr,int pal); |
| 539 | |
| 540 | // *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf); |
| 541 | |
| 542 | while((code=*hc++)) { |
| 543 | pal=(code&0x30); |
| 544 | delta=code&0xf; |
| 545 | width=delta>>2; delta&=3; |
| 546 | width++; delta++; // Width and height in tiles |
| 547 | if (code&0x10000) delta=-delta; // Flip X |
| 548 | delta<<=4; |
| 549 | tile=((unsigned int)code>>17)<<1; |
| 550 | sx=(code<<16)>>22; // sx can be negative (start offscreen), so sign extend |
| 551 | |
| 552 | if(sh && pal == 0x30) { // |
| 553 | if(code&0x10000) fTileFunc=TileFlipSH; |
| 554 | else fTileFunc=TileNormSH; |
| 555 | } else { |
| 556 | if(code&0x10000) fTileFunc=TileFlip; |
| 557 | else fTileFunc=TileNorm; |
| 558 | } |
| 559 | |
| 560 | for (; width; width--,sx+=8,tile+=delta) |
| 561 | { |
| 562 | if(sx<=0) continue; |
| 563 | if(sx>=328) break; // Offscreen |
| 564 | |
| 565 | tile&=0x7fff; // Clip tile address |
| 566 | fTileFunc(sx,tile,pal); |
| 567 | } |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | |
| 572 | void BackFill(int reg7, int sh) |
| 573 | { |
| 574 | unsigned int back=0; |
| 575 | unsigned int *pd=NULL,*end=NULL; |
| 576 | |
| 577 | // Start with a blank scanline (background colour): |
| 578 | back=reg7&0x3f; |
| 579 | back|=sh<<6; |
| 580 | back|=back<<8; |
| 581 | back|=back<<16; |
| 582 | |
| 583 | pd= (unsigned int *)(HighCol+8); |
| 584 | end=(unsigned int *)(HighCol+8+320); |
| 585 | |
| 586 | do { pd[0]=pd[1]=pd[2]=pd[3]=back; pd+=4; } while (pd<end); |
| 587 | } |
| 588 | |
| 589 | // -------------------------------------------- |
| 590 | |
| 591 | extern unsigned short HighPal[0x100]; |
| 592 | |
| 593 | void FinalizeLineBGR444(int sh) |
| 594 | { |
| 595 | unsigned short *pd=DrawLineDest; |
| 596 | unsigned char *ps=HighCol+8; |
| 597 | unsigned short *pal=Pico.cram; |
| 598 | int len, i, t; |
| 599 | |
| 600 | if (Pico.video.reg[12]&1) { |
| 601 | len = 320; |
| 602 | } else { |
| 603 | if(!(PicoOpt&0x100)) pd+=32; |
| 604 | len = 256; |
| 605 | } |
| 606 | |
| 607 | if(sh) { |
| 608 | pal=HighPal; |
| 609 | if(Pico.m.dirtyPal) { |
| 610 | blockcpy(pal, Pico.cram, 0x40*2); |
| 611 | // shadowed pixels |
| 612 | for(i = 0x3f; i >= 0; i--) |
| 613 | pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x0777); |
| 614 | // hilighted pixels |
| 615 | for(i = 0x3f; i >= 0; i--) { |
| 616 | t=pal[i]&0xeee;t+=0x444;if(t&0x10)t|=0xe;if(t&0x100)t|=0xe0;if(t&0x1000)t|=0xe00;t&=0xeee; |
| 617 | pal[0x80|i]=(unsigned short)t; |
| 618 | } |
| 619 | Pico.m.dirtyPal = 0; |
| 620 | } |
| 621 | } |
| 622 | |
| 623 | for(i = 0; i < len; i++) |
| 624 | pd[i] = pal[ps[i]]; |
| 625 | } |
| 626 | |
| 627 | |
| 628 | void FinalizeLineRGB555(int sh) |
| 629 | { |
| 630 | unsigned short *pd=DrawLineDest; |
| 631 | unsigned char *ps=HighCol+8; |
| 632 | unsigned short *pal=HighPal; |
| 633 | int len, i, t, dirtyPal = Pico.m.dirtyPal; |
| 634 | |
| 635 | if(dirtyPal) { |
| 636 | unsigned short *ppal=Pico.cram; |
| 637 | for(i = 0x3f; i >= 0; i--) |
| 638 | pal[i] = (unsigned short) (((ppal[i]&0x00f)<<12)|((ppal[i]&0x0f0)<<3)|((ppal[i]&0xf00)>>7)); |
| 639 | Pico.m.dirtyPal = 0; |
| 640 | } |
| 641 | |
| 642 | if (Pico.video.reg[12]&1) { |
| 643 | len = 320; |
| 644 | } else { |
| 645 | if(!(PicoOpt&0x100)) pd+=32; |
| 646 | len = 256; |
| 647 | } |
| 648 | |
| 649 | if(sh) { |
| 650 | if(dirtyPal) { |
| 651 | // shadowed pixels |
| 652 | for(i = 0x3f; i >= 0; i--) |
| 653 | pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x738e); |
| 654 | // hilighted pixels |
| 655 | for(i = 0x3f; i >= 0; i--) { |
| 656 | t=pal[i]&0xe71c;t+=0x4208;if(t&0x20)t|=0x1c;if(t&0x800)t|=0x700;if(t&0x10000)t|=0xe000;t&=0xe71c; |
| 657 | pal[0x80|i]=(unsigned short)t; |
| 658 | } |
| 659 | } |
| 660 | } |
| 661 | |
| 662 | for(i = 0; i < len; i++) |
| 663 | pd[i] = pal[ps[i]]; |
| 664 | } |
| 665 | |
| 666 | |
| 667 | |