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