adjustments, fix for 'save accept switcher renderer'
[picodrive.git] / Pico / Draw.c
CommitLineData
cc68a136 1// This is part of Pico Library\r
2\r
3// (c) Copyright 2004 Dave, All rights reserved.\r
381eea9b 4// (c) Copyright 2006-2008 notaz, All rights reserved.\r
cc68a136 5// Free for non-commercial use.\r
6\r
7// For commercial use, separate licencing terms must be obtained.\r
8\r
9\r
10#include "PicoInt.h"\r
cc68a136 11\r
602133e1 12int (*PicoScanBegin)(unsigned int num) = NULL;\r
13int (*PicoScanEnd) (unsigned int num) = NULL;\r
cc68a136 14\r
ea8c405f 15#if OVERRIDE_HIGHCOL\r
16static unsigned char DefHighCol[8+320+8];\r
17unsigned char *HighCol=DefHighCol;\r
18#else\r
cc68a136 19unsigned char HighCol[8+320+8];\r
ea8c405f 20#endif\r
21unsigned short DefOutBuff[320*2];\r
22void *DrawLineDest=DefOutBuff; // pointer to dest buffer where to draw this line to\r
23\r
cc68a136 24static int HighCacheA[41+1]; // caches for high layers\r
25static int HighCacheB[41+1];\r
26static int HighCacheS[80+1]; // and sprites\r
27static int HighPreSpr[80*2+1]; // slightly preprocessed sprites\r
381eea9b 28\r
29static unsigned char HighSprZ[320+8+8]; // Z-buffer for accurate sprites\r
30\r
602133e1 31int rendstatus = 0;\r
32int Scanline = 0; // Scanline\r
cc68a136 33\r
34static int SpriteBlocks;\r
602133e1 35static int skip_next_line=0;\r
36\r
cc68a136 37//unsigned short ppt[] = { 0x0f11, 0x0ff1, 0x01f1, 0x011f, 0x01ff, 0x0f1f, 0x0f0e, 0x0e7c };\r
38\r
39struct TileStrip\r
40{\r
41 int nametab; // Position in VRAM of name table (for this tile line)\r
6d7acf9e 42 int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap\r
cc68a136 43 int hscroll; // Horizontal scroll value in pixels for the line\r
44 int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap\r
45 int *hc; // cache for high tile codes and their positions\r
46 int cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320)\r
47};\r
48\r
49// stuff available in asm:\r
50#ifdef _ASM_DRAW_C\r
51void DrawWindow(int tstart, int tend, int prio, int sh);\r
52void BackFill(int reg7, int sh);\r
53void DrawSprite(int *sprite, int **hc, int sh);\r
7a7c6476 54void DrawTilesFromCache(int *hc, int sh, int rlim);\r
cc68a136 55void DrawSpritesFromCache(int *hc, int sh);\r
83c093a4 56void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells);\r
cc68a136 57void FinalizeLineBGR444(int sh);\r
58void FinalizeLineRGB555(int sh);\r
7b802576 59void *blockcpy(void *dst, const void *src, size_t n);\r
cc68a136 60void blockcpy_or(void *dst, void *src, size_t n, int pat);\r
61#else\r
62// utility\r
63void blockcpy_or(void *dst, void *src, size_t n, int pat)\r
64{\r
65 unsigned char *pd = dst, *ps = src;\r
66 for (; n; n--)\r
67 *pd++ = (unsigned char) (*ps++ | pat);\r
68}\r
7b802576 69#define blockcpy memcpy\r
cc68a136 70#endif\r
71\r
72\r
b542be46 73#ifdef _ASM_DRAW_C_AMIPS\r
8ef001cc 74int TileNorm(int sx,int addr,int pal);\r
75int TileFlip(int sx,int addr,int pal);\r
76#else\r
cc68a136 77static int TileNorm(int sx,int addr,int pal)\r
78{\r
79 unsigned char *pd = HighCol+sx;\r
80 unsigned int pack=0; unsigned int t=0;\r
81\r
82 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
83 if (pack)\r
84 {\r
85 t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12));\r
86 t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8));\r
87 t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4));\r
88 t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t ));\r
89 t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28));\r
90 t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24));\r
91 t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20));\r
92 t=pack&0x000f0000; if (t) pd[7]=(unsigned char)(pal|(t>>16));\r
93 return 0;\r
94 }\r
95\r
96 return 1; // Tile blank\r
97}\r
98\r
99static int TileFlip(int sx,int addr,int pal)\r
100{\r
101 unsigned char *pd = HighCol+sx;\r
102 unsigned int pack=0; unsigned int t=0;\r
103\r
104 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
105 if (pack)\r
106 {\r
107 t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16));\r
108 t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20));\r
109 t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24));\r
110 t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28));\r
111 t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t ));\r
112 t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4));\r
113 t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8));\r
114 t=pack&0x0000f000; if (t) pd[7]=(unsigned char)(pal|(t>>12));\r
115 return 0;\r
116 }\r
117 return 1; // Tile blank\r
118}\r
8ef001cc 119#endif\r
cc68a136 120\r
121// tile renderers for hacky operator sprite support\r
122#define sh_pix(x) \\r
123 if(!t); \\r
124 else if(t==0xe) pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ \\r
125 else if(t==0xf) pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ \\r
126 else pd[x]=(unsigned char)(pal|t)\r
127\r
128#ifndef _ASM_DRAW_C\r
129static int TileNormSH(int sx,int addr,int pal)\r
130{\r
131 unsigned int pack=0; unsigned int t=0;\r
132 unsigned char *pd = HighCol+sx;\r
133\r
134 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
135 if (pack)\r
136 {\r
137 t=(pack&0x0000f000)>>12; sh_pix(0);\r
138 t=(pack&0x00000f00)>> 8; sh_pix(1);\r
139 t=(pack&0x000000f0)>> 4; sh_pix(2);\r
140 t=(pack&0x0000000f) ; sh_pix(3);\r
141 t=(pack&0xf0000000)>>28; sh_pix(4);\r
142 t=(pack&0x0f000000)>>24; sh_pix(5);\r
143 t=(pack&0x00f00000)>>20; sh_pix(6);\r
144 t=(pack&0x000f0000)>>16; sh_pix(7);\r
145 return 0;\r
146 }\r
147\r
148 return 1; // Tile blank\r
149}\r
150\r
151static int TileFlipSH(int sx,int addr,int pal)\r
152{\r
153 unsigned int pack=0; unsigned int t=0;\r
154 unsigned char *pd = HighCol+sx;\r
155\r
156 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
157 if (pack)\r
158 {\r
159 t=(pack&0x000f0000)>>16; sh_pix(0);\r
160 t=(pack&0x00f00000)>>20; sh_pix(1);\r
161 t=(pack&0x0f000000)>>24; sh_pix(2);\r
162 t=(pack&0xf0000000)>>28; sh_pix(3);\r
163 t=(pack&0x0000000f) ; sh_pix(4);\r
164 t=(pack&0x000000f0)>> 4; sh_pix(5);\r
165 t=(pack&0x00000f00)>> 8; sh_pix(6);\r
166 t=(pack&0x0000f000)>>12; sh_pix(7);\r
167 return 0;\r
168 }\r
169 return 1; // Tile blank\r
170}\r
171#endif\r
172\r
173static int TileNormZ(int sx,int addr,int pal,int zval)\r
174{\r
175 unsigned int pack=0; unsigned int t=0;\r
176 unsigned char *pd = HighCol+sx;\r
381eea9b 177 unsigned char *zb = HighSprZ+sx;\r
178 int collision = 0;\r
cc68a136 179\r
180 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
181 if (pack)\r
182 {\r
381eea9b 183 t=pack&0x0000f000; if(t) { if(zb[0]) collision=1; if(zval>zb[0]) { pd[0]=(unsigned char)(pal|(t>>12)); zb[0]=(char)zval; } }\r
184 t=pack&0x00000f00; if(t) { if(zb[1]) collision=1; if(zval>zb[1]) { pd[1]=(unsigned char)(pal|(t>> 8)); zb[1]=(char)zval; } }\r
185 t=pack&0x000000f0; if(t) { if(zb[2]) collision=1; if(zval>zb[2]) { pd[2]=(unsigned char)(pal|(t>> 4)); zb[2]=(char)zval; } }\r
186 t=pack&0x0000000f; if(t) { if(zb[3]) collision=1; if(zval>zb[3]) { pd[3]=(unsigned char)(pal|(t )); zb[3]=(char)zval; } }\r
187 t=pack&0xf0000000; if(t) { if(zb[4]) collision=1; if(zval>zb[4]) { pd[4]=(unsigned char)(pal|(t>>28)); zb[4]=(char)zval; } }\r
188 t=pack&0x0f000000; if(t) { if(zb[5]) collision=1; if(zval>zb[5]) { pd[5]=(unsigned char)(pal|(t>>24)); zb[5]=(char)zval; } }\r
189 t=pack&0x00f00000; if(t) { if(zb[6]) collision=1; if(zval>zb[6]) { pd[6]=(unsigned char)(pal|(t>>20)); zb[6]=(char)zval; } }\r
190 t=pack&0x000f0000; if(t) { if(zb[7]) collision=1; if(zval>zb[7]) { pd[7]=(unsigned char)(pal|(t>>16)); zb[7]=(char)zval; } }\r
191 if (collision) Pico.video.status|=0x20;\r
cc68a136 192 return 0;\r
193 }\r
194\r
195 return 1; // Tile blank\r
196}\r
381eea9b 197 \r
cc68a136 198static int TileFlipZ(int sx,int addr,int pal,int zval)\r
199{\r
200 unsigned int pack=0; unsigned int t=0;\r
201 unsigned char *pd = HighCol+sx;\r
381eea9b 202 unsigned char *zb = HighSprZ+sx;\r
203 int collision = 0;\r
cc68a136 204\r
205 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
206 if (pack)\r
207 {\r
381eea9b 208 t=pack&0x000f0000; if(t) { if(zb[0]) collision=1; if(zval>zb[0]) { pd[0]=(unsigned char)(pal|(t>>16)); zb[0]=(char)zval; } }\r
209 t=pack&0x00f00000; if(t) { if(zb[1]) collision=1; if(zval>zb[1]) { pd[1]=(unsigned char)(pal|(t>>20)); zb[1]=(char)zval; } }\r
210 t=pack&0x0f000000; if(t) { if(zb[2]) collision=1; if(zval>zb[2]) { pd[2]=(unsigned char)(pal|(t>>24)); zb[2]=(char)zval; } }\r
211 t=pack&0xf0000000; if(t) { if(zb[3]) collision=1; if(zval>zb[3]) { pd[3]=(unsigned char)(pal|(t>>28)); zb[3]=(char)zval; } }\r
212 t=pack&0x0000000f; if(t) { if(zb[4]) collision=1; if(zval>zb[4]) { pd[4]=(unsigned char)(pal|(t )); zb[4]=(char)zval; } }\r
213 t=pack&0x000000f0; if(t) { if(zb[5]) collision=1; if(zval>zb[5]) { pd[5]=(unsigned char)(pal|(t>> 4)); zb[5]=(char)zval; } }\r
214 t=pack&0x00000f00; if(t) { if(zb[6]) collision=1; if(zval>zb[6]) { pd[6]=(unsigned char)(pal|(t>> 8)); zb[6]=(char)zval; } }\r
215 t=pack&0x0000f000; if(t) { if(zb[7]) collision=1; if(zval>zb[7]) { pd[7]=(unsigned char)(pal|(t>>12)); zb[7]=(char)zval; } }\r
216 if (collision) Pico.video.status|=0x20;\r
cc68a136 217 return 0;\r
218 }\r
219 return 1; // Tile blank\r
220}\r
221\r
222\r
223#define sh_pixZ(x) \\r
224 if(t) { \\r
225 if(zb[x]) collision=1; \\r
226 if(zval>zb[x]) { \\r
227 if (t==0xe) { pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ } \\r
228 else if(t==0xf) { pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ } \\r
229 else { zb[x]=(char)zval; pd[x]=(unsigned char)(pal|t); } \\r
230 } \\r
231 }\r
232\r
233static int TileNormZSH(int sx,int addr,int pal,int zval)\r
234{\r
235 unsigned int pack=0; unsigned int t=0;\r
236 unsigned char *pd = HighCol+sx;\r
381eea9b 237 unsigned char *zb = HighSprZ+sx;\r
cc68a136 238 int collision = 0;\r
239\r
240 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
241 if (pack)\r
242 {\r
243 t=(pack&0x0000f000)>>12; sh_pixZ(0);\r
244 t=(pack&0x00000f00)>> 8; sh_pixZ(1);\r
245 t=(pack&0x000000f0)>> 4; sh_pixZ(2);\r
246 t=(pack&0x0000000f) ; sh_pixZ(3);\r
247 t=(pack&0xf0000000)>>28; sh_pixZ(4);\r
248 t=(pack&0x0f000000)>>24; sh_pixZ(5);\r
249 t=(pack&0x00f00000)>>20; sh_pixZ(6);\r
250 t=(pack&0x000f0000)>>16; sh_pixZ(7);\r
251 if(collision) Pico.video.status|=0x20;\r
252 return 0;\r
253 }\r
254\r
255 return 1; // Tile blank\r
256}\r
257\r
258static int TileFlipZSH(int sx,int addr,int pal,int zval)\r
259{\r
260 unsigned int pack=0; unsigned int t=0;\r
261 unsigned char *pd = HighCol+sx;\r
381eea9b 262 unsigned char *zb = HighSprZ+sx;\r
cc68a136 263 int collision = 0;\r
264\r
265 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
266 if (pack)\r
267 {\r
268 t=(pack&0x000f0000)>>16; sh_pixZ(0);\r
269 t=(pack&0x00f00000)>>20; sh_pixZ(1);\r
270 t=(pack&0x0f000000)>>24; sh_pixZ(2);\r
271 t=(pack&0xf0000000)>>28; sh_pixZ(3);\r
272 t=(pack&0x0000000f) ; sh_pixZ(4);\r
273 t=(pack&0x000000f0)>> 4; sh_pixZ(5);\r
274 t=(pack&0x00000f00)>> 8; sh_pixZ(6);\r
275 t=(pack&0x0000f000)>>12; sh_pixZ(7);\r
276 if(collision) Pico.video.status|=0x20;\r
277 return 0;\r
278 }\r
279 return 1; // Tile blank\r
280}\r
281\r
282// --------------------------------------------\r
283\r
284#ifndef _ASM_DRAW_C\r
83c093a4 285static void DrawStrip(struct TileStrip *ts, int plane_sh, int cellskip)\r
cc68a136 286{\r
83c093a4 287 int tilex,dx,ty,code=0,addr=0,cells;\r
cc68a136 288 int oldcode=-1,blank=-1; // The tile we know is blank\r
83c093a4 289 int pal=0,sh;\r
cc68a136 290\r
291 // Draw tiles across screen:\r
83c093a4 292 sh=(plane_sh<<5)&0x40;\r
293 tilex=((-ts->hscroll)>>3)+cellskip;\r
cc68a136 294 ty=(ts->line&7)<<1; // Y-Offset into tile\r
295 dx=((ts->hscroll-1)&7)+1;\r
83c093a4 296 cells = ts->cells - cellskip;\r
cc68a136 297 if(dx != 8) cells++; // have hscroll, need to draw 1 cell more\r
83c093a4 298 dx+=cellskip<<3;\r
cc68a136 299\r
83c093a4 300 for (; cells > 0; dx+=8,tilex++,cells--)\r
cc68a136 301 {\r
302 int zero=0;\r
303\r
304 code=Pico.vram[ts->nametab+(tilex&ts->xmask)];\r
305 if (code==blank) continue;\r
306 if (code>>15) { // high priority tile\r
307 int cval = code | (dx<<16) | (ty<<25);\r
308 if(code&0x1000) cval^=7<<26;\r
309 *ts->hc++ = cval; // cache it\r
310 continue;\r
311 }\r
312\r
313 if (code!=oldcode) {\r
314 oldcode = code;\r
315 // Get tile address/2:\r
316 addr=(code&0x7ff)<<4;\r
317 addr+=ty;\r
318 if (code&0x1000) addr^=0xe; // Y-flip\r
319\r
83c093a4 320 pal=((code>>9)&0x30)|sh;\r
cc68a136 321 }\r
322\r
323 if (code&0x0800) zero=TileFlip(dx,addr,pal);\r
324 else zero=TileNorm(dx,addr,pal);\r
325\r
326 if (zero) blank=code; // We know this tile is blank now\r
327 }\r
328\r
329 // terminate the cache list\r
330 *ts->hc = 0;\r
740da8c6 331 // if oldcode wasn't changed, it means all layer is hi priority\r
602133e1 332 if (oldcode == -1) rendstatus |= PDRAW_PLANE_HI_PRIO;\r
cc68a136 333}\r
cc68a136 334\r
335// this is messy\r
83c093a4 336void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)\r
cc68a136 337{\r
83c093a4 338 int tilex,dx,code=0,addr=0,cell=0;\r
cc68a136 339 int oldcode=-1,blank=-1; // The tile we know is blank\r
340 int pal=0,scan=Scanline;\r
341\r
342 // Draw tiles across screen:\r
343 tilex=(-ts->hscroll)>>3;\r
344 dx=((ts->hscroll-1)&7)+1;\r
83c093a4 345 if(dx != 8) cell--; // have hscroll, start with negative cell\r
346 cell+=cellskip;\r
347 tilex+=cellskip;\r
348 dx+=cellskip<<3;\r
cc68a136 349\r
350 for (; cell < ts->cells; dx+=8,tilex++,cell++)\r
351 {\r
83c093a4 352 int zero=0,nametabadd,ty;\r
cc68a136 353\r
83c093a4 354 //if((cell&1)==0)\r
355 {\r
cc68a136 356 int line,vscroll;\r
83c093a4 357 vscroll=Pico.vsram[(plane_sh&1)+(cell&~1)];\r
cc68a136 358\r
359 // Find the line in the name table\r
360 line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..\r
361 nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width]\r
362 ty=(line&7)<<1; // Y-Offset into tile\r
363 }\r
364\r
365 code=Pico.vram[ts->nametab+nametabadd+(tilex&ts->xmask)];\r
366 if (code==blank) continue;\r
367 if (code>>15) { // high priority tile\r
368 int cval = code | (dx<<16) | (ty<<25);\r
369 if(code&0x1000) cval^=7<<26;\r
370 *ts->hc++ = cval; // cache it\r
371 continue;\r
372 }\r
373\r
374 if (code!=oldcode) {\r
375 oldcode = code;\r
376 // Get tile address/2:\r
377 addr=(code&0x7ff)<<4;\r
378 if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip\r
379\r
83c093a4 380 pal=((code>>9)&0x30)|((plane_sh<<5)&0x40);\r
cc68a136 381 }\r
382\r
383 if (code&0x0800) zero=TileFlip(dx,addr,pal);\r
384 else zero=TileNorm(dx,addr,pal);\r
385\r
386 if (zero) blank=code; // We know this tile is blank now\r
387 }\r
388\r
389 // terminate the cache list\r
390 *ts->hc = 0;\r
602133e1 391 if (oldcode == -1) rendstatus |= PDRAW_PLANE_HI_PRIO;\r
cc68a136 392}\r
6d7acf9e 393#endif\r
cc68a136 394\r
395#ifndef _ASM_DRAW_C\r
396static\r
397#endif\r
398void DrawStripInterlace(struct TileStrip *ts)\r
399{\r
400 int tilex=0,dx=0,ty=0,code=0,addr=0,cells;\r
401 int oldcode=-1,blank=-1; // The tile we know is blank\r
402 int pal=0;\r
403\r
404 // Draw tiles across screen:\r
405 tilex=(-ts->hscroll)>>3;\r
406 ty=(ts->line&15)<<1; // Y-Offset into tile\r
407 dx=((ts->hscroll-1)&7)+1;\r
408 cells = ts->cells;\r
409 if(dx != 8) cells++; // have hscroll, need to draw 1 cell more\r
410\r
411 for (; cells; dx+=8,tilex++,cells--)\r
412 {\r
413 int zero=0;\r
414\r
415 code=Pico.vram[ts->nametab+(tilex&ts->xmask)];\r
416 if (code==blank) continue;\r
417 if (code>>15) { // high priority tile\r
418 int cval = (code&0xfc00) | (dx<<16) | (ty<<25);\r
419 cval|=(code&0x3ff)<<1;\r
420 if(code&0x1000) cval^=0xf<<26;\r
421 *ts->hc++ = cval; // cache it\r
422 continue;\r
423 }\r
424\r
425 if (code!=oldcode) {\r
426 oldcode = code;\r
427 // Get tile address/2:\r
428 addr=(code&0x7ff)<<5;\r
429 if (code&0x1000) addr+=30-ty; else addr+=ty; // Y-flip\r
430\r
431// pal=Pico.cram+((code>>9)&0x30);\r
432 pal=((code>>9)&0x30);\r
433 }\r
434\r
435 if (code&0x0800) zero=TileFlip(dx,addr,pal);\r
436 else zero=TileNorm(dx,addr,pal);\r
437\r
438 if (zero) blank=code; // We know this tile is blank now\r
439 }\r
440\r
441 // terminate the cache list\r
442 *ts->hc = 0;\r
443}\r
444\r
445// --------------------------------------------\r
446\r
447#ifndef _ASM_DRAW_C\r
83c093a4 448static void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells)\r
cc68a136 449{\r
450 struct PicoVideo *pvid=&Pico.video;\r
451 const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid)\r
452 struct TileStrip ts;\r
453 int width, height, ymask;\r
454 int vscroll, htab;\r
455\r
456 ts.hc=hcache;\r
457 ts.cells=maxcells;\r
458\r
459 // Work out the TileStrip to draw\r
460\r
461 // Work out the name table size: 32 64 or 128 tiles (0-3)\r
462 width=pvid->reg[16];\r
463 height=(width>>4)&3; width&=3;\r
464\r
465 ts.xmask=(1<<shift[width])-1; // X Mask in tiles (0x1f-0x7f)\r
466 ymask=(height<<8)|0xff; // Y Mask in pixels\r
467 if(width == 1) ymask&=0x1ff;\r
468 else if(width>1) ymask =0x0ff;\r
469\r
470 // Find name table:\r
83c093a4 471 if (plane_sh&1) ts.nametab=(pvid->reg[4]&0x07)<<12; // B\r
472 else ts.nametab=(pvid->reg[2]&0x38)<< 9; // A\r
cc68a136 473\r
474 htab=pvid->reg[13]<<9; // Horizontal scroll table address\r
475 if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line\r
476 if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile\r
83c093a4 477 htab+=plane_sh&1; // A or B\r
cc68a136 478\r
479 // Get horizontal scroll value, will be masked later\r
480 ts.hscroll=Pico.vram[htab&0x7fff];\r
481\r
482 if((pvid->reg[12]&6) == 6) {\r
483 // interlace mode 2\r
83c093a4 484 vscroll=Pico.vsram[plane_sh&1]; // Get vertical scroll value\r
cc68a136 485\r
486 // Find the line in the name table\r
487 ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1);\r
488 ts.nametab+=(ts.line>>4)<<shift[width];\r
489\r
490 DrawStripInterlace(&ts);\r
491 } else if( pvid->reg[11]&4) {\r
492 // shit, we have 2-cell column based vscroll\r
493 // luckily this doesn't happen too often\r
494 ts.line=ymask|(shift[width]<<24); // save some stuff instead of line\r
83c093a4 495 DrawStripVSRam(&ts, plane_sh, cellskip);\r
cc68a136 496 } else {\r
83c093a4 497 vscroll=Pico.vsram[plane_sh&1]; // Get vertical scroll value\r
cc68a136 498\r
499 // Find the line in the name table\r
500 ts.line=(vscroll+Scanline)&ymask;\r
501 ts.nametab+=(ts.line>>3)<<shift[width];\r
502\r
83c093a4 503 DrawStrip(&ts, plane_sh, cellskip);\r
cc68a136 504 }\r
505}\r
506\r
507\r
508// --------------------------------------------\r
509\r
510// tstart & tend are tile pair numbers\r
511static void DrawWindow(int tstart, int tend, int prio, int sh) // int *hcache\r
512{\r
513 struct PicoVideo *pvid=&Pico.video;\r
514 int tilex=0,ty=0,nametab,code=0;\r
515 int blank=-1; // The tile we know is blank\r
516\r
517 // Find name table line:\r
518 if (pvid->reg[12]&1)\r
519 {\r
520 nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode\r
521 nametab+=(Scanline>>3)<<6;\r
522 }\r
523 else\r
524 {\r
525 nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode\r
526 nametab+=(Scanline>>3)<<5;\r
527 }\r
528\r
529 tilex=tstart<<1;\r
530 tend<<=1;\r
531\r
532 ty=(Scanline&7)<<1; // Y-Offset into tile\r
533\r
602133e1 534 if (!(rendstatus & PDRAW_WND_DIFF_PRIO)) {\r
cc68a136 535 // check the first tile code\r
536 code=Pico.vram[nametab+tilex];\r
537 // if the whole window uses same priority (what is often the case), we may be able to skip this field\r
602133e1 538 if ((code>>15) != prio) return;\r
cc68a136 539 }\r
540\r
541 // Draw tiles across screen:\r
81fda4e8 542 if (!sh)\r
cc68a136 543 {\r
81fda4e8 544 for (; tilex < tend; tilex++)\r
545 {\r
546 int addr=0,zero=0;\r
547 int pal;\r
548\r
549 code=Pico.vram[nametab+tilex];\r
602133e1 550 if (code==blank) continue;\r
551 if ((code>>15) != prio) {\r
552 rendstatus |= PDRAW_WND_DIFF_PRIO;\r
81fda4e8 553 continue;\r
554 }\r
cc68a136 555\r
81fda4e8 556 pal=((code>>9)&0x30);\r
557\r
558 // Get tile address/2:\r
559 addr=(code&0x7ff)<<4;\r
560 if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip\r
561\r
562 if (code&0x0800) zero=TileFlip(8+(tilex<<3),addr,pal);\r
563 else zero=TileNorm(8+(tilex<<3),addr,pal);\r
564\r
565 if (zero) blank=code; // We know this tile is blank now\r
cc68a136 566 }\r
81fda4e8 567 }\r
568 else\r
569 {\r
570 for (; tilex < tend; tilex++)\r
571 {\r
572 int addr=0,zero=0;\r
573 int pal, tmp, *zb;\r
574\r
575 code=Pico.vram[nametab+tilex];\r
576 if(code==blank) continue;\r
577 if((code>>15) != prio) {\r
602133e1 578 rendstatus |= PDRAW_WND_DIFF_PRIO;\r
81fda4e8 579 continue;\r
580 }\r
cc68a136 581\r
81fda4e8 582 pal=((code>>9)&0x30);\r
cc68a136 583\r
81fda4e8 584 zb = (int *)(HighCol+8+(tilex<<3));\r
cc68a136 585 if(prio) {\r
586 tmp = *zb;\r
587 if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000;\r
588 if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000;\r
589 *zb++=tmp; tmp = *zb;\r
590 if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000;\r
591 if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000;\r
592 *zb++=tmp;\r
593 } else {\r
594 pal |= 0x40;\r
595 }\r
cc68a136 596\r
81fda4e8 597 // Get tile address/2:\r
598 addr=(code&0x7ff)<<4;\r
599 if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip\r
cc68a136 600\r
81fda4e8 601 if (code&0x0800) zero=TileFlip(8+(tilex<<3),addr,pal);\r
602 else zero=TileNorm(8+(tilex<<3),addr,pal);\r
cc68a136 603\r
81fda4e8 604 if (zero) blank=code; // We know this tile is blank now\r
605 }\r
cc68a136 606 }\r
cc68a136 607}\r
608\r
609// --------------------------------------------\r
610\r
81fda4e8 611static void DrawTilesFromCacheShPrep(void)\r
612{\r
602133e1 613 // as some layer has covered whole line with hi priority tiles,\r
614 // we can process whole line and then act as if sh/hi mode was off.\r
615 int c = 320/4, *zb = (int *)(HighCol+8);\r
616 rendstatus |= PDRAW_SHHI_DONE;\r
617 while (c--)\r
81fda4e8 618 {\r
602133e1 619 int tmp = *zb;\r
620 if (!(tmp & 0x80808080)) *zb=tmp&0x3f3f3f3f;\r
621 else {\r
622 if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000;\r
623 if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000;\r
624 *zb=tmp;\r
81fda4e8 625 }\r
602133e1 626 zb++;\r
81fda4e8 627 }\r
628}\r
629\r
7a7c6476 630static void DrawTilesFromCache(int *hc, int sh, int rlim)\r
cc68a136 631{\r
740da8c6 632 int code, addr, dx;\r
cc68a136 633 int pal;\r
cc68a136 634\r
635 // *ts->hc++ = code | (dx<<16) | (ty<<25); // cache it\r
636\r
602133e1 637 if (sh && (rendstatus & (PDRAW_SHHI_DONE|PDRAW_PLANE_HI_PRIO)))\r
740da8c6 638 {\r
602133e1 639 if (!(rendstatus & PDRAW_SHHI_DONE))\r
640 DrawTilesFromCacheShPrep();\r
740da8c6 641 sh = 0;\r
642 }\r
cc68a136 643\r
81fda4e8 644 if (!sh)\r
740da8c6 645 {\r
81fda4e8 646 short blank=-1; // The tile we know is blank\r
7a7c6476 647 while ((code=*hc++)) {\r
81fda4e8 648 int zero;\r
649 if((short)code == blank) continue;\r
740da8c6 650 // Get tile address/2:\r
651 addr=(code&0x7ff)<<4;\r
652 addr+=(unsigned int)code>>25; // y offset into tile\r
653 dx=(code>>16)&0x1ff;\r
740da8c6 654\r
655 pal=((code>>9)&0x30);\r
7a7c6476 656 if (rlim-dx < 0) goto last_cut_tile;\r
740da8c6 657\r
81fda4e8 658 if (code&0x0800) zero=TileFlip(dx,addr,pal);\r
659 else zero=TileNorm(dx,addr,pal);\r
660\r
661 if (zero) blank=(short)code;\r
cc68a136 662 }\r
740da8c6 663 }\r
664 else\r
665 {\r
7a7c6476 666 while ((code=*hc++)) {\r
81fda4e8 667 unsigned char *zb;\r
740da8c6 668 // Get tile address/2:\r
669 addr=(code&0x7ff)<<4;\r
670 addr+=(unsigned int)code>>25; // y offset into tile\r
671 dx=(code>>16)&0x1ff;\r
81fda4e8 672 zb = HighCol+dx;\r
673 if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++;\r
674 if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++;\r
675 if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++;\r
676 if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++;\r
cc68a136 677\r
740da8c6 678 pal=((code>>9)&0x30);\r
7a7c6476 679 if (rlim-dx < 0) goto last_cut_tile;\r
cc68a136 680\r
81fda4e8 681 if (code&0x0800) TileFlip(dx,addr,pal);\r
682 else TileNorm(dx,addr,pal);\r
7a7c6476 683 }\r
684 }\r
685 return;\r
686\r
687last_cut_tile:\r
688 {\r
689 unsigned int t, pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
690 unsigned char *pd = HighCol+dx;\r
691 if (!pack) return;\r
692 if (code&0x0800)\r
693 {\r
694 switch (rlim-dx+8)\r
695 {\r
696 case 7: t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8)); // "break" is left out intentionally\r
697 case 6: t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4));\r
698 case 5: t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t ));\r
699 case 4: t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28));\r
700 case 3: t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24));\r
701 case 2: t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20));\r
702 case 1: t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16));\r
703 default: break;\r
704 }\r
705 }\r
706 else\r
707 {\r
708 switch (rlim-dx+8)\r
709 {\r
710 case 7: t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20));\r
711 case 6: t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24));\r
712 case 5: t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28));\r
713 case 4: t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t ));\r
714 case 3: t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4));\r
715 case 2: t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8));\r
716 case 1: t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12));\r
717 default: break;\r
718 }\r
740da8c6 719 }\r
cc68a136 720 }\r
721}\r
722\r
723// --------------------------------------------\r
724\r
725// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size\r
726// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8\r
727\r
728static void DrawSprite(int *sprite, int **hc, int sh)\r
729{\r
730 int width=0,height=0;\r
731 int row=0,code=0;\r
732 int pal;\r
733 int tile=0,delta=0;\r
734 int sx, sy;\r
735 int (*fTileFunc)(int sx,int addr,int pal);\r
736\r
737 // parse the sprite data\r
738 sy=sprite[0];\r
739 code=sprite[1];\r
740 sx=code>>16; // X\r
741 width=sy>>28;\r
742 height=(sy>>24)&7; // Width and height in tiles\r
743 sy=(sy<<16)>>16; // Y\r
744\r
745 row=Scanline-sy; // Row of the sprite we are on\r
746\r
747 if (code&0x1000) row=(height<<3)-1-row; // Flip Y\r
748\r
749 tile=code&0x7ff; // Tile number\r
750 tile+=row>>3; // Tile number increases going down\r
751 delta=height; // Delta to increase tile by going right\r
752 if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X\r
753\r
754 tile<<=4; tile+=(row&7)<<1; // Tile address\r
755\r
756 if(code&0x8000) { // high priority - cache it\r
757 *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>16)&0xf);\r
758 } else {\r
759 delta<<=4; // Delta of address\r
760 pal=((code>>9)&0x30)|(sh<<6);\r
761\r
762 if(sh && (code&0x6000) == 0x6000) {\r
763 if(code&0x0800) fTileFunc=TileFlipSH;\r
764 else fTileFunc=TileNormSH;\r
765 } else {\r
766 if(code&0x0800) fTileFunc=TileFlip;\r
767 else fTileFunc=TileNorm;\r
768 }\r
769\r
770 for (; width; width--,sx+=8,tile+=delta)\r
771 {\r
772 if(sx<=0) continue;\r
773 if(sx>=328) break; // Offscreen\r
774\r
775 tile&=0x7fff; // Clip tile address\r
776 fTileFunc(sx,tile,pal);\r
777 }\r
778 }\r
779}\r
780#endif\r
781\r
782\r
783// Index + 0 : hhhhvvvv s---hhvv yyyyyyyy yyyyyyyy // s: skip flag, h: horiz. size\r
784// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8\r
785\r
786static void DrawSpriteZ(int pack, int pack2, int shpri, int sprio)\r
787{\r
788 int width=0,height=0;\r
789 int row=0;\r
790 int pal;\r
791 int tile=0,delta=0;\r
792 int sx, sy;\r
793 int (*fTileFunc)(int sx,int addr,int pal,int zval);\r
794\r
795 // parse the sprite data\r
796 sx=pack2>>16; // X\r
797 sy=(pack <<16)>>16; // Y\r
798 width=pack>>28;\r
799 height=(pack>>24)&7; // Width and height in tiles\r
800\r
801 row=Scanline-sy; // Row of the sprite we are on\r
802\r
803 if (pack2&0x1000) row=(height<<3)-1-row; // Flip Y\r
804\r
805 tile=pack2&0x7ff; // Tile number\r
806 tile+=row>>3; // Tile number increases going down\r
807 delta=height; // Delta to increase tile by going right\r
808 if (pack2&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X\r
809\r
810 tile<<=4; tile+=(row&7)<<1; // Tile address\r
811 delta<<=4; // Delta of address\r
812 pal=((pack2>>9)&0x30);\r
813 if((shpri&1)&&!(shpri&2)) pal|=0x40;\r
814\r
815 shpri&=1;\r
816 if((pack2&0x6000) != 0x6000) shpri = 0;\r
817 shpri |= (pack2&0x0800)>>10;\r
818 switch(shpri) {\r
819 default:\r
820 case 0: fTileFunc=TileNormZ; break;\r
821 case 1: fTileFunc=TileNormZSH; break;\r
822 case 2: fTileFunc=TileFlipZ; break;\r
823 case 3: fTileFunc=TileFlipZSH; break;\r
824 }\r
825\r
826 for (; width; width--,sx+=8,tile+=delta)\r
827 {\r
828 if(sx<=0) continue;\r
829 if(sx>=328) break; // Offscreen\r
830\r
831 tile&=0x7fff; // Clip tile address\r
832 fTileFunc(sx,tile,pal,sprio);\r
833 }\r
834}\r
835\r
836static void DrawSpriteInterlace(unsigned int *sprite)\r
837{\r
838 int width=0,height=0;\r
839 int row=0,code=0;\r
840 int pal;\r
841 int tile=0,delta=0;\r
842 int sx, sy;\r
843\r
844 // parse the sprite data\r
845 sy=sprite[0];\r
846 height=sy>>24;\r
847 sy=(sy&0x3ff)-0x100; // Y\r
848 width=(height>>2)&3; height&=3;\r
849 width++; height++; // Width and height in tiles\r
850\r
851 row=(Scanline<<1)-sy; // Row of the sprite we are on\r
852\r
853 code=sprite[1];\r
854 sx=((code>>16)&0x1ff)-0x78; // X\r
855\r
856 if (code&0x1000) row^=(16<<height)-1; // Flip Y\r
857\r
858 tile=code&0x3ff; // Tile number\r
859 tile+=row>>4; // Tile number increases going down\r
860 delta=height; // Delta to increase tile by going right\r
861 if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X\r
862\r
863 tile<<=5; tile+=(row&15)<<1; // Tile address\r
864\r
865 delta<<=5; // Delta of address\r
866 pal=((code>>9)&0x30); // Get palette pointer\r
867\r
868 for (; width; width--,sx+=8,tile+=delta)\r
869 {\r
870 if(sx<=0) continue;\r
871 if(sx>=328) break; // Offscreen\r
872\r
873 tile&=0x7fff; // Clip tile address\r
874 if (code&0x0800) TileFlip(sx,tile,pal);\r
875 else TileNorm(sx,tile,pal);\r
876 }\r
877}\r
878\r
879\r
880static void DrawAllSpritesInterlace(int pri, int maxwidth)\r
881{\r
882 struct PicoVideo *pvid=&Pico.video;\r
883 int i,u,table,link=0,sline=Scanline<<1;\r
884 unsigned int *sprites[80]; // Sprite index\r
885\r
886 table=pvid->reg[5]&0x7f;\r
887 if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode\r
888 table<<=8; // Get sprite table address/2\r
889\r
890 for (i=u=0; u < 80 && i < 21; u++)\r
891 {\r
892 unsigned int *sprite;\r
893 int code, sx, sy, height;\r
894\r
895 sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite\r
896\r
897 // get sprite info\r
898 code = sprite[0];\r
899 sx = sprite[1];\r
900 if(((sx>>15)&1) != pri) goto nextsprite; // wrong priority sprite\r
901\r
902 // check if it is on this line\r
903 sy = (code&0x3ff)-0x100;\r
904 height = (((code>>24)&3)+1)<<4;\r
905 if(sline < sy || sline >= sy+height) goto nextsprite; // no\r
906\r
907 // check if sprite is not hidden offscreen\r
908 sx = (sx>>16)&0x1ff;\r
909 sx -= 0x78; // Get X coordinate + 8\r
910 if(sx <= -8*3 || sx >= maxwidth) goto nextsprite;\r
911\r
912 // sprite is good, save it's pointer\r
913 sprites[i++]=sprite;\r
914\r
915 nextsprite:\r
916 // Find next sprite\r
917 link=(code>>16)&0x7f;\r
918 if(!link) break; // End of sprites\r
919 }\r
920\r
921 // Go through sprites backwards:\r
922 for (i-- ;i>=0; i--)\r
923 DrawSpriteInterlace(sprites[i]);\r
924}\r
925\r
926\r
927#ifndef _ASM_DRAW_C\r
928static void DrawSpritesFromCache(int *hc, int sh)\r
929{\r
930 int code, tile, sx, delta, width;\r
931 int pal;\r
932 int (*fTileFunc)(int sx,int addr,int pal);\r
933\r
934 // *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf);\r
935\r
936 while((code=*hc++)) {\r
937 pal=(code&0x30);\r
938 delta=code&0xf;\r
939 width=delta>>2; delta&=3;\r
940 width++; delta++; // Width and height in tiles\r
941 if (code&0x10000) delta=-delta; // Flip X\r
942 delta<<=4;\r
943 tile=((unsigned int)code>>17)<<1;\r
944 sx=(code<<16)>>22; // sx can be negative (start offscreen), so sign extend\r
945\r
946 if(sh && pal == 0x30) { //\r
947 if(code&0x10000) fTileFunc=TileFlipSH;\r
948 else fTileFunc=TileNormSH;\r
949 } else {\r
950 if(code&0x10000) fTileFunc=TileFlip;\r
951 else fTileFunc=TileNorm;\r
952 }\r
953\r
954 for (; width; width--,sx+=8,tile+=delta)\r
955 {\r
956 if(sx<=0) continue;\r
957 if(sx>=328) break; // Offscreen\r
958\r
959 tile&=0x7fff; // Clip tile address\r
960 fTileFunc(sx,tile,pal);\r
961 }\r
962 }\r
963}\r
964#endif\r
965\r
966\r
967// Index + 0 : ----hhvv -lllllll -------y yyyyyyyy\r
968// Index + 4 : -------x xxxxxxxx pccvhnnn nnnnnnnn\r
969// v\r
970// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size\r
971// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8\r
972\r
973static void PrepareSprites(int full)\r
974{\r
975 struct PicoVideo *pvid=&Pico.video;\r
976 int u=0,link=0,sblocks=0;\r
977 int table=0;\r
978 int *pd = HighPreSpr;\r
979\r
980 table=pvid->reg[5]&0x7f;\r
981 if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode\r
982 table<<=8; // Get sprite table address/2\r
983\r
984 if (!full)\r
985 {\r
986 int pack;\r
987 // updates: tilecode, sx\r
988 for (u=0; u < 80 && (pack = *pd); u++, pd+=2)\r
989 {\r
990 unsigned int *sprite;\r
991 int code, code2, sx, sy, skip=0;\r
992\r
993 sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite\r
994\r
995 // parse sprite info\r
996 code = sprite[0];\r
997 code2 = sprite[1];\r
998 code2 &= ~0xfe000000;\r
999 code2 -= 0x00780000; // Get X coordinate + 8 in upper 16 bits\r
1000 sx = code2>>16;\r
1001\r
1002 if((sx <= 8-((pack>>28)<<3) && sx >= -0x76) || sx >= 328) skip=1<<23;\r
1003 else if ((sy = (pack<<16)>>16) < 240 && sy > -32) {\r
1004 int sbl = (2<<(pack>>28))-1;\r
1005 sblocks |= sbl<<(sy>>3);\r
1006 }\r
1007\r
1008 *pd = (pack&~(1<<23))|skip;\r
1009 *(pd+1) = code2;\r
1010\r
1011 // Find next sprite\r
1012 link=(code>>16)&0x7f;\r
1013 if(!link) break; // End of sprites\r
1014 }\r
1015 SpriteBlocks |= sblocks;\r
1016 }\r
1017 else\r
1018 {\r
1019 for (; u < 80; u++)\r
1020 {\r
1021 unsigned int *sprite;\r
1022 int code, code2, sx, sy, hv, height, width, skip=0, sx_min;\r
1023\r
1024 sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite\r
1025\r
1026 // parse sprite info\r
1027 code = sprite[0];\r
1028 sy = (code&0x1ff)-0x80;\r
1029 hv = (code>>24)&0xf;\r
1030 height = (hv&3)+1;\r
1031\r
381eea9b 1032 if (sy > 240 || sy + (height<<3) <= 0) skip|=1<<22; // sprite offscreen (completely, y)\r
6d7acf9e 1033\r
cc68a136 1034 width = (hv>>2)+1;\r
1035 code2 = sprite[1];\r
1036 sx = (code2>>16)&0x1ff;\r
1037 sx -= 0x78; // Get X coordinate + 8\r
1038 sx_min = 8-(width<<3);\r
6d7acf9e 1039\r
381eea9b 1040 if ((sx <= sx_min && sx >= -0x76) || sx >= 328) skip|=1<<23; // offscreen x\r
cc68a136 1041 else if (sx > sx_min && !skip) {\r
1042 int sbl = (2<<height)-1;\r
1043 int shi = sy>>3;\r
1044 if(shi < 0) shi=0; // negative sy\r
1045 sblocks |= sbl<<shi;\r
1046 }\r
6d7acf9e 1047\r
cc68a136 1048 *pd++ = (width<<28)|(height<<24)|skip|(hv<<16)|((unsigned short)sy);\r
1049 *pd++ = (sx<<16)|((unsigned short)code2);\r
6d7acf9e 1050\r
cc68a136 1051 // Find next sprite\r
1052 link=(code>>16)&0x7f;\r
1053 if(!link) break; // End of sprites\r
1054 }\r
1055 SpriteBlocks = sblocks;\r
1056 *pd = 0; // terminate\r
1057 }\r
1058}\r
1059\r
1060static void DrawAllSprites(int *hcache, int maxwidth, int prio, int sh)\r
1061{\r
1062 int i,u,n;\r
381eea9b 1063 int sx1seen = 0; // sprite with x coord 1 or 0 seen\r
cc68a136 1064 int ntiles = 0; // tile counter for sprite limit emulation\r
1065 int *sprites[40]; // Sprites to draw in fast mode\r
381eea9b 1066 int max_line_sprites = 20; // 20 sprites, 40 tiles\r
1067 int *ps, pack, rs = rendstatus, scan = Scanline;\r
cc68a136 1068\r
1069 if(rs&8) {\r
1070 DrawAllSpritesInterlace(prio, maxwidth);\r
1071 return;\r
1072 }\r
602133e1 1073 if (rs & (PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES)) {\r
cc68a136 1074 //dprintf("PrepareSprites(%i) [%i]", (rs>>4)&1, scan);\r
602133e1 1075 PrepareSprites(rs & PDRAW_DIRTY_SPRITES);\r
1076 rendstatus = rs & ~(PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES);\r
cc68a136 1077 }\r
1078 if (!(SpriteBlocks & (1<<(scan>>3)))) return;\r
1079\r
602133e1 1080 if (((rs&PDRAW_ACC_SPRITES)||sh) && prio==0)\r
cc68a136 1081 memset(HighSprZ, 0, 328);\r
602133e1 1082 if (!(rs&PDRAW_ACC_SPRITES)&&prio) {\r
cc68a136 1083 if(hcache[0]) DrawSpritesFromCache(hcache, sh);\r
1084 return;\r
1085 }\r
1086\r
381eea9b 1087 if (PicoOpt & POPT_DIS_SPRITE_LIM)\r
1088 max_line_sprites = 80;\r
1089\r
cc68a136 1090 ps = HighPreSpr;\r
1091\r
1092 // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size\r
1093 // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8\r
1094\r
381eea9b 1095 for (i=u=n=0; (pack = *ps) && n < max_line_sprites; ps+=2, u++)\r
cc68a136 1096 {\r
1097 int sx, sy, row, pack2;\r
1098\r
381eea9b 1099 elprintf(EL_ANOMALY, "x: %i y: %i %ix%i", pack2>>16, (pack<<16)>>16, (pack>>28)<<3, (pack>>21)&0x38);\r
1100\r
1101 if (pack & 0x00400000) continue;\r
cc68a136 1102\r
1103 // get sprite info\r
1104 pack2 = *(ps+1);\r
1105 sx = pack2>>16;\r
1106 sy = (pack <<16)>>16;\r
1107 row = scan-sy;\r
1108\r
381eea9b 1109 if (sx == -0x77) sx1seen|=1; // for masking mode 2\r
cc68a136 1110\r
1111 // check if it is on this line\r
381eea9b 1112 if (row < 0 || row >= ((pack>>21)&0x38)) continue; // no\r
1113 n++; // number of sprites on this line (both visible and hidden, max is 20)\r
cc68a136 1114\r
1115 // sprite limit\r
1116 ntiles += pack>>28;\r
381eea9b 1117 if (ntiles > max_line_sprites*2) break;\r
cc68a136 1118\r
381eea9b 1119 if (pack & 0x00800000) continue;\r
cc68a136 1120\r
1121 // masking sprite?\r
381eea9b 1122 if (sx == -0x78) {\r
cc68a136 1123 if(!(sx1seen&1) || sx1seen==3) {\r
1124 break; // this sprite is not drawn and remaining sprites are masked\r
1125 }\r
1126 if((sx1seen>>8) == 0) sx1seen=(i+1)<<8;\r
1127 continue;\r
1128 }\r
381eea9b 1129 else if (sx == -0x77) {\r
cc68a136 1130 // masking mode2 (Outrun, Galaxy Force II, Shadow of the beast)\r
1131 if(sx1seen>>8) { i=(sx1seen>>8)-1; break; } // seen both 0 and 1\r
1132 sx1seen |= 2;\r
1133 continue;\r
1134 }\r
1135\r
1136 // accurate sprites\r
1137 //dprintf("P:%i",((sx>>15)&1));\r
602133e1 1138 if (rs & PDRAW_ACC_SPRITES) {\r
cc68a136 1139 // might need to skip this sprite\r
602133e1 1140 if ((pack2&0x8000) ^ (prio<<15)) continue;\r
381eea9b 1141 DrawSpriteZ(pack, pack2, sh|(prio<<1), n^0xff);\r
cc68a136 1142 continue;\r
1143 }\r
1144\r
1145 // sprite is good, save it's pointer\r
1146 sprites[i++]=ps;\r
1147 }\r
1148\r
1149 // Go through sprites backwards:\r
602133e1 1150 if (!(rs & PDRAW_ACC_SPRITES)) {\r
cc68a136 1151 for (i--; i>=0; i--)\r
1152 DrawSprite(sprites[i],&hcache,sh);\r
1153\r
1154 // terminate cache list\r
1155 *hcache = 0;\r
1156 }\r
1157}\r
1158\r
1159\r
1160// --------------------------------------------\r
1161\r
1162#ifndef _ASM_DRAW_C\r
1163static void BackFill(int reg7, int sh)\r
1164{\r
b542be46 1165 unsigned int back;\r
cc68a136 1166\r
1167 // Start with a blank scanline (background colour):\r
1168 back=reg7&0x3f;\r
1169 back|=sh<<6;\r
1170 back|=back<<8;\r
1171 back|=back<<16;\r
1172\r
b542be46 1173 memset32((int *)(HighCol+8), back, 320/4);\r
cc68a136 1174}\r
1175#endif\r
1176\r
1177// --------------------------------------------\r
1178\r
1179unsigned short HighPal[0x100];\r
1180\r
1181#ifndef _ASM_DRAW_C\r
1182static void FinalizeLineBGR444(int sh)\r
1183{\r
1184 unsigned short *pd=DrawLineDest;\r
1185 unsigned char *ps=HighCol+8;\r
1186 unsigned short *pal=Pico.cram;\r
1187 int len, i, t;\r
1188\r
1189 if (Pico.video.reg[12]&1) {\r
1190 len = 320;\r
1191 } else {\r
602133e1 1192 if(!(PicoOpt&POPT_DIS_32C_BORDER)) pd+=32;\r
cc68a136 1193 len = 256;\r
1194 }\r
1195\r
1196 if(sh) {\r
1197 pal=HighPal;\r
1198 if(Pico.m.dirtyPal) {\r
1199 blockcpy(pal, Pico.cram, 0x40*2);\r
1200 // shadowed pixels\r
1201 for(i = 0x3f; i >= 0; i--)\r
1202 pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x0777);\r
1203 // hilighted pixels\r
1204 for(i = 0x3f; i >= 0; i--) {\r
1205 t=pal[i]&0xeee;t+=0x444;if(t&0x10)t|=0xe;if(t&0x100)t|=0xe0;if(t&0x1000)t|=0xe00;t&=0xeee;\r
1206 pal[0x80|i]=(unsigned short)t;\r
1207 }\r
1208 Pico.m.dirtyPal = 0;\r
1209 }\r
1210 }\r
1211\r
1212 for(i = 0; i < len; i++)\r
1213 pd[i] = pal[ps[i]];\r
1214}\r
1215\r
1216\r
1217static void FinalizeLineRGB555(int sh)\r
1218{\r
1219 unsigned short *pd=DrawLineDest;\r
1220 unsigned char *ps=HighCol+8;\r
1221 unsigned short *pal=HighPal;\r
1222 int len, i, t, dirtyPal = Pico.m.dirtyPal;\r
1223\r
70357ce5 1224 if (dirtyPal)\r
1225 {\r
1226 unsigned int *spal=(void *)Pico.cram;\r
1227 unsigned int *dpal=(void *)HighPal;\r
1228 for (i = 0x3f/2; i >= 0; i--)\r
1229#ifdef USE_BGR555\r
1230 dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);\r
1231#else\r
1232 dpal[i] = ((spal[i]&0x000f000f)<<12)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)>>7);\r
1233#endif\r
cc68a136 1234 Pico.m.dirtyPal = 0;\r
1235 }\r
1236\r
70357ce5 1237 if (sh)\r
1238 {\r
1239 if (dirtyPal) {\r
cc68a136 1240 // shadowed pixels\r
70357ce5 1241 for (i = 0x3f; i >= 0; i--)\r
cc68a136 1242 pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x738e);\r
1243 // hilighted pixels\r
70357ce5 1244 for (i = 0x3f; i >= 0; i--) {\r
cc68a136 1245 t=pal[i]&0xe71c;t+=0x4208;if(t&0x20)t|=0x1c;if(t&0x800)t|=0x700;if(t&0x10000)t|=0xe000;t&=0xe71c;\r
1246 pal[0x80|i]=(unsigned short)t;\r
1247 }\r
1248 }\r
1249 }\r
1250\r
70357ce5 1251 if (Pico.video.reg[12]&1) {\r
1252 len = 320;\r
1253 } else {\r
602133e1 1254 if (!(PicoOpt&POPT_DIS_32C_BORDER)) pd+=32;\r
70357ce5 1255 len = 256;\r
1256 }\r
1257\r
1258#ifndef PSP\r
1259 for (i = 0; i < len; i++)\r
cc68a136 1260 pd[i] = pal[ps[i]];\r
70357ce5 1261#else\r
1262 {\r
1263 extern void amips_clut(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);\r
1264 amips_clut(pd, ps, pal, len);\r
1265 }\r
1266#endif\r
cc68a136 1267}\r
1268#endif\r
1269\r
1270static void FinalizeLine8bit(int sh)\r
1271{\r
1272 unsigned char *pd=DrawLineDest;\r
1273 int len, rs = rendstatus;\r
1274 static int dirty_count;\r
1275\r
602133e1 1276 if (!sh && Pico.m.dirtyPal == 1 && Scanline < 222)\r
1277 {\r
cc68a136 1278 // a hack for mid-frame palette changes\r
602133e1 1279 if (!(rs & PDRAW_SONIC_MODE))\r
cc68a136 1280 dirty_count = 1;\r
1281 else dirty_count++;\r
602133e1 1282 rs |= PDRAW_SONIC_MODE;\r
cc68a136 1283 rendstatus = rs;\r
1284 if (dirty_count == 3) {\r
1285 blockcpy(HighPal, Pico.cram, 0x40*2);\r
1286 } else if (dirty_count == 11) {\r
1287 blockcpy(HighPal+0x40, Pico.cram, 0x40*2);\r
1288 }\r
1289 }\r
1290\r
1291 if (Pico.video.reg[12]&1) {\r
1292 len = 320;\r
1293 } else {\r
602133e1 1294 if (!(PicoOpt&POPT_DIS_32C_BORDER)) pd+=32;\r
cc68a136 1295 len = 256;\r
1296 }\r
1297\r
602133e1 1298 if (!sh && (rs & PDRAW_SONIC_MODE)) {\r
cc68a136 1299 if (dirty_count >= 11) {\r
1300 blockcpy_or(pd, HighCol+8, len, 0x80);\r
1301 } else {\r
1302 blockcpy_or(pd, HighCol+8, len, 0x40);\r
1303 }\r
1304 } else {\r
1305 blockcpy(pd, HighCol+8, len);\r
1306 }\r
1307}\r
1308\r
ea8c405f 1309static void (*FinalizeLine)(int sh) = FinalizeLineBGR444;\r
cc68a136 1310\r
602133e1 1311// hblank was enabled early during prev line processng -\r
1312// it should have been blanked\r
1313static void handle_early_blank(int scanline, int sh)\r
1314{\r
1315 scanline--;\r
1316\r
1317 if (PicoScanBegin != NULL)\r
1318 PicoScanBegin(scanline);\r
1319\r
1320 BackFill(Pico.video.reg[7], sh);\r
1321\r
1322 if (FinalizeLine != NULL)\r
1323 FinalizeLine(sh);\r
1324\r
1325 if (PicoScanEnd != NULL)\r
1326 PicoScanEnd(scanline);\r
1327}\r
1328\r
cc68a136 1329// --------------------------------------------\r
1330\r
1331static int DrawDisplay(int sh)\r
1332{\r
1333 struct PicoVideo *pvid=&Pico.video;\r
1334 int win=0,edge=0,hvwind=0;\r
1335 int maxw, maxcells;\r
1336\r
602133e1 1337 rendstatus &= ~(PDRAW_SHHI_DONE|PDRAW_PLANE_HI_PRIO);\r
740da8c6 1338\r
cc68a136 1339 if(pvid->reg[12]&1) {\r
1340 maxw = 328; maxcells = 40;\r
1341 } else {\r
1342 maxw = 264; maxcells = 32;\r
1343 }\r
1344\r
1345 // Find out if the window is on this line:\r
1346 win=pvid->reg[0x12];\r
1347 edge=(win&0x1f)<<3;\r
1348\r
1349 if (win&0x80) { if (Scanline>=edge) hvwind=1; }\r
1350 else { if (Scanline< edge) hvwind=1; }\r
1351\r
7a7c6476 1352 if (!hvwind) { // we might have a vertical window here\r
cc68a136 1353 win=pvid->reg[0x11];\r
1354 edge=win&0x1f;\r
7a7c6476 1355 if (win&0x80) {\r
1356 if (!edge) hvwind=1;\r
cc68a136 1357 else if(edge < (maxcells>>1)) hvwind=2;\r
1358 } else {\r
7a7c6476 1359 if (!edge);\r
cc68a136 1360 else if(edge < (maxcells>>1)) hvwind=2;\r
1361 else hvwind=1;\r
1362 }\r
1363 }\r
1364\r
83c093a4 1365 DrawLayer(1|(sh<<1), HighCacheB, 0, maxcells);\r
7a7c6476 1366 if (hvwind == 1)\r
83c093a4 1367 DrawWindow(0, maxcells>>1, 0, sh);\r
7a7c6476 1368 else if (hvwind == 2) {\r
cc68a136 1369 // ahh, we have vertical window\r
83c093a4 1370 DrawLayer(0|(sh<<1), HighCacheA, (win&0x80) ? 0 : edge<<1, (win&0x80) ? edge<<1 : maxcells);\r
1371 DrawWindow( (win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 0, sh);\r
cc68a136 1372 } else\r
83c093a4 1373 DrawLayer(0|(sh<<1), HighCacheA, 0, maxcells);\r
cc68a136 1374 DrawAllSprites(HighCacheS, maxw, 0, sh);\r
1375\r
7a7c6476 1376 if (HighCacheB[0]) DrawTilesFromCache(HighCacheB, sh, 328);\r
1377 if (hvwind == 1)\r
cc68a136 1378 DrawWindow(0, maxcells>>1, 1, sh);\r
7a7c6476 1379 else if (hvwind == 2) {\r
83c093a4 1380 if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : 328);\r
cc68a136 1381 DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh);\r
1382 } else\r
7a7c6476 1383 if (HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh, 328);\r
cc68a136 1384 DrawAllSprites(HighCacheS, maxw, 1, sh);\r
1385\r
740da8c6 1386#if 0\r
1387 {\r
1388 int *c, a, b;\r
1389 for (a = 0, c = HighCacheA; *c; c++, a++);\r
1390 for (b = 0, c = HighCacheB; *c; c++, b++);\r
1391 printf("%i:%03i: a=%i, b=%i\n", Pico.m.frame_count, Scanline, a, b);\r
1392 }\r
1393#endif\r
1394\r
cc68a136 1395 return 0;\r
1396}\r
1397\r
1398\r
eff55556 1399PICO_INTERNAL void PicoFrameStart(void)\r
cc68a136 1400{\r
1401 // prepare to do this frame\r
602133e1 1402 rendstatus = (PicoOpt&0x80)>>5; // accurate sprites, clear everything else\r
1403 if (rendstatus)\r
cc68a136 1404 Pico.video.status &= ~0x0020;\r
1405 else Pico.video.status |= 0x0020; // sprite collision\r
602133e1 1406 if ((Pico.video.reg[12]&6) == 6) rendstatus |= PDRAW_INTERLACE; // interlace mode\r
1407 if (Pico.m.dirtyPal) Pico.m.dirtyPal = 2; // reset dirty if needed\r
cc68a136 1408\r
1409 PrepareSprites(1);\r
602133e1 1410 skip_next_line=0;\r
cc68a136 1411}\r
1412\r
eff55556 1413PICO_INTERNAL int PicoLine(int scan)\r
cc68a136 1414{\r
1415 int sh;\r
602133e1 1416 if (skip_next_line>0) { skip_next_line--; return 0; } // skip_next_line rendering lines\r
cc68a136 1417\r
1418 Scanline=scan;\r
1419 sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight?\r
1420\r
602133e1 1421 if (rendstatus & PDRAW_EARLY_BLANK) {\r
1422 if (scan > 0) handle_early_blank(scan, sh);\r
1423 rendstatus &= ~PDRAW_EARLY_BLANK;\r
1424 }\r
1425\r
1426 if (PicoScanBegin != NULL)\r
1427 skip_next_line = PicoScanBegin(scan);\r
1428\r
cc68a136 1429 // Draw screen:\r
1430 BackFill(Pico.video.reg[7], sh);\r
1431 if (Pico.video.reg[1]&0x40)\r
1432 DrawDisplay(sh);\r
1433\r
ea8c405f 1434 if (FinalizeLine != NULL)\r
1435 FinalizeLine(sh);\r
cc68a136 1436\r
602133e1 1437 if (PicoScanEnd != NULL)\r
1438 PicoScanEnd(scan);\r
cc68a136 1439\r
1440 return 0;\r
1441}\r
1442\r
1443\r
1444void PicoDrawSetColorFormat(int which)\r
1445{\r
ea8c405f 1446 switch (which)\r
1447 {\r
1448 case 2: FinalizeLine = FinalizeLine8bit; break;\r
1449 case 1: FinalizeLine = FinalizeLineRGB555; break;\r
1450 case 0: FinalizeLine = FinalizeLineBGR444; break;\r
1451 default:FinalizeLine = NULL; break;\r
1452 }\r
499a0be3 1453#if OVERRIDE_HIGHCOL\r
1454 if (which) HighCol=DefHighCol;\r
1455#endif\r
cc68a136 1456}\r
ea8c405f 1457\r