1 /***************************************************************************
2 
3   vidhrdw/mcr3.c
4 
5 	Functions to emulate the video hardware of an mcr3-style machine.
6 
7 ***************************************************************************/
8 
9 #include "driver.h"
10 #include "artwork.h"
11 #include "machine/mcr.h"
12 #include "vidhrdw/generic.h"
13 
14 
15 #ifndef MIN
16 #define MIN(x,y) (x)<(y)?(x):(y)
17 #endif
18 
19 /* These are used to align Discs of Tron with the backdrop */
20 #define DOTRON_X_START 144
21 #define DOTRON_Y_START 40
22 #define DOTRON_HORIZON 138
23 
24 
25 
26 /*************************************
27  *
28  *	Global variables
29  *
30  *************************************/
31 
32 /* Spy Hunter hardware extras */
33 UINT8 spyhunt_sprite_color_mask;
34 INT16 spyhunt_scrollx, spyhunt_scrolly;
35 INT16 spyhunt_scroll_offset;
36 UINT8 spyhunt_draw_lamps;
37 UINT8 spyhunt_lamp[8];
38 
39 UINT8 *spyhunt_alpharam;
40 size_t spyhunt_alpharam_size;
41 
42 
43 
44 /*************************************
45  *
46  *	Local variables
47  *
48  *************************************/
49 
50 /* Spy Hunter-specific scrolling background */
51 static struct osd_bitmap *spyhunt_backbitmap;
52 
53 /* Discs of Tron artwork globals */
54 static UINT8 dotron_palettes[3][3*256];
55 static UINT8 light_status;
56 
57 static UINT8 last_cocktail_flip;
58 
59 
60 
61 /*************************************
62  *
63  *	Palette RAM writes
64  *
65  *************************************/
66 
WRITE_HANDLER(mcr3_paletteram_w)67 WRITE_HANDLER( mcr3_paletteram_w )
68 {
69 	int r, g, b;
70 
71 	paletteram[offset] = data;
72 	offset &= 0x7f;
73 
74 	/* high bit of red comes from low bit of address */
75 	r = ((offset & 1) << 2) + (data >> 6);
76 	g = (data >> 0) & 7;
77 	b = (data >> 3) & 7;
78 
79 	/* up to 8 bits */
80 	r = (r << 5) | (r << 2) | (r >> 1);
81 	g = (g << 5) | (g << 2) | (g >> 1);
82 	b = (b << 5) | (b << 2) | (b >> 1);
83 
84 	palette_change_color(offset / 2, r, g, b);
85 }
86 
87 
88 
89 /*************************************
90  *
91  *	Video RAM writes
92  *
93  *************************************/
94 
WRITE_HANDLER(mcr3_videoram_w)95 WRITE_HANDLER( mcr3_videoram_w )
96 {
97 	if (videoram[offset] != data)
98 	{
99 		dirtybuffer[offset & ~1] = 1;
100 		videoram[offset] = data;
101 	}
102 }
103 
104 
105 
106 /*************************************
107  *
108  *	Background update
109  *
110  *************************************/
111 
mcr3_update_background(struct osd_bitmap * bitmap,UINT8 color_xor)112 static void mcr3_update_background(struct osd_bitmap *bitmap, UINT8 color_xor)
113 {
114 	int offs;
115 
116 	/* for every character in the Video RAM, check if it has been modified */
117 	/* since last time and update it accordingly. */
118 	for (offs = videoram_size - 2; offs >= 0; offs -= 2)
119 	{
120 		if (dirtybuffer[offs])
121 		{
122 			int mx = (offs / 2) % 32;
123 			int my = (offs / 2) / 32;
124 			int attr = videoram[offs + 1];
125 			int color = ((attr & 0x30) >> 4) ^ color_xor;
126 			int code = videoram[offs] + 256 * (attr & 0x03);
127 
128 			if (!mcr_cocktail_flip)
129 				drawgfx(bitmap, Machine->gfx[0], code, color, attr & 0x04, attr & 0x08,
130 						16 * mx, 16 * my, &Machine->visible_area, TRANSPARENCY_NONE, 0);
131 			else
132 				drawgfx(bitmap, Machine->gfx[0], code, color, !(attr & 0x04), !(attr & 0x08),
133 						16 * (31 - mx), 16 * (29 - my), &Machine->visible_area, TRANSPARENCY_NONE, 0);
134 
135 			dirtybuffer[offs] = 0;
136 		}
137 	}
138 }
139 
140 
141 
142 /*************************************
143  *
144  *	Sprite update
145  *
146  *************************************/
147 
mcr3_update_sprites(struct osd_bitmap * bitmap,int color_mask,int code_xor,int dx,int dy)148 void mcr3_update_sprites(struct osd_bitmap *bitmap, int color_mask, int code_xor, int dx, int dy)
149 {
150 	int offs;
151 
152 	/* loop over sprite RAM */
153 	for (offs = 0; offs < spriteram_size; offs += 4)
154 	{
155 		int code, color, flipx, flipy, sx, sy, flags;
156 
157 		/* skip if zero */
158 		if (spriteram[offs] == 0)
159 			continue;
160 
161 		/* extract the bits of information */
162 		flags = spriteram[offs + 1];
163 		code = spriteram[offs + 2] + 256 * ((flags >> 3) & 0x01);
164 		color = ~flags & color_mask;
165 		flipx = flags & 0x10;
166 		flipy = flags & 0x20;
167 		sx = (spriteram[offs + 3] - 3) * 2;
168 		sy = (241 - spriteram[offs]) * 2;
169 
170 		code ^= code_xor;
171 
172 		sx += dx;
173 		sy += dy;
174 
175 		/* draw the sprite */
176 		if (!mcr_cocktail_flip)
177 			drawgfx(bitmap, Machine->gfx[1], code, color, flipx, flipy, sx, sy,
178 					&Machine->visible_area, TRANSPARENCY_PEN, 0);
179 		else
180 			drawgfx(bitmap, Machine->gfx[1], code, color, !flipx, !flipy, 480 - sx, 452 - sy,
181 					&Machine->visible_area, TRANSPARENCY_PEN, 0);
182 
183 		/* sprites use color 0 for background pen and 8 for the 'under tile' pen.
184 			The color 8 is used to cover over other sprites. */
185 		if (Machine->gfx[1]->pen_usage[code] & 0x0100)
186 		{
187 			struct rectangle clip;
188 
189 			clip.min_x = sx;
190 			clip.max_x = sx + 31;
191 			clip.min_y = sy;
192 			clip.max_y = sy + 31;
193 
194 			copybitmap(bitmap, tmpbitmap, 0, 0, 0, 0, &clip, TRANSPARENCY_THROUGH, Machine->pens[8 + color * 16]);
195 		}
196 	}
197 }
198 
199 
200 
201 /*************************************
202  *
203  *	Generic MCR3 redraw
204  *
205  *************************************/
206 
mcr3_vh_screenrefresh(struct osd_bitmap * bitmap,int full_refresh)207 void mcr3_vh_screenrefresh(struct osd_bitmap *bitmap, int full_refresh)
208 {
209 	/* mark everything dirty on a cocktail flip change */
210 	if (palette_recalc() || last_cocktail_flip != mcr_cocktail_flip)
211 		memset(dirtybuffer, 1, videoram_size);
212 	last_cocktail_flip = mcr_cocktail_flip;
213 
214 	/* redraw the background */
215 	mcr3_update_background(tmpbitmap, 0);
216 
217 	/* copy it to the destination */
218 	copybitmap(bitmap, tmpbitmap, 0, 0, 0, 0, &Machine->visible_area, TRANSPARENCY_NONE, 0);
219 
220 	/* draw the sprites */
221 	mcr3_update_sprites(bitmap, 0x03, 0, 0, 0);
222 }
223 
224 
225 
226 /*************************************
227  *
228  *	MCR monoboard-specific redraw
229  *
230  *************************************/
231 
mcrmono_vh_screenrefresh(struct osd_bitmap * bitmap,int full_refresh)232 void mcrmono_vh_screenrefresh(struct osd_bitmap *bitmap, int full_refresh)
233 {
234 	if (palette_recalc())
235 		memset(dirtybuffer, 1, videoram_size);
236 
237 	/* redraw the background */
238 	mcr3_update_background(tmpbitmap, 3);
239 
240 	/* copy it to the destination */
241 	copybitmap(bitmap, tmpbitmap, 0, 0, 0, 0, &Machine->visible_area, TRANSPARENCY_NONE, 0);
242 
243 	/* draw the sprites */
244 	mcr3_update_sprites(bitmap, 0x03, 0, 0, 0);
245 }
246 
247 
248 
249 /*************************************
250  *
251  *	Spy Hunter-specific color PROM decoder
252  *
253  *************************************/
254 
spyhunt_vh_convert_color_prom(unsigned char * palette,unsigned short * colortable,const unsigned char * color_prom)255 void spyhunt_vh_convert_color_prom(unsigned char *palette, unsigned short *colortable, const unsigned char *color_prom)
256 {
257 	/* add some colors for the alpha RAM */
258 	palette[(8*16)*3+0] = 0;
259 	palette[(8*16)*3+1] = 0;
260 	palette[(8*16)*3+2] = 0;
261 	palette[(8*16+1)*3+0] = 0;
262 	palette[(8*16+1)*3+1] = 255;
263 	palette[(8*16+1)*3+2] = 0;
264 	palette[(8*16+2)*3+0] = 0;
265 	palette[(8*16+2)*3+1] = 0;
266 	palette[(8*16+2)*3+2] = 255;
267 	palette[(8*16+3)*3+0] = 255;
268 	palette[(8*16+3)*3+1] = 255;
269 	palette[(8*16+3)*3+2] = 255;
270 
271 	/* put them into the color table */
272 	colortable[8*16+0] = 8*16;
273 	colortable[8*16+1] = 8*16+1;
274 	colortable[8*16+2] = 8*16+2;
275 	colortable[8*16+3] = 8*16+3;
276 }
277 
278 
279 
280 /*************************************
281  *
282  *	Spy Hunter-specific video startup
283  *
284  *************************************/
285 
spyhunt_vh_start(void)286 int spyhunt_vh_start(void)
287 {
288 	/* allocate our own dirty buffer */
289 	dirtybuffer = (unsigned char*)malloc(videoram_size);
290 	if (!dirtybuffer)
291 		return 1;
292 	memset(dirtybuffer, 1, videoram_size);
293 
294 	/* allocate a bitmap for the background */
295 	spyhunt_backbitmap = bitmap_alloc(64*64, 32*32);
296 	if (!spyhunt_backbitmap)
297 	{
298 		free(dirtybuffer);
299 		return 1;
300 	}
301 
302 	/* reset the scrolling */
303 	spyhunt_scrollx = spyhunt_scrolly = 0;
304 
305 	return 0;
306 }
307 
308 
309 
310 /*************************************
311  *
312  *	Spy Hunter-specific video shutdown
313  *
314  *************************************/
315 
spyhunt_vh_stop(void)316 void spyhunt_vh_stop(void)
317 {
318 	/* free the buffers */
319 	bitmap_free(spyhunt_backbitmap);
320 	free(dirtybuffer);
321 }
322 
323 
324 
325 /*************************************
326  *
327  *	Spy Hunter-specific redraw
328  *
329  *************************************/
330 
spyhunt_vh_screenrefresh(struct osd_bitmap * bitmap,int full_refresh)331 void spyhunt_vh_screenrefresh(struct osd_bitmap *bitmap, int full_refresh)
332 {
333 	static const struct rectangle clip = { 0, 30*16-1, 0, 30*16-1 };
334 	int offs, scrollx, scrolly;
335 
336 	if (palette_recalc())
337 		memset(dirtybuffer, 1, videoram_size);
338 
339 	/* for every character in the Video RAM, check if it has been modified */
340 	/* since last time and update it accordingly. */
341 	for (offs = videoram_size - 1; offs >= 0; offs--)
342 	{
343 		if (dirtybuffer[offs])
344 		{
345 			int code = videoram[offs];
346 			int vflip = code & 0x40;
347 			int mx = (offs >> 4) & 0x3f;
348 			int my = (offs & 0x0f) | ((offs >> 6) & 0x10);
349 
350 			code = (code & 0x3f) | ((code & 0x80) >> 1);
351 
352 			drawgfx(spyhunt_backbitmap, Machine->gfx[0], code, 0, 0, vflip,
353 					64 * mx, 32 * my, NULL, TRANSPARENCY_NONE, 0);
354 
355 			dirtybuffer[offs] = 0;
356 		}
357 	}
358 
359 	/* copy it to the destination */
360 	scrollx = -spyhunt_scrollx * 2 + spyhunt_scroll_offset;
361 	scrolly = -spyhunt_scrolly * 2;
362 	copyscrollbitmap(bitmap, spyhunt_backbitmap, 1, &scrollx, 1, &scrolly, &clip, TRANSPARENCY_NONE, 0);
363 
364 	/* draw the sprites */
365 	mcr3_update_sprites(bitmap, spyhunt_sprite_color_mask, 0x80, -12, 0);
366 
367 	/* render any characters on top */
368 	for (offs = spyhunt_alpharam_size - 1; offs >= 0; offs--)
369 	{
370 		int ch = spyhunt_alpharam[offs];
371 		if (ch)
372 		{
373 			int mx = offs / 32;
374 			int my = offs % 32;
375 
376 			drawgfx(bitmap, Machine->gfx[2], ch, 0, 0, 0,
377 					16 * mx - 16, 16 * my, &clip, TRANSPARENCY_PEN, 0);
378 		}
379 	}
380 
381 	/* lamp indicators */
382 	if (spyhunt_draw_lamps)
383 	{
384 		char buffer[32];
385 
386 		sprintf(buffer, "%s  %s  %s  %s  %s",
387 				spyhunt_lamp[0] ? "OIL" : "   ",
388 				spyhunt_lamp[1] ? "MISSILE" : "       ",
389 				spyhunt_lamp[2] ? "VAN" : "   ",
390 				spyhunt_lamp[3] ? "SMOKE" : "     ",
391 				spyhunt_lamp[4] ? "GUNS" : "    ");
392 		for (offs = 0; offs < 30; offs++)
393 			drawgfx(bitmap, Machine->gfx[2], buffer[offs], 0, 0, 0,
394 					30 * 16, (29 - offs) * 16, &Machine->visible_area, TRANSPARENCY_NONE, 0);
395 	}
396 }
397 
398 
399 
400 /*************************************
401  *
402  *	Discs of Tron-specific video startup
403  *
404  *************************************/
405 
dotron_vh_start(void)406 int dotron_vh_start(void)
407 {
408 	int i, x, y;
409 
410 	/* do generic initialization to start */
411 	if (generic_vh_start())
412 		return 1;
413 
414 	backdrop_load("dotron.png", 64, Machine->drv->total_colors-64);
415 
416 	/* if we got it, compute palettes */
417 	if (artwork_backdrop)
418 	{
419 		/* from the horizon upwards, use the second palette */
420 		for (y = 0; y < DOTRON_HORIZON; y++)
421 			for (x = 0; x < artwork_backdrop->artwork->width; x++)
422 			{
423 				int newpixel = read_pixel(artwork_backdrop->orig_artwork, x, y) + 95;
424 				plot_pixel(artwork_backdrop->orig_artwork, x, y, newpixel);
425 			}
426 
427 		backdrop_refresh(artwork_backdrop);
428 
429 		/* create palettes with different levels of brightness */
430 		memcpy(dotron_palettes[0], artwork_backdrop->orig_palette, 3 * artwork_backdrop->num_pens_used);
431 		for (i = 0; i < artwork_backdrop->num_pens_used; i++)
432 		{
433 			/* only boost red and blue */
434 			dotron_palettes[1][i * 3 + 0] = MIN(artwork_backdrop->orig_palette[i * 3] * 2, 255);
435 			dotron_palettes[1][i * 3 + 1] = artwork_backdrop->orig_palette[i * 3 + 1];
436 			dotron_palettes[1][i * 3 + 2] = MIN(artwork_backdrop->orig_palette[i * 3 + 2] * 2, 255);
437 			dotron_palettes[2][i * 3 + 0] = MIN(artwork_backdrop->orig_palette[i * 3] * 3, 255);
438 			dotron_palettes[2][i * 3 + 1] = artwork_backdrop->orig_palette[i * 3 + 1];
439 			dotron_palettes[2][i * 3 + 2] = MIN(artwork_backdrop->orig_palette[i * 3 + 2] * 3, 255);
440 		}
441 
442 		//logerror("Backdrop loaded.\n");
443 	}
444 
445 	return 0;
446 }
447 
448 
449 
450 /*************************************
451  *
452  *	Discs of Tron light management
453  *
454  *************************************/
455 
dotron_change_light(int light)456 void dotron_change_light(int light)
457 {
458 	light_status = light;
459 }
460 
461 
dotron_change_palette(int which)462 static void dotron_change_palette(int which)
463 {
464 	UINT8 *new_palette;
465 	int i, offset;
466 
467 	/* get the palette indices */
468 	offset = artwork_backdrop->start_pen + 95;
469 	new_palette = dotron_palettes[which];
470 
471 	/* update the palette entries */
472 	for (i = 0; i < artwork_backdrop->num_pens_used; i++)
473 		palette_change_color(i + offset, new_palette[i * 3], new_palette[i * 3 + 1], new_palette[i * 3 + 2]);
474 }
475 
476 
477 
478 /*************************************
479  *
480  *	Discs of Tron-specific redraw
481  *
482  *************************************/
483 
dotron_vh_screenrefresh(struct osd_bitmap * bitmap,int full_refresh)484 void dotron_vh_screenrefresh(struct osd_bitmap *bitmap, int full_refresh)
485 {
486 	struct rectangle sclip;
487 	int offs;
488 
489 	/* handle background lights */
490 	if (artwork_backdrop != NULL)
491 	{
492 		int light = light_status & 1;
493 		if ((light_status & 2) && (cpu_getcurrentframe() & 1)) light++;	/* strobe */
494 		dotron_change_palette(light);
495 		/* This is necessary because Discs of Tron modifies the palette */
496 		if (backdrop_black_recalc())
497 			memset(dirtybuffer, 1, videoram_size);
498 
499 	}
500 
501 	if (full_refresh || palette_recalc())
502 	{
503 		if (artwork_backdrop)
504 		{
505 			backdrop_refresh(artwork_backdrop);
506 			copybitmap(tmpbitmap, artwork_backdrop->artwork, 0, 0, 0, 0, &Machine->visible_area, TRANSPARENCY_NONE, 0);
507 			copybitmap(bitmap, artwork_backdrop->artwork, 0, 0, 0, 0, &Machine->visible_area, TRANSPARENCY_NONE, 0);
508 			osd_mark_dirty(0,0,bitmap->width, bitmap->height, 0);
509 		}
510 		memset(dirtybuffer, 1 ,videoram_size);
511 	}
512 
513 	/* Screen clip, because our backdrop is a different resolution than the game */
514 	sclip.min_x = DOTRON_X_START + 0;
515 	sclip.max_x = DOTRON_X_START + 32*16 - 1;
516 	sclip.min_y = DOTRON_Y_START + 0;
517 	sclip.max_y = DOTRON_Y_START + 30*16 - 1;
518 
519 	/* for every character in the Video RAM, check if it has been modified */
520 	/* since last time and update it accordingly. */
521 	for (offs = videoram_size - 2; offs >= 0; offs -= 2)
522 	{
523 		if (dirtybuffer[offs])
524 		{
525 			int attr = videoram[offs+1];
526 			int code = videoram[offs] + 256 * (attr & 0x03);
527 			int color = (attr & 0x30) >> 4;
528 			int mx = ((offs / 2) % 32) * 16;
529 			int my = ((offs / 2) / 32) * 16;
530 
531 			/* center for the backdrop */
532 			mx += DOTRON_X_START;
533 			my += DOTRON_Y_START;
534 
535 			drawgfx(tmpbitmap, Machine->gfx[0], code, color, attr & 0x04, attr & 0x08,
536 					mx, my, &sclip, TRANSPARENCY_NONE, 0);
537 
538 			if (artwork_backdrop != NULL)
539 			{
540 				struct rectangle bclip;
541 
542 				bclip.min_x = mx;
543 				bclip.max_x = mx + 16 - 1;
544 				bclip.min_y = my;
545 				bclip.max_y = my + 16 - 1;
546 
547 				draw_backdrop(tmpbitmap, artwork_backdrop->artwork, 0, 0, &bclip);
548 			}
549 
550 			dirtybuffer[offs] = 0;
551 		}
552 	}
553 
554 	/* copy the resulting bitmap to the screen */
555 	copybitmap(bitmap, tmpbitmap, 0, 0, 0, 0, 0, TRANSPARENCY_NONE, 0);
556 
557 	/* draw the sprites */
558 	mcr3_update_sprites(bitmap, 0x03, 0, DOTRON_X_START, DOTRON_Y_START);
559 }
560 
561