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