2 // This file is part of the PicoDrive Megadrive Emulator
\r
4 // This code is licensed under the GNU General Public License version 2.0 and the MAME License.
\r
5 // You can choose the license that has the most advantages for you.
\r
7 // SVN repository can be found at http://code.google.com/p/cyclone68000/
\r
11 #pragma warning (disable:4706) // Disable assignment with conditional
\r
14 int (*PicoScan)(unsigned int num,unsigned short *data)=NULL;
\r
16 // Line colour indices - in the format 00ppcccc pp=palette, cccc=colour
\r
17 static unsigned short HighCol[32+320+8]; // Gap for 32 column, and messy border on right
\r
18 static int Scanline=0; // Scanline
\r
20 int PicoMask=0xfff; // Mask of which layers to draw
\r
22 static int TileNorm(unsigned short *pd,int addr,unsigned int *pal)
\r
24 unsigned int pack=0; unsigned int t=0;
\r
26 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
\r
29 t=pack&0x0000f000; if (t) { t=pal[t>>12]; pd[0]=(unsigned short)t; }
\r
30 t=pack&0x00000f00; if (t) { t=pal[t>> 8]; pd[1]=(unsigned short)t; }
\r
31 t=pack&0x000000f0; if (t) { t=pal[t>> 4]; pd[2]=(unsigned short)t; }
\r
32 t=pack&0x0000000f; if (t) { t=pal[t ]; pd[3]=(unsigned short)t; }
\r
33 t=pack&0xf0000000; if (t) { t=pal[t>>28]; pd[4]=(unsigned short)t; }
\r
34 t=pack&0x0f000000; if (t) { t=pal[t>>24]; pd[5]=(unsigned short)t; }
\r
35 t=pack&0x00f00000; if (t) { t=pal[t>>20]; pd[6]=(unsigned short)t; }
\r
36 t=pack&0x000f0000; if (t) { t=pal[t>>16]; pd[7]=(unsigned short)t; }
\r
40 return 1; // Tile blank
\r
43 static int TileFlip(unsigned short *pd,int addr,unsigned int *pal)
\r
45 unsigned int pack=0; unsigned int t=0;
\r
47 pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
\r
50 t=pack&0x000f0000; if (t) { t=pal[t>>16]; pd[0]=(unsigned short)t; }
\r
51 t=pack&0x00f00000; if (t) { t=pal[t>>20]; pd[1]=(unsigned short)t; }
\r
52 t=pack&0x0f000000; if (t) { t=pal[t>>24]; pd[2]=(unsigned short)t; }
\r
53 t=pack&0xf0000000; if (t) { t=pal[t>>28]; pd[3]=(unsigned short)t; }
\r
54 t=pack&0x0000000f; if (t) { t=pal[t ]; pd[4]=(unsigned short)t; }
\r
55 t=pack&0x000000f0; if (t) { t=pal[t>> 4]; pd[5]=(unsigned short)t; }
\r
56 t=pack&0x00000f00; if (t) { t=pal[t>> 8]; pd[6]=(unsigned short)t; }
\r
57 t=pack&0x0000f000; if (t) { t=pal[t>>12]; pd[7]=(unsigned short)t; }
\r
60 return 1; // Tile blank
\r
65 int nametab; // Position in VRAM of name table (for this tile line)
\r
66 int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap
\r
67 int hscroll; // Horizontal scroll value in pixels for the line
\r
68 int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap
\r
69 int high; // High or low tiles
\r
72 static int WrongPri=0; // 1 if there were tiles which are the wrong priority
\r
74 static int DrawStrip(struct TileStrip ts)
\r
76 int tilex=0,dx=0,ty=0;
\r
77 int blank=-1; // The tile we know is blank
\r
81 // Draw tiles across screen:
\r
82 tilex=(-ts.hscroll)>>3;
\r
83 ty=(ts.line&7)<<1; // Y-Offset into tile
\r
84 for (dx=((ts.hscroll-1)&7)+1; dx<328; dx+=8,tilex++)
\r
86 int code=0,addr=0,zero=0;
\r
87 unsigned int *pal=NULL;
\r
89 code=Pico.vram[ts.nametab+(tilex&ts.xmask)];
\r
90 if (code==blank) continue;
\r
91 if ((code>>15)!=ts.high) { WrongPri=1; continue; }
\r
93 // Get tile address/2:
\r
94 addr=(code&0x7ff)<<4;
\r
95 if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip
\r
97 pal=Pico.highpal+((code>>9)&0x30);
\r
99 if (code&0x0800) zero=TileFlip(HighCol+24+dx,addr,pal);
\r
100 else zero=TileNorm(HighCol+24+dx,addr,pal);
\r
102 if (zero) blank=code; // We know this tile is blank now
\r
108 static int DrawLayer(int plane,int high)
\r
110 struct PicoVideo *pvid=&Pico.video;
\r
111 static char shift[4]={5,6,6,7}; // 32,64 or 128 sized tilemaps
\r
112 struct TileStrip ts;
\r
114 // Work out the TileStrip to draw
\r
116 // Get vertical scroll value:
\r
117 int vscroll=Pico.vsram[plane];
\r
119 int htab=pvid->reg[13]<<9; // Horizontal scroll table address
\r
120 if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line
\r
121 if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile
\r
122 htab+=plane; // A or B
\r
124 // Get horizontal scroll value
\r
125 ts.hscroll=Pico.vram[htab&0x7fff];
\r
127 // Work out the name table size: 32 64 or 128 tiles (0-3)
\r
128 int width=pvid->reg[16];
\r
129 int height=(width>>4)&3; width&=3;
\r
131 ts.xmask=(1<<shift[width ])-1; // X Mask in tiles
\r
132 int ymask=(8<<shift[height])-1; // Y Mask in pixels
\r
134 // Find name table:
\r
135 if (plane==0) ts.nametab=(pvid->reg[2]&0x38)<< 9; // A
\r
136 else ts.nametab=(pvid->reg[4]&0x07)<<12; // B
\r
138 // Find the line in the name table
\r
139 ts.line=(vscroll+Scanline)&ymask;
\r
140 ts.nametab+=(ts.line>>3)<<shift[width];
\r
148 static int DrawWindow(int high)
\r
150 struct PicoVideo *pvid=&Pico.video;
\r
151 struct TileStrip ts;
\r
156 // Find name table line:
\r
157 if (Pico.video.reg[12]&1)
\r
159 ts.nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode
\r
160 ts.nametab+=(ts.line>>3)<<6;
\r
164 ts.nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode
\r
165 ts.nametab+=(ts.line>>3)<<5;
\r
175 static int DrawSprite(int sy,unsigned short *sprite,int high)
\r
177 int sx=0,width=0,height=0;
\r
179 unsigned int *pal=NULL;
\r
180 int tile=0,delta=0;
\r
184 if ((code>>15)!=high) { WrongPri=1; return 0; } // Wrong priority
\r
186 height=sprite[1]>>8;
\r
187 width=(height>>2)&3; height&=3;
\r
188 width++; height++; // Width and height in tiles
\r
189 if (Scanline>=sy+(height<<3)) return 0; // Not on this line after all
\r
191 row=Scanline-sy; // Row of the sprite we are on
\r
192 pal=Pico.highpal+((code>>9)&0x30); // Get palette pointer
\r
193 if (code&0x1000) row=(height<<3)-1-row; // Flip Y
\r
195 tile=code&0x7ff; // Tile number
\r
196 tile+=row>>3; // Tile number increases going down
\r
197 delta=height; // Delta to increase tile by going right
\r
198 if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X
\r
200 tile<<=4; tile+=(row&7)<<1; // Tile address
\r
201 delta<<=4; // Delta of address
\r
203 sx=(sprite[3]&0x1ff)-0x78; // Get X coordinate + 8
\r
205 for (i=0; i<width; i++,sx+=8,tile+=delta)
\r
207 if (sx<=0 || sx>=328) continue; // Offscreen
\r
209 tile&=0x7fff; // Clip tile address
\r
210 if (code&0x0800) TileFlip(HighCol+24+sx,tile,pal);
\r
211 else TileNorm(HighCol+24+sx,tile,pal);
\r
217 static int DrawAllSprites(int high)
\r
219 struct PicoVideo *pvid=&Pico.video;
\r
222 unsigned char spin[80]; // Sprite index
\r
226 table=pvid->reg[5]&0x7f;
\r
227 if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
\r
228 table<<=8; // Get sprite table address/2
\r
232 unsigned short *sprite=NULL;
\r
234 spin[i]=(unsigned char)link;
\r
235 sprite=Pico.vram+((table+(link<<2))&0x7ffc); // Find sprite
\r
237 // Find next sprite
\r
238 link=sprite[1]&0x7f;
\r
239 if (link==0 || i>=79) break; // End of sprites
\r
243 // Go through sprites backwards:
\r
246 unsigned short *sprite=NULL;
\r
249 sprite=Pico.vram+((table+(spin[i]<<2))&0x7ffc); // Find sprite
\r
251 sy=(sprite[0]&0x1ff)-0x80; // Get Y coordinate
\r
253 if (Scanline>=sy && Scanline<sy+32) DrawSprite(sy,sprite,high); // Possibly on this line
\r
259 static void BackFill()
\r
261 unsigned int back=0;
\r
262 unsigned int *pd=NULL,*end=NULL;
\r
264 // Start with a blank scanline (background colour):
\r
265 back=Pico.video.reg[7]&0x3f;
\r
266 back=Pico.highpal[back];
\r
269 pd= (unsigned int *)(HighCol+32);
\r
270 end=(unsigned int *)(HighCol+32+320);
\r
272 do { pd[0]=pd[1]=pd[2]=pd[3]=back; pd+=4; } while (pd<end);
\r
275 static int DrawDisplay()
\r
277 int win=0,edge=0,full=0;
\r
278 int bhigh=1,ahigh=1,shigh=1;
\r
280 // Find out if the window is on this line:
\r
281 win=Pico.video.reg[0x12];
\r
282 edge=(win&0x1f)<<3;
\r
284 if (win&0x80) { if (Scanline>=edge) full=1; }
\r
285 else { if (Scanline< edge) full=1; }
\r
287 if (PicoMask&0x04) { DrawLayer(1,0); bhigh=WrongPri; }
\r
288 if (PicoMask&0x08) { if (full) DrawWindow(0); else DrawLayer(0,0); ahigh=WrongPri; }
\r
289 if (PicoMask&0x10) { DrawAllSprites(0); shigh=WrongPri; }
\r
291 if (bhigh) if (PicoMask&0x20) DrawLayer(1,1);
\r
292 if (ahigh) if (PicoMask&0x40) { if (full) DrawWindow(1); else DrawLayer(0,1); }
\r
293 if (shigh) if (PicoMask&0x80) DrawAllSprites(1);
\r
297 static int UpdatePalette()
\r
302 for (c=0;c<64;c++) Pico.highpal[c]=(unsigned short)PicoCram(Pico.cram[c]);
\r
308 static int Overlay()
\r
312 if (PmovAction==0) return 0;
\r
313 if (Scanline>=4) return 0;
\r
315 if (PmovAction&1) col =0x00f;
\r
316 if (PmovAction&2) col|=0x0f0;
\r
319 for (x=0;x<4;x++) HighCol[32+x]=(unsigned short)col;
\r
327 int PicoLine(int scan)
\r
329 if (Skip>0) { Skip--; return 0; } // Skip rendering lines
\r
333 if (Pico.m.dirtyPal) UpdatePalette();
\r
336 if (PicoMask&0x02) BackFill();
\r
337 if (Pico.video.reg[1]&0x40) DrawDisplay();
\r
341 if (Pico.video.reg[12]&1)
\r
343 Skip=PicoScan(Scanline,HighCol+32); // 40-column mode
\r
347 // Crop, centre and return 32-column mode
\r
348 memset(HighCol, 0,64); // Left border
\r
349 memset(HighCol+288,0,64); // Right border
\r
350 Skip=PicoScan(Scanline,HighCol);
\r