1 /***************************************************************************
2
3 Atari Gauntlet hardware
4
5 ****************************************************************************/
6
7
8 #include "driver.h"
9 #include "machine/atarigen.h"
10 #include "vidhrdw/generic.h"
11
12 #define XCHARS 42
13 #define YCHARS 30
14
15 #define XDIM (XCHARS*8)
16 #define YDIM (YCHARS*8)
17
18
19
20 /*************************************
21 *
22 * Globals we own
23 *
24 *************************************/
25
26 UINT8 vindctr2_screen_refresh;
27
28
29
30 /*************************************
31 *
32 * Statics
33 *
34 *************************************/
35
36 struct mo_data
37 {
38 struct osd_bitmap *bitmap;
39 UINT8 color_xor;
40 };
41
42 static struct atarigen_pf_state pf_state;
43
44 static UINT8 playfield_color_base;
45
46
47
48 /*************************************
49 *
50 * Prototypes
51 *
52 *************************************/
53
54 static const UINT8 *update_palette(void);
55
56 static void pf_color_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *data);
57 static void pf_render_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *data);
58 static void pf_overrender_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *param);
59
60 static void mo_color_callback(const UINT16 *data, const struct rectangle *clip, void *param);
61 static void mo_render_callback(const UINT16 *data, const struct rectangle *clip, void *param);
62
63
64
65 /*************************************
66 *
67 * Video system start
68 *
69 *************************************/
70
gauntlet_vh_start(void)71 int gauntlet_vh_start(void)
72 {
73 static struct atarigen_mo_desc mo_desc =
74 {
75 1024, /* maximum number of MO's */
76 2, /* number of bytes per MO entry */
77 0x800, /* number of bytes between MO words */
78 3, /* ignore an entry if this word == 0xffff */
79 3, 0, 0x3ff, /* link = (data[linkword] >> linkshift) & linkmask */
80 0 /* render in reverse link order */
81 };
82
83 static struct atarigen_pf_desc pf_desc =
84 {
85 8, 8, /* width/height of each tile */
86 64, 64 /* number of tiles in each direction */
87 };
88
89 /* reset statics */
90 memset(&pf_state, 0, sizeof(pf_state));
91 playfield_color_base = vindctr2_screen_refresh ? 0x10 : 0x18;
92
93 /* initialize the playfield */
94 if (atarigen_pf_init(&pf_desc))
95 return 1;
96
97 /* initialize the motion objects */
98 if (atarigen_mo_init(&mo_desc))
99 {
100 atarigen_pf_free();
101 return 1;
102 }
103
104 return 0;
105 }
106
107
108
109 /*************************************
110 *
111 * Video system shutdown
112 *
113 *************************************/
114
gauntlet_vh_stop(void)115 void gauntlet_vh_stop(void)
116 {
117 atarigen_pf_free();
118 atarigen_mo_free();
119 }
120
121
122
123 /*************************************
124 *
125 * Horizontal scroll register
126 *
127 *************************************/
128
WRITE_HANDLER(gauntlet_hscroll_w)129 WRITE_HANDLER( gauntlet_hscroll_w )
130 {
131 /* update memory */
132 int oldword = READ_WORD(&atarigen_hscroll[offset]);
133 int newword = COMBINE_WORD(oldword, data);
134 WRITE_WORD(&atarigen_hscroll[offset], newword);
135
136 /* update parameters */
137 pf_state.hscroll = newword & 0x1ff;
138 atarigen_pf_update(&pf_state, cpu_getscanline());
139 }
140
141
142
143 /*************************************
144 *
145 * Vertical scroll/PF bank register
146 *
147 *************************************/
148
WRITE_HANDLER(gauntlet_vscroll_w)149 WRITE_HANDLER( gauntlet_vscroll_w )
150 {
151 /* update memory */
152 int oldword = READ_WORD(&atarigen_vscroll[offset]);
153 int newword = COMBINE_WORD(oldword, data);
154 WRITE_WORD(&atarigen_vscroll[offset], newword);
155
156 /* update parameters */
157 pf_state.vscroll = (newword >> 7) & 0x1ff;
158 pf_state.param[0] = newword & 3;
159 atarigen_pf_update(&pf_state, cpu_getscanline());
160 }
161
162
163
164 /*************************************
165 *
166 * Playfield RAM write handler
167 *
168 *************************************/
169
WRITE_HANDLER(gauntlet_playfieldram_w)170 WRITE_HANDLER( gauntlet_playfieldram_w )
171 {
172 int oldword = READ_WORD(&atarigen_playfieldram[offset]);
173 int newword = COMBINE_WORD(oldword, data);
174 if (oldword != newword)
175 {
176 WRITE_WORD(&atarigen_playfieldram[offset], newword);
177 atarigen_pf_dirty[offset / 2] = 0xff;
178 }
179 }
180
181
182
183 /*************************************
184 *
185 * Periodic scanline updater
186 *
187 *************************************/
188
gauntlet_scanline_update(int scanline)189 void gauntlet_scanline_update(int scanline)
190 {
191 atarigen_mo_update_slip_512(atarigen_spriteram, pf_state.vscroll, scanline, &atarigen_alpharam[0xf80]);
192 }
193
194
195
196 /*************************************
197 *
198 * Main refresh
199 *
200 *************************************/
201
gauntlet_vh_screenrefresh(struct osd_bitmap * bitmap,int full_refresh)202 void gauntlet_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
203 {
204 /* update the palette, and mark things dirty */
205 if (update_palette())
206 memset(atarigen_pf_dirty, 0xff, atarigen_playfieldram_size / 2);
207
208 /* draw the playfield */
209 memset(atarigen_pf_visit, 0, 64*64);
210 atarigen_pf_process(pf_render_callback, bitmap, &Machine->visible_area);
211
212 /* draw the motion objects */
213 atarigen_mo_process(mo_render_callback, bitmap);
214
215 /* draw the alphanumerics */
216 {
217 const struct GfxElement *gfx = Machine->gfx[1];
218 int x, y, offs;
219
220 for (y = 0; y < YCHARS; y++)
221 for (x = 0, offs = y * 64; x < XCHARS; x++, offs++)
222 {
223 int data = READ_WORD(&atarigen_alpharam[offs * 2]);
224 int code = data & 0x3ff;
225 int opaque = data & 0x8000;
226
227 if (code || opaque)
228 {
229 int color = ((data >> 10) & 0xf) | ((data >> 9) & 0x20);
230 drawgfx(bitmap, gfx, code, color, 0, 0, 8 * x, 8 * y, 0, opaque ? TRANSPARENCY_NONE : TRANSPARENCY_PEN, 0);
231 }
232 }
233 }
234
235 /* update onscreen messages */
236 atarigen_update_messages();
237 }
238
239
240
241 /*************************************
242 *
243 * Palette management
244 *
245 *************************************/
246
update_palette(void)247 static const UINT8 *update_palette(void)
248 {
249 UINT16 pf_map[32], al_map[64], mo_map[16];
250 int i, j;
251
252 /* reset color tracking */
253 memset(mo_map, 0, sizeof(mo_map));
254 memset(pf_map, 0, sizeof(pf_map));
255 memset(al_map, 0, sizeof(al_map));
256 palette_init_used_colors();
257
258 /* update color usage for the playfield */
259 atarigen_pf_process(pf_color_callback, pf_map, &Machine->visible_area);
260
261 /* update color usage for the mo's */
262 atarigen_mo_process(mo_color_callback, mo_map);
263
264 /* update color usage for the alphanumerics */
265 {
266 const unsigned int *usage = Machine->gfx[1]->pen_usage;
267 int x, y, offs;
268
269 for (y = 0; y < YCHARS; y++)
270 for (x = 0, offs = y * 64; x < XCHARS; x++, offs++)
271 {
272 int data = READ_WORD(&atarigen_alpharam[offs * 2]);
273 int code = data & 0x3ff;
274 int color = ((data >> 10) & 0xf) | ((data >> 9) & 0x20);
275 al_map[color] |= usage[code];
276 }
277 }
278
279 /* rebuild the playfield palette */
280 for (i = 0; i < 16; i++)
281 {
282 UINT16 used = pf_map[i + 16];
283 if (used)
284 for (j = 0; j < 16; j++)
285 if (used & (1 << j))
286 palette_used_colors[0x200 + i * 16 + j] = PALETTE_COLOR_USED;
287 }
288
289 /* rebuild the motion object palette */
290 for (i = 0; i < 16; i++)
291 {
292 UINT16 used = mo_map[i];
293 if (used)
294 {
295 palette_used_colors[0x100 + i * 16 + 0] = PALETTE_COLOR_TRANSPARENT;
296 palette_used_colors[0x100 + i * 16 + 1] = PALETTE_COLOR_TRANSPARENT;
297 for (j = 2; j < 16; j++)
298 if (used & (1 << j))
299 palette_used_colors[0x100 + i * 16 + j] = PALETTE_COLOR_USED;
300 }
301 }
302
303 /* rebuild the alphanumerics palette */
304 for (i = 0; i < 64; i++)
305 {
306 UINT16 used = al_map[i];
307 if (used)
308 for (j = 0; j < 4; j++)
309 if (used & (1 << j))
310 palette_used_colors[0x000 + i * 4 + j] = PALETTE_COLOR_USED;
311 }
312
313 /* recalc */
314 return palette_recalc();
315 }
316
317
318
319 /*************************************
320 *
321 * Playfield palette
322 *
323 *************************************/
324
pf_color_callback(const struct rectangle * clip,const struct rectangle * tiles,const struct atarigen_pf_state * state,void * param)325 static void pf_color_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *param)
326 {
327 const unsigned int *usage = &Machine->gfx[0]->pen_usage[state->param[0] * 0x1000];
328 UINT16 *colormap = (UINT16 *)param;
329 int x, y;
330
331 for (y = tiles->min_y; y != tiles->max_y; y = (y + 1) & 63)
332 for (x = tiles->min_x; x != tiles->max_x; x = (x + 1) & 63)
333 {
334 int offs = x * 64 + y;
335 int data = READ_WORD(&atarigen_playfieldram[offs * 2]);
336 int code = (data & 0xfff) ^ 0x800;
337 int color = playfield_color_base + ((data >> 12) & 7);
338 colormap[color] |= usage[code];
339 colormap[color ^ 8] |= usage[code];
340
341 /* also mark unvisited tiles dirty */
342 if (!atarigen_pf_visit[offs]) atarigen_pf_dirty[offs] = 0xff;
343 }
344 }
345
346
347
348 /*************************************
349 *
350 * Playfield rendering
351 *
352 *************************************/
353
pf_render_callback(const struct rectangle * clip,const struct rectangle * tiles,const struct atarigen_pf_state * state,void * param)354 static void pf_render_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *param)
355 {
356 const struct GfxElement *gfx = Machine->gfx[0];
357 struct osd_bitmap *bitmap = (struct osd_bitmap *)param;
358 int bank = state->param[0];
359 int x, y;
360
361 /* first update any tiles whose color is out of date */
362 for (y = tiles->min_y; y != tiles->max_y; y = (y + 1) & 63)
363 for (x = tiles->min_x; x != tiles->max_x; x = (x + 1) & 63)
364 {
365 int offs = x * 64 + y;
366 int data = READ_WORD(&atarigen_playfieldram[offs * 2]);
367
368 if (atarigen_pf_dirty[offs] != bank)
369 {
370 int color = playfield_color_base + ((data >> 12) & 7);
371 int code = bank * 0x1000 + ((data & 0xfff) ^ 0x800);
372 int hflip = data & 0x8000;
373
374 drawgfx(atarigen_pf_bitmap, gfx, code, color, hflip, 0, 8 * x, 8 * y, 0, TRANSPARENCY_NONE, 0);
375 atarigen_pf_dirty[offs] = bank;
376 }
377
378 /* track the tiles we've visited */
379 atarigen_pf_visit[offs] = 1;
380 }
381
382 /* then blast the result */
383 x = -state->hscroll;
384 y = -state->vscroll;
385 copyscrollbitmap(bitmap, atarigen_pf_bitmap, 1, &x, 1, &y, clip, TRANSPARENCY_NONE, 0);
386 }
387
388
389
390 /*************************************
391 *
392 * Playfield overrendering
393 *
394 *************************************/
395
pf_overrender_callback(const struct rectangle * clip,const struct rectangle * tiles,const struct atarigen_pf_state * state,void * param)396 static void pf_overrender_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *param)
397 {
398 const struct GfxElement *gfx = Machine->gfx[0];
399 const struct mo_data *modata = (const struct mo_data *)param;
400 struct osd_bitmap *bitmap = modata->bitmap;
401 int color_xor = modata->color_xor;
402 int bank = state->param[0];
403 int x, y;
404
405 /* first update any tiles whose color is out of date */
406 for (y = tiles->min_y; y != tiles->max_y; y = (y + 1) & 63)
407 {
408 int sy = (8 * y - state->vscroll) & 0x1ff;
409 if (sy >= YDIM) sy -= 0x200;
410
411 for (x = tiles->min_x; x != tiles->max_x; x = (x + 1) & 63)
412 {
413 int offs = x * 64 + y;
414 int data = READ_WORD(&atarigen_playfieldram[offs * 2]);
415 int color = playfield_color_base + ((data >> 12) & 7);
416 int code = bank * 0x1000 + ((data & 0xfff) ^ 0x800);
417 int hflip = data & 0x8000;
418 int sx = (8 * x - state->hscroll) & 0x1ff;
419 if (sx >= XDIM) sx -= 0x200;
420
421 drawgfx(bitmap, gfx, code, color ^ color_xor, hflip, 0, sx, sy, 0, TRANSPARENCY_THROUGH, palette_transparent_pen);
422 }
423 }
424 }
425
426
427
428 /*************************************
429 *
430 * Motion object palette
431 *
432 *************************************/
433
mo_color_callback(const UINT16 * data,const struct rectangle * clip,void * param)434 static void mo_color_callback(const UINT16 *data, const struct rectangle *clip, void *param)
435 {
436 const unsigned int *usage = Machine->gfx[0]->pen_usage;
437 UINT16 *colormap = (UINT16 *)param;
438 int code = (data[0] & 0x7fff) ^ 0x800;
439 int hsize = ((data[2] >> 3) & 7) + 1;
440 int vsize = (data[2] & 7) + 1;
441 int color = data[1] & 0x000f;
442 int tiles = hsize * vsize;
443 UINT16 temp = 0;
444 int i;
445
446 for (i = 0; i < tiles; i++)
447 temp |= usage[code++];
448 colormap[color] |= temp;
449 }
450
451
452
453 /*************************************
454 *
455 * Motion object rendering
456 *
457 *************************************/
458
mo_render_callback(const UINT16 * data,const struct rectangle * clip,void * param)459 static void mo_render_callback(const UINT16 *data, const struct rectangle *clip, void *param)
460 {
461 const struct GfxElement *gfx = Machine->gfx[0];
462 const unsigned int *usage = gfx->pen_usage;
463 unsigned int total_usage = 0;
464 struct osd_bitmap *bitmap = (struct osd_bitmap *)param;
465 struct rectangle pf_clip;
466 int x, y, sx, sy;
467
468 /* extract data from the various words */
469 int code = (data[0] & 0x7fff) ^ 0x800;
470 int color = data[1] & 0x000f;
471 int ypos = -pf_state.vscroll - (data[2] >> 7);
472 int hflip = data[2] & 0x0040;
473 int hsize = ((data[2] >> 3) & 7) + 1;
474 int vsize = (data[2] & 7) + 1;
475 int xpos = -pf_state.hscroll + (data[1] >> 7);
476 int xadv;
477
478 /* adjust for height */
479 ypos -= vsize * 8;
480
481 /* adjust the final coordinates */
482 xpos &= 0x1ff;
483 ypos &= 0x1ff;
484 if (xpos >= XDIM) xpos -= 0x200;
485 if (ypos >= YDIM) ypos -= 0x200;
486
487 /* determine the bounding box */
488 atarigen_mo_compute_clip_8x8(pf_clip, xpos, ypos, hsize, vsize, clip);
489
490 /* adjust for h flip */
491 if (hflip)
492 xpos += (hsize - 1) * 8, xadv = -8;
493 else
494 xadv = 8;
495
496 /* loop over the height */
497 for (y = 0, sy = ypos; y < vsize; y++, sy += 8)
498 {
499 /* clip the Y coordinate */
500 if (sy <= clip->min_y - 8)
501 {
502 code += hsize;
503 continue;
504 }
505 else if (sy > clip->max_y)
506 break;
507
508 /* loop over the width */
509 for (x = 0, sx = xpos; x < hsize; x++, sx += xadv, code++)
510 {
511 /* clip the X coordinate */
512 if (sx <= -8 || sx >= XDIM)
513 continue;
514
515 /* draw the sprite */
516 drawgfx(bitmap, gfx, code, color, hflip, 0, sx, sy, clip, TRANSPARENCY_PEN, 0);
517 total_usage |= usage[code];
518 }
519 }
520
521 /* overrender the playfield */
522 if (total_usage & 0x0002)
523 {
524 struct mo_data modata;
525 modata.bitmap = bitmap;
526 modata.color_xor = (color == 0 && vindctr2_screen_refresh) ? 0 : 8;
527 atarigen_pf_process(pf_overrender_callback, &modata, &pf_clip);
528 }
529 }
530