1 #include "genesis_vid.h"
2 #include "burnint.h"
3 
4 INT32 GenesisScreenNumber;
5 UINT32 *GenesisPalette = NULL;
6 UINT16 *GenesisPaletteRaw = NULL;
7 UINT16 GenesisPaletteBase;
8 UINT8 VdpBgColour;
9 
10 UINT8 *VdpVRAM = NULL;
11 UINT8 *VdpVSRAM = NULL;
12 UINT16 *VdpTransLookup = NULL;
13 UINT8 GenesisVdpRegs[32];
14 UINT16 GenesisBgPalLookup[4];
15 UINT16 GenesisSpPalLookup[4];
16 UINT32 VdpScrollABase;
17 UINT32 VdpScrollBBase;
18 UINT32 VdpWindowBase;
19 UINT32 VdpSpriteBase;
20 
21 INT32 VdpHScrollMask;
22 UINT32 VdpHScrollSize;
23 UINT32 VdpHScrollBase;
24 UINT8 VdpVScrollMode;
25 
26 UINT8 VdpWindowWidth;
27 UINT8 VdpScrollWidth;
28 UINT8 VdpScrollHeight;
29 UINT8 VdpWindowRight;
30 UINT8 VdpWindowDown;
31 UINT32 VdpWindowHPos;
32 UINT32 VdpWindowVPos;
33 
34 UINT8 VdpCmdPart;
35 UINT8 VdpCode;
36 UINT32 VdpAddress;
37 
38 #define VRAM_SIZE			0x10000
39 #define VRAM_MASK			(VRAM_SIZE - 1)
40 #define VSRAM_SIZE			0x80
41 #define VSRAM_MASK			(VSRAM_SIZE - 1)
42 #define CRAM_SIZE			0x40
43 
44 #define VDP_VRAM_BYTE(x)	(VdpVRAM[(x) & VRAM_MASK])
45 #define VDP_VSRAM_BYTE(x)	(VdpVSRAM[(x) & VSRAM_MASK])
46 #define VDP_VRAM_WORD(x)	((VDP_VRAM_BYTE(x) << 8) | VDP_VRAM_BYTE((x) + 1))
47 #define VDP_VSRAM_WORD(x)	((VDP_VSRAM_BYTE(x) << 8) | VDP_VSRAM_BYTE((x) + 1))
48 
49 #define EXTRACT_PIXEL(x,i)	(((x) >> (((i) ^ 1) * 4)) & 0x0f)
50 
VdpRegisterWrite(INT32 d,INT32)51 static void VdpRegisterWrite(INT32 d, INT32 /*vBlank*/)
52 {
53 	UINT8 RegNum = (d & 0x1f00) >> 8;
54 	UINT8 RegDat = d & 0x00ff;
55 
56 	GenesisVdpRegs[RegNum] = RegDat;
57 
58 	switch (RegNum) {
59 		case 0x01: {
60 			// Video Modes
61 			return;
62 		}
63 
64 		case 0x02: {
65 			// Scroll A Name Table Base
66 			VdpScrollABase = (RegDat & 0x38) << 10;
67 			return;
68 		}
69 
70 		case 0x03: {
71 			// Window Name Table Base
72 			VdpWindowBase = (RegDat & 0x3e) << 10;
73 			return;
74 		}
75 
76 		case 0x04: {
77 			// Scroll B Name Table Base
78 			VdpScrollBBase = (RegDat & 0x07) << 13;
79 			return;
80 		}
81 
82 		case 0x05: {
83 			// Sprite Table Base
84 			VdpSpriteBase = (RegDat & 0x7e) << 9;
85 			return;
86 		}
87 
88 		case 0x07: {
89 			// BG Colour
90 			VdpBgColour = RegDat & 0x3f;
91 			return;
92 		}
93 
94 		case 0x0b: {
95 			// Scroll Modes
96 			static const UINT16 MaskTable[4] = { 0x000, 0x007, 0xff8, 0xfff };
97 			VdpVScrollMode = (RegDat & 0x04) >> 2;
98 			VdpHScrollMask = MaskTable[RegDat & 3];
99 			VdpHScrollSize = 4 * ((VdpHScrollMask < 224) ? (VdpHScrollMask + 1) : 224);
100 			return;
101 		}
102 
103 		case 0x0c: {
104 			// Video Modes
105 			switch (RegDat & 0x81) {
106 				case 0x00: {
107 					// 32 cell
108 					VdpWindowWidth = 32;
109 					return;
110 				}
111 
112 				case 0x01: {
113 					// 40 cell corrupted
114 					VdpWindowWidth = 64;
115 					return;
116 				}
117 
118 				case 0x80: {
119 					// illegal
120 					VdpWindowWidth = 64;
121 					return;
122 				}
123 
124 				case 0x81: {
125 					// 40 cell
126 					VdpWindowWidth = 64;
127 					return;
128 				}
129 			}
130 			return;
131 		}
132 
133 		case 0x0d: {
134 			// H Scroll Base
135 			VdpHScrollBase = (RegDat & 0x3f) << 10;
136 			return;
137 		}
138 
139 		case 0x10: {
140 			// Scroll Size
141 			static const UINT8 SizeTable[4] = { 32, 64, 128, 128 };
142 			VdpScrollWidth = SizeTable[RegDat & 0x03];
143 			VdpScrollHeight = SizeTable[(RegDat & 0x30) >> 4];
144 			return;
145 		}
146 
147 		case 0x11: {
148 			// Window H Pos
149 			VdpWindowRight = RegDat & 0x80;
150 			VdpWindowHPos = (RegDat & 0x1f) << 4;
151 			return;
152 		}
153 
154 		case 012: {
155 			// Window V Pos
156 			VdpWindowDown = RegDat & 0x80;
157 			VdpWindowVPos = (RegDat & 0x1f) << 3;
158 			return;
159 		}
160 	}
161 }
162 
VDPDataRead()163 static UINT16 VDPDataRead()
164 {
165 	INT32 read = 0;
166 
167 	VdpCmdPart = 0;
168 
169 	switch (VdpCode & 0xf) {
170 		case 0x00: {
171 			read = VDP_VRAM_WORD(VdpAddress & ~1);
172 			break;
173 		}
174 
175 		case 0x04: {
176 			read = VDP_VSRAM_WORD(VdpAddress & ~1);
177 			break;
178 		}
179 
180 //		default: {
181 //			bprintf(PRINT_NORMAL, _T("Genesis VDP Data Read %x\n"), VdpCode);
182 //		}
183 	}
184 
185 	VdpAddress += GenesisVdpRegs[15];
186 	return read;
187 }
188 
VDPControlRead()189 static UINT16 VDPControlRead()
190 {
191 	INT32 status = 0x3600;
192 
193 	VdpCmdPart = 0;
194 
195 	// If Vblank status |= 0x8
196 	// if Hblank status |= 0x4
197 
198 	return status;
199 }
200 
GenesisVDPRead(UINT32 offset)201 UINT16 GenesisVDPRead(UINT32 offset)
202 {
203 	switch(offset) {
204 		case 0x00:
205 		case 0x01: {
206 			return VDPDataRead();
207 		}
208 
209 		case 0x02:
210 		case 0x03: {
211 			return VDPControlRead();
212 		}
213 	}
214 
215 //	bprintf(PRINT_NORMAL, _T("Genesis VDP Read %x\n"), offset);
216 
217 	return 0;
218 }
219 
VDPControlWrite(UINT16 data)220 static void VDPControlWrite(UINT16 data)
221 {
222 	if (!VdpCmdPart) {
223 		if ((data & 0xc000) == 0x8000) {
224 			VdpRegisterWrite(data, 0);
225 		} else {
226 			VdpCode = (VdpCode & 0x3c) | ((data >> 14) & 0x03);
227 			VdpAddress = (VdpAddress & 0xc000) | (data & 0x3fff);
228 			VdpCmdPart = 1;
229 		}
230 	} else {
231 		VdpCode = (VdpCode & 0x03) | ((data >> 2) & 0x3c);
232 		VdpAddress = (VdpAddress & 0x3fff) | ((data << 14) & 0xc000);
233 		VdpCmdPart = 0;
234 		// DMA Stuff here
235 	}
236 }
237 
pal3bit(UINT8 bits)238 inline static UINT8 pal3bit(UINT8 bits)
239 {
240 	bits &= 7;
241 	return (bits << 5) | (bits << 2) | (bits >> 1);
242 }
243 
GenesisPaletteRecalc()244 void GenesisPaletteRecalc()
245 {
246 	for (INT32 i = 0; i < CRAM_SIZE; i++) {
247 		UINT16 data = GenesisPaletteRaw[i];
248 
249 		GenesisPalette[i + GenesisPaletteBase] = BurnHighCol(pal3bit(data >> 1), pal3bit(data >> 5), pal3bit(data >> 9), 0);
250 	}
251 }
252 
VDPDataWrite(UINT16 data)253 static void VDPDataWrite(UINT16 data)
254 {
255 	VdpCmdPart = 0;
256 
257 	// DMA Stuff here
258 
259 	switch (VdpCode & 0xf) {
260 		case 0x01: {
261 			if (VdpAddress & 1) data = ((data & 0xff) << 8) | ((data >> 8) & 0xff);
262 			VDP_VRAM_BYTE(VdpAddress & ~1) = data >> 8;
263 			VDP_VRAM_BYTE(VdpAddress | 1 ) = data;
264 			break;
265 		}
266 
267 		case 0x03: {
268 			INT32 offset = (VdpAddress >> 1) % CRAM_SIZE;
269 			//palette_set_color(Machine, offset + genesis_palette_base, pal3bit(data >> 1), pal3bit(data >> 5), pal3bit(data >> 9));
270 			//System16Palette[offset + 0x1800 /*GenesisPaletteBase*/] = BurnHighCol(pal3bit(data >> 1), pal3bit(data >> 5), pal3bit(data >> 9), 0);
271 			GenesisPalette[offset + GenesisPaletteBase] = BurnHighCol(pal3bit(data >> 1), pal3bit(data >> 5), pal3bit(data >> 9), 0);
272 			GenesisPaletteRaw[offset] = data;
273 			break;
274 		}
275 
276 		case 0x05: {
277 			if (VdpAddress & 1) data = ((data & 0xff) << 8) | ((data >> 8) & 0xff);
278 			VDP_VSRAM_BYTE(VdpAddress & ~1) = data >> 8;
279 			VDP_VSRAM_BYTE(VdpAddress |  1) = data;
280 			break;
281 		}
282 
283 //		default: {
284 //			bprintf(PRINT_NORMAL, _T("Genesis VDP Data Write %x\n"), VdpCode);
285 //		}
286 	}
287 
288 	VdpAddress += GenesisVdpRegs[15];
289 }
290 
GenesisVDPWrite(UINT32 offset,UINT16 data)291 void GenesisVDPWrite(UINT32 offset, UINT16 data)
292 {
293 	switch (offset) {
294 		case 0x00:
295 		case 0x01: {
296 			VDPDataWrite(data);
297 			return;
298 		}
299 
300 		case 0x02:
301 		case 0x03: {
302 			VDPControlWrite(data);
303 			return;
304 		}
305 	}
306 
307 //	bprintf(PRINT_NORMAL, _T("Genesis VDP Write %x\n"), data);
308 }
309 
StartGenesisVDP(INT32 ScreenNum,UINT32 * pal)310 INT32 StartGenesisVDP(INT32 ScreenNum, UINT32* pal)
311 {
312 	INT32 i;
313 
314 	GenesisScreenNumber = ScreenNum;
315 
316 	GenesisPalette = pal;
317 
318 	VdpVRAM = (UINT8*)BurnMalloc(VRAM_SIZE);
319 	VdpVSRAM = (UINT8*)BurnMalloc(VSRAM_SIZE);
320 	VdpTransLookup = (UINT16*)BurnMalloc(0x1000 * sizeof(UINT16));
321 	GenesisPaletteRaw = (UINT16*)BurnMalloc(CRAM_SIZE * sizeof(UINT16));
322 
323 	// Init the transparency lookup table
324 	for (i = 0; i < 0x1000; i++) {
325 		INT32 OriginalColour = i & 0x7ff;
326 		INT32 HalfBright = i & 0x800;
327 
328 		if (OriginalColour & 0x100)
329 			VdpTransLookup[i] = OriginalColour;
330 		else if (HalfBright)
331 			VdpTransLookup[i] = OriginalColour | 0x800;
332 		else
333 			VdpTransLookup[i] = OriginalColour | 0x1000;
334 	}
335 
336 	// Reset Palettes
337 	GenesisPaletteBase = 0;
338 	GenesisBgPalLookup[0] = GenesisSpPalLookup[0] = 0x00;
339 	GenesisBgPalLookup[1] = GenesisSpPalLookup[1] = 0x10;
340 	GenesisBgPalLookup[2] = GenesisSpPalLookup[2] = 0x20;
341 	GenesisBgPalLookup[3] = GenesisSpPalLookup[3] = 0x30;
342 
343 	// Reset VDP
344 	GenesisVDPReset();
345 
346 	return 0;
347 }
348 
GenesisVDPReset()349 void GenesisVDPReset()
350 {
351 	static const UINT8 VdpInit[24] =
352 	{
353 		0x04, 0x44, 0x30, 0x3C, 0x07, 0x6C, 0x00, 0x00,
354 		0x00, 0x00, 0xFF, 0x00, 0x01, 0x37, 0x00, 0x02,
355 		0x01, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x80,
356 	};
357 
358 	memset(VdpVRAM, 0, VRAM_SIZE);
359 	memset(VdpVSRAM, 0, VSRAM_SIZE);
360 	memset(GenesisPaletteRaw, 0, CRAM_SIZE * sizeof(UINT16));
361 
362 	// Reset VDP
363 	for (INT32 i = 0; i < 24; i++) {
364 		VdpRegisterWrite(0x8000 | (i << 8) | VdpInit[i], 1);
365 	}
366 
367 	VdpCmdPart = 0;
368 	VdpCode = 0;
369 	VdpAddress = 0;
370 }
371 
GenesisVDPExit()372 void GenesisVDPExit()
373 {
374 	BurnFree(VdpVRAM);
375 	BurnFree(VdpVSRAM);
376 	BurnFree(VdpTransLookup);
377 	BurnFree(GenesisPaletteRaw);
378 
379 	memset(GenesisVdpRegs, 0, sizeof(GenesisVdpRegs));
380 	memset(GenesisBgPalLookup, 0, sizeof(GenesisBgPalLookup));
381 	memset(GenesisSpPalLookup, 0, sizeof(GenesisSpPalLookup));
382 
383 	GenesisPalette = NULL;
384 
385 	GenesisScreenNumber = 0;
386 	GenesisPaletteBase = 0;
387 	VdpBgColour = 0;
388 	VdpScrollABase = 0;
389 	VdpScrollBBase = 0;
390 	VdpWindowBase = 0;
391 	VdpSpriteBase = 0;
392 	VdpHScrollMask = 0;
393 	VdpHScrollSize = 0;
394 	VdpHScrollBase = 0;
395 	VdpVScrollMode = 0;
396 	VdpWindowWidth = 0;
397 	VdpScrollWidth = 0;
398 	VdpScrollHeight = 0;
399 	VdpWindowRight = 0;
400 	VdpWindowDown = 0;
401 	VdpWindowHPos = 0;
402 	VdpWindowVPos = 0;
403 	VdpCmdPart = 0;
404 	VdpCode = 0;
405 	VdpAddress = 0;
406 }
407 
GenesisVDPScan()408 void GenesisVDPScan()
409 {
410 	ScanVar(VdpVRAM, VRAM_SIZE, "GenVDP VRAM");
411 	ScanVar(VdpVSRAM, VSRAM_SIZE, "GenVDP VSRAM");
412 	ScanVar(GenesisPaletteRaw, CRAM_SIZE * sizeof(UINT16), "GenVDPPalette");
413 
414 	SCAN_VAR(GenesisVdpRegs);
415 
416 	SCAN_VAR(VdpBgColour);
417 	SCAN_VAR(VdpScrollABase);
418 	SCAN_VAR(VdpScrollBBase);
419 	SCAN_VAR(VdpWindowBase);
420 	SCAN_VAR(VdpSpriteBase);
421 	SCAN_VAR(VdpHScrollMask);
422 	SCAN_VAR(VdpHScrollSize);
423 	SCAN_VAR(VdpHScrollBase);
424 	SCAN_VAR(VdpVScrollMode);
425 	SCAN_VAR(VdpWindowWidth);
426 	SCAN_VAR(VdpScrollWidth);
427 	SCAN_VAR(VdpScrollHeight);
428 	SCAN_VAR(VdpWindowRight);
429 	SCAN_VAR(VdpWindowDown);
430 	SCAN_VAR(VdpWindowHPos);
431 	SCAN_VAR(VdpWindowVPos);
432 	SCAN_VAR(VdpCmdPart);
433 	SCAN_VAR(VdpCode);
434 	SCAN_VAR(VdpAddress);
435 }
436 
vdp_gethscroll(INT32 plane,INT32 line)437 inline INT32 vdp_gethscroll(INT32 plane, INT32 line)
438 {
439 	line &= VdpHScrollMask;
440 	return 0x400 - (VDP_VRAM_WORD(VdpHScrollBase + (4 * line) + plane) & 0x3ff);
441 }
442 
443 
444 /* Note: We expect plane = 0 for Scroll A, plane = 2 for Scroll B
445    A Column is 8 Pixels Wide                                     */
vdp_getvscroll(INT32 plane,INT32 column)446 static INT32 vdp_getvscroll(INT32 plane, INT32 column)
447 {
448 	UINT32 vsramoffset;
449 
450 	switch (VdpVScrollMode)
451 	{
452 		case 0x00: /* Overall Scroll */
453 			return VDP_VSRAM_WORD(plane) & 0x7ff;
454 
455 		case 0x01: /* Column Scroll */
456 			if (column == 40) column = 39; /* Fix Minor Innacuracy Only affects PotoPoto */
457 			vsramoffset = (4 * (column >> 1)) + plane;
458 			return VDP_VSRAM_WORD(vsramoffset) & 0x7ff;
459 	}
460 	return 0;
461 }
462 
get_scroll_tiles(UINT32 line,INT32 scrollnum,UINT32 scrollbase,UINT32 * tiles,INT32 * offset)463 static void get_scroll_tiles(UINT32 line, INT32 scrollnum, UINT32 scrollbase, UINT32 *tiles, INT32 *offset)
464 {
465 	INT32 linehscroll = vdp_gethscroll(scrollnum, line);
466 	INT32 column;
467 
468 	/* adjust for partial tiles and then pre-divide hscroll to get the tile offset */
469 	*offset = -(linehscroll % 8);
470 	linehscroll /= 8;
471 
472 	/* loop over columns */
473 	for (column = 0; column < 41; column++)
474 	{
475 		INT32 columnvscroll = vdp_getvscroll(scrollnum, (column - (linehscroll & 1)) & 0x3f) + line;
476 
477 		/* determine the base of the tilemap row */
478 		INT32 temp = ((columnvscroll / 8) & (VdpScrollHeight - 1)) * VdpScrollWidth;
479 		INT32 tilebase = scrollbase + 2 * temp;
480 
481 		/* offset into the tilemap based on the column */
482 		temp = (linehscroll + column) & (VdpScrollWidth - 1);
483 		tilebase += 2 * temp;
484 
485 		/* get the tile info */
486 		*tiles++ = ((columnvscroll % 8) << 16) | VDP_VRAM_WORD(tilebase);
487 	}
488 }
489 
get_window_tiles(UINT32 line,UINT32 scrollbase,UINT32 * tiles)490 static void get_window_tiles(UINT32 line, UINT32 scrollbase, UINT32 *tiles)
491 {
492 	INT32 column;
493 
494 	/* loop over columns */
495 	for (column = 0; column < 40; column++)
496 	{
497 		/* determine the base of the tilemap row */
498 		INT32 temp = (line / 8) * VdpWindowWidth + column;
499 		INT32 tilebase = scrollbase + 2 * temp;
500 
501 		/* get the tile info */
502 		*tiles++ = ((line % 8) << 16) | VDP_VRAM_WORD(tilebase);
503 	}
504 }
505 
drawline_tiles(UINT32 * tiles,UINT16 * bmap,UINT32 pri,INT32 offset,INT32 lclip,INT32 rclip)506 static void drawline_tiles(UINT32 *tiles, UINT16 *bmap, UINT32 pri, INT32 offset, INT32 lclip, INT32 rclip)
507 {
508 	/* adjust for the 8-pixel slop */
509 	bmap += offset;
510 	if (lclip > rclip)
511 		return;
512 
513 	/* loop over columns */
514 	for ( ; offset < 320; offset += 8, bmap += 8)
515 	{
516 		UINT32 tile = *tiles++;
517 
518 		/* if the tile is the correct priority, draw it */
519 		if (((tile >> 15) & 1) == pri && offset < 320)
520 		{
521 			INT32 colbase = GenesisBgPalLookup[(tile & 0x6000) >> 13];
522 			UINT32 *tp = (UINT32 *)&VDP_VRAM_BYTE((tile & 0x7ff) * 32);
523 			UINT32 mytile;
524 			INT32 col;
525 
526 			/* vertical flipping */
527 			if (!(tile & 0x1000))
528 				mytile = BURN_ENDIAN_SWAP_INT32(tp[tile >> 16]);
529 			else
530 				mytile = BURN_ENDIAN_SWAP_INT32(tp[(tile >> 16) ^ 7]);
531 
532 			/* skip if all-transparent */
533 			if (!mytile)
534 				continue;
535 
536 			/* non-clipped */
537 			if (offset >= lclip && offset <= rclip - 7)
538 			{
539 				/* non-flipped */
540 				if (!(tile & 0x0800))
541 				{
542 					col = EXTRACT_PIXEL(mytile, 0); if (col) bmap[0] = colbase + col;
543 					col = EXTRACT_PIXEL(mytile, 1); if (col) bmap[1] = colbase + col;
544 					col = EXTRACT_PIXEL(mytile, 2); if (col) bmap[2] = colbase + col;
545 					col = EXTRACT_PIXEL(mytile, 3); if (col) bmap[3] = colbase + col;
546 					col = EXTRACT_PIXEL(mytile, 4); if (col) bmap[4] = colbase + col;
547 					col = EXTRACT_PIXEL(mytile, 5); if (col) bmap[5] = colbase + col;
548 					col = EXTRACT_PIXEL(mytile, 6); if (col) bmap[6] = colbase + col;
549 					col = EXTRACT_PIXEL(mytile, 7); if (col) bmap[7] = colbase + col;
550 				}
551 
552 				/* horizontal flip */
553 				else
554 				{
555 					col = EXTRACT_PIXEL(mytile, 7); if (col) bmap[0] = colbase + col;
556 					col = EXTRACT_PIXEL(mytile, 6); if (col) bmap[1] = colbase + col;
557 					col = EXTRACT_PIXEL(mytile, 5); if (col) bmap[2] = colbase + col;
558 					col = EXTRACT_PIXEL(mytile, 4); if (col) bmap[3] = colbase + col;
559 					col = EXTRACT_PIXEL(mytile, 3); if (col) bmap[4] = colbase + col;
560 					col = EXTRACT_PIXEL(mytile, 2); if (col) bmap[5] = colbase + col;
561 					col = EXTRACT_PIXEL(mytile, 1); if (col) bmap[6] = colbase + col;
562 					col = EXTRACT_PIXEL(mytile, 0); if (col) bmap[7] = colbase + col;
563 				}
564 			}
565 
566 			/* clipped */
567 			else if (offset >= lclip - 8 && offset <= rclip)
568 			{
569 				/* non-flipped */
570 				if (!(tile & 0x0800))
571 				{
572 					col = EXTRACT_PIXEL(mytile, 0); if (col && (offset + 0) >= lclip && (offset + 0) <= rclip) bmap[0] = colbase + col;
573 					col = EXTRACT_PIXEL(mytile, 1); if (col && (offset + 1) >= lclip && (offset + 1) <= rclip) bmap[1] = colbase + col;
574 					col = EXTRACT_PIXEL(mytile, 2); if (col && (offset + 2) >= lclip && (offset + 2) <= rclip) bmap[2] = colbase + col;
575 					col = EXTRACT_PIXEL(mytile, 3); if (col && (offset + 3) >= lclip && (offset + 3) <= rclip) bmap[3] = colbase + col;
576 					col = EXTRACT_PIXEL(mytile, 4); if (col && (offset + 4) >= lclip && (offset + 4) <= rclip) bmap[4] = colbase + col;
577 					col = EXTRACT_PIXEL(mytile, 5); if (col && (offset + 5) >= lclip && (offset + 5) <= rclip) bmap[5] = colbase + col;
578 					col = EXTRACT_PIXEL(mytile, 6); if (col && (offset + 6) >= lclip && (offset + 6) <= rclip) bmap[6] = colbase + col;
579 					col = EXTRACT_PIXEL(mytile, 7); if (col && (offset + 7) >= lclip && (offset + 7) <= rclip) bmap[7] = colbase + col;
580 				}
581 
582 				/* horizontal flip */
583 				else
584 				{
585 					col = EXTRACT_PIXEL(mytile, 7); if (col && (offset + 0) >= lclip && (offset + 0) <= rclip) bmap[0] = colbase + col;
586 					col = EXTRACT_PIXEL(mytile, 6); if (col && (offset + 1) >= lclip && (offset + 1) <= rclip) bmap[1] = colbase + col;
587 					col = EXTRACT_PIXEL(mytile, 5); if (col && (offset + 2) >= lclip && (offset + 2) <= rclip) bmap[2] = colbase + col;
588 					col = EXTRACT_PIXEL(mytile, 4); if (col && (offset + 3) >= lclip && (offset + 3) <= rclip) bmap[3] = colbase + col;
589 					col = EXTRACT_PIXEL(mytile, 3); if (col && (offset + 4) >= lclip && (offset + 4) <= rclip) bmap[4] = colbase + col;
590 					col = EXTRACT_PIXEL(mytile, 2); if (col && (offset + 5) >= lclip && (offset + 5) <= rclip) bmap[5] = colbase + col;
591 					col = EXTRACT_PIXEL(mytile, 1); if (col && (offset + 6) >= lclip && (offset + 6) <= rclip) bmap[6] = colbase + col;
592 					col = EXTRACT_PIXEL(mytile, 0); if (col && (offset + 7) >= lclip && (offset + 7) <= rclip) bmap[7] = colbase + col;
593 				}
594 			}
595 		}
596 	}
597 }
598 
draw8pixs(UINT16 * bmap,INT32 patno,INT32,INT32 colbase,INT32 patline)599 static void draw8pixs(UINT16 *bmap, INT32 patno, INT32 /*priority*/, INT32 colbase, INT32 patline)
600 {
601 	UINT32 tile = BURN_ENDIAN_SWAP_INT32(*(UINT32 *)&VDP_VRAM_BYTE(patno * 32 + 4 * patline));
602 	INT32 col;
603 
604 	/* skip if all-transparent */
605 	if (!tile)
606 		return;
607 
608 	/* non-transparent */
609 	if ((colbase & 0x30) != 0x30 || !(GenesisVdpRegs[12] & 0x08))
610 	{
611 		col = EXTRACT_PIXEL(tile, 0); if (col) bmap[0] = colbase + col;
612 		col = EXTRACT_PIXEL(tile, 1); if (col) bmap[1] = colbase + col;
613 		col = EXTRACT_PIXEL(tile, 2); if (col) bmap[2] = colbase + col;
614 		col = EXTRACT_PIXEL(tile, 3); if (col) bmap[3] = colbase + col;
615 		col = EXTRACT_PIXEL(tile, 4); if (col) bmap[4] = colbase + col;
616 		col = EXTRACT_PIXEL(tile, 5); if (col) bmap[5] = colbase + col;
617 		col = EXTRACT_PIXEL(tile, 6); if (col) bmap[6] = colbase + col;
618 		col = EXTRACT_PIXEL(tile, 7); if (col) bmap[7] = colbase + col;
619 	}
620 
621 	/* transparent */
622 	else
623 	{
624 		col = EXTRACT_PIXEL(tile, 0);
625 		if (col)
626 		{
627 			if (col < 0x0e) bmap[0] = colbase + col;
628 			else bmap[0] = VdpTransLookup[((col & 1) << 11) | (bmap[0] & 0x7ff)];
629 		}
630 		col = EXTRACT_PIXEL(tile, 1);
631 		if (col)
632 		{
633 			if (col < 0x0e) bmap[1] = colbase + col;
634 			else bmap[1] = VdpTransLookup[((col & 1) << 11) | (bmap[1] & 0x7ff)];
635 		}
636 		col = EXTRACT_PIXEL(tile, 2);
637 		if (col)
638 		{
639 			if (col < 0x0e) bmap[2] = colbase + col;
640 			else bmap[2] = VdpTransLookup[((col & 1) << 11) | (bmap[2] & 0x7ff)];
641 		}
642 		col = EXTRACT_PIXEL(tile, 3);
643 		if (col)
644 		{
645 			if (col < 0x0e) bmap[3] = colbase + col;
646 			else bmap[3] = VdpTransLookup[((col & 1) << 11) | (bmap[3] & 0x7ff)];
647 		}
648 		col = EXTRACT_PIXEL(tile, 4);
649 		if (col)
650 		{
651 			if (col < 0x0e) bmap[4] = colbase + col;
652 			else bmap[4] = VdpTransLookup[((col & 1) << 11) | (bmap[4] & 0x7ff)];
653 		}
654 		col = EXTRACT_PIXEL(tile, 5);
655 		if (col)
656 		{
657 			if (col < 0x0e) bmap[5] = colbase + col;
658 			else bmap[5] = VdpTransLookup[((col & 1) << 11) | (bmap[5] & 0x7ff)];
659 		}
660 		col = EXTRACT_PIXEL(tile, 6);
661 		if (col)
662 		{
663 			if (col < 0x0e) bmap[6] = colbase + col;
664 			else bmap[6] = VdpTransLookup[((col & 1) << 11) | (bmap[6] & 0x7ff)];
665 		}
666 		col = EXTRACT_PIXEL(tile, 7);
667 		if (col)
668 		{
669 			if (col < 0x0e) bmap[7] = colbase + col;
670 			else bmap[7] = VdpTransLookup[((col & 1) << 11) | (bmap[7] & 0x7ff)];
671 		}
672 	}
673 }
674 
675 
676 /* draw a horizontally-flipped section of a sprite */
draw8pixs_hflip(UINT16 * bmap,INT32 patno,INT32,INT32 colbase,INT32 patline)677 static void draw8pixs_hflip(UINT16 *bmap, INT32 patno, INT32 /*priority*/, INT32 colbase, INT32 patline)
678 {
679 	UINT32 tile = BURN_ENDIAN_SWAP_INT32(*(UINT32 *)&VDP_VRAM_BYTE(patno * 32 + 4 * patline));
680 	INT32 col;
681 
682 	/* skip if all-transparent */
683 	if (!tile)
684 		return;
685 
686 	/* non-transparent */
687 	if ((colbase & 0x30) != 0x30 || !(GenesisVdpRegs[12] & 0x08))
688 	{
689 		col = EXTRACT_PIXEL(tile, 7); if (col) bmap[0] = colbase + col;
690 		col = EXTRACT_PIXEL(tile, 6); if (col) bmap[1] = colbase + col;
691 		col = EXTRACT_PIXEL(tile, 5); if (col) bmap[2] = colbase + col;
692 		col = EXTRACT_PIXEL(tile, 4); if (col) bmap[3] = colbase + col;
693 		col = EXTRACT_PIXEL(tile, 3); if (col) bmap[4] = colbase + col;
694 		col = EXTRACT_PIXEL(tile, 2); if (col) bmap[5] = colbase + col;
695 		col = EXTRACT_PIXEL(tile, 1); if (col) bmap[6] = colbase + col;
696 		col = EXTRACT_PIXEL(tile, 0); if (col) bmap[7] = colbase + col;
697 	}
698 
699 	/* transparent */
700 	else
701 	{
702 		col = EXTRACT_PIXEL(tile, 7);
703 		if (col)
704 		{
705 			if (col < 0x0e) bmap[0] = colbase + col;
706 			else bmap[0] = VdpTransLookup[((col & 1) << 11) | (bmap[0] & 0x7ff)];
707 		}
708 		col = EXTRACT_PIXEL(tile, 6);
709 		if (col)
710 		{
711 			if (col < 0x0e) bmap[1] = colbase + col;
712 			else bmap[1] = VdpTransLookup[((col & 1) << 11) | (bmap[1] & 0x7ff)];
713 		}
714 		col = EXTRACT_PIXEL(tile, 5);
715 		if (col)
716 		{
717 			if (col < 0x0e) bmap[2] = colbase + col;
718 			else bmap[2] = VdpTransLookup[((col & 1) << 11) | (bmap[2] & 0x7ff)];
719 		}
720 		col = EXTRACT_PIXEL(tile, 4);
721 		if (col)
722 		{
723 			if (col < 0x0e) bmap[3] = colbase + col;
724 			else bmap[3] = VdpTransLookup[((col & 1) << 11) | (bmap[3] & 0x7ff)];
725 		}
726 		col = EXTRACT_PIXEL(tile, 3);
727 		if (col)
728 		{
729 			if (col < 0x0e) bmap[4] = colbase + col;
730 			else bmap[4] = VdpTransLookup[((col & 1) << 11) | (bmap[4] & 0x7ff)];
731 		}
732 		col = EXTRACT_PIXEL(tile, 2);
733 		if (col)
734 		{
735 			if (col < 0x0e) bmap[5] = colbase + col;
736 			else bmap[5] = VdpTransLookup[((col & 1) << 11) | (bmap[5] & 0x7ff)];
737 		}
738 		col = EXTRACT_PIXEL(tile, 1);
739 		if (col)
740 		{
741 			if (col < 0x0e) bmap[6] = colbase + col;
742 			else bmap[6] = VdpTransLookup[((col & 1) << 11) | (bmap[6] & 0x7ff)];
743 		}
744 		col = EXTRACT_PIXEL(tile, 0);
745 		if (col)
746 		{
747 			if (col < 0x0e) bmap[7] = colbase + col;
748 			else bmap[7] = VdpTransLookup[((col & 1) << 11) | (bmap[7] & 0x7ff)];
749 		}
750 	}
751 }
752 
drawline_sprite(INT32 line,UINT16 * bmap,INT32 priority,UINT8 * spritebase)753 static void drawline_sprite(INT32 line, UINT16 *bmap, INT32 priority, UINT8 *spritebase)
754 {
755 	INT32 spriteypos   = (((spritebase[0] & 0x01) << 8) | spritebase[1]) - 0x80;
756 	INT32 spritexpos   = (((spritebase[6] & 0x01) << 8) | spritebase[7]) - 0x80;
757 	INT32 spriteheight = ((spritebase[2] & 0x03) + 1) * 8;
758 	INT32 spritewidth  = (((spritebase[2] & 0x0c) >> 2) + 1) * 8;
759 	INT32 spriteattr, patno, patflip, patline, colbase, x;
760 
761 	/* skip if out of range */
762 	if (line < spriteypos || line >= spriteypos + spriteheight)
763 		return;
764 	if (spritexpos + spritewidth < 0 || spritexpos >= 320)
765 		return;
766 
767 	/* extract the remaining data */
768 	spriteattr = (spritebase[4] << 8) | spritebase[5];
769 	patno      = spriteattr & 0x07FF;
770 	patflip    = (spriteattr & 0x1800) >> 11;
771 	patline    = line - spriteypos;
772 
773 	/* determine the color base */
774 	colbase = GenesisSpPalLookup[(spriteattr & 0x6000) >> 13];
775 
776 	/* adjust for the X position */
777 	spritewidth >>= 3;
778 	spriteheight >>= 3;
779 
780 	/* switch off the flip mode */
781 	bmap += spritexpos;
782 	switch (patflip)
783 	{
784 		case 0x00: /* No Flip */
785 			for (x = 0; x < spritewidth; x++, bmap += 8)
786 			{
787 				if (spritexpos >= -7 && spritexpos < 320)
788 					draw8pixs(bmap, patno, priority, colbase, patline);
789 				spritexpos += 8;
790 				patno += spriteheight;
791 			}
792 			break;
793 
794 		case 0x01: /* Horizontal Flip */
795 			patno += spriteheight * (spritewidth - 1);
796 			for (x = 0; x < spritewidth; x++, bmap += 8)
797 			{
798 				if (spritexpos >= -7 && spritexpos < 320)
799 					draw8pixs_hflip(bmap, patno, priority, colbase, patline);
800 				spritexpos += 8;
801 				patno -= spriteheight;
802 			}
803 			break;
804 
805 		case 0x02: /* Vertical Flip */
806 			patline = 8 * spriteheight - patline - 1;
807 			for (x = 0; x < spritewidth; x++, bmap += 8)
808 			{
809 				if (spritexpos >= -7 && spritexpos < 320)
810 					draw8pixs(bmap, patno, priority, colbase, patline);
811 				spritexpos += 8;
812 				patno += spriteheight;
813 			}
814 			break;
815 
816 		case 0x03: /* Both Flip */
817 			patno += spriteheight * (spritewidth - 1);
818 			patline = 8 * spriteheight - patline - 1;
819 			for (x = 0; x < spritewidth; x++, bmap += 8)
820 			{
821 				if (spritexpos >= -7 && spritexpos < 320)
822 					draw8pixs_hflip(bmap, patno, priority, colbase, patline);
823 				spritexpos += 8;
824 				patno -= spriteheight;
825 			}
826 			break;
827 	}
828 }
829 
vdp_drawline(UINT16 * bitmap,UINT32 line,INT32 bgfill)830 void vdp_drawline(UINT16 *bitmap, UINT32 line, INT32 bgfill)
831 {
832 	INT32 lowsprites, highsprites, link;
833 	UINT32 scrolla_tiles[41], scrollb_tiles[41], window_tiles[41];
834 	INT32 scrolla_offset, scrollb_offset;
835 	UINT8 *lowlist[81], *highlist[81];
836 	INT32 bgcolor = bgfill ? bgfill : GenesisBgPalLookup[0];
837 	INT32 window_lclip, window_rclip;
838 	INT32 scrolla_lclip, scrolla_rclip;
839 	INT32 column, sprite;
840 
841 	/* clear to the background color */
842 	for (column = 0; column < 320; column++)
843 		bitmap[column] = bgcolor;
844 
845 	/* if display is disabled, stop */
846 	if (!(GenesisVdpRegs[1] & 0x40)) {
847 		return;
848 	}
849 
850 	/* Sprites need to be Drawn in Reverse order .. may as well sort them here */
851 	link = lowsprites = highsprites = 0;
852 	for (sprite = 0; sprite < 80; sprite++)
853 	{
854 		UINT8 *spritebase = &VDP_VRAM_BYTE(VdpSpriteBase + 8 * link);
855 
856 		/* sort into high/low priorities */
857 		if (spritebase[4] & 0x0080)
858 			highlist[++highsprites] = spritebase;
859 		else
860 			lowlist[++lowsprites] = spritebase;
861 
862 		/* get the link; if 0, stop processing */
863 		link = spritebase[3] & 0x7F;
864 		if (!link)
865 			break;
866 	}
867 
868 	/* get tiles for the B scroll layer */
869 	get_scroll_tiles(line, 2, VdpScrollBBase, scrollb_tiles, &scrollb_offset);
870 
871 	/* get tiles for the A scroll layer */
872 	get_scroll_tiles(line, 0, VdpScrollABase, scrolla_tiles, &scrolla_offset);
873 
874 	/* get tiles for the window layer */
875 	get_window_tiles(line, VdpWindowBase, window_tiles);
876 
877 	/* compute the windowing for this line */
878 	if ((VdpWindowDown && line >= VdpWindowVPos) || (!VdpWindowDown && line < VdpWindowVPos))
879 		window_lclip = 0, window_rclip = 320 - 1;
880 	else if (VdpWindowRight)
881 		window_lclip = VdpWindowHPos, window_rclip = 320 - 1;
882 	else
883 		window_lclip = 0, window_rclip = VdpWindowHPos - 1;
884 
885 	/* compute the clipping of the scroll A layer */
886 	if (window_lclip == 0)
887 	{
888 		scrolla_lclip = window_rclip + 1;
889 		scrolla_rclip = 320 - 1;
890 	}
891 	else
892 	{
893 		scrolla_lclip = 0;
894 		scrolla_rclip = window_lclip - 1;
895 	}
896 
897 	/* Scroll B Low */
898 	drawline_tiles(scrollb_tiles, bitmap, 0, scrollb_offset, 0, 320 - 1);
899 
900 	/* Scroll A Low */
901 	drawline_tiles(scrolla_tiles, bitmap, 0, scrolla_offset, scrolla_lclip, scrolla_rclip);
902 
903 	/* Window Low */
904 	drawline_tiles(window_tiles, bitmap, 0, 0, window_lclip, window_rclip);
905 
906 	/* Sprites Low */
907 	for (sprite = lowsprites; sprite > 0; sprite--)
908 		drawline_sprite(line, bitmap, 0, lowlist[sprite]);
909 
910 	/* Scroll B High */
911 	drawline_tiles(scrollb_tiles, bitmap, 1, scrollb_offset, 0, 320 - 1);
912 
913 	/* Scroll A High */
914 	drawline_tiles(scrolla_tiles, bitmap, 1, scrolla_offset, scrolla_lclip, scrolla_rclip);
915 
916 	/* Window High */
917 	drawline_tiles(window_tiles, bitmap, 1, 0, window_lclip, window_rclip);
918 
919 	/* Sprites High */
920 	for (sprite = highsprites; sprite > 0; sprite--)
921 		drawline_sprite(line, bitmap, 1, highlist[sprite]);
922 }
923