cc68a136 |
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) |
fb9bec94 |
26 | int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap |
cc68a136 |
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 | } |
fb9bec94 |
169 | continue; |
cc68a136 |
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 | |