1 /*************************************************************************
2 
3 	Atari Tunnel Hunt hardware
4 
5 *************************************************************************/
6 
7 #include "driver.h"
8 #include "vidhrdw/generic.h"
9 
10 extern UINT8 tunhunt_control;
11 
12 /****************************************************************************************/
13 
14 /* Video Hardware Addresses */
15 
16 /* Square Generator (13 bytes each) */
17 #define LINEV	0x1403	// LINES VERTICAL START
18 #define LINEVS	0x1483	// LINES VERT STOP
19 #define LINEH	0x1083	// LINES HORIZ START
20 #define LINEC	0x1283	// LINE COLOR, 4 BITS D0-D3
21 #define LINESH	0x1203	// LINES SLOPE 4 BITS D0-D3 (signed)
22 /* LINESH was used for rotation effects in an older version of the game */
23 
24 /* Shell Object0 */
25 #define SHEL0H	0x1800	// SHELL H POSITON (NORMAL SCREEN)
26 #define SHL0V	0x1400	// SHELL V START(NORMAL SCREEN)
27 #define SHL0VS	0x1480	// SHELL V STOP (NORMAL SCREEN)
28 #define SHL0ST	0x1200	// SHELL VSTRETCH (LIKE MST OBJ STRECTH)
29 #define SHL0PC	0x1280	// SHELL PICTURE CODE (D3-D0)
30 
31 /* Shell Object1 (see above) */
32 #define SHEL1H	0x1A00
33 #define SHL1V	0x1401
34 #define SHL1VS	0x1481
35 #define SHL1ST	0x1201
36 #define SHL1PC	0x1281
37 
38 /* Motion Object RAM */
39 #define MOBJV	0x1C00	// V POSITION (SCREEN ON SIDE)
40 #define MOBVS	0x1482	// V STOP OF MOTION OBJECT (NORMAL SCREEN)
41 #define MOBJH	0x1402	// H POSITON (SCREEN ON SIDE) (VSTART - NORMAL SCREEN)
42 #define MOBST	0x1082	// STARTING LINE FOR RAM SCAN ON MOBJ
43 #define VSTRLO	0x1202	// VERT (SCREEN ON SIDE) STRETCH MOJ OBJ
44 #define MOTT	0x2C00	// MOTION OBJECT RAM (00-0F NOT USED, BYT CLEARED)
45 #define MOBSC0	0x1080	// SCAN ROM START FOR MOBJ (unused?)
46 #define MOBSC1	0x1081	// (unused?)
47 
48 static struct tilemap *fg_tilemap;
49 
50 /****************************************************************************************/
51 
WRITE_HANDLER(tunhunt_videoram_w)52 WRITE_HANDLER( tunhunt_videoram_w )
53 {
54 	if (videoram[offset] != data)
55 	{
56 		videoram[offset] = data;
57 		tilemap_mark_tile_dirty(fg_tilemap, offset);
58 	}
59 }
60 
WRITE_HANDLER(tunhunt_mott_w)61 WRITE_HANDLER( tunhunt_mott_w )
62 {
63 	if( spriteram[offset]!=data )
64 	{
65 		spriteram[offset] = data;
66 		dirtybuffer[offset>>4] = 1;
67 	}
68 }
69 
get_fg_tile_info(int tile_index)70 static void get_fg_tile_info(int tile_index)
71 {
72 	int attr = videoram[tile_index];
73 	int code = attr & 0x3f;
74 	int color = attr >> 6;
75 	int flags = color ? TILE_IGNORE_TRANSPARENCY : 0;
76 
77 	SET_TILE_INFO(0, code, color, flags)
78 }
79 
VIDEO_START(tunhunt)80 VIDEO_START( tunhunt )
81 {
82 	/*
83 	Motion Object RAM contains 64 lines of run-length encoded data.
84 	We keep track of dirty lines and cache the expanded bitmap.
85 	With max RLE expansion, bitmap size is 256x64.
86 	*/
87 	dirtybuffer = auto_malloc(64);
88 	if (!dirtybuffer)
89 		return 1;
90 
91 	memset( dirtybuffer, 1, 64 );
92 	tmpbitmap = auto_bitmap_alloc( 256, 64 );
93 	if (!tmpbitmap)
94 		return 1;
95 
96 	fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
97 		TILEMAP_TRANSPARENT, 8, 8, 32, 32);
98 
99 	if ( !fg_tilemap )
100 		return 1;
101 
102 	tilemap_set_transparent_pen(fg_tilemap, 0);
103 	tilemap_set_scrollx(fg_tilemap, 0, 64);
104 
105 	return 0;
106 }
107 
PALETTE_INIT(tunhunt)108 PALETTE_INIT( tunhunt )
109 {
110 	/* Tunnel Hunt uses a combination of color proms and palette RAM to specify a 16 color
111 	 * palette.  Here, we manage only the mappings for alphanumeric characters and SHELL
112 	 * graphics, which are unpacked ahead of time and drawn using MAME's drawgfx primitives.
113 	 */
114 
115 	/* AlphaNumerics (1bpp)
116 	 *	2 bits of hilite select from 4 different background colors
117 	 *	Foreground color is always pen#4
118 	 *	Background color is mapped as follows:
119 	 */
120 
121 	/* alpha hilite#0 */
122 	colortable[0] = 0x0; /* background color#0 (transparent) */
123 	colortable[1] = 0x4; /* foreground color */
124 
125 	/* alpha hilite#1 */
126 	colortable[2] = 0x5; /* background color#1 */
127 	colortable[3] = 0x4; /* foreground color */
128 
129 	/* alpha hilite#2 */
130 	colortable[4] = 0x6; /* background color#2 */
131 	colortable[5] = 0x4; /* foreground color */
132 
133 	/* alpha hilite#3 */
134 	colortable[6] = 0xf; /* background color#3 */
135 	colortable[7] = 0x4; /* foreground color */
136 
137 	/* shell graphics; these are either 1bpp (2 banks) or 2bpp.  It isn't clear which.
138 	 * In any event, the following pens are associated with the shell graphics:
139 	 */
140 	colortable[0x8] = 0;
141 	colortable[0x9] = 4;//1;
142 	colortable[0xa] = 2;
143 	colortable[0xb] = 4;
144 }
145 
146 /*
147 Color Array Ram Assignments:
148     Location
149         0               Blanking, border
150         1               Mot Obj (10) (D), Shell (01)
151         2               Mot Obj (01) (G), Shell (10)
152         3               Mot Obj (00) (W)
153         4               Alpha & Shell (11) - shields
154         5               Hilight 1
155         6               Hilight 2
156         8-E             Lines (as normal) background
157         F               Hilight 3
158 */
update_palette(void)159 static void update_palette( void )
160 {
161 //	const unsigned char *color_prom = memory_region( REGION_PROMS );
162 /*
163 	The actual contents of the color proms (unused by this driver)
164 	are as follows:
165 
166 	D11 "blue/green"
167 	0000:	00 00 8b 0b fb 0f ff 0b
168 			00 00 0f 0f fb f0 f0 ff
169 
170 	C11 "red"
171 	0020:	00 f0 f0 f0 b0 b0 00 f0
172 			00 f0 f0 00 b0 00 f0 f0
173 */
174 	int color;
175 	int shade;
176 	int i;
177 	int red,green,blue;
178 
179 	for( i=0; i<16; i++ )
180 	{
181 		color = paletteram[i];
182 		shade = 0xf^(color>>4);
183 
184 		color &= 0xf; /* hue select */
185 		switch( color )
186 		{
187 		default:
188 		case 0x0: red = 0xff; green = 0xff; blue = 0xff; break; /* white */
189 		case 0x1: red = 0xff; green = 0x00; blue = 0xff; break; /* purple */
190 		case 0x2: red = 0x00; green = 0x00; blue = 0xff; break; /* blue */
191 		case 0x3: red = 0x00; green = 0xff; blue = 0xff; break; /* cyan */
192 		case 0x4: red = 0x00; green = 0xff; blue = 0x00; break; /* green */
193 		case 0x5: red = 0xff; green = 0xff; blue = 0x00; break; /* yellow */
194 		case 0x6: red = 0xff; green = 0x00; blue = 0x00; break; /* red */
195 		case 0x7: red = 0x00; green = 0x00; blue = 0x00; break; /* black? */
196 
197 		case 0x8: red = 0xff; green = 0x7f; blue = 0x00; break; /* orange */
198 		case 0x9: red = 0x7f; green = 0xff; blue = 0x00; break; /* ? */
199 		case 0xa: red = 0x00; green = 0xff; blue = 0x7f; break; /* ? */
200 		case 0xb: red = 0x00; green = 0x7f; blue = 0xff; break; /* ? */
201 		case 0xc: red = 0xff; green = 0x00; blue = 0x7f; break; /* ? */
202 		case 0xd: red = 0x7f; green = 0x00; blue = 0xff; break; /* ? */
203 		case 0xe: red = 0xff; green = 0xaa; blue = 0xaa; break; /* ? */
204 		case 0xf: red = 0xaa; green = 0xaa; blue = 0xff; break; /* ? */
205 		}
206 
207 	/* combine color components with shade value (0..0xf) */
208 		#define APPLY_SHADE( C,S ) ((C*S)/0xf)
209 		red		= APPLY_SHADE(red,shade);
210 		green	= APPLY_SHADE(green,shade);
211 		blue	= APPLY_SHADE(blue,shade);
212 
213 		palette_set_color( i,red,green,blue );
214 	}
215 }
216 
draw_motion_object(struct mame_bitmap * bitmap)217 static void draw_motion_object( struct mame_bitmap *bitmap )
218 {
219 /*
220  *		VSTRLO	0x1202
221  *			normally 0x02 (gameplay, attract1)
222  *			in attract2 (with "Tunnel Hunt" graphic), decrements from 0x2f down to 0x01
223  *			goes to 0x01 for some enemy shots
224  *
225  *		MOBSC0	0x1080
226  *		MOBSC1	0x1081
227  *			always 0x00?
228  */
229 	const UINT8 *pMem = memory_region( REGION_CPU1 );
230 //	int skip = pMem[MOBST];
231 	int x0 = 255-pMem[MOBJV];
232 	int y0 = 255-pMem[MOBJH];
233 	int scalex,scaley;
234 	int line,span;
235 	int x,span_data;
236 	int color;
237 	int count,pen;
238 	const unsigned char *source;
239 	struct rectangle clip = Machine->visible_area;
240 
241 	for( line=0; line<64; line++ )
242 	{
243 		if( dirtybuffer[line] )
244 		{
245 			dirtybuffer[line] = 0;
246 			x = 0;
247 			source = &spriteram[line*0x10];
248 			for( span=0; span<0x10; span++ )
249 			{
250 				span_data = source[span];
251 				if( span_data == 0xff ) break;
252 				pen = ((span_data>>6)&0x3)^0x3;
253 				color = Machine->pens[pen];
254 				count = (span_data&0x1f)+1;
255 				while( count-- )
256 				{
257 					plot_pixel( tmpbitmap, x++,line,color );
258 				}
259 			}
260 			color = Machine->pens[0];
261 			while( x<256 )
262 			{
263 				plot_pixel( tmpbitmap, x++,line,color );
264 			}
265 		} /* dirty line */
266 	} /* next line */
267 
268 	switch( pMem[VSTRLO] )
269 	{
270 	case 0x01:
271 		scaley = (1<<16)*0.33; /* seems correct */
272 		break;
273 
274 	case 0x02:
275 		scaley = (1<<16)*0.50; /* seems correct */
276 		break;
277 
278 	default:
279 		scaley = (1<<16)*pMem[VSTRLO]/4; /* ??? */
280 		break;
281 	}
282 	scalex = (1<<16);
283 
284 	copyrozbitmap(
285 		bitmap,tmpbitmap,
286 		-x0*scalex,/* startx */
287 		-y0*scaley,/* starty */
288 		scalex,/* incxx */
289 		0,0,/* incxy,incyx */
290 		scaley,/* incyy */
291 		0, /* no wraparound */
292 		&clip,
293 		TRANSPARENCY_PEN,Machine->pens[0],
294 		0 /* priority */
295 	);
296 }
297 
draw_box(struct mame_bitmap * bitmap)298 static void draw_box( struct mame_bitmap *bitmap )
299 {
300 /*
301 	This is unnecessarily slow, but the box priorities aren't completely understood,
302 	yet.  Once understood, this function should be converted to use fillbitmap with
303 	rectangular chunks instead of plot_pixel.
304 
305 	Tunnels:
306 		1080: 00 00 00 		01	e7 18   ae 51   94 6b   88 77   83 7c   80 7f  	x0
307 		1480: 00 f0 17 		00	22 22   5b 5b   75 75   81 81   86 86   89 89  	y0
308 		1400: 00 00 97 		ff	f1 f1   b8 b8   9e 9e   92 92   8d 8d   8a 8a  	y1
309 		1280: 07 03 00 		07	07 0c   0c 0d   0d 0e   0e 08   08 09   09 0a  	palette select
310 
311 	Color Bars:
312 		1080: 00 00 00 		01	00 20 40 60 80 a0 c0 e0		01 2a	50 7a		x0
313 		1480: 00 f0 00 		00	40 40 40 40 40 40 40 40		00 00	00 00		y0
314 		1400: 00 00 00 		ff	ff ff ff ff ff ff ff ff		40 40	40 40		y1
315 		1280: 07 03 00 		01	07 06 04 05 02 07 03 00		09 0a	0b 0c		palette select
316 		->hue 06 02 ff 		60	06 05 03 04 01 06 02 ff		d2 00	c2 ff
317 */
318 	int span,x,y;
319 	UINT8 *pMem;
320 	int color;
321 	int pen;
322 //	struct rectangle bbox;
323 	int z;
324 	int x0,y0,y1;
325 	pMem = memory_region( REGION_CPU1 );
326 
327 	for( y=0; y<256; y++ )
328 	{
329 		for( x=0; x<256; x++ )
330 		{
331 			pen = 0;
332 			z = 0;
333 			for( span=3; span<16; span++ )
334 			{
335 				x0 = pMem[span+0x1080];
336 				y0 = pMem[span+0x1480];
337 				y1 = pMem[span+0x1400];
338 
339 				if( y>=y0 && y<=y1 && x>=x0 && x0>=z )
340 				{
341 					pen = pMem[span+0x1280]&0xf;
342 					z = x0; /* give priority to rightmost spans */
343 				}
344 			}
345 			color = Machine->pens[pen];
346 			plot_pixel( bitmap, x, 0xff-y, color );
347 		}
348 	}
349 	return;
350 }
351 
352 /* "shell" graphics are 16x16 pixel tiles used for player shots and targeting cursor */
draw_shell(struct mame_bitmap * bitmap,int picture_code,int hposition,int vstart,int vstop,int vstretch,int hstretch)353 static void draw_shell(
354 		struct mame_bitmap *bitmap,
355 		int picture_code,
356 		int hposition,
357 		int vstart,
358 		int vstop,
359 		int vstretch,
360 		int hstretch )
361 {
362 	if( hstretch )
363 	{
364 		int sx,sy;
365 		for( sx=0; sx<256; sx+=16 )
366 		{
367 			for( sy=0; sy<256; sy+=16 )
368 			{
369 				drawgfx( bitmap, Machine->gfx[1],
370 					picture_code,
371 					0, /* color */
372 					0,0, /* flip */
373 					sx,sy,
374 					&Machine->visible_area,
375 					TRANSPARENCY_PEN,0 );
376 			}
377 		}
378 	}
379 	else
380 	/*
381 		vstretch is normally 0x01
382 
383 		targeting cursor:
384 			hposition	= 0x78
385 			vstart		= 0x90
386 			vstop		= 0x80
387 
388 		during grid test:
389 			vstretch	= 0xff
390 			hposition	= 0xff
391 			vstart		= 0xff
392 			vstop		= 0x00
393 
394 	*/
395 	drawgfx( bitmap, Machine->gfx[1],
396 			picture_code,
397 			0, /* color */
398 			0,0, /* flip */
399 			255-hposition-16,vstart-32,
400 			&Machine->visible_area,
401 			TRANSPARENCY_PEN,0 );
402 }
403 
VIDEO_UPDATE(tunhunt)404 VIDEO_UPDATE( tunhunt )
405 {
406 	const UINT8 *pMem = memory_region( REGION_CPU1 );
407 
408 	update_palette();
409 
410 	draw_box( bitmap );
411 
412 	draw_motion_object( bitmap );
413 
414 	draw_shell( bitmap,
415 		pMem[SHL0PC],	/* picture code */
416 		pMem[SHEL0H],	/* hposition */
417 		pMem[SHL0V],	/* vstart */
418 		pMem[SHL0VS],	/* vstop */
419 		pMem[SHL0ST],	/* vstretch */
420 		tunhunt_control&0x08 ); /* hstretch */
421 
422 	draw_shell( bitmap,
423 		pMem[SHL1PC],	/* picture code */
424 		pMem[SHEL1H],	/* hposition */
425 		pMem[SHL1V],	/* vstart */
426 		pMem[SHL1VS],	/* vstop */
427 		pMem[SHL1ST],	/* vstretch */
428 		tunhunt_control&0x10 ); /* hstretch */
429 
430 	tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
431 }
432