1 #include "driver.h"
2 #include "state.h"
3 #include "vidhrdw/generic.h"
4 #include "namcos2.h"	/* for game-specific hacks */
5 #include "namcoic.h"
6 
7 static data16_t mSpritePos[4];
8 
WRITE16_HANDLER(namco_spritepos16_w)9 WRITE16_HANDLER( namco_spritepos16_w )
10 {
11 	COMBINE_DATA( &mSpritePos[offset] );
12 }
READ16_HANDLER(namco_spritepos16_r)13 READ16_HANDLER( namco_spritepos16_r )
14 {
15 	return mSpritePos[offset];
16 }
17 
WRITE32_HANDLER(namco_spritepos32_w)18 WRITE32_HANDLER( namco_spritepos32_w )
19 {
20 	data32_t v;
21 	offset *= 2;
22 	v = (mSpritePos[offset]<<16)|mSpritePos[offset+1];
23 	COMBINE_DATA( &v );
24 	mSpritePos[offset+0] = v>>16;
25 	mSpritePos[offset+1] = v&0xffff;
26 }
READ32_HANDLER(namco_spritepos32_r)27 READ32_HANDLER( namco_spritepos32_r )
28 {
29 	offset *= 2;
30 	return (mSpritePos[offset]<<16)|mSpritePos[offset+1];
31 }
32 
33 static INLINE data8_t
nth_byte16(const data16_t * pSource,int which)34 nth_byte16( const data16_t *pSource, int which )
35 {
36 	data16_t data = pSource[which/2];
37 	if( which&1 )
38 	{
39 		return data&0xff;
40 	}
41 	else
42 	{
43 		return data>>8;
44 	}
45 } /* nth_byte16 */
46 
47 /* nth_word32 is a general-purpose utility function, which allows us to
48  * read from 32-bit aligned memory as if it were an array of 16 bit words.
49  */
50 static INLINE data16_t
nth_word32(const data32_t * pSource,int which)51 nth_word32( const data32_t *pSource, int which )
52 {
53 	data32_t data = pSource[which/2];
54 	if( which&1 )
55 	{
56 		return data&0xffff;
57 	}
58 	else
59 	{
60 		return data>>16;
61 	}
62 } /* nth_word32 */
63 
64 /* nth_byte32 is a general-purpose utility function, which allows us to
65  * read from 32-bit aligned memory as if it were an array of bytes.
66  */
67 static INLINE data8_t
nth_byte32(const data32_t * pSource,int which)68 nth_byte32( const data32_t *pSource, int which )
69 {
70 		data32_t data = pSource[which/4];
71 		switch( which&3 )
72 		{
73 		case 0: return data>>24;
74 		case 1: return (data>>16)&0xff;
75 		case 2: return (data>>8)&0xff;
76 		default: return data&0xff;
77 		}
78 } /* nth_byte32 */
79 
80 /**************************************************************************************************************/
81 
82 static int (*mpCodeToTile)( int code ); /* sprite banking callback */
83 static int mGfxC355;	/* gfx bank for sprites */
84 static int mPalXOR;		/* XOR'd with palette select register; needed for System21 */
85 
86 /**
87  * 0x00000 sprite attr (page0)
88  * 0x02000 sprite list (page0)
89  * 0x02400 window attributes
90  * 0x04000 format
91  * 0x08000 tile
92  * 0x10000 sprite attr (page1)
93  * 0x14000 sprite list (page1)
94  */
95 static void
draw_spriteC355(int page,struct mame_bitmap * bitmap,const struct rectangle * cliprect,const data16_t * pSource,int pri,int zpos)96 draw_spriteC355( int page, struct mame_bitmap *bitmap, const struct rectangle *cliprect, const data16_t *pSource, int pri, int zpos )
97 {
98 	unsigned screen_height_remaining, screen_width_remaining;
99 	unsigned source_height_remaining, source_width_remaining;
100 	INT32 hpos,vpos;
101 	data16_t hsize,vsize;
102 	data16_t palette;
103 	data16_t linkno;
104 	data16_t offset;
105 	data16_t format;
106 	int tile_index;
107 	int num_cols,num_rows;
108 	int dx,dy;
109 	int row,col;
110 	int sx,sy,tile;
111 	int flipx,flipy;
112 	UINT32 zoomx, zoomy;
113 	int tile_screen_width;
114 	int tile_screen_height;
115 	const data16_t *spriteformat16 = &spriteram16[0x4000/2];
116 	const data16_t *spritetile16 = &spriteram16[0x8000/2];
117 	int color;
118 
119 	struct rectangle clip;
120 
121 	/**
122 	 * ----xxxx-------- window select
123 	 * --------xxxx---- priority
124 	 * ------------xxxx palette select
125 	 */
126 	palette = pSource[6];
127 	switch( namcos2_gametype )
128 	{
129 	case NAMCONB2_OUTFOXIES:
130 	case NAMCONB2_MACH_BREAKERS:
131 	case NAMCOS2_SUZUKA_8_HOURS_2:
132 	case NAMCOS2_SUZUKA_8_HOURS:
133 	case NAMCOS2_LUCKY_AND_WILD:
134 		if( pri != ((palette>>5)&7) ) return;
135 		break;
136 
137 	default:
138 		if( pri != ((palette>>4)&0x7) ) return;
139 		break;
140 	}
141 
142 	linkno		= pSource[0]; /* LINKNO */
143 	offset		= pSource[1]; /* OFFSET */
144 	hpos		= pSource[2]; /* HPOS		0x000..0x7ff (signed) */
145 	vpos		= pSource[3]; /* VPOS		0x000..0x7ff (signed) */
146 	hsize		= pSource[4]; /* HSIZE		max 0x3ff pixels */
147 	vsize		= pSource[5]; /* VSIZE		max 0x3ff pixels */
148 	/* pSource[6] contains priority/palette */
149 	/* pSource[7] is used in Lucky & Wild, possibly for sprite-road priority */
150 
151 	if( linkno*4>=0x4000/2 ) return; /* avoid garbage memory read */
152 
153 	switch( namcos2_gametype )
154 	{
155 	case NAMCOS21_SOLVALOU: /* hack */
156 		hpos -= 0x80;
157 		vpos -= 0x40;
158 		clip = Machine->visible_area;
159 		break;
160 
161 	case NAMCOS21_CYBERSLED: /* hack */
162 		hpos -= 0x110;
163 		vpos -= 2+32;
164 		clip = Machine->visible_area;
165 		break;
166 
167 	case NAMCOS21_AIRCOMBAT: /* hack */
168 		vpos -= 0x22;
169 		hpos -= 0x02;
170 		clip = Machine->visible_area;
171 		break;
172 
173 	case NAMCOS21_STARBLADE: /* hack */
174 		if( page )
175 		{
176 			hpos -= 0x80;
177 			vpos -= 0x20;
178 		}
179 		clip = Machine->visible_area;
180 		break;
181 
182 	case NAMCONB1_NEBULRAY:
183 	case NAMCONB1_GUNBULET:
184 	case NAMCONB1_GSLGR94U:
185 	case NAMCONB1_SWS95:
186 	case NAMCONB1_SWS96:
187 	case NAMCONB1_SWS97:
188 	case NAMCONB2_OUTFOXIES:
189 	case NAMCONB2_MACH_BREAKERS:
190 	case NAMCONB1_VSHOOT:
191 	case NAMCOS2_SUZUKA_8_HOURS_2:
192 	case NAMCOS2_SUZUKA_8_HOURS:
193 	case NAMCOS2_LUCKY_AND_WILD:
194 	case NAMCOS2_STEEL_GUNNER_2:
195 	default:
196 		{
197 			int dh = mSpritePos[1];
198 			int dv = mSpritePos[0];
199 			const data16_t *pWinAttr = &spriteram16[0x2400/2+((palette>>8)&0xf)*4];
200 
201 			dh &= 0x1ff; if( dh&0x100 ) dh |= ~0x1ff;
202 			dv &= 0x1ff; if( dv&0x100 ) dv |= ~0x1ff;
203 			vpos&=0x7ff; if( vpos&0x400 ) vpos |= ~0x7ff;
204 			hpos&=0x7ff; if( hpos&0x400 ) hpos |= ~0x7ff;
205 			hpos += -0x26 - dh;
206 			vpos += -0x19 - dv;
207 			/* 0026 0145 0019 00f8 (lucky&wild)*/
208 			/* 0025 0145 0019 00f8 (point blank)*/
209 			clip.min_x = pWinAttr[0] - 0x26 - dh;
210 			clip.max_x = pWinAttr[1] - 0x26 - dh;
211 			clip.min_y = pWinAttr[2] - 0x19 - dv;
212 			clip.max_y = pWinAttr[3] - 0x19 - dv;
213 			if( clip.min_x < cliprect->min_x ) clip.min_x = cliprect->min_x;
214 			if( clip.min_y < cliprect->min_y ) clip.min_y = cliprect->min_y;
215 			if( clip.max_x > cliprect->max_x ) clip.max_x = cliprect->max_x;
216 			if( clip.max_y > cliprect->max_y ) clip.max_y = cliprect->max_y;
217 		}
218 		break;
219 	}
220 	tile_index		= spriteformat16[linkno*4+0];
221 	format			= spriteformat16[linkno*4+1];
222 	dx				= spriteformat16[linkno*4+2];
223 	dy				= spriteformat16[linkno*4+3];
224 	num_cols		= (format>>4)&0xf;
225 	num_rows		= (format)&0xf;
226 
227 	if( num_cols == 0 ) num_cols = 0x10;
228 	flipx = (hsize&0x8000)?1:0;
229 	hsize &= 0x1ff;
230 	if( hsize == 0 ) return;
231 
232 	zoomx = (hsize<<16)/(num_cols*16);
233 	dx = (dx*zoomx+0x8000)>>16;
234 	if( flipx )
235 	{
236 		hpos += dx;
237 	}
238 	else
239 	{
240 		hpos -= dx;
241 	}
242 
243 	if( num_rows == 0 ) num_rows = 0x10;
244 	flipy = (vsize&0x8000)?1:0;
245 	vsize&=0x1ff;
246 	if( vsize == 0 ) return;
247 
248 	zoomy = (vsize<<16)/(num_rows*16);
249 	dy = (dy*zoomy+0x8000)>>16;
250 	if( flipy )
251 	{
252 		vpos += dy;
253 	}
254 	else
255 	{
256 		vpos -= dy;
257 	}
258 
259 	color = (palette&0xf)^mPalXOR;
260 
261 	source_height_remaining = num_rows*16;
262 	screen_height_remaining = vsize;
263 	sy = vpos;
264 	for( row=0; row<num_rows; row++ )
265 	{
266 		tile_screen_height = 16*screen_height_remaining/source_height_remaining;
267 		zoomy = (screen_height_remaining<<16)/source_height_remaining;
268 		if( flipy )
269 		{
270 			sy -= tile_screen_height;
271 		}
272 		source_width_remaining = num_cols*16;
273 		screen_width_remaining = hsize;
274 		sx = hpos;
275 		for( col=0; col<num_cols; col++ )
276 		{
277 			tile_screen_width = 16*screen_width_remaining/source_width_remaining;
278 			zoomx = (screen_width_remaining<<16)/source_width_remaining;
279 			if( flipx )
280 			{
281 				sx -= tile_screen_width;
282 			}
283 			tile = spritetile16[tile_index++];
284 			if( (tile&0x8000)==0 )
285 			{
286 				/*z*/drawgfxzoom(bitmap,Machine->gfx[mGfxC355],
287 					mpCodeToTile(tile) + offset,
288 					color,
289 					flipx,flipy,
290 					sx,sy,
291 					&clip,
292 					TRANSPARENCY_PEN,0xff,
293 					zoomx, zoomy/*, zpos*/ );
294 			}
295 			if( !flipx )
296 			{
297 				sx += tile_screen_width;
298 			}
299 			screen_width_remaining -= tile_screen_width;
300 			source_width_remaining -= 16;
301 		} /* next col */
302 		if( !flipy )
303 		{
304 			sy += tile_screen_height;
305 		}
306 		screen_height_remaining -= tile_screen_height;
307 		source_height_remaining -= 16;
308 	} /* next row */
309 } /* draw_spriteC355 */
310 
311 
DefaultCodeToTile(int code)312 static int DefaultCodeToTile( int code )
313 {
314 	return code;
315 }
316 
namco_obj_init(int gfxbank,int palXOR,int (* codeToTile)(int code))317 void namco_obj_init( int gfxbank, int palXOR, int (*codeToTile)( int code ) )
318 {
319 	mGfxC355 = gfxbank;
320 	mPalXOR = palXOR;
321 	if( codeToTile )
322 	{
323 		mpCodeToTile = codeToTile;
324 	}
325 	else
326 	{
327 		mpCodeToTile = DefaultCodeToTile;
328 	}
329 	spriteram16 = auto_malloc(0x14200);
330 	memset( mSpritePos,0x00,sizeof(mSpritePos) );
331 } /* namcosC355_init */
332 
333 static void
DrawObjectList(struct mame_bitmap * bitmap,const struct rectangle * cliprect,int pri,const data16_t * pSpriteList16,const data16_t * pSpriteTable,int n)334 DrawObjectList(
335 		struct mame_bitmap *bitmap,
336 		const struct rectangle *cliprect,
337 		int pri,
338 		const data16_t *pSpriteList16,
339 		const data16_t *pSpriteTable,
340 		int n )
341 {
342 	data16_t which;
343 	int i;
344 	int count = 0;
345 	/* count the sprites */
346 	for( i=0; i<256; i++ )
347 	{
348 		which = pSpriteList16[i];
349 		count++;
350 		if( which&0x100 ) break;
351 	}
352 	/* draw the sprites */
353 	for( i=0; i<count; i++ )
354 	{
355 		which = pSpriteList16[i];
356 		draw_spriteC355( n, bitmap, cliprect, &pSpriteTable[(which&0xff)*8], pri, i );
357 	}
358 } /* DrawObjectList */
359 
360 void
namco_obj_draw(struct mame_bitmap * bitmap,const struct rectangle * cliprect,int pri)361 namco_obj_draw( struct mame_bitmap *bitmap, const struct rectangle *cliprect, int pri )
362 {
363 	DrawObjectList( bitmap,cliprect,pri,&spriteram16[0x02000/2], &spriteram16[0x00000/2],0 );
364 	DrawObjectList( bitmap,cliprect,pri,&spriteram16[0x14000/2], &spriteram16[0x10000/2],1 );
365 } /* namco_obj_draw */
366 
WRITE16_HANDLER(namco_obj16_w)367 WRITE16_HANDLER( namco_obj16_w )
368 {
369 	COMBINE_DATA( &spriteram16[offset] );
370 } /* namco_obj16_w */
371 
READ16_HANDLER(namco_obj16_r)372 READ16_HANDLER( namco_obj16_r )
373 {
374 	return spriteram16[offset];
375 } /* namco_obj16_r */
376 
WRITE32_HANDLER(namco_obj32_w)377 WRITE32_HANDLER( namco_obj32_w )
378 {
379 	data32_t v;
380 	offset *= 2;
381 	v = (spriteram16[offset]<<16)|spriteram16[offset+1];
382 	COMBINE_DATA( &v );
383 	spriteram16[offset] = v>>16;
384 	spriteram16[offset+1] = v&0xffff;
385 } /* namco_obj32_w */
386 
READ32_HANDLER(namco_obj32_r)387 READ32_HANDLER( namco_obj32_r )
388 {
389 	offset *= 2;
390 	return (spriteram16[offset]<<16)|spriteram16[offset+1];
391 } /* namco_obj32_r */
392 
393 /**************************************************************************************************************/
394 
395 /* ROZ abstraction (preliminary)
396  *
397  * Used by:
398  *	Namco NB2 - The Outfoxies, Mach Breakers
399  *	Namco System 2 - Metal Hawk, Lucky and Wild
400  */
401 static data16_t *rozbank16;
402 static data16_t *rozvideoram16;
403 static data16_t *rozcontrol16;
404 static int mRozGfxBank;
405 static int mRozMaskRegion;
406 static struct tilemap *mRozTilemap[2];
407 static int mRozPage[2];		/* base addr for tilemap */
408 
409 /* It looks like the ROZ tilemap attributes also encode
410  * the source size.  Right now, the implementation assumes ROZ
411  * layers are always 128x128 tiles.
412  */
413 static void
roz_get_info(int tile_index,int which)414 roz_get_info( int tile_index,int which )
415 {
416 	data16_t tile;
417 	int bank;
418 	int mangle;
419 	/* when size control is understood, we can simulate it by masking column and row, which will
420 	 * mirror the contents of the ROZ tilemap.
421 	 */
422 	tile = rozvideoram16[mRozPage[which]+tile_index];
423 
424 	switch( namcos2_gametype )
425 	{
426 	case NAMCONB2_MACH_BREAKERS:
427 		bank = nth_byte16( &rozbank16[which*8/2], (tile>>11)&0x7 );
428 		tile = (tile&0x7ff)|(bank*0x800);
429 		mangle = tile;
430 		break;
431 
432 	case NAMCONB2_OUTFOXIES:
433 		bank = nth_byte16( &rozbank16[which*8/2], (tile>>11)&0x7 );
434 		tile = (tile&0x7ff)|(bank*0x800);
435 		mangle = tile&~(0x50);
436 		/* the pixmap index is mangled, the transparency bitmask index is not */
437 		if( tile&0x10 ) mangle |= 0x40;
438 		if( tile&0x40 ) mangle |= 0x10;
439 		break;
440 
441 	case NAMCOS2_LUCKY_AND_WILD:
442 		mangle	= tile&0x01ff;
443 		tile &= 0x3fff;
444 		switch( tile>>9 )
445 		{
446 		case 0x00: mangle |= 0x1c00; break;
447 		case 0x01: mangle |= 0x0800; break;
448 		case 0x02: mangle |= 0x0000; break;
449 
450 		case 0x08: mangle |= 0x1e00; break;
451 		case 0x09: mangle |= 0x0a00; break;
452 		case 0x0a: mangle |= 0x0200; break;
453 
454 		case 0x10: mangle |= 0x2000; break;
455 		case 0x11: mangle |= 0x0c00; break;
456 		case 0x12: mangle |= 0x0400; break;
457 
458 		case 0x18: mangle |= 0x2200; break;
459 		case 0x19: mangle |= 0x0e00; break;
460 		case 0x1a: mangle |= 0x0600; break;
461 		}
462 		break;
463 
464 	case NAMCOS2_METAL_HAWK:
465 	default:
466 		mangle = tile&0x01ff;
467 		if( tile&0x1000 ) mangle |= 0x0200;
468 		if( tile&0x0200 ) mangle |= 0x0400;
469 		if( tile&0x0400 ) mangle |= 0x0800;
470 		if( tile&0x0800 ) mangle |= 0x1000;
471 		break;
472 	}
473 	SET_TILE_INFO( mRozGfxBank,mangle,0/*color*/,0 );
474 	tile_info.mask_data = 32*tile + (UINT8 *)memory_region( mRozMaskRegion );
475 } /* roz_get_info */
476 
roz_get_info0(int tile_index)477 static void roz_get_info0( int tile_index )
478 {
479 	roz_get_info( tile_index,0 );
480 }
roz_get_info1(int tile_index)481 static void roz_get_info1( int tile_index )
482 {
483 	roz_get_info( tile_index,1 );
484 }
485 
486 int
namco_roz_init(int gfxbank,int maskregion)487 namco_roz_init( int gfxbank, int maskregion )
488 {
489 	/* allocate both ROZ layers */
490 	int i;
491 	static void (*roz_info[2])(int tile_index) = { roz_get_info0, roz_get_info1 };
492 
493 	mRozGfxBank = gfxbank;
494 	mRozMaskRegion = maskregion;
495 
496 	rozbank16 = auto_malloc(0x10);
497 	rozvideoram16 = auto_malloc(0x20000);
498 	rozcontrol16 = auto_malloc(0x20);
499 	if( rozbank16 && rozvideoram16 && rozcontrol16 )
500 	{
501 		for( i=0; i<2; i++ )
502 		{
503 			mRozPage[i] = -1;
504 			mRozTilemap[i] = tilemap_create( roz_info[i], tilemap_scan_rows,
505 				TILEMAP_BITMASK,16,16,128,128 );
506 
507 			if( mRozTilemap[i] == NULL ) return 1; /* error */
508 		}
509 		return 0;
510 	}
511 	return -1;
512 } /* namco_roz_init */
513 
514 /**
515  * ROZ control attributes:
516  *
517  * unk  attr   xx   xy   yx   yy   x0   y0
518  *
519  * Lucky & Wild:
520  * 0000 080e 2100 0000 0000 0100 38e0 fde0	0:badge
521  * 1000 084e 00fe 0000 0000 00fe f9f6 fd96	0:zooming car
522  * 0000 080e 1100 0000 0000 0000 26d0 0450	0:"LUCKY & WILD"
523  * 0000 03bf 0100 0000 0000 0100 fde0 7fe0	1:talking heads
524  * 1000 080a 0100 0000 0000 0100 fde0 ffe0	0:player select
525  *
526  * Outfoxies:
527  * 1000 0211 02ff 02ff 0000 0000 02ff f97b ffa7 (tv)
528  * 0000 0211 00ff 0000 0000 0000 00ff fddb 0de7 (char select)
529  * 1000 0271 0101 0000 0000 0101 0fc4 56d7 (stage)
530  * 0000 0252 0101 4000 0000 0101 0fc4 d6d7 (stage)
531  *
532  * Mach Breakers:
533  * 1000 0871 4100 0000 0000 0100 f4d0 f8e0
534  * 0000 0210 0100 0000 0000 0100 40d0 38e0
535  * 0000 0000 0100 0000 0000 0100 f4d0 f8e0 // charsel (512x512)
536  * 0000 0020 0100 0000 0000 0100 f4d0 f8e0 // map
537  */
namco_roz_draw(struct mame_bitmap * bitmap,const struct rectangle * cliprect,int pri)538 void namco_roz_draw(
539 	struct mame_bitmap *bitmap,
540 	const struct rectangle *cliprect,
541 	int pri )
542 {
543 	const int xoffset = 38-2,yoffset = 3;
544 	int which;
545 	for( which=0; which<2; which++ )
546 	{
547 		const data16_t *pSource = &rozcontrol16[which*8];
548 		data16_t attrs = pSource[1];
549 		if( (attrs&0x8000)==0 )
550 		{ /* layer is enabled */
551 			int color = attrs&0xf;
552 			int page;
553 			int roz_pri;
554 			/*int roz_size = 128;*/
555 			switch( namcos2_gametype )
556 			{
557 			case NAMCONB2_OUTFOXIES:
558 				roz_pri = 4-which; /* ? */
559 				page = pSource[3]&0x4000;
560 				if( attrs == 0x0211 ) roz_pri = 1; /* hack */
561 				break;
562 
563 			case NAMCONB2_MACH_BREAKERS:
564 				roz_pri = 4-which; /* ? */
565 				page = (pSource[2]&0x6000)*2;
566 				break;
567 
568 			case NAMCOS2_LUCKY_AND_WILD:
569 				roz_pri = 5-which; /* ? */
570 				page = (attrs&0x0800)?0:0x4000; /* ? */
571 				break;
572 
573 			case NAMCOS2_METAL_HAWK:
574 			default:
575 				roz_pri = which; /* ? */
576 				page = pSource[3]&0x4000;
577 				break;
578 			}
579 			if( roz_pri==pri )
580 			{
581 				int bDirty;
582 				UINT32 startx,starty;
583 				int incxx,incxy,incyx,incyy;
584 				data16_t temp;
585 
586 				temp = pSource[2];
587 				if( temp&0x8000 ) temp |= 0xf000; else temp&=0x0fff; /* sign extend */
588 				incxx = (INT16)temp;
589 
590 				temp = pSource[3];
591 				if( temp&0x8000 ) temp |= 0xf000; else temp&=0x0fff; /* sign extend */
592 				incxy =  (INT16)temp;
593 
594 				temp = pSource[4];
595 				if( temp&0x8000 ) temp |= 0xf000; else temp&=0x0fff; /* sign extend */
596 				incyx =  (INT16)temp;
597 
598 				incyy =  (INT16)pSource[5];
599 				startx = (INT16)pSource[6];
600 				starty = (INT16)pSource[7];
601 
602 				startx <<= 4;
603 				starty <<= 4;
604 				startx += xoffset * incxx + yoffset * incyx;
605 				starty += xoffset * incxy + yoffset * incyy;
606 
607 				bDirty = 0;
608 				tilemap_set_palette_offset(mRozTilemap[which],color*256);
609 				if( mRozPage[which] != page )
610 				{
611 					mRozPage[which] = page;
612 					bDirty = 1;
613 				}
614 				if( bDirty )
615 				{
616 					tilemap_mark_all_tiles_dirty( mRozTilemap[which] );
617 				}
618 
619 				tilemap_draw_roz(bitmap,cliprect,mRozTilemap[which],
620 					startx << 8,
621 					starty << 8,
622 					incxx << 8,
623 					incxy << 8,
624 					incyx << 8,
625 					incyy << 8,
626 					1,	/* copy with wraparound */
627 					0,0);
628 			}
629 		}
630 	}
631 } /* namco_roz_draw */
632 
READ16_HANDLER(namco_rozcontrol16_r)633 READ16_HANDLER( namco_rozcontrol16_r )
634 {
635 	return rozcontrol16[offset];
636 }
637 
WRITE16_HANDLER(namco_rozcontrol16_w)638 WRITE16_HANDLER( namco_rozcontrol16_w )
639 {
640 	COMBINE_DATA( &rozcontrol16[offset] );
641 }
642 
READ16_HANDLER(namco_rozbank16_r)643 READ16_HANDLER( namco_rozbank16_r )
644 {
645 	return rozbank16[offset];
646 }
647 
WRITE16_HANDLER(namco_rozbank16_w)648 WRITE16_HANDLER( namco_rozbank16_w )
649 {
650 	data16_t old_data;
651 
652 	old_data = rozbank16[offset];
653 	COMBINE_DATA( &rozbank16[offset] );
654 	if( rozbank16[offset]!=old_data )
655 	{
656 		tilemap_mark_all_tiles_dirty( mRozTilemap[0] );
657 		tilemap_mark_all_tiles_dirty( mRozTilemap[1] );
658 	}
659 }
660 
writerozvideo(int offset,data16_t data)661 static void writerozvideo( int offset, data16_t data )
662 {
663 	int i;
664 	if( rozvideoram16[offset]!=data )
665 	{
666 		rozvideoram16[offset] = data;
667 		for( i=0; i<2; i++ )
668 		{
669 			if( mRozPage[i]==(offset&0xc000) )
670 			{
671 				tilemap_mark_tile_dirty( mRozTilemap[i], offset&0x3fff );
672 			}
673 		}
674 	}
675 }
676 
READ16_HANDLER(namco_rozvideoram16_r)677 READ16_HANDLER( namco_rozvideoram16_r )
678 {
679 	return rozvideoram16[offset];
680 }
681 
WRITE16_HANDLER(namco_rozvideoram16_w)682 WRITE16_HANDLER( namco_rozvideoram16_w )
683 {
684 	data16_t v;
685 
686 	v = rozvideoram16[offset];
687 	COMBINE_DATA( &v );
688 	writerozvideo( offset, v );
689 }
690 
READ32_HANDLER(namco_rozcontrol32_r)691 READ32_HANDLER( namco_rozcontrol32_r )
692 {
693 	offset *= 2;
694 	return (rozcontrol16[offset]<<16)|rozcontrol16[offset+1];
695 }
696 
WRITE32_HANDLER(namco_rozcontrol32_w)697 WRITE32_HANDLER( namco_rozcontrol32_w )
698 {
699 	data32_t v;
700 	offset *=2;
701 	v = (rozcontrol16[offset]<<16)|rozcontrol16[offset+1];
702 	COMBINE_DATA(&v);
703 	rozcontrol16[offset] = v>>16;
704 	rozcontrol16[offset+1] = v&0xffff;
705 }
706 
READ32_HANDLER(namco_rozbank32_r)707 READ32_HANDLER( namco_rozbank32_r )
708 {
709 	offset *= 2;
710 	return (rozbank16[offset]<<16)|rozbank16[offset+1];
711 }
712 
WRITE32_HANDLER(namco_rozbank32_w)713 WRITE32_HANDLER( namco_rozbank32_w )
714 {
715 	data32_t v;
716 	offset *=2;
717 	v = (rozbank16[offset]<<16)|rozbank16[offset+1];
718 	COMBINE_DATA(&v);
719 	rozbank16[offset] = v>>16;
720 	rozbank16[offset+1] = v&0xffff;
721 }
722 
READ32_HANDLER(namco_rozvideoram32_r)723 READ32_HANDLER( namco_rozvideoram32_r )
724 {
725 	offset *= 2;
726 	return (rozvideoram16[offset]<<16)|rozvideoram16[offset+1];
727 }
728 
WRITE32_HANDLER(namco_rozvideoram32_w)729 WRITE32_HANDLER( namco_rozvideoram32_w )
730 {
731 	data32_t v;
732 	offset *= 2;
733 	v = (rozvideoram16[offset]<<16)|rozvideoram16[offset+1];
734 	COMBINE_DATA( &v );
735 	writerozvideo(offset,v>>16);
736 	writerozvideo(offset+1,v&0xffff);
737 }
738 
739 /**************************************************************************************************************/
740 /*
741 	Land Line Buffer
742 	Land Generator
743 		0xf,0x7,0xe,0x6,0xd,0x5,0xc,0x4,
744 		0xb,0x3,0xa,0x2,0x9,0x1,0x8,0x0
745 
746 */
747 
748 /* Preliminary!  The road circuitry is identical for all the driving games.
749  *
750  * There are several chunks of RAM
751  *
752  *	Road Tilemap:
753  *		0x00000..0x0ffff	64x512 tilemap
754  *
755  *	Road Tiles:
756  *		0x10000..0x1f9ff	16x16x2bpp tiles
757  *
758  *
759  *	Line Attributes:
760  *
761  *		0x1fa00..0x1fbdf	xxx- ---- ---- ----		priority
762  *							---- xxxx xxxx xxxx		xscroll
763  *
764  *		0x1fbfe				horizontal adjust?
765  *							0x0017
766  *							0x0018 (Final Lap3)
767  *
768  *		0x1fc00..0x1fddf	selects line in source bitmap
769  *		0x1fdfe				yscroll
770  *
771  *		0x1fe00..0x1ffdf	---- --xx xxxx xxxx		zoomx
772  *		0x1fffd				always 0xffff 0xffff?
773  */
774 static data16_t *mpRoadRAM; /* at 0x880000 in Final Lap; at 0xa00000 in Lucky&Wild */
775 static unsigned char *mpRoadDirty;
776 static int mbRoadSomethingIsDirty;
777 static int mRoadGfxBank;
778 static struct tilemap *mpRoadTilemap;
779 static pen_t mRoadTransparentColor;
780 static int mbRoadNeedTransparent;
781 
782 #define ROAD_COLS			64
783 #define ROAD_ROWS			512
784 #define ROAD_TILE_SIZE		16
785 #define ROAD_TILEMAP_WIDTH	(ROAD_TILE_SIZE*ROAD_COLS)
786 #define ROAD_TILEMAP_HEIGHT (ROAD_TILE_SIZE*ROAD_ROWS)
787 
788 #define ROAD_TILE_COUNT_MAX	(0xfa00/0x40) /* 0x3e8 */
789 #define WORDS_PER_ROAD_TILE (0x40/2)
790 
791 static struct GfxLayout RoadTileLayout =
792 {
793 	ROAD_TILE_SIZE,
794 	ROAD_TILE_SIZE,
795 	ROAD_TILE_COUNT_MAX,
796 	2,
797 	{
798 #ifdef MSB_FIRST
799 		0,8
800 #else
801 		8,0
802 #endif
803 	},
804 	{/* x offset */
805 		0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
806 		0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
807 	},
808 	{/* y offset */
809 		0x000,0x020,0x040,0x060,0x080,0x0a0,0x0c0,0x0e0,
810 		0x100,0x120,0x140,0x160,0x180,0x1a0,0x1c0,0x1e0
811 	},
812 	0x200, /* offset to next tile */
813 };
814 
get_road_info(int tile_index)815 void get_road_info( int tile_index )
816 {
817 	data16_t data = mpRoadRAM[tile_index];
818 	/* ------xx xxxxxxxx tile number
819 	 * xxxxxx-- -------- palette select
820 	 */
821 	int tile = (data&0x3ff);
822 	int color = (data>>10);
823 
824 	SET_TILE_INFO( mRoadGfxBank, tile, color , 0 )
825 } /* get_road_info */
826 
READ16_HANDLER(namco_road16_r)827 READ16_HANDLER( namco_road16_r )
828 {
829 	return mpRoadRAM[offset];
830 }
831 
WRITE16_HANDLER(namco_road16_w)832 WRITE16_HANDLER( namco_road16_w )
833 {
834 	COMBINE_DATA( &mpRoadRAM[offset] );
835 	if( offset<0x10000/2 )
836 	{
837 		tilemap_mark_tile_dirty( mpRoadTilemap, offset );
838 	}
839 	else
840 	{
841 		offset -= 0x10000/2;
842 		if( offset<ROAD_TILE_COUNT_MAX*WORDS_PER_ROAD_TILE )
843 		{
844 			mpRoadDirty[offset/WORDS_PER_ROAD_TILE] = 1;
845 			mbRoadSomethingIsDirty = 1;
846 		}
847 	}
848 }
849 
850 static void
UpdateRoad(void)851 UpdateRoad( void )
852 {
853 	int i;
854 	if( mbRoadSomethingIsDirty )
855 	{
856 		for( i=0; i<ROAD_TILE_COUNT_MAX; i++ )
857 		{
858 			if( mpRoadDirty[i] )
859 			{
860 				decodechar(
861 					Machine->gfx[mRoadGfxBank],
862 					i,
863 					0x10000+(UINT8 *)mpRoadRAM,
864 					&RoadTileLayout );
865 				mpRoadDirty[i] = 0;
866 			}
867 		}
868 		tilemap_mark_all_tiles_dirty( mpRoadTilemap );
869 		mbRoadSomethingIsDirty = 0;
870 	}
871 }
872 
873 static void
RoadMarkAllDirty(void)874 RoadMarkAllDirty(void)
875 {
876 	memset( mpRoadDirty,0x01,ROAD_TILE_COUNT_MAX );
877 	mbRoadSomethingIsDirty = 1;
878 }
879 
880 int
namco_road_init(int gfxbank)881 namco_road_init( int gfxbank )
882 {
883 	mbRoadNeedTransparent = 0;
884 	mRoadGfxBank = gfxbank;
885 	mpRoadDirty = auto_malloc(ROAD_TILE_COUNT_MAX);
886 	if( mpRoadDirty )
887 	{
888 		memset( mpRoadDirty,0x00,ROAD_TILE_COUNT_MAX );
889 		mbRoadSomethingIsDirty = 0;
890 		mpRoadRAM = auto_malloc(0x20000);
891 		if( mpRoadRAM )
892 		{
893 			struct GfxElement *pGfx = decodegfx( 0x10000+(UINT8 *)mpRoadRAM, &RoadTileLayout );
894 			if( pGfx )
895 			{
896 				pGfx->colortable = &Machine->remapped_colortable[0xf00];
897 				pGfx->total_colors = 0x3f;
898 
899 				Machine->gfx[gfxbank] = pGfx;
900 				mpRoadTilemap = tilemap_create(
901 					get_road_info,tilemap_scan_rows,
902 					TILEMAP_OPAQUE,
903 					ROAD_TILE_SIZE,ROAD_TILE_SIZE,
904 					ROAD_COLS,ROAD_ROWS);
905 
906 				if( mpRoadTilemap )
907 				{
908 					state_save_register_UINT8 ("namco_road", 0, "RoadDirty", mpRoadDirty, ROAD_TILE_COUNT_MAX);
909 					state_save_register_UINT16("namco_road", 0, "RoadRAM",   mpRoadRAM,   0x20000 / 2);
910 					state_save_register_func_postload(RoadMarkAllDirty);
911 
912 					return 0;
913 				}
914 			}
915 		}
916 	}
917 	return -1;
918 } /* namco_road_init */
919 
920 void
namco_road_set_transparent_color(pen_t pen)921 namco_road_set_transparent_color(pen_t pen)
922 {
923 	mbRoadNeedTransparent = 1;
924 	mRoadTransparentColor = pen;
925 }
926 
927 void
namco_road_draw(struct mame_bitmap * bitmap,const struct rectangle * cliprect,int pri)928 namco_road_draw( struct mame_bitmap *bitmap, const struct rectangle *cliprect, int pri )
929 {
930 	struct mame_bitmap *pSourceBitmap;
931 	unsigned yscroll;
932 	int i;
933 
934 	UpdateRoad();
935 
936 	pSourceBitmap = tilemap_get_pixmap(mpRoadTilemap);
937 	yscroll = mpRoadRAM[0x1fdfe/2];
938 
939 	for( i=cliprect->min_y; i<=cliprect->max_y; i++ )
940 	{
941 		UINT16 *pDest = bitmap->line[i];
942 		int screenx	= mpRoadRAM[0x1fa00/2+i+15];
943 
944 		if( pri == ((screenx&0xe000)>>13) )
945 		{
946 			unsigned zoomx	= mpRoadRAM[0x1fe00/2+i+15]&0x3ff;
947 			if( zoomx )
948 			{
949 				unsigned sourcey = mpRoadRAM[0x1fc00/2+i+15]+yscroll;
950 				const UINT16 *pSourceGfx = pSourceBitmap->line[sourcey&(ROAD_TILEMAP_HEIGHT-1)];
951 				unsigned dsourcex = (ROAD_TILEMAP_WIDTH<<16)/zoomx;
952 				unsigned sourcex = 0;
953 				int numpixels = (44*ROAD_TILE_SIZE<<16)/dsourcex;
954 
955 				/* draw this scanline */
956 				screenx &= 0x0fff; /* mask off priority bits */
957 				if( screenx&0x0800 )
958 				{
959 					/* sign extend */
960 					screenx -= 0x1000;
961 				}
962 
963 				/* adjust the horizontal placement */
964 				screenx -= 64; /*needs adjustment to left*/
965 
966 				if( screenx<0 )
967 				{ /* crop left */
968 					numpixels += screenx;
969 					sourcex -= dsourcex*screenx;
970 					screenx = 0;
971 				}
972 
973 				if( screenx + numpixels > bitmap->width )
974 				{ /* crop right */
975 					numpixels = bitmap->width - screenx;
976 				}
977 
978 				/* BUT: support transparent color for Thunder Ceptor */
979 				if (mbRoadNeedTransparent)
980 				{
981 					while( numpixels-- > 0 )
982 					{
983 						int pen = pSourceGfx[sourcex>>16];
984 						/* TBA: work out palette mapping for Final Lap, Suzuka */
985 						if (pen != mRoadTransparentColor)
986 							pDest[screenx] = pen;
987 						screenx++;
988 						sourcex += dsourcex;
989 					}
990 				}
991 				else
992 				{
993 					while( numpixels-- > 0 )
994 					{
995 						int pen = pSourceGfx[sourcex>>16];
996 						/* TBA: work out palette mapping for Final Lap, Suzuka */
997 						pDest[screenx++] = pen;
998 						sourcex += dsourcex;
999 					}
1000 				}
1001 			}
1002 		}
1003 	}
1004 } /* namco_road_draw */
1005