1 /*
2 
3 	Konami Twin16 Hardware - Video
4 
5 	TODO:
6 
7 	- convert background to tilemap
8 	- clean up sprite drawing
9 	- sprite-background priorities
10 	- rogue sprites in devilw
11 	- corrupt sprites in vulcan end sequence
12 	- sprite lag in devilw
13 	- sprite Y axis lag in vulcan
14 	- add shadow sprites (alpha blending) to sprites in at least devilw
15 
16 */
17 
18 #include "driver.h"
19 #include "vidhrdw/generic.h"
20 
21 extern UINT16 twin16_custom_vidhrdw;
22 extern UINT16 *twin16_gfx_rom;
23 extern UINT16 *twin16_videoram2;
24 extern UINT16 *twin16_sprite_gfx_ram;
25 extern UINT16 *twin16_tile_gfx_ram;
26 extern int twin16_spriteram_process_enable( void );
27 
28 static int need_process_spriteram;
29 static UINT16 gfx_bank;
30 static UINT16 scrollx[3], scrolly[3];
31 static UINT16 video_register;
32 
33 enum {
34 	TWIN16_SCREEN_FLIPY		= 0x01,	/* ? breaks devils world text layer */
35 	TWIN16_SCREEN_FLIPX		= 0x02,	/* confirmed: Hard Puncher Intro */
36 	TWIN16_UNKNOWN1			= 0x04,	/* ?Hard Puncher uses this */
37 	TWIN16_PLANE_ORDER		= 0x08,	/* confirmed: Devil Worlds */
38 	TWIN16_TILE_FLIPY		= 0x20	/* confirmed? Vulcan Venture */
39 };
40 
41 static struct tilemap *fg_tilemap;
42 
WRITE16_HANDLER(twin16_videoram2_w)43 WRITE16_HANDLER( twin16_videoram2_w )
44 {
45 	int oldword = twin16_videoram2[offset];
46 
47 	COMBINE_DATA(&twin16_videoram2[offset]);
48 
49 	if (oldword != twin16_videoram2[offset])
50 	{
51 		tilemap_mark_tile_dirty(fg_tilemap, offset);
52 	}
53 }
54 
WRITE16_HANDLER(twin16_paletteram_word_w)55 WRITE16_HANDLER( twin16_paletteram_word_w )
56 { // identical to tmnt_paletteram_w
57 	int r, g, b;
58 
59 	COMBINE_DATA(paletteram16 + offset);
60 	offset &= ~1;
61 
62 	data = ((paletteram16[offset] & 0xff) << 8) | (paletteram16[offset + 1] & 0xff);
63 
64 	r = (data >>  0) & 0x1f;
65 	g = (data >>  5) & 0x1f;
66 	b = (data >> 10) & 0x1f;
67 
68 	r = (r << 3) | (r >> 2);
69 	g = (g << 3) | (g >> 2);
70 	b = (b << 3) | (b >> 2);
71 
72 	palette_set_color(offset / 2, r, g, b);
73 }
74 
WRITE16_HANDLER(fround_gfx_bank_w)75 WRITE16_HANDLER( fround_gfx_bank_w )
76 {
77 	COMBINE_DATA(&gfx_bank);
78 }
79 
WRITE16_HANDLER(twin16_video_register_w)80 WRITE16_HANDLER( twin16_video_register_w )
81 {
82 	switch (offset) {
83 	case 0:
84 		COMBINE_DATA( &video_register );
85 
86 		flip_screen_x_set(video_register & TWIN16_SCREEN_FLIPX);
87 
88 		if (twin16_custom_vidhrdw)
89 			flip_screen_y_set(video_register & TWIN16_SCREEN_FLIPY);
90 		else
91 			flip_screen_y_set(~video_register & TWIN16_SCREEN_FLIPY);
92 
93 		break;
94 
95 	case 1: COMBINE_DATA( &scrollx[0] ); break;
96 	case 2: COMBINE_DATA( &scrolly[0] ); break;
97 	case 3: COMBINE_DATA( &scrollx[1] ); break;
98 	case 4: COMBINE_DATA( &scrolly[1] ); break;
99 	case 5: COMBINE_DATA( &scrollx[2] ); break;
100 	case 6: COMBINE_DATA( &scrolly[2] ); break;
101 
102 	default:
103 		logerror("unknown video_register write:%d", data );
104 		break;
105 	}
106 }
107 
draw_sprite(struct mame_bitmap * bitmap,const UINT16 * pen_data,const pen_t * pal_data,int xpos,int ypos,int width,int height,int flipx,int flipy,int pri)108 static void draw_sprite( /* slow slow slow, but it's ok for now */
109 	struct mame_bitmap *bitmap,
110 	const UINT16 *pen_data,
111 	const pen_t *pal_data,
112 	int xpos, int ypos,
113 	int width, int height,
114 	int flipx, int flipy, int pri )
115 {
116 
117 	int x,y,pval;
118 	if( xpos>=320 ) xpos -= 65536;
119 	if( ypos>=256 ) ypos -= 65536;
120 
121 	if (pri) pval=2; else pval=8;
122 
123 	{
124 		{
125 			for( y=0; y<height; y++ )
126 			{
127 				int sy = (flipy)?(ypos+height-1-y):(ypos+y);
128 				if( sy>=16 && sy<256-16 )
129 				{
130 					UINT16 *dest = (UINT16 *)bitmap->line[sy];
131 					UINT8 *pdest = (UINT8 *)priority_bitmap->line[sy];
132 
133 					for( x=0; x<width; x++ )
134 					{
135 						int sx = (flipx)?(xpos+width-1-x):(xpos+x);
136 						if( sx>=0 && sx<320 )
137 						{
138 							UINT16 pen = pen_data[x/4];
139 							switch( x%4 )
140 							{
141 							case 0: pen = pen>>12; break;
142 							case 1: pen = (pen>>8)&0xf; break;
143 							case 2: pen = (pen>>4)&0xf; break;
144 							case 3: pen = pen&0xf; break;
145 							}
146 							if( pen && pdest[sx]<pval) { dest[sx] = pal_data[pen]; pdest[sx]|=0x10; }
147 						}
148 					}
149 				}
150 				pen_data += width/4;
151 			}
152 		}
153 	}
154 }
155 
twin16_spriteram_process(void)156 void twin16_spriteram_process( void )
157 {
158 	UINT16 dx = scrollx[0];
159 	UINT16 dy = scrolly[0];
160 
161 	const UINT16 *source = &spriteram16[0x0000];
162 	const UINT16 *finish = &spriteram16[0x1800];
163 
164 	memset( &spriteram16[0x1800], 0, 0x800 );
165 	while( source<finish ){
166 		UINT16 priority = source[0];
167 		if( priority & 0x8000 ){
168 			UINT16 *dest = &spriteram16[0x1800 + 4*(priority&0xff)];
169 
170 			INT32 xpos = (0x10000*source[4])|source[5];
171 			INT32 ypos = (0x10000*source[6])|source[7];
172 
173 			UINT16 attributes = source[2]&0x03ff; /* scale,size,color */
174 			if( priority & 0x0200 ) attributes |= 0x4000;
175 			/* Todo:  priority & 0x0100 is also used */
176 			attributes |= 0x8000;
177 
178 			dest[0] = source[3]; /* gfx data */
179 			dest[1] = ((xpos>>8) - dx)&0xffff;
180 			dest[2] = ((ypos>>8) - dy)&0xffff;
181 			dest[3] = attributes;
182 		}
183 		source += 0x50/2;
184 	}
185 	need_process_spriteram = 0;
186 }
187 
188 /*
189  * Sprite Format
190  * ----------------------------------
191  *
192  * Word | Bit(s)           | Use
193  * -----+-fedcba9876543210-+----------------
194  *   0  | --xxxxxxxxxxxxxx | code
195  * -----+------------------+
196  *   1  | -------xxxxxxxxx | ypos
197  * -----+------------------+
198  *   2  | -------xxxxxxxxx | xpos
199  * -----+------------------+
200  *   3  | x--------------- | enble
201  *   3  | -x-------------- | priority?
202  *   3  | ------x--------- | yflip?
203  *   3  | -------x-------- | xflip
204  *   3  | --------xx------ | height
205  *   3  | ----------xx---- | width
206  *   3  | ------------xxxx | color
207 
208 shadow bit?
209 
210  */
211 
draw_sprites(struct mame_bitmap * bitmap)212 static void draw_sprites( struct mame_bitmap *bitmap)
213 {
214 	int count = 0;
215 
216 	const UINT16 *source = 0x1800+buffered_spriteram16 + 0x800 -4;
217 	const UINT16 *finish = 0x1800+buffered_spriteram16;
218 
219 	while( source>=finish ){
220 		UINT16 attributes = source[3];
221 		UINT16 code = source[0];
222 
223 		if( code!=0xffff && (attributes&0x8000)){
224 			int xpos = source[1];
225 			int ypos = source[2];
226 
227 			const pen_t *pal_data = Machine->pens+((attributes&0xf)+0x10)*16;
228 			int height	= 16<<((attributes>>6)&0x3);
229 			int width	= 16<<((attributes>>4)&0x3);
230 			const UINT16 *pen_data = 0;
231 			int flipy = attributes&0x0200;
232 			int flipx = attributes&0x0100;
233 
234 			if( twin16_custom_vidhrdw == 1 ){
235 				pen_data = twin16_gfx_rom + 0x80000;
236 			}
237 			else {
238 				switch( (code>>12)&0x3 ){ /* bank select */
239 					case 0:
240 					pen_data = twin16_gfx_rom;
241 					break;
242 
243 					case 1:
244 					pen_data = twin16_gfx_rom + 0x40000;
245 					break;
246 
247 					case 2:
248 					pen_data = twin16_gfx_rom + 0x80000;
249 					if( code&0x4000 ) pen_data += 0x40000;
250 					break;
251 
252 					case 3:
253 					pen_data = twin16_sprite_gfx_ram;
254 					break;
255 				}
256 				code &= 0xfff;
257 			}
258 			pen_data += code*0x40;
259 
260 			if( video_register&TWIN16_SCREEN_FLIPY ){
261 				if (ypos>65000) ypos=ypos-65536; /* Bit hacky */
262 				ypos = 256-ypos-height;
263 				flipy = !flipy;
264 			}
265 			if( video_register&TWIN16_SCREEN_FLIPX ){
266 				if (xpos>65000) xpos=xpos-65536; /* Bit hacky */
267 				xpos = 320-xpos-width;
268 				flipx = !flipx;
269 			}
270 
271 			//if( sprite_which==count || !keyboard_pressed( KEYCODE_B ) )
272 			draw_sprite( bitmap, pen_data, pal_data, xpos, ypos, width, height, flipx, flipy, (attributes&0x4000) );
273 		}
274 
275 		count++;
276 		source -= 4;
277 	}
278 }
279 
draw_layer(struct mame_bitmap * bitmap,int opaque)280 static void draw_layer( struct mame_bitmap *bitmap, int opaque ){
281 	const UINT16 *gfx_base;
282 	const UINT16 *source = videoram16;
283 	int i, y1, y2, yd;
284 	int bank_table[4];
285 	int dx, dy, palette;
286 	int tile_flipx = 0; // video_register&TWIN16_TILE_FLIPX;
287 	int tile_flipy = video_register&TWIN16_TILE_FLIPY;
288 
289 	if( ((video_register&TWIN16_PLANE_ORDER)?1:0) != opaque ){
290 		source += 0x1000;
291 		dx = scrollx[2];
292 		dy = scrolly[2];
293 		palette = 1;
294 	}
295 	else {
296 		source += 0x0000;
297 		dx = scrollx[1];
298 		dy = scrolly[1];
299 		palette = 0;
300 	}
301 
302 	if( twin16_custom_vidhrdw == 1 ){
303 		gfx_base = twin16_gfx_rom;
304 		bank_table[3] = (gfx_bank>>(4*3))&0xf;
305 		bank_table[2] = (gfx_bank>>(4*2))&0xf;
306 		bank_table[1] = (gfx_bank>>(4*1))&0xf;
307 		bank_table[0] = (gfx_bank>>(4*0))&0xf;
308 	}
309 	else {
310 		gfx_base = twin16_tile_gfx_ram;
311 		bank_table[0] = 0;
312 		bank_table[1] = 1;
313 		bank_table[2] = 2;
314 		bank_table[3] = 3;
315 	}
316 
317 	if( video_register&TWIN16_SCREEN_FLIPX ){
318 		dx = 256-dx-64;
319 		tile_flipx = !tile_flipx;
320 	}
321 
322 	if( video_register&TWIN16_SCREEN_FLIPY ){
323 		dy = 256-dy;
324 		tile_flipy = !tile_flipy;
325 	}
326 
327 	if( tile_flipy ){
328 		y1 = 7; y2 = -1; yd = -1;
329 	}
330 	else {
331 		y1 = 0; y2 = 8; yd = 1;
332 	}
333 
334 	for( i=0; i<64*64; i++ ){
335 		int sx = (i%64)*8;
336 		int sy = (i/64)*8;
337 		int xpos,ypos;
338 
339 		if( video_register&TWIN16_SCREEN_FLIPX ) sx = 63*8 - sx;
340 		if( video_register&TWIN16_SCREEN_FLIPY ) sy = 63*8 - sy;
341 
342 		xpos = (sx-dx)&0x1ff;
343 		ypos = (sy-dy)&0x1ff;
344 		if( xpos>=320 ) xpos -= 512;
345 		if( ypos>=256 ) ypos -= 512;
346 
347 		if(  xpos>-8 && ypos>8 && xpos<320 && ypos<256-16 ){
348 			int code = source[i];
349 			/*
350 				xxx-------------	color
351 				---xx-----------	tile bank
352 				-----xxxxxxxxxxx	tile number
353 			*/
354 			const UINT16 *gfx_data = gfx_base + (code&0x7ff)*16 + bank_table[(code>>11)&0x3]*0x8000;
355 			int color = (code>>13);
356 			pen_t *pal_data = Machine->pens + 16*(0x20+color+8*palette);
357 
358 			{
359 				int y;
360 				UINT16 data;
361 				int pen;
362 
363 				if( tile_flipx )
364 				{
365 					if( opaque )
366 					{
367 						{
368 							for( y=y1; y!=y2; y+=yd )
369 							{
370 								UINT16 *dest = ((UINT16 *)bitmap->line[ypos+y])+xpos;
371 								UINT8 *pdest = ((UINT8 *)priority_bitmap->line[ypos+y])+xpos;
372 
373 								data = *gfx_data++;
374 								dest[7] = pal_data[(data>>4*3)&0xf];
375 								dest[6] = pal_data[(data>>4*2)&0xf];
376 								dest[5] = pal_data[(data>>4*1)&0xf];
377 								dest[4] = pal_data[(data>>4*0)&0xf];
378 								data = *gfx_data++;
379 								dest[3] = pal_data[(data>>4*3)&0xf];
380 								dest[2] = pal_data[(data>>4*2)&0xf];
381 								dest[1] = pal_data[(data>>4*1)&0xf];
382 								dest[0] = pal_data[(data>>4*0)&0xf];
383 
384 								pdest[7]|=1;
385 								pdest[6]|=1;
386 								pdest[5]|=1;
387 								pdest[4]|=1;
388 								pdest[3]|=1;
389 								pdest[2]|=1;
390 								pdest[1]|=1;
391 								pdest[0]|=1;
392 							}
393 						}
394 					}
395 					else
396 					{
397 						{
398 							for( y=y1; y!=y2; y+=yd )
399 							{
400 								UINT16 *dest = ((UINT16 *)bitmap->line[ypos+y])+xpos;
401 								UINT8 *pdest = ((UINT8 *)priority_bitmap->line[ypos+y])+xpos;
402 
403 								data = *gfx_data++;
404 								if( data )
405 								{
406 									pen = (data>>4*3)&0xf; if( pen ) { dest[7] = pal_data[pen]; pdest[7]|=4; }
407 									pen = (data>>4*2)&0xf; if( pen ) { dest[6] = pal_data[pen]; pdest[6]|=4; }
408 									pen = (data>>4*1)&0xf; if( pen ) { dest[5] = pal_data[pen]; pdest[5]|=4; }
409 									pen = (data>>4*0)&0xf; if( pen ) { dest[4] = pal_data[pen]; pdest[4]|=4; }
410 								}
411 								data = *gfx_data++;
412 								if( data )
413 								{
414 									pen = (data>>4*3)&0xf; if( pen ) { dest[3] = pal_data[pen]; pdest[3]|=4; }
415 									pen = (data>>4*2)&0xf; if( pen ) { dest[2] = pal_data[pen]; pdest[2]|=4; }
416 									pen = (data>>4*1)&0xf; if( pen ) { dest[1] = pal_data[pen]; pdest[1]|=4; }
417 									pen = (data>>4*0)&0xf; if( pen ) { dest[0] = pal_data[pen]; pdest[0]|=4; }
418 								}
419 							}
420 						}
421 					}
422 				}
423 				else
424 				{
425 					if( opaque )
426 					{
427 						{
428 							for( y=y1; y!=y2; y+=yd )
429 							{
430 								UINT16 *dest = ((UINT16 *)bitmap->line[ypos+y])+xpos;
431 								UINT8 *pdest = ((UINT8 *)priority_bitmap->line[ypos+y])+xpos;
432 
433 								data = *gfx_data++;
434 								*dest++ = pal_data[(data>>4*3)&0xf];
435 								*dest++ = pal_data[(data>>4*2)&0xf];
436 								*dest++ = pal_data[(data>>4*1)&0xf];
437 								*dest++ = pal_data[(data>>4*0)&0xf];
438 								data = *gfx_data++;
439 								*dest++ = pal_data[(data>>4*3)&0xf];
440 								*dest++ = pal_data[(data>>4*2)&0xf];
441 								*dest++ = pal_data[(data>>4*1)&0xf];
442 								*dest++ = pal_data[(data>>4*0)&0xf];
443 
444 								pdest[7]|=1;
445 								pdest[6]|=1;
446 								pdest[5]|=1;
447 								pdest[4]|=1;
448 								pdest[3]|=1;
449 								pdest[2]|=1;
450 								pdest[1]|=1;
451 								pdest[0]|=1;
452 
453 							}
454 						}
455 					}
456 					else
457 					{
458 						{
459 							for( y=y1; y!=y2; y+=yd )
460 							{
461 								UINT16 *dest = ((UINT16 *)bitmap->line[ypos+y])+xpos;
462 								UINT8 *pdest = ((UINT8 *)priority_bitmap->line[ypos+y])+xpos;
463 
464 								data = *gfx_data++;
465 								if( data )
466 								{
467 									pen = (data>>4*3)&0xf; if( pen ) { dest[0] = pal_data[pen]; pdest[0]|=4; }
468 									pen = (data>>4*2)&0xf; if( pen ) { dest[1] = pal_data[pen]; pdest[1]|=4; }
469 									pen = (data>>4*1)&0xf; if( pen ) { dest[2] = pal_data[pen]; pdest[2]|=4; }
470 									pen = (data>>4*0)&0xf; if( pen ) { dest[3] = pal_data[pen]; pdest[3]|=4; }
471 								}
472 								data = *gfx_data++;
473 								if( data )
474 								{
475 									pen = (data>>4*3)&0xf; if( pen ) { dest[4] = pal_data[pen]; pdest[4]|=4; }
476 									pen = (data>>4*2)&0xf; if( pen ) { dest[5] = pal_data[pen]; pdest[5]|=4; }
477 									pen = (data>>4*1)&0xf; if( pen ) { dest[6] = pal_data[pen]; pdest[6]|=4; }
478 									pen = (data>>4*0)&0xf; if( pen ) { dest[7] = pal_data[pen]; pdest[7]|=4; }
479 								}
480 							}
481 						}
482 					}
483 				}
484 			}
485 		}
486 	}
487 }
488 
get_fg_tile_info(int tile_index)489 static void get_fg_tile_info(int tile_index)
490 {
491 	const UINT16 *source = twin16_videoram2;
492 	int attr = source[tile_index];
493 	int code = attr & 0x1ff;
494 	int color = (attr >> 9) & 0x0f;
495 
496 	SET_TILE_INFO(0, code, color, 0)
497 }
498 
VIDEO_START(twin16)499 VIDEO_START( twin16 )
500 {
501 	fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows_flip_y,
502 		TILEMAP_TRANSPARENT, 8, 8, 64, 32);
503 
504 	if ( !fg_tilemap )
505 		return 1;
506 
507 	tilemap_set_transparent_pen(fg_tilemap, 0);
508 
509 	return 0;
510 }
511 
VIDEO_START(fround)512 VIDEO_START( fround )
513 {
514 	fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
515 		TILEMAP_TRANSPARENT, 8, 8, 64, 32);
516 
517 	if ( !fg_tilemap )
518 		return 1;
519 
520 	tilemap_set_transparent_pen(fg_tilemap, 0);
521 
522 	return 0;
523 }
524 
VIDEO_EOF(twin16)525 VIDEO_EOF( twin16 )
526 {
527 	if( twin16_spriteram_process_enable() && need_process_spriteram )
528 		twin16_spriteram_process();
529 
530 	need_process_spriteram = 1;
531 
532 	buffer_spriteram16_w(0,0,0);
533 }
534 
VIDEO_UPDATE(twin16)535 VIDEO_UPDATE( twin16 )
536 {
537 	fillbitmap(priority_bitmap,0,cliprect);
538 	draw_layer( bitmap,1 );
539 	draw_layer( bitmap,0 );
540 	draw_sprites( bitmap );
541 	tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
542 }
543