Draw.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288
  1. // This is part of Pico Library
  2. // (c) Copyright 2004 Dave, All rights reserved.
  3. // (c) Copyright 2006 notaz, All rights reserved.
  4. // Free for non-commercial use.
  5. // For commercial use, separate licencing terms must be obtained.
  6. #include "PicoInt.h"
  7. #ifndef __GNUC__
  8. #pragma warning (disable:4706) // Disable assignment within conditional
  9. #endif
  10. int (*PicoScan)(unsigned int num, void *data)=NULL;
  11. unsigned short DefOutBuff[320*2];
  12. unsigned char HighCol[8+320+8];
  13. static int HighCacheA[41+1]; // caches for high layers
  14. static int HighCacheB[41+1];
  15. static int HighCacheS[80+1]; // and sprites
  16. static int HighPreSpr[80*2+1]; // slightly preprocessed sprites
  17. char HighSprZ[320+8+8]; // Z-buffer for accurate sprites and shadow/hilight mode
  18. // (if bit 7 == 0, sh caused by tile; if bit 6 == 0 pixel must be shadowed, else hilighted, if bit5 == 1)
  19. // lsb->msb: moved sprites, all window tiles don't use same priority, accurate sprites (copied from PicoOpt), interlace
  20. // dirty sprites, sonic mode
  21. int rendstatus;
  22. void *DrawLineDest=DefOutBuff; // pointer to dest buffer where to draw this line to
  23. int Scanline=0; // Scanline
  24. static int SpriteBlocks;
  25. //unsigned short ppt[] = { 0x0f11, 0x0ff1, 0x01f1, 0x011f, 0x01ff, 0x0f1f, 0x0f0e, 0x0e7c };
  26. struct TileStrip
  27. {
  28. int nametab; // Position in VRAM of name table (for this tile line)
  29. int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap
  30. int hscroll; // Horizontal scroll value in pixels for the line
  31. int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap
  32. int *hc; // cache for high tile codes and their positions
  33. int cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320)
  34. };
  35. // stuff available in asm:
  36. #ifdef _ASM_DRAW_C
  37. void DrawWindow(int tstart, int tend, int prio, int sh);
  38. void BackFill(int reg7, int sh);
  39. void DrawSprite(int *sprite, int **hc, int sh);
  40. void DrawTilesFromCache(int *hc, int sh);
  41. void DrawSpritesFromCache(int *hc, int sh);
  42. void DrawLayer(int plane, int *hcache, int maxcells, int sh);
  43. void FinalizeLineBGR444(int sh);
  44. void FinalizeLineRGB555(int sh);
  45. void blockcpy_or(void *dst, void *src, size_t n, int pat);
  46. #else
  47. // utility
  48. void blockcpy_or(void *dst, void *src, size_t n, int pat)
  49. {
  50. unsigned char *pd = dst, *ps = src;
  51. for (; n; n--)
  52. *pd++ = (unsigned char) (*ps++ | pat);
  53. }
  54. #endif
  55. static int TileNorm(int sx,int addr,int pal)
  56. {
  57. unsigned char *pd = HighCol+sx;
  58. unsigned int pack=0; unsigned int t=0;
  59. pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
  60. if (pack)
  61. {
  62. t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12));
  63. t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8));
  64. t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4));
  65. t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t ));
  66. t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28));
  67. t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24));
  68. t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20));
  69. t=pack&0x000f0000; if (t) pd[7]=(unsigned char)(pal|(t>>16));
  70. return 0;
  71. }
  72. return 1; // Tile blank
  73. }
  74. static int TileFlip(int sx,int addr,int pal)
  75. {
  76. unsigned char *pd = HighCol+sx;
  77. unsigned int pack=0; unsigned int t=0;
  78. pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
  79. if (pack)
  80. {
  81. t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16));
  82. t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20));
  83. t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24));
  84. t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28));
  85. t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t ));
  86. t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4));
  87. t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8));
  88. t=pack&0x0000f000; if (t) pd[7]=(unsigned char)(pal|(t>>12));
  89. return 0;
  90. }
  91. return 1; // Tile blank
  92. }
  93. // tile renderers for hacky operator sprite support
  94. #define sh_pix(x) \
  95. if(!t); \
  96. else if(t==0xe) pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ \
  97. else if(t==0xf) pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ \
  98. else pd[x]=(unsigned char)(pal|t)
  99. #ifndef _ASM_DRAW_C
  100. static int TileNormSH(int sx,int addr,int pal)
  101. {
  102. unsigned int pack=0; unsigned int t=0;
  103. unsigned char *pd = HighCol+sx;
  104. pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
  105. if (pack)
  106. {
  107. t=(pack&0x0000f000)>>12; sh_pix(0);
  108. t=(pack&0x00000f00)>> 8; sh_pix(1);
  109. t=(pack&0x000000f0)>> 4; sh_pix(2);
  110. t=(pack&0x0000000f) ; sh_pix(3);
  111. t=(pack&0xf0000000)>>28; sh_pix(4);
  112. t=(pack&0x0f000000)>>24; sh_pix(5);
  113. t=(pack&0x00f00000)>>20; sh_pix(6);
  114. t=(pack&0x000f0000)>>16; sh_pix(7);
  115. return 0;
  116. }
  117. return 1; // Tile blank
  118. }
  119. static int TileFlipSH(int sx,int addr,int pal)
  120. {
  121. unsigned int pack=0; unsigned int t=0;
  122. unsigned char *pd = HighCol+sx;
  123. pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
  124. if (pack)
  125. {
  126. t=(pack&0x000f0000)>>16; sh_pix(0);
  127. t=(pack&0x00f00000)>>20; sh_pix(1);
  128. t=(pack&0x0f000000)>>24; sh_pix(2);
  129. t=(pack&0xf0000000)>>28; sh_pix(3);
  130. t=(pack&0x0000000f) ; sh_pix(4);
  131. t=(pack&0x000000f0)>> 4; sh_pix(5);
  132. t=(pack&0x00000f00)>> 8; sh_pix(6);
  133. t=(pack&0x0000f000)>>12; sh_pix(7);
  134. return 0;
  135. }
  136. return 1; // Tile blank
  137. }
  138. #endif
  139. static int TileNormZ(int sx,int addr,int pal,int zval)
  140. {
  141. unsigned int pack=0; unsigned int t=0;
  142. unsigned char *pd = HighCol+sx;
  143. char *zb = HighSprZ+sx;
  144. int collision = 0, zb_s;
  145. pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
  146. if (pack)
  147. {
  148. t=pack&0x0000f000; if(t) { zb_s=zb[0]; if(zb_s) collision=1; if(zval>zb_s) { pd[0]=(unsigned char)(pal|(t>>12)); zb[0]=(char)zval; } }
  149. t=pack&0x00000f00; if(t) { zb_s=zb[1]; if(zb_s) collision=1; if(zval>zb_s) { pd[1]=(unsigned char)(pal|(t>> 8)); zb[1]=(char)zval; } }
  150. t=pack&0x000000f0; if(t) { zb_s=zb[2]; if(zb_s) collision=1; if(zval>zb_s) { pd[2]=(unsigned char)(pal|(t>> 4)); zb[2]=(char)zval; } }
  151. t=pack&0x0000000f; if(t) { zb_s=zb[3]; if(zb_s) collision=1; if(zval>zb_s) { pd[3]=(unsigned char)(pal|(t )); zb[3]=(char)zval; } }
  152. t=pack&0xf0000000; if(t) { zb_s=zb[4]; if(zb_s) collision=1; if(zval>zb_s) { pd[4]=(unsigned char)(pal|(t>>28)); zb[4]=(char)zval; } }
  153. t=pack&0x0f000000; if(t) { zb_s=zb[5]; if(zb_s) collision=1; if(zval>zb_s) { pd[5]=(unsigned char)(pal|(t>>24)); zb[5]=(char)zval; } }
  154. t=pack&0x00f00000; if(t) { zb_s=zb[6]; if(zb_s) collision=1; if(zval>zb_s) { pd[6]=(unsigned char)(pal|(t>>20)); zb[6]=(char)zval; } }
  155. t=pack&0x000f0000; if(t) { zb_s=zb[7]; if(zb_s) collision=1; if(zval>zb_s) { pd[7]=(unsigned char)(pal|(t>>16)); zb[7]=(char)zval; } }
  156. if(collision) Pico.video.status|=0x20;
  157. return 0;
  158. }
  159. return 1; // Tile blank
  160. }
  161. static int TileFlipZ(int sx,int addr,int pal,int zval)
  162. {
  163. unsigned int pack=0; unsigned int t=0;
  164. unsigned char *pd = HighCol+sx;
  165. char *zb = HighSprZ+sx;
  166. int collision = 0, zb_s;
  167. pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
  168. if (pack)
  169. {
  170. t=pack&0x000f0000; if(t) { zb_s=zb[0]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[0]=(unsigned char)(pal|(t>>16)); zb[0]=(char)zval; } }
  171. t=pack&0x00f00000; if(t) { zb_s=zb[1]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[1]=(unsigned char)(pal|(t>>20)); zb[1]=(char)zval; } }
  172. t=pack&0x0f000000; if(t) { zb_s=zb[2]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[2]=(unsigned char)(pal|(t>>24)); zb[2]=(char)zval; } }
  173. t=pack&0xf0000000; if(t) { zb_s=zb[3]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[3]=(unsigned char)(pal|(t>>28)); zb[3]=(char)zval; } }
  174. t=pack&0x0000000f; if(t) { zb_s=zb[4]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[4]=(unsigned char)(pal|(t )); zb[4]=(char)zval; } }
  175. t=pack&0x000000f0; if(t) { zb_s=zb[5]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[5]=(unsigned char)(pal|(t>> 4)); zb[5]=(char)zval; } }
  176. t=pack&0x00000f00; if(t) { zb_s=zb[6]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[6]=(unsigned char)(pal|(t>> 8)); zb[6]=(char)zval; } }
  177. t=pack&0x0000f000; if(t) { zb_s=zb[7]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[7]=(unsigned char)(pal|(t>>12)); zb[7]=(char)zval; } }
  178. if(collision) Pico.video.status|=0x20;
  179. return 0;
  180. }
  181. return 1; // Tile blank
  182. }
  183. #define sh_pixZ(x) \
  184. if(t) { \
  185. if(zb[x]) collision=1; \
  186. if(zval>zb[x]) { \
  187. if (t==0xe) { pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ } \
  188. else if(t==0xf) { pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ } \
  189. else { zb[x]=(char)zval; pd[x]=(unsigned char)(pal|t); } \
  190. } \
  191. }
  192. static int TileNormZSH(int sx,int addr,int pal,int zval)
  193. {
  194. unsigned int pack=0; unsigned int t=0;
  195. unsigned char *pd = HighCol+sx;
  196. char *zb = HighSprZ+sx;
  197. int collision = 0;
  198. pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
  199. if (pack)
  200. {
  201. t=(pack&0x0000f000)>>12; sh_pixZ(0);
  202. t=(pack&0x00000f00)>> 8; sh_pixZ(1);
  203. t=(pack&0x000000f0)>> 4; sh_pixZ(2);
  204. t=(pack&0x0000000f) ; sh_pixZ(3);
  205. t=(pack&0xf0000000)>>28; sh_pixZ(4);
  206. t=(pack&0x0f000000)>>24; sh_pixZ(5);
  207. t=(pack&0x00f00000)>>20; sh_pixZ(6);
  208. t=(pack&0x000f0000)>>16; sh_pixZ(7);
  209. if(collision) Pico.video.status|=0x20;
  210. return 0;
  211. }
  212. return 1; // Tile blank
  213. }
  214. static int TileFlipZSH(int sx,int addr,int pal,int zval)
  215. {
  216. unsigned int pack=0; unsigned int t=0;
  217. unsigned char *pd = HighCol+sx;
  218. char *zb = HighSprZ+sx;
  219. int collision = 0;
  220. pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
  221. if (pack)
  222. {
  223. t=(pack&0x000f0000)>>16; sh_pixZ(0);
  224. t=(pack&0x00f00000)>>20; sh_pixZ(1);
  225. t=(pack&0x0f000000)>>24; sh_pixZ(2);
  226. t=(pack&0xf0000000)>>28; sh_pixZ(3);
  227. t=(pack&0x0000000f) ; sh_pixZ(4);
  228. t=(pack&0x000000f0)>> 4; sh_pixZ(5);
  229. t=(pack&0x00000f00)>> 8; sh_pixZ(6);
  230. t=(pack&0x0000f000)>>12; sh_pixZ(7);
  231. if(collision) Pico.video.status|=0x20;
  232. return 0;
  233. }
  234. return 1; // Tile blank
  235. }
  236. // --------------------------------------------
  237. #ifndef _ASM_DRAW_C
  238. static void DrawStrip(struct TileStrip *ts, int sh)
  239. {
  240. int tilex=0,dx=0,ty=0,code=0,addr=0,cells;
  241. int oldcode=-1,blank=-1; // The tile we know is blank
  242. int pal=0;
  243. // Draw tiles across screen:
  244. tilex=(-ts->hscroll)>>3;
  245. ty=(ts->line&7)<<1; // Y-Offset into tile
  246. dx=((ts->hscroll-1)&7)+1;
  247. cells = ts->cells;
  248. if(dx != 8) cells++; // have hscroll, need to draw 1 cell more
  249. for (; cells; dx+=8,tilex++,cells--)
  250. {
  251. int zero=0;
  252. code=Pico.vram[ts->nametab+(tilex&ts->xmask)];
  253. if (code==blank) continue;
  254. if (code>>15) { // high priority tile
  255. int cval = code | (dx<<16) | (ty<<25);
  256. if(code&0x1000) cval^=7<<26;
  257. *ts->hc++ = cval; // cache it
  258. continue;
  259. }
  260. if (code!=oldcode) {
  261. oldcode = code;
  262. // Get tile address/2:
  263. addr=(code&0x7ff)<<4;
  264. addr+=ty;
  265. if (code&0x1000) addr^=0xe; // Y-flip
  266. // pal=Pico.cram+((code>>9)&0x30);
  267. pal=((code>>9)&0x30)|(sh<<6);
  268. }
  269. if (code&0x0800) zero=TileFlip(dx,addr,pal);
  270. else zero=TileNorm(dx,addr,pal);
  271. if (zero) blank=code; // We know this tile is blank now
  272. }
  273. // terminate the cache list
  274. *ts->hc = 0;
  275. }
  276. // this is messy
  277. void DrawStripVSRam(struct TileStrip *ts, int plane)
  278. {
  279. int tilex=0,dx=0,ty=0,code=0,addr=0,cell=0,nametabadd=0;
  280. int oldcode=-1,blank=-1; // The tile we know is blank
  281. int pal=0,scan=Scanline;
  282. // Draw tiles across screen:
  283. tilex=(-ts->hscroll)>>3;
  284. dx=((ts->hscroll-1)&7)+1;
  285. if(dx != 8) {
  286. int vscroll, line;
  287. cell--; // have hscroll, start with negative cell
  288. // also calculate intial VS stuff
  289. vscroll=Pico.vsram[plane];
  290. // Find the line in the name table
  291. line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..
  292. nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width]
  293. ty=(line&7)<<1; // Y-Offset into tile
  294. }
  295. for (; cell < ts->cells; dx+=8,tilex++,cell++)
  296. {
  297. int zero=0;
  298. if((cell&1)==0) {
  299. int line,vscroll;
  300. vscroll=Pico.vsram[plane+(cell&~1)];
  301. // Find the line in the name table
  302. line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..
  303. nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width]
  304. ty=(line&7)<<1; // Y-Offset into tile
  305. }
  306. code=Pico.vram[ts->nametab+nametabadd+(tilex&ts->xmask)];
  307. if (code==blank) continue;
  308. if (code>>15) { // high priority tile
  309. int cval = code | (dx<<16) | (ty<<25);
  310. if(code&0x1000) cval^=7<<26;
  311. *ts->hc++ = cval; // cache it
  312. continue;
  313. }
  314. if (code!=oldcode) {
  315. oldcode = code;
  316. // Get tile address/2:
  317. addr=(code&0x7ff)<<4;
  318. if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip
  319. // pal=Pico.cram+((code>>9)&0x30);
  320. pal=((code>>9)&0x30);
  321. }
  322. if (code&0x0800) zero=TileFlip(dx,addr,pal);
  323. else zero=TileNorm(dx,addr,pal);
  324. if (zero) blank=code; // We know this tile is blank now
  325. }
  326. // terminate the cache list
  327. *ts->hc = 0;
  328. }
  329. #endif
  330. #ifndef _ASM_DRAW_C
  331. static
  332. #endif
  333. void DrawStripInterlace(struct TileStrip *ts)
  334. {
  335. int tilex=0,dx=0,ty=0,code=0,addr=0,cells;
  336. int oldcode=-1,blank=-1; // The tile we know is blank
  337. int pal=0;
  338. // Draw tiles across screen:
  339. tilex=(-ts->hscroll)>>3;
  340. ty=(ts->line&15)<<1; // Y-Offset into tile
  341. dx=((ts->hscroll-1)&7)+1;
  342. cells = ts->cells;
  343. if(dx != 8) cells++; // have hscroll, need to draw 1 cell more
  344. for (; cells; dx+=8,tilex++,cells--)
  345. {
  346. int zero=0;
  347. code=Pico.vram[ts->nametab+(tilex&ts->xmask)];
  348. if (code==blank) continue;
  349. if (code>>15) { // high priority tile
  350. int cval = (code&0xfc00) | (dx<<16) | (ty<<25);
  351. cval|=(code&0x3ff)<<1;
  352. if(code&0x1000) cval^=0xf<<26;
  353. *ts->hc++ = cval; // cache it
  354. continue;
  355. }
  356. if (code!=oldcode) {
  357. oldcode = code;
  358. // Get tile address/2:
  359. addr=(code&0x7ff)<<5;
  360. if (code&0x1000) addr+=30-ty; else addr+=ty; // Y-flip
  361. // pal=Pico.cram+((code>>9)&0x30);
  362. pal=((code>>9)&0x30);
  363. }
  364. if (code&0x0800) zero=TileFlip(dx,addr,pal);
  365. else zero=TileNorm(dx,addr,pal);
  366. if (zero) blank=code; // We know this tile is blank now
  367. }
  368. // terminate the cache list
  369. *ts->hc = 0;
  370. }
  371. // --------------------------------------------
  372. #ifndef _ASM_DRAW_C
  373. static void DrawLayer(int plane, int *hcache, int maxcells, int sh)
  374. {
  375. struct PicoVideo *pvid=&Pico.video;
  376. const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid)
  377. struct TileStrip ts;
  378. int width, height, ymask;
  379. int vscroll, htab;
  380. ts.hc=hcache;
  381. ts.cells=maxcells;
  382. // Work out the TileStrip to draw
  383. // Work out the name table size: 32 64 or 128 tiles (0-3)
  384. width=pvid->reg[16];
  385. height=(width>>4)&3; width&=3;
  386. ts.xmask=(1<<shift[width])-1; // X Mask in tiles (0x1f-0x7f)
  387. ymask=(height<<8)|0xff; // Y Mask in pixels
  388. if(width == 1) ymask&=0x1ff;
  389. else if(width>1) ymask =0x0ff;
  390. // Find name table:
  391. if (plane==0) ts.nametab=(pvid->reg[2]&0x38)<< 9; // A
  392. else ts.nametab=(pvid->reg[4]&0x07)<<12; // B
  393. htab=pvid->reg[13]<<9; // Horizontal scroll table address
  394. if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line
  395. if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile
  396. htab+=plane; // A or B
  397. // Get horizontal scroll value, will be masked later
  398. ts.hscroll=Pico.vram[htab&0x7fff];
  399. if((pvid->reg[12]&6) == 6) {
  400. // interlace mode 2
  401. vscroll=Pico.vsram[plane]; // Get vertical scroll value
  402. // Find the line in the name table
  403. ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1);
  404. ts.nametab+=(ts.line>>4)<<shift[width];
  405. DrawStripInterlace(&ts);
  406. } else if( pvid->reg[11]&4) {
  407. // shit, we have 2-cell column based vscroll
  408. // luckily this doesn't happen too often
  409. ts.line=ymask|(shift[width]<<24); // save some stuff instead of line
  410. DrawStripVSRam(&ts, plane);
  411. } else {
  412. vscroll=Pico.vsram[plane]; // Get vertical scroll value
  413. // Find the line in the name table
  414. ts.line=(vscroll+Scanline)&ymask;
  415. ts.nametab+=(ts.line>>3)<<shift[width];
  416. DrawStrip(&ts, sh);
  417. }
  418. }
  419. // --------------------------------------------
  420. // tstart & tend are tile pair numbers
  421. static void DrawWindow(int tstart, int tend, int prio, int sh) // int *hcache
  422. {
  423. struct PicoVideo *pvid=&Pico.video;
  424. int tilex=0,ty=0,nametab,code=0;
  425. int blank=-1; // The tile we know is blank
  426. // Find name table line:
  427. if (pvid->reg[12]&1)
  428. {
  429. nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode
  430. nametab+=(Scanline>>3)<<6;
  431. }
  432. else
  433. {
  434. nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode
  435. nametab+=(Scanline>>3)<<5;
  436. }
  437. tilex=tstart<<1;
  438. tend<<=1;
  439. ty=(Scanline&7)<<1; // Y-Offset into tile
  440. if(!(rendstatus&2)) {
  441. // check the first tile code
  442. code=Pico.vram[nametab+tilex];
  443. // if the whole window uses same priority (what is often the case), we may be able to skip this field
  444. if((code>>15) != prio) return;
  445. }
  446. // Draw tiles across screen:
  447. for (; tilex < tend; tilex++)
  448. {
  449. int addr=0,zero=0;
  450. int pal;
  451. code=Pico.vram[nametab+tilex];
  452. if(code==blank) continue;
  453. if((code>>15) != prio) {
  454. rendstatus|=2;
  455. continue;
  456. }
  457. pal=((code>>9)&0x30);
  458. if(sh) {
  459. int tmp, *zb = (int *)(HighCol+8+(tilex<<3));
  460. if(prio) {
  461. tmp = *zb;
  462. if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000;
  463. if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000;
  464. *zb++=tmp; tmp = *zb;
  465. if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000;
  466. if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000;
  467. *zb++=tmp;
  468. } else {
  469. pal |= 0x40;
  470. }
  471. }
  472. // Get tile address/2:
  473. addr=(code&0x7ff)<<4;
  474. if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip
  475. if (code&0x0800) zero=TileFlip(8+(tilex<<3),addr,pal);
  476. else zero=TileNorm(8+(tilex<<3),addr,pal);
  477. if (zero) blank=code; // We know this tile is blank now
  478. }
  479. // terminate the cache list
  480. //*hcache = 0;
  481. }
  482. // --------------------------------------------
  483. static void DrawTilesFromCache(int *hc, int sh)
  484. {
  485. int code, addr, zero, dx;
  486. int pal;
  487. short blank=-1; // The tile we know is blank
  488. // *ts->hc++ = code | (dx<<16) | (ty<<25); // cache it
  489. while((code=*hc++)) {
  490. if(!sh && (short)code == blank) continue;
  491. // Get tile address/2:
  492. addr=(code&0x7ff)<<4;
  493. addr+=(unsigned int)code>>25; // y offset into tile
  494. dx=(code>>16)&0x1ff;
  495. if(sh) {
  496. unsigned char *zb = HighCol+dx;
  497. if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++;
  498. if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++;
  499. if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++;
  500. if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++;
  501. }
  502. pal=((code>>9)&0x30);
  503. if (code&0x0800) zero=TileFlip(dx,addr,pal);
  504. else zero=TileNorm(dx,addr,pal);
  505. if(zero) blank=(short)code;
  506. }
  507. }
  508. // --------------------------------------------
  509. // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size
  510. // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
  511. static void DrawSprite(int *sprite, int **hc, int sh)
  512. {
  513. int width=0,height=0;
  514. int row=0,code=0;
  515. int pal;
  516. int tile=0,delta=0;
  517. int sx, sy;
  518. int (*fTileFunc)(int sx,int addr,int pal);
  519. // parse the sprite data
  520. sy=sprite[0];
  521. code=sprite[1];
  522. sx=code>>16; // X
  523. width=sy>>28;
  524. height=(sy>>24)&7; // Width and height in tiles
  525. sy=(sy<<16)>>16; // Y
  526. row=Scanline-sy; // Row of the sprite we are on
  527. if (code&0x1000) row=(height<<3)-1-row; // Flip Y
  528. tile=code&0x7ff; // Tile number
  529. tile+=row>>3; // Tile number increases going down
  530. delta=height; // Delta to increase tile by going right
  531. if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X
  532. tile<<=4; tile+=(row&7)<<1; // Tile address
  533. if(code&0x8000) { // high priority - cache it
  534. *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>16)&0xf);
  535. } else {
  536. delta<<=4; // Delta of address
  537. pal=((code>>9)&0x30)|(sh<<6);
  538. if(sh && (code&0x6000) == 0x6000) {
  539. if(code&0x0800) fTileFunc=TileFlipSH;
  540. else fTileFunc=TileNormSH;
  541. } else {
  542. if(code&0x0800) fTileFunc=TileFlip;
  543. else fTileFunc=TileNorm;
  544. }
  545. for (; width; width--,sx+=8,tile+=delta)
  546. {
  547. if(sx<=0) continue;
  548. if(sx>=328) break; // Offscreen
  549. tile&=0x7fff; // Clip tile address
  550. fTileFunc(sx,tile,pal);
  551. }
  552. }
  553. }
  554. #endif
  555. // Index + 0 : hhhhvvvv s---hhvv yyyyyyyy yyyyyyyy // s: skip flag, h: horiz. size
  556. // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
  557. static void DrawSpriteZ(int pack, int pack2, int shpri, int sprio)
  558. {
  559. int width=0,height=0;
  560. int row=0;
  561. int pal;
  562. int tile=0,delta=0;
  563. int sx, sy;
  564. int (*fTileFunc)(int sx,int addr,int pal,int zval);
  565. // parse the sprite data
  566. sx=pack2>>16; // X
  567. sy=(pack <<16)>>16; // Y
  568. width=pack>>28;
  569. height=(pack>>24)&7; // Width and height in tiles
  570. row=Scanline-sy; // Row of the sprite we are on
  571. if (pack2&0x1000) row=(height<<3)-1-row; // Flip Y
  572. tile=pack2&0x7ff; // Tile number
  573. tile+=row>>3; // Tile number increases going down
  574. delta=height; // Delta to increase tile by going right
  575. if (pack2&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X
  576. tile<<=4; tile+=(row&7)<<1; // Tile address
  577. delta<<=4; // Delta of address
  578. pal=((pack2>>9)&0x30);
  579. if((shpri&1)&&!(shpri&2)) pal|=0x40;
  580. shpri&=1;
  581. if((pack2&0x6000) != 0x6000) shpri = 0;
  582. shpri |= (pack2&0x0800)>>10;
  583. switch(shpri) {
  584. default:
  585. case 0: fTileFunc=TileNormZ; break;
  586. case 1: fTileFunc=TileNormZSH; break;
  587. case 2: fTileFunc=TileFlipZ; break;
  588. case 3: fTileFunc=TileFlipZSH; break;
  589. }
  590. for (; width; width--,sx+=8,tile+=delta)
  591. {
  592. if(sx<=0) continue;
  593. if(sx>=328) break; // Offscreen
  594. tile&=0x7fff; // Clip tile address
  595. fTileFunc(sx,tile,pal,sprio);
  596. }
  597. }
  598. static void DrawSpriteInterlace(unsigned int *sprite)
  599. {
  600. int width=0,height=0;
  601. int row=0,code=0;
  602. int pal;
  603. int tile=0,delta=0;
  604. int sx, sy;
  605. // parse the sprite data
  606. sy=sprite[0];
  607. height=sy>>24;
  608. sy=(sy&0x3ff)-0x100; // Y
  609. width=(height>>2)&3; height&=3;
  610. width++; height++; // Width and height in tiles
  611. row=(Scanline<<1)-sy; // Row of the sprite we are on
  612. code=sprite[1];
  613. sx=((code>>16)&0x1ff)-0x78; // X
  614. if (code&0x1000) row^=(16<<height)-1; // Flip Y
  615. tile=code&0x3ff; // Tile number
  616. tile+=row>>4; // Tile number increases going down
  617. delta=height; // Delta to increase tile by going right
  618. if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X
  619. tile<<=5; tile+=(row&15)<<1; // Tile address
  620. delta<<=5; // Delta of address
  621. pal=((code>>9)&0x30); // Get palette pointer
  622. for (; width; width--,sx+=8,tile+=delta)
  623. {
  624. if(sx<=0) continue;
  625. if(sx>=328) break; // Offscreen
  626. tile&=0x7fff; // Clip tile address
  627. if (code&0x0800) TileFlip(sx,tile,pal);
  628. else TileNorm(sx,tile,pal);
  629. }
  630. }
  631. static void DrawAllSpritesInterlace(int pri, int maxwidth)
  632. {
  633. struct PicoVideo *pvid=&Pico.video;
  634. int i,u,table,link=0,sline=Scanline<<1;
  635. unsigned int *sprites[80]; // Sprite index
  636. table=pvid->reg[5]&0x7f;
  637. if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
  638. table<<=8; // Get sprite table address/2
  639. for (i=u=0; u < 80 && i < 21; u++)
  640. {
  641. unsigned int *sprite;
  642. int code, sx, sy, height;
  643. sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
  644. // get sprite info
  645. code = sprite[0];
  646. sx = sprite[1];
  647. if(((sx>>15)&1) != pri) goto nextsprite; // wrong priority sprite
  648. // check if it is on this line
  649. sy = (code&0x3ff)-0x100;
  650. height = (((code>>24)&3)+1)<<4;
  651. if(sline < sy || sline >= sy+height) goto nextsprite; // no
  652. // check if sprite is not hidden offscreen
  653. sx = (sx>>16)&0x1ff;
  654. sx -= 0x78; // Get X coordinate + 8
  655. if(sx <= -8*3 || sx >= maxwidth) goto nextsprite;
  656. // sprite is good, save it's pointer
  657. sprites[i++]=sprite;
  658. nextsprite:
  659. // Find next sprite
  660. link=(code>>16)&0x7f;
  661. if(!link) break; // End of sprites
  662. }
  663. // Go through sprites backwards:
  664. for (i-- ;i>=0; i--)
  665. DrawSpriteInterlace(sprites[i]);
  666. }
  667. #ifndef _ASM_DRAW_C
  668. static void DrawSpritesFromCache(int *hc, int sh)
  669. {
  670. int code, tile, sx, delta, width;
  671. int pal;
  672. int (*fTileFunc)(int sx,int addr,int pal);
  673. // *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf);
  674. while((code=*hc++)) {
  675. pal=(code&0x30);
  676. delta=code&0xf;
  677. width=delta>>2; delta&=3;
  678. width++; delta++; // Width and height in tiles
  679. if (code&0x10000) delta=-delta; // Flip X
  680. delta<<=4;
  681. tile=((unsigned int)code>>17)<<1;
  682. sx=(code<<16)>>22; // sx can be negative (start offscreen), so sign extend
  683. if(sh && pal == 0x30) { //
  684. if(code&0x10000) fTileFunc=TileFlipSH;
  685. else fTileFunc=TileNormSH;
  686. } else {
  687. if(code&0x10000) fTileFunc=TileFlip;
  688. else fTileFunc=TileNorm;
  689. }
  690. for (; width; width--,sx+=8,tile+=delta)
  691. {
  692. if(sx<=0) continue;
  693. if(sx>=328) break; // Offscreen
  694. tile&=0x7fff; // Clip tile address
  695. fTileFunc(sx,tile,pal);
  696. }
  697. }
  698. }
  699. #endif
  700. // Index + 0 : ----hhvv -lllllll -------y yyyyyyyy
  701. // Index + 4 : -------x xxxxxxxx pccvhnnn nnnnnnnn
  702. // v
  703. // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size
  704. // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
  705. static void PrepareSprites(int full)
  706. {
  707. struct PicoVideo *pvid=&Pico.video;
  708. int u=0,link=0,sblocks=0;
  709. int table=0;
  710. int *pd = HighPreSpr;
  711. table=pvid->reg[5]&0x7f;
  712. if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
  713. table<<=8; // Get sprite table address/2
  714. if (!full)
  715. {
  716. int pack;
  717. // updates: tilecode, sx
  718. for (u=0; u < 80 && (pack = *pd); u++, pd+=2)
  719. {
  720. unsigned int *sprite;
  721. int code, code2, sx, sy, skip=0;
  722. sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
  723. // parse sprite info
  724. code = sprite[0];
  725. code2 = sprite[1];
  726. code2 &= ~0xfe000000;
  727. code2 -= 0x00780000; // Get X coordinate + 8 in upper 16 bits
  728. sx = code2>>16;
  729. if((sx <= 8-((pack>>28)<<3) && sx >= -0x76) || sx >= 328) skip=1<<23;
  730. else if ((sy = (pack<<16)>>16) < 240 && sy > -32) {
  731. int sbl = (2<<(pack>>28))-1;
  732. sblocks |= sbl<<(sy>>3);
  733. }
  734. *pd = (pack&~(1<<23))|skip;
  735. *(pd+1) = code2;
  736. // Find next sprite
  737. link=(code>>16)&0x7f;
  738. if(!link) break; // End of sprites
  739. }
  740. SpriteBlocks |= sblocks;
  741. }
  742. else
  743. {
  744. for (; u < 80; u++)
  745. {
  746. unsigned int *sprite;
  747. int code, code2, sx, sy, hv, height, width, skip=0, sx_min;
  748. sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
  749. // parse sprite info
  750. code = sprite[0];
  751. sy = (code&0x1ff)-0x80;
  752. hv = (code>>24)&0xf;
  753. height = (hv&3)+1;
  754. if(sy > 240 || sy + (height<<3) <= 0) skip|=1<<22;
  755. width = (hv>>2)+1;
  756. code2 = sprite[1];
  757. sx = (code2>>16)&0x1ff;
  758. sx -= 0x78; // Get X coordinate + 8
  759. sx_min = 8-(width<<3);
  760. if((sx <= sx_min && sx >= -0x76) || sx >= 328) skip|=1<<23;
  761. else if (sx > sx_min && !skip) {
  762. int sbl = (2<<height)-1;
  763. int shi = sy>>3;
  764. if(shi < 0) shi=0; // negative sy
  765. sblocks |= sbl<<shi;
  766. }
  767. *pd++ = (width<<28)|(height<<24)|skip|(hv<<16)|((unsigned short)sy);
  768. *pd++ = (sx<<16)|((unsigned short)code2);
  769. // Find next sprite
  770. link=(code>>16)&0x7f;
  771. if(!link) break; // End of sprites
  772. }
  773. SpriteBlocks = sblocks;
  774. *pd = 0; // terminate
  775. }
  776. }
  777. static void DrawAllSprites(int *hcache, int maxwidth, int prio, int sh)
  778. {
  779. int i,u,n;
  780. int sx1seen=0; // sprite with x coord 1 or 0 seen
  781. int ntiles = 0; // tile counter for sprite limit emulation
  782. int *sprites[40]; // Sprites to draw in fast mode
  783. int *ps, pack, rs = rendstatus, scan=Scanline;
  784. if(rs&8) {
  785. DrawAllSpritesInterlace(prio, maxwidth);
  786. return;
  787. }
  788. if(rs&0x11) {
  789. //dprintf("PrepareSprites(%i) [%i]", (rs>>4)&1, scan);
  790. PrepareSprites(rs&0x10);
  791. rendstatus=rs&~0x11;
  792. }
  793. if (!(SpriteBlocks & (1<<(scan>>3)))) return;
  794. if(((rs&4)||sh)&&prio==0)
  795. memset(HighSprZ, 0, 328);
  796. if(!(rs&4)&&prio) {
  797. if(hcache[0]) DrawSpritesFromCache(hcache, sh);
  798. return;
  799. }
  800. ps = HighPreSpr;
  801. // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size
  802. // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
  803. for(i=u=n=0; (pack = *ps) && n < 20; ps+=2, u++)
  804. {
  805. int sx, sy, row, pack2;
  806. if(pack & 0x00400000) continue;
  807. // get sprite info
  808. pack2 = *(ps+1);
  809. sx = pack2>>16;
  810. sy = (pack <<16)>>16;
  811. row = scan-sy;
  812. //dprintf("x: %i y: %i %ix%i", sx, sy, (pack>>28)<<3, (pack>>21)&0x38);
  813. if(sx == -0x77) sx1seen|=1; // for masking mode 2
  814. // check if it is on this line
  815. if(row < 0 || row >= ((pack>>21)&0x38)) continue; // no
  816. n++; // number of sprites on this line (both visible and hidden, max is 20) [broken]
  817. // sprite limit
  818. ntiles += pack>>28;
  819. if(ntiles > 40) break;
  820. if(pack & 0x00800000) continue;
  821. // masking sprite?
  822. if(sx == -0x78) {
  823. if(!(sx1seen&1) || sx1seen==3) {
  824. break; // this sprite is not drawn and remaining sprites are masked
  825. }
  826. if((sx1seen>>8) == 0) sx1seen=(i+1)<<8;
  827. continue;
  828. }
  829. else if(sx == -0x77) {
  830. // masking mode2 (Outrun, Galaxy Force II, Shadow of the beast)
  831. if(sx1seen>>8) { i=(sx1seen>>8)-1; break; } // seen both 0 and 1
  832. sx1seen |= 2;
  833. continue;
  834. }
  835. // accurate sprites
  836. //dprintf("P:%i",((sx>>15)&1));
  837. if(rs&4) {
  838. // might need to skip this sprite
  839. if((pack2&0x8000) ^ (prio<<15)) continue;
  840. DrawSpriteZ(pack,pack2,sh|(prio<<1),(char)(0x1f-n));
  841. continue;
  842. }
  843. // sprite is good, save it's pointer
  844. sprites[i++]=ps;
  845. }
  846. // Go through sprites backwards:
  847. if(!(rs&4)) {
  848. for (i--; i>=0; i--)
  849. DrawSprite(sprites[i],&hcache,sh);
  850. // terminate cache list
  851. *hcache = 0;
  852. }
  853. }
  854. // --------------------------------------------
  855. #ifndef _ASM_DRAW_C
  856. static void BackFill(int reg7, int sh)
  857. {
  858. unsigned int back=0;
  859. unsigned int *pd=NULL,*end=NULL;
  860. // Start with a blank scanline (background colour):
  861. back=reg7&0x3f;
  862. back|=sh<<6;
  863. back|=back<<8;
  864. back|=back<<16;
  865. pd= (unsigned int *)(HighCol+8);
  866. end=(unsigned int *)(HighCol+8+320);
  867. do { pd[0]=pd[1]=pd[2]=pd[3]=back; pd+=4; } while (pd<end);
  868. }
  869. #endif
  870. // --------------------------------------------
  871. unsigned short HighPal[0x100];
  872. #ifndef _ASM_DRAW_C
  873. static void FinalizeLineBGR444(int sh)
  874. {
  875. unsigned short *pd=DrawLineDest;
  876. unsigned char *ps=HighCol+8;
  877. unsigned short *pal=Pico.cram;
  878. int len, i, t;
  879. if (Pico.video.reg[12]&1) {
  880. len = 320;
  881. } else {
  882. if(!(PicoOpt&0x100)) pd+=32;
  883. len = 256;
  884. }
  885. if(sh) {
  886. pal=HighPal;
  887. if(Pico.m.dirtyPal) {
  888. blockcpy(pal, Pico.cram, 0x40*2);
  889. // shadowed pixels
  890. for(i = 0x3f; i >= 0; i--)
  891. pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x0777);
  892. // hilighted pixels
  893. for(i = 0x3f; i >= 0; i--) {
  894. t=pal[i]&0xeee;t+=0x444;if(t&0x10)t|=0xe;if(t&0x100)t|=0xe0;if(t&0x1000)t|=0xe00;t&=0xeee;
  895. pal[0x80|i]=(unsigned short)t;
  896. }
  897. Pico.m.dirtyPal = 0;
  898. }
  899. }
  900. for(i = 0; i < len; i++)
  901. pd[i] = pal[ps[i]];
  902. }
  903. static void FinalizeLineRGB555(int sh)
  904. {
  905. unsigned short *pd=DrawLineDest;
  906. unsigned char *ps=HighCol+8;
  907. unsigned short *pal=HighPal;
  908. int len, i, t, dirtyPal = Pico.m.dirtyPal;
  909. if(dirtyPal) {
  910. unsigned short *ppal=Pico.cram;
  911. for(i = 0x3f; i >= 0; i--)
  912. pal[i] = (unsigned short) (((ppal[i]&0x00f)<<12)|((ppal[i]&0x0f0)<<3)|((ppal[i]&0xf00)>>7));
  913. Pico.m.dirtyPal = 0;
  914. }
  915. if (Pico.video.reg[12]&1) {
  916. len = 320;
  917. } else {
  918. if(!(PicoOpt&0x100)) pd+=32;
  919. len = 256;
  920. }
  921. if(sh) {
  922. if(dirtyPal) {
  923. // shadowed pixels
  924. for(i = 0x3f; i >= 0; i--)
  925. pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x738e);
  926. // hilighted pixels
  927. for(i = 0x3f; i >= 0; i--) {
  928. t=pal[i]&0xe71c;t+=0x4208;if(t&0x20)t|=0x1c;if(t&0x800)t|=0x700;if(t&0x10000)t|=0xe000;t&=0xe71c;
  929. pal[0x80|i]=(unsigned short)t;
  930. }
  931. }
  932. }
  933. for(i = 0; i < len; i++)
  934. pd[i] = pal[ps[i]];
  935. }
  936. #endif
  937. static void FinalizeLine8bit(int sh)
  938. {
  939. unsigned char *pd=DrawLineDest;
  940. int len, rs = rendstatus;
  941. static int dirty_count;
  942. if (!sh && Pico.m.dirtyPal == 1 && Scanline < 222) {
  943. // a hack for mid-frame palette changes
  944. if (!(rs & 0x20))
  945. dirty_count = 1;
  946. else dirty_count++;
  947. rs |= 0x20;
  948. rendstatus = rs;
  949. if (dirty_count == 3) {
  950. blockcpy(HighPal, Pico.cram, 0x40*2);
  951. } else if (dirty_count == 11) {
  952. blockcpy(HighPal+0x40, Pico.cram, 0x40*2);
  953. }
  954. }
  955. if (Pico.video.reg[12]&1) {
  956. len = 320;
  957. } else {
  958. if(!(PicoOpt&0x100)) pd+=32;
  959. len = 256;
  960. }
  961. if (!sh && rs & 0x20) {
  962. if (dirty_count >= 11) {
  963. blockcpy_or(pd, HighCol+8, len, 0x80);
  964. } else {
  965. blockcpy_or(pd, HighCol+8, len, 0x40);
  966. }
  967. } else {
  968. blockcpy(pd, HighCol+8, len);
  969. }
  970. }
  971. void (*FinalizeLine)(int sh) = FinalizeLineBGR444;
  972. // --------------------------------------------
  973. static int DrawDisplay(int sh)
  974. {
  975. struct PicoVideo *pvid=&Pico.video;
  976. int win=0,edge=0,hvwind=0;
  977. int maxw, maxcells;
  978. if(pvid->reg[12]&1) {
  979. maxw = 328; maxcells = 40;
  980. } else {
  981. maxw = 264; maxcells = 32;
  982. }
  983. // Find out if the window is on this line:
  984. win=pvid->reg[0x12];
  985. edge=(win&0x1f)<<3;
  986. if (win&0x80) { if (Scanline>=edge) hvwind=1; }
  987. else { if (Scanline< edge) hvwind=1; }
  988. if(!hvwind) { // we might have a vertical window here
  989. win=pvid->reg[0x11];
  990. edge=win&0x1f;
  991. if(win&0x80) {
  992. if(!edge) hvwind=1;
  993. else if(edge < (maxcells>>1)) hvwind=2;
  994. } else {
  995. if(!edge);
  996. else if(edge < (maxcells>>1)) hvwind=2;
  997. else hvwind=1;
  998. }
  999. }
  1000. DrawLayer(1, HighCacheB, maxcells, sh);
  1001. if(hvwind == 1)
  1002. DrawWindow(0, maxcells>>1, 0, sh); // HighCacheAW
  1003. else if(hvwind == 2) {
  1004. // ahh, we have vertical window
  1005. DrawLayer(0, HighCacheA, (win&0x80) ? edge<<1 : maxcells, sh);
  1006. DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 0, sh); // HighCacheW
  1007. } else
  1008. DrawLayer(0, HighCacheA, maxcells, sh);
  1009. DrawAllSprites(HighCacheS, maxw, 0, sh);
  1010. if(HighCacheB[0]) DrawTilesFromCache(HighCacheB, sh);
  1011. if(hvwind == 1)
  1012. DrawWindow(0, maxcells>>1, 1, sh);
  1013. else if(hvwind == 2) {
  1014. if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh);
  1015. DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh);
  1016. } else
  1017. if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh);
  1018. DrawAllSprites(HighCacheS, maxw, 1, sh);
  1019. return 0;
  1020. }
  1021. static int Skip=0;
  1022. PICO_INTERNAL void PicoFrameStart(void)
  1023. {
  1024. // prepare to do this frame
  1025. rendstatus = (PicoOpt&0x80)>>5; // accurate sprites
  1026. if(rendstatus)
  1027. Pico.video.status &= ~0x0020;
  1028. else Pico.video.status |= 0x0020; // sprite collision
  1029. if((Pico.video.reg[12]&6) == 6) rendstatus |= 8; // interlace mode
  1030. if(Pico.m.dirtyPal) Pico.m.dirtyPal = 2; // reset dirty if needed
  1031. PrepareSprites(1);
  1032. Skip=0;
  1033. }
  1034. PICO_INTERNAL int PicoLine(int scan)
  1035. {
  1036. int sh;
  1037. if (Skip>0) { Skip--; return 0; } // Skip rendering lines
  1038. Scanline=scan;
  1039. sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight?
  1040. // Draw screen:
  1041. BackFill(Pico.video.reg[7], sh);
  1042. if (Pico.video.reg[1]&0x40)
  1043. DrawDisplay(sh);
  1044. FinalizeLine(sh);
  1045. //if (SpriteBlocks & (1<<(scan>>3))) for (sh=0; sh < 30; sh++) DrawLineDest[sh] = 0xf;
  1046. Skip=PicoScan(Scanline,DrawLineDest);
  1047. return 0;
  1048. }
  1049. void PicoDrawSetColorFormat(int which)
  1050. {
  1051. if (which == 2)
  1052. FinalizeLine = FinalizeLine8bit;
  1053. else if (which == 1)
  1054. FinalizeLine = FinalizeLineRGB555;
  1055. else FinalizeLine = FinalizeLineBGR444;
  1056. }