optimizations, fixes, hacks, psp, ...
[picodrive.git] / Pico / Draw2.c
1 // This is part of Pico Library\r
2 \r
3 // (c) Copyright 2007, Grazvydas "notaz" Ignotas\r
4 // Free for non-commercial use.\r
5 \r
6 // For commercial use, separate licencing terms must be obtained.\r
7 \r
8 \r
9 // this is a frame-based renderer, alternative to Dave's line based which is in Draw.c\r
10 \r
11 \r
12 #include "PicoInt.h"\r
13 \r
14 // port_config.h include must define these 2 defines:\r
15 // #define START_ROW  1 // which row of tiles to start rendering at?\r
16 // #define END_ROW   27 // ..end\r
17 // one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered.\r
18 \r
19 #define TILE_ROWS END_ROW-START_ROW\r
20 \r
21 #define USE_CACHE\r
22 \r
23 // note: this is not implemented in ARM asm\r
24 #if defined(DRAW2_OVERRIDE_LINE_WIDTH)\r
25 #define LINE_WIDTH DRAW2_OVERRIDE_LINE_WIDTH\r
26 #else\r
27 #define LINE_WIDTH 328\r
28 #endif\r
29 \r
30 int currpri = 0;\r
31 \r
32 static int HighCache2A[41*(TILE_ROWS+1)+1+1]; // caches for high layers\r
33 static int HighCache2B[41*(TILE_ROWS+1)+1+1];\r
34 \r
35 unsigned short *PicoCramHigh=Pico.cram; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now)\r
36 void (*PicoPrepareCram)()=0;            // prepares PicoCramHigh for renderer to use\r
37 \r
38 \r
39 // stuff available in asm:\r
40 #ifdef _ASM_DRAW_C\r
41 void BackFillFull(int reg7);\r
42 void DrawLayerFull(int plane, int *hcache, int planestart, int planeend);\r
43 void DrawTilesFromCacheF(int *hc);\r
44 void DrawWindowFull(int start, int end, int prio);\r
45 void DrawSpriteFull(unsigned int *sprite);\r
46 #else\r
47 \r
48 \r
49 static int TileXnormYnorm(unsigned char *pd,int addr,unsigned char pal)\r
50 {\r
51         unsigned int pack=0; unsigned int t=0, blank = 1;\r
52         int i;\r
53 \r
54         for(i=8; i; i--, addr+=2, pd += LINE_WIDTH) {\r
55                 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
56                 if(!pack) continue;\r
57 \r
58                 t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal);\r
59                 t=pack&0x00000f00; if (t) pd[1]=(unsigned char)((t>> 8)|pal);\r
60                 t=pack&0x000000f0; if (t) pd[2]=(unsigned char)((t>> 4)|pal);\r
61                 t=pack&0x0000000f; if (t) pd[3]=(unsigned char)((t    )|pal);\r
62                 t=pack&0xf0000000; if (t) pd[4]=(unsigned char)((t>>28)|pal);\r
63                 t=pack&0x0f000000; if (t) pd[5]=(unsigned char)((t>>24)|pal);\r
64                 t=pack&0x00f00000; if (t) pd[6]=(unsigned char)((t>>20)|pal);\r
65                 t=pack&0x000f0000; if (t) pd[7]=(unsigned char)((t>>16)|pal);\r
66                 blank = 0;\r
67         }\r
68 \r
69         return blank; // Tile blank?\r
70 }\r
71 \r
72 static int TileXflipYnorm(unsigned char *pd,int addr,unsigned char pal)\r
73 {\r
74         unsigned int pack=0; unsigned int t=0, blank = 1;\r
75         int i;\r
76 \r
77         for(i=8; i; i--, addr+=2, pd += LINE_WIDTH) {\r
78                 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
79                 if(!pack) continue;\r
80 \r
81                 t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal);\r
82                 t=pack&0x00f00000; if (t) pd[1]=(unsigned char)((t>>20)|pal);\r
83                 t=pack&0x0f000000; if (t) pd[2]=(unsigned char)((t>>24)|pal);\r
84                 t=pack&0xf0000000; if (t) pd[3]=(unsigned char)((t>>28)|pal);\r
85                 t=pack&0x0000000f; if (t) pd[4]=(unsigned char)((t    )|pal);\r
86                 t=pack&0x000000f0; if (t) pd[5]=(unsigned char)((t>> 4)|pal);\r
87                 t=pack&0x00000f00; if (t) pd[6]=(unsigned char)((t>> 8)|pal);\r
88                 t=pack&0x0000f000; if (t) pd[7]=(unsigned char)((t>>12)|pal);\r
89                 blank = 0;\r
90         }\r
91         return blank; // Tile blank?\r
92 }\r
93 \r
94 static int TileXnormYflip(unsigned char *pd,int addr,unsigned char pal)\r
95 {\r
96         unsigned int pack=0; unsigned int t=0, blank = 1;\r
97         int i;\r
98 \r
99         addr+=14;\r
100         for(i=8; i; i--, addr-=2, pd += LINE_WIDTH) {\r
101                 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
102                 if(!pack) continue;\r
103 \r
104                 t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal);\r
105                 t=pack&0x00000f00; if (t) pd[1]=(unsigned char)((t>> 8)|pal);\r
106                 t=pack&0x000000f0; if (t) pd[2]=(unsigned char)((t>> 4)|pal);\r
107                 t=pack&0x0000000f; if (t) pd[3]=(unsigned char)((t    )|pal);\r
108                 t=pack&0xf0000000; if (t) pd[4]=(unsigned char)((t>>28)|pal);\r
109                 t=pack&0x0f000000; if (t) pd[5]=(unsigned char)((t>>24)|pal);\r
110                 t=pack&0x00f00000; if (t) pd[6]=(unsigned char)((t>>20)|pal);\r
111                 t=pack&0x000f0000; if (t) pd[7]=(unsigned char)((t>>16)|pal);\r
112                 blank = 0;\r
113         }\r
114 \r
115         return blank; // Tile blank?\r
116 }\r
117 \r
118 static int TileXflipYflip(unsigned char *pd,int addr,unsigned char pal)\r
119 {\r
120         unsigned int pack=0; unsigned int t=0, blank = 1;\r
121         int i;\r
122 \r
123         addr+=14;\r
124         for(i=8; i; i--, addr-=2, pd += LINE_WIDTH) {\r
125                 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
126                 if(!pack) continue;\r
127 \r
128                 t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal);\r
129                 t=pack&0x00f00000; if (t) pd[1]=(unsigned char)((t>>20)|pal);\r
130                 t=pack&0x0f000000; if (t) pd[2]=(unsigned char)((t>>24)|pal);\r
131                 t=pack&0xf0000000; if (t) pd[3]=(unsigned char)((t>>28)|pal);\r
132                 t=pack&0x0000000f; if (t) pd[4]=(unsigned char)((t    )|pal);\r
133                 t=pack&0x000000f0; if (t) pd[5]=(unsigned char)((t>> 4)|pal);\r
134                 t=pack&0x00000f00; if (t) pd[6]=(unsigned char)((t>> 8)|pal);\r
135                 t=pack&0x0000f000; if (t) pd[7]=(unsigned char)((t>>12)|pal);\r
136                 blank = 0;\r
137         }\r
138         return blank; // Tile blank?\r
139 }\r
140 \r
141 \r
142 // start: (tile_start<<16)|row_start, end: [same]\r
143 static void DrawWindowFull(int start, int end, int prio)\r
144 {\r
145         struct PicoVideo *pvid=&Pico.video;\r
146         int nametab, nametab_step, trow, tilex, blank=-1, code;\r
147         unsigned char *scrpos = PicoDraw2FB;\r
148         int tile_start, tile_end; // in cells\r
149 \r
150         // parse ranges\r
151         tile_start = start>>16;\r
152         tile_end = end>>16;\r
153         start = start<<16>>16;\r
154         end = end<<16>>16;\r
155 \r
156         // Find name table line:\r
157         if (pvid->reg[12]&1)\r
158         {\r
159                 nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode\r
160                 nametab_step = 1<<6;\r
161         }\r
162         else\r
163         {\r
164                 nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode\r
165                 nametab_step = 1<<5;\r
166         }\r
167         nametab += nametab_step*start;\r
168 \r
169         // check priority\r
170         code=Pico.vram[nametab+tile_start];\r
171         if ((code>>15) != prio) return; // hack: just assume that whole window uses same priority\r
172 \r
173         scrpos+=8*LINE_WIDTH+8;\r
174         scrpos+=8*LINE_WIDTH*(start-START_ROW);\r
175 \r
176         // do a window until we reach planestart row\r
177         for(trow = start; trow < end; trow++, nametab+=nametab_step) { // current tile row\r
178                 for (tilex=tile_start; tilex<tile_end; tilex++)\r
179                 {\r
180                         int code,addr,zero=0;\r
181 //                      unsigned short *pal=NULL;\r
182                         unsigned char pal;\r
183 \r
184                         code=Pico.vram[nametab+tilex];\r
185                         if (code==blank) continue;\r
186 \r
187                         // Get tile address/2:\r
188                         addr=(code&0x7ff)<<4;\r
189 \r
190 //                      pal=PicoCramHigh+((code>>9)&0x30);\r
191                         pal=(unsigned char)((code>>9)&0x30);\r
192 \r
193                         switch((code>>11)&3) {\r
194                                 case 0: zero=TileXnormYnorm(scrpos+(tilex<<3),addr,pal); break;\r
195                                 case 1: zero=TileXflipYnorm(scrpos+(tilex<<3),addr,pal); break;\r
196                                 case 2: zero=TileXnormYflip(scrpos+(tilex<<3),addr,pal); break;\r
197                                 case 3: zero=TileXflipYflip(scrpos+(tilex<<3),addr,pal); break;\r
198                         }\r
199                         if(zero) blank=code; // We know this tile is blank now\r
200                 }\r
201 \r
202                 scrpos += LINE_WIDTH*8;\r
203         }\r
204 }\r
205 \r
206 \r
207 static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend)\r
208 {\r
209         struct PicoVideo *pvid=&Pico.video;\r
210         static char shift[4]={5,6,6,7}; // 32,64 or 128 sized tilemaps\r
211         int width, height, ymask, htab;\r
212         int nametab, hscroll=0, vscroll, cells;\r
213         unsigned char *scrpos;\r
214         int blank=-1, xmask, nametab_row, trow;\r
215 \r
216         // parse ranges\r
217         cells = (planeend>>16)-(planestart>>16);\r
218         planestart = planestart<<16>>16;\r
219         planeend = planeend<<16>>16;\r
220 \r
221         // Work out the Tiles to draw\r
222 \r
223         htab=pvid->reg[13]<<9; // Horizontal scroll table address\r
224 //      if ( pvid->reg[11]&2)     htab+=Scanline<<1; // Offset by line\r
225 //      if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile\r
226         htab+=plane; // A or B\r
227 \r
228         if(!(pvid->reg[11]&3)) { // full screen scroll\r
229                 // Get horizontal scroll value\r
230                 hscroll=Pico.vram[htab&0x7fff];\r
231                 htab = 0; // this marks that we don't have to update scroll value\r
232         }\r
233 \r
234         // Work out the name table size: 32 64 or 128 tiles (0-3)\r
235         width=pvid->reg[16];\r
236         height=(width>>4)&3; width&=3;\r
237 \r
238         xmask=(1<<shift[width ])-1; // X Mask in tiles\r
239         ymask=(height<<5)|0x1f;     // Y Mask in tiles\r
240         if(width == 1)   ymask&=0x3f;\r
241         else if(width>1) ymask =0x1f;\r
242 \r
243         // Find name table:\r
244         if (plane==0) nametab=(pvid->reg[2]&0x38)<< 9; // A\r
245         else          nametab=(pvid->reg[4]&0x07)<<12; // B\r
246 \r
247         scrpos = PicoDraw2FB;\r
248         scrpos+=8*LINE_WIDTH*(planestart-START_ROW);\r
249 \r
250         // Get vertical scroll value:\r
251         vscroll=Pico.vsram[plane]&0x1ff;\r
252         scrpos+=(8-(vscroll&7))*LINE_WIDTH;\r
253         if(vscroll&7) planeend++; // we have vertically clipped tiles due to vscroll, so we need 1 more row\r
254 \r
255         *hcache++ = 8-(vscroll&7); // push y-offset to tilecache\r
256 \r
257 \r
258         for(trow = planestart; trow < planeend; trow++) { // current tile row\r
259                 int cellc=cells,tilex,dx;\r
260 \r
261                 // Find the tile row in the name table\r
262                 //ts.line=(vscroll+Scanline)&ymask;\r
263                 //ts.nametab+=(ts.line>>3)<<shift[width];\r
264                 nametab_row = nametab + (((trow+(vscroll>>3))&ymask)<<shift[width]); // pointer to nametable entries for this row\r
265 \r
266                 // update hscroll if needed\r
267                 if(htab) {\r
268                         int htaddr=htab+(trow<<4);\r
269                         if(trow) htaddr-=(vscroll&7)<<1;\r
270                         hscroll=Pico.vram[htaddr&0x7fff];\r
271                 }\r
272 \r
273                 // Draw tiles across screen:\r
274                 tilex=(-hscroll)>>3;\r
275                 dx=((hscroll-1)&7)+1;\r
276                 if(dx != 8) cellc++; // have hscroll, do more cells\r
277 \r
278                 for (; cellc; dx+=8,tilex++,cellc--)\r
279                 {\r
280                         int code=0,addr=0,zero=0;\r
281 //                      unsigned short *pal=NULL;\r
282                         unsigned char pal;\r
283 \r
284                         code=Pico.vram[nametab_row+(tilex&xmask)];\r
285                         if (code==blank) continue;\r
286 \r
287 #ifdef USE_CACHE\r
288                         if (code>>15) { // high priority tile\r
289                                 *hcache++ = code|(dx<<16)|(trow<<27); // cache it\r
290 #else\r
291                         if ((code>>15) != currpri) {\r
292 #endif\r
293                                 continue;\r
294                         }\r
295 \r
296                         // Get tile address/2:\r
297                         addr=(code&0x7ff)<<4;\r
298 \r
299 //                      pal=PicoCramHigh+((code>>9)&0x30);\r
300                         pal=(unsigned char)((code>>9)&0x30);\r
301 \r
302                         switch((code>>11)&3) {\r
303                                 case 0: zero=TileXnormYnorm(scrpos+dx,addr,pal); break;\r
304                                 case 1: zero=TileXflipYnorm(scrpos+dx,addr,pal); break;\r
305                                 case 2: zero=TileXnormYflip(scrpos+dx,addr,pal); break;\r
306                                 case 3: zero=TileXflipYflip(scrpos+dx,addr,pal); break;\r
307                         }\r
308                         if(zero) blank=code; // We know this tile is blank now\r
309                 }\r
310 \r
311                 scrpos += LINE_WIDTH*8;\r
312         }\r
313 \r
314         *hcache = 0; // terminate cache\r
315 }\r
316 \r
317 \r
318 static void DrawTilesFromCacheF(int *hc)\r
319 {\r
320         int code, addr, zero = 0;\r
321         unsigned int prevy=0xFFFFFFFF;\r
322 //      unsigned short *pal;\r
323         unsigned char pal;\r
324         short blank=-1; // The tile we know is blank\r
325         unsigned char *scrpos = PicoDraw2FB, *pd = 0;\r
326 \r
327         // *hcache++ = code|(dx<<16)|(trow<<27); // cache it\r
328         scrpos+=(*hc++)*LINE_WIDTH - START_ROW*LINE_WIDTH*8;\r
329 \r
330         while((code=*hc++)) {\r
331                 if((short)code == blank) continue;\r
332 \r
333                 // y pos\r
334                 if(((unsigned)code>>27) != prevy) {\r
335                         prevy = (unsigned)code>>27;\r
336                         pd = scrpos + prevy*LINE_WIDTH*8;\r
337                 }\r
338 \r
339                 // Get tile address/2:\r
340                 addr=(code&0x7ff)<<4;\r
341 //              pal=PicoCramHigh+((code>>9)&0x30);\r
342                 pal=(unsigned char)((code>>9)&0x30);\r
343 \r
344                 switch((code>>11)&3) {\r
345                         case 0: zero=TileXnormYnorm(pd+((code>>16)&0x1ff),addr,pal); break;\r
346                         case 1: zero=TileXflipYnorm(pd+((code>>16)&0x1ff),addr,pal); break;\r
347                         case 2: zero=TileXnormYflip(pd+((code>>16)&0x1ff),addr,pal); break;\r
348                         case 3: zero=TileXflipYflip(pd+((code>>16)&0x1ff),addr,pal); break;\r
349                 }\r
350 \r
351                 if(zero) blank=(short)code;\r
352         }\r
353 }\r
354 \r
355 \r
356 // sx and sy are coords of virtual screen with 8pix borders on top and on left\r
357 static void DrawSpriteFull(unsigned int *sprite)\r
358 {\r
359         int width=0,height=0;\r
360 //      unsigned short *pal=NULL;\r
361         unsigned char pal;\r
362         int tile,code,tdeltax,tdeltay;\r
363         unsigned char *scrpos;\r
364         int sx, sy;\r
365 \r
366         sy=sprite[0];\r
367         height=sy>>24;\r
368         sy=(sy&0x1ff)-0x78; // Y\r
369         width=(height>>2)&3; height&=3;\r
370         width++; height++; // Width and height in tiles\r
371 \r
372         code=sprite[1];\r
373         sx=((code>>16)&0x1ff)-0x78; // X\r
374 \r
375         tile=code&0x7ff; // Tile number\r
376         tdeltax=height; // Delta to increase tile by going right\r
377         tdeltay=1;      // Delta to increase tile by going down\r
378         if (code&0x0800) { tdeltax=-tdeltax; tile+=height*(width-1); } // Flip X\r
379         if (code&0x1000) { tdeltay=-tdeltay; tile+=height-1; } // Flip Y\r
380 \r
381         //delta<<=4; // Delta of address\r
382 //      pal=PicoCramHigh+((code>>9)&0x30); // Get palette pointer\r
383         pal=(unsigned char)((code>>9)&0x30);\r
384 \r
385         // goto first vertically visible tile\r
386         while(sy <= START_ROW*8) { sy+=8; tile+=tdeltay; height--; }\r
387 \r
388         scrpos = PicoDraw2FB;\r
389         scrpos+=(sy-START_ROW*8)*LINE_WIDTH;\r
390 \r
391         for (; height > 0; height--, sy+=8, tile+=tdeltay)\r
392         {\r
393                 int w = width, x=sx, t=tile;\r
394 \r
395                 if(sy >= END_ROW*8+8) return; // offscreen\r
396 \r
397                 for (; w; w--,x+=8,t+=tdeltax)\r
398                 {\r
399                         if(x<=0)   continue;\r
400                         if(x>=328) break; // Offscreen\r
401 \r
402                         t&=0x7fff; // Clip tile address\r
403                         switch((code>>11)&3) {\r
404                                 case 0: TileXnormYnorm(scrpos+x,t<<4,pal); break;\r
405                                 case 1: TileXflipYnorm(scrpos+x,t<<4,pal); break;\r
406                                 case 2: TileXnormYflip(scrpos+x,t<<4,pal); break;\r
407                                 case 3: TileXflipYflip(scrpos+x,t<<4,pal); break;\r
408                         }\r
409                 }\r
410 \r
411                 scrpos+=8*LINE_WIDTH;\r
412         }\r
413 }\r
414 #endif\r
415 \r
416 \r
417 static void DrawAllSpritesFull(int prio, int maxwidth)\r
418 {\r
419         struct PicoVideo *pvid=&Pico.video;\r
420         int table=0,maskrange=0;\r
421         int i,u,link=0;\r
422         unsigned int *sprites[80]; // Sprites\r
423         int y_min=START_ROW*8, y_max=END_ROW*8; // for a simple sprite masking\r
424 \r
425         table=pvid->reg[5]&0x7f;\r
426         if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode\r
427         table<<=8; // Get sprite table address/2\r
428 \r
429         for (i=u=0; u < 80; u++)\r
430         {\r
431                 unsigned int *sprite=NULL;\r
432                 int code, code2, sx, sy, height;\r
433 \r
434                 sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite\r
435 \r
436                 // get sprite info\r
437                 code = sprite[0];\r
438 \r
439                 // check if it is not hidden vertically\r
440                 sy = (code&0x1ff)-0x80;\r
441                 height = (((code>>24)&3)+1)<<3;\r
442                 if(sy+height <= y_min || sy > y_max) goto nextsprite;\r
443 \r
444                 // masking sprite?\r
445                 code2=sprite[1];\r
446                 sx = (code2>>16)&0x1ff;\r
447                 if(!sx) {\r
448                         int to = sy+height; // sy ~ from\r
449                         if(maskrange) {\r
450                                 // try to merge with previous range\r
451                                 if((maskrange>>16)+1 >= sy && (maskrange>>16) <= to && (maskrange&0xffff) < sy) sy = (maskrange&0xffff);\r
452                                 else if((maskrange&0xffff)-1 <= to && (maskrange&0xffff) >= sy && (maskrange>>16) > to) to = (maskrange>>16);\r
453                         }\r
454                         // support only very simple masking (top and bottom of screen)\r
455                         if(sy <= y_min && to+1 > y_min) y_min = to+1;\r
456                         else if(to >= y_max && sy-1 < y_max) y_max = sy-1;\r
457                         else maskrange=sy|(to<<16);\r
458 \r
459                         goto nextsprite;\r
460                 }\r
461 \r
462                 // priority\r
463                 if(((code2>>15)&1) != prio) goto nextsprite; // wrong priority\r
464 \r
465                 // check if sprite is not hidden horizontally\r
466                 sx -= 0x78; // Get X coordinate + 8\r
467                 if(sx <= -8*3 || sx >= maxwidth) goto nextsprite;\r
468 \r
469                 // sprite is good, save it's index\r
470                 sprites[i++]=sprite;\r
471 \r
472                 nextsprite:\r
473                 // Find next sprite\r
474                 link=(code>>16)&0x7f;\r
475                 if(!link) break; // End of sprites\r
476         }\r
477 \r
478         // Go through sprites backwards:\r
479         for (i-- ;i>=0; i--)\r
480         {\r
481                 DrawSpriteFull(sprites[i]);\r
482         }\r
483 }\r
484 \r
485 #ifndef _ASM_DRAW_C\r
486 static void BackFillFull(int reg7)\r
487 {\r
488         unsigned int back;\r
489 \r
490         // Start with a background color:\r
491 //      back=PicoCramHigh[reg7&0x3f];\r
492         back=reg7&0x3f;\r
493         back|=back<<8;\r
494         back|=back<<16;\r
495 \r
496         memset32((int *)PicoDraw2FB, back, LINE_WIDTH*(8+(END_ROW-START_ROW)*8)/4);\r
497 }\r
498 #endif\r
499 \r
500 static void DrawDisplayFull()\r
501 {\r
502         struct PicoVideo *pvid=&Pico.video;\r
503         int win, edge=0, hvwin=0; // LSb->MSb: hwin&plane, vwin&plane, full\r
504         int planestart=START_ROW, planeend=END_ROW; // plane A start/end when window shares display with plane A (in tile rows or columns)\r
505         int winstart=START_ROW, winend=END_ROW;     // same for window\r
506         int maxw, maxcolc; // max width and col cells\r
507 \r
508         if(pvid->reg[12]&1) {\r
509                 maxw = 328; maxcolc = 40;\r
510         } else {\r
511                 maxw = 264; maxcolc = 32;\r
512         }\r
513 \r
514         // horizontal window?\r
515         if((win=pvid->reg[0x12])) {\r
516                 hvwin=1; // hwindow shares display with plane A\r
517                 edge=win&0x1f;\r
518                 if(win == 0x80) {\r
519                         // fullscreen window\r
520                         hvwin=4;\r
521                 } else if(win < 0x80) {\r
522                         // window on the top\r
523                              if(edge <= START_ROW) hvwin=0; // window not visible in our drawing region\r
524                         else if(edge >= END_ROW)   hvwin=4;\r
525                         else planestart = winend = edge;\r
526                 } else if(win > 0x80) {\r
527                         // window at the bottom\r
528                         if(edge >= END_ROW) hvwin=0;\r
529                         else planeend = winstart = edge;\r
530                 }\r
531         }\r
532 \r
533         // check for vertical window, but only if win is not fullscreen\r
534         if(hvwin != 4) {\r
535                 win=pvid->reg[0x11];\r
536                 edge=win&0x1f;\r
537                 if (win&0x80) {\r
538                         if(!edge) hvwin=4;\r
539                         else if(edge < (maxcolc>>1)) {\r
540                                 // window is on the right\r
541                                 hvwin|=2;\r
542                                 planeend|=edge<<17;\r
543                                 winstart|=edge<<17;\r
544                                 winend|=maxcolc<<16;\r
545                         }\r
546                 } else {\r
547                         if(edge >= (maxcolc>>1)) hvwin=4;\r
548                         else if(edge) {\r
549                                 // window is on the left\r
550                                 hvwin|=2;\r
551                                 winend|=edge<<17;\r
552                                 planestart|=edge<<17;\r
553                                 planeend|=maxcolc<<16;\r
554                         }\r
555                 }\r
556         }\r
557 \r
558         if(hvwin==1) { winend|=maxcolc<<16; planeend|=maxcolc<<16; }\r
559 \r
560         currpri = 0;\r
561         DrawLayerFull(1, HighCache2B, START_ROW, (maxcolc<<16)|END_ROW);\r
562         switch(hvwin) {\r
563                 case 4:\r
564                 // fullscreen window\r
565                 DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 0);\r
566                 HighCache2A[1] = 0;\r
567                 break;\r
568 \r
569                 case 3:\r
570                 // we have plane A and both v and h windows\r
571                 DrawLayerFull(0, HighCache2A, planestart, planeend);\r
572                 DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 0); // h\r
573                 DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 0);    // v\r
574                 break;\r
575 \r
576                 case 2:\r
577                 case 1:\r
578                 // both window and plane A visible, window is vertical XOR horizontal\r
579                 DrawLayerFull(0, HighCache2A, planestart, planeend);\r
580                 DrawWindowFull(winstart, winend, 0);\r
581                 break;\r
582 \r
583                 default:\r
584                 // fullscreen plane A\r
585                 DrawLayerFull(0, HighCache2A, START_ROW, (maxcolc<<16)|END_ROW);\r
586                 break;\r
587         }\r
588         DrawAllSpritesFull(0, maxw);\r
589 \r
590 #ifdef USE_CACHE\r
591         if(HighCache2B[1]) DrawTilesFromCacheF(HighCache2B);\r
592         if(HighCache2A[1]) DrawTilesFromCacheF(HighCache2A);\r
593         switch(hvwin) {\r
594                 case 4:\r
595                 // fullscreen window\r
596                 DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 1);\r
597                 break;\r
598 \r
599                 case 3:\r
600                 // we have plane A and both v and h windows\r
601                 DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 1); // h\r
602                 DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 1);    // v\r
603                 break;\r
604 \r
605                 case 2:\r
606                 case 1:\r
607                 // both window and plane A visible, window is vertical XOR horizontal\r
608                 DrawWindowFull(winstart, winend, 1);\r
609                 break;\r
610         }\r
611 #else\r
612         currpri = 1;\r
613         // TODO\r
614 #endif\r
615         DrawAllSpritesFull(1, maxw);\r
616 }\r
617 \r
618 \r
619 PICO_INTERNAL void PicoFrameFull()\r
620 {\r
621         // prepare cram?\r
622         if(PicoPrepareCram) PicoPrepareCram();\r
623 \r
624         // Draw screen:\r
625         BackFillFull(Pico.video.reg[7]);\r
626         if (Pico.video.reg[1]&0x40) DrawDisplayFull();\r
627 }\r
628 \r