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