/*** Video *******************************************************************/ /* see drivers/pgm.c for notes on where improvements can be made */ #include "driver.h" extern UINT16 *pgm_mainram, *pgm_bg_videoram, *pgm_tx_videoram, *pgm_videoregs, *pgm_rowscrollram; static tilemap *pgm_tx_tilemap, *pgm_bg_tilemap; static UINT16 *pgm_spritebufferram; // buffered spriteram static UINT16 *sprite_temp_render; extern UINT8 *pgm_sprite_a_region; /* = memory_region ( REGION_GFX4 ); */ extern size_t pgm_sprite_a_region_allocate; /* Sprites - These are a pain! */ /* this decodes one of the funky sprites to a bitmap so we can draw it more easily -- slow but easier to use*/ static void pgm_prepare_sprite(int wide, int high,int palt, int boffset) { UINT8 *bdata = memory_region ( REGION_GFX4 ); size_t bdatasize = memory_region_length( REGION_GFX4 )-1; UINT8 *adata = pgm_sprite_a_region; size_t adatasize = pgm_sprite_a_region_allocate-1; int xcnt, ycnt; UINT32 aoffset; UINT16 msk; aoffset = (bdata[(boffset+3) & bdatasize] << 24) | (bdata[(boffset+2) & bdatasize] << 16) | (bdata[(boffset+1) & bdatasize] << 8) | (bdata[(boffset+0) & bdatasize] << 0); aoffset = aoffset >> 2; aoffset *= 3; boffset += 4; /* because the first dword is the a data offset */ for (ycnt = 0 ; ycnt < high ; ycnt++) { for (xcnt = 0 ; xcnt < wide ; xcnt++) { int x; msk = (( bdata[(boffset+1) & bdatasize] << 8) |( bdata[(boffset+0) & bdatasize] << 0) ); for (x=0;x<16;x++) { if (!(msk & 0x0001)) { sprite_temp_render[(ycnt*(wide*16))+(xcnt*16+x)] = adata[aoffset & adatasize]+ palt*32; aoffset++; } else { sprite_temp_render[(ycnt*(wide*16))+(xcnt*16+x)] = 0x8000; } msk >>=1; } boffset+=2; } } } static void draw_sprite_line(int wide, UINT16* dest, int xzoom, int xgrow, int yoffset, int flip, int xpos) { int xcnt,xcntdraw; int xzoombit; int xoffset; int xdrawpos = 0; xcnt = 0; xcntdraw = 0; while (xcnt < wide*16) { UINT32 srcdat; if (!(flip&0x01)) xoffset = xcnt; else xoffset = (wide*16)-xcnt-1; srcdat = sprite_temp_render[yoffset+xoffset]; xzoombit = (xzoom >> (xcnt&0x1f))&1; if (xzoombit == 1 && xgrow ==1) { // double this column xdrawpos = xpos + xcntdraw; if (!(srcdat&0x8000)) { if ((xdrawpos >= 0) && (xdrawpos < 448)) dest[xdrawpos] = srcdat; } xcntdraw++; xdrawpos = xpos + xcntdraw; if (!(srcdat&0x8000)) { if ((xdrawpos >= 0) && (xdrawpos < 448)) dest[xdrawpos] = srcdat; } xcntdraw++; } else if (xzoombit ==1 && xgrow ==0) { /* skip this column */ } else //normal column { xdrawpos = xpos + xcntdraw; if (!(srcdat&0x8000)) { if ((xdrawpos >= 0) && (xdrawpos < 448)) dest[xdrawpos] = srcdat; } xcntdraw++; } xcnt++; if (xdrawpos == 448) xcnt = wide*16; } } /* this just loops over our decoded bitmap and puts it on the screen */ static void draw_sprite_new_zoomed(int wide, int high, int xpos, int ypos, int palt, int boffset, int flip, mame_bitmap* bitmap, UINT32 xzoom, int xgrow, UINT32 yzoom, int ygrow ) { int ycnt; int ydrawpos; UINT16 *dest; int yoffset; int ycntdraw; int yzoombit; pgm_prepare_sprite( wide,high, palt, boffset ); /* now draw it */ ycnt = 0; ycntdraw = 0; while (ycnt < high) { yzoombit = (yzoom >> (ycnt&0x1f))&1; if (yzoombit == 1 && ygrow == 1) // double this line { ydrawpos = ypos + ycntdraw; if (!(flip&0x02)) yoffset = (ycnt*(wide*16)); else yoffset = ( (high-ycnt-1)*(wide*16)); if ((ydrawpos >= 0) && (ydrawpos < 224)) { dest = BITMAP_ADDR16(bitmap, ydrawpos, 0); draw_sprite_line(wide, dest, xzoom, xgrow, yoffset, flip, xpos); } ycntdraw++; ydrawpos = ypos + ycntdraw; if (!(flip&0x02)) yoffset = (ycnt*(wide*16)); else yoffset = ( (high-ycnt-1)*(wide*16)); if ((ydrawpos >= 0) && (ydrawpos < 224)) { dest = BITMAP_ADDR16(bitmap, ydrawpos, 0); draw_sprite_line(wide, dest, xzoom, xgrow, yoffset, flip, xpos); } ycntdraw++; if (ydrawpos ==224) ycnt = high; } else if (yzoombit ==1 && ygrow == 0) { /* skip this line */ /* we should process anyway if we don't do the pre-decode.. */ } else /* normal line */ { ydrawpos = ypos + ycntdraw; if (!(flip&0x02)) yoffset = (ycnt*(wide*16)); else yoffset = ( (high-ycnt-1)*(wide*16)); if ((ydrawpos >= 0) && (ydrawpos < 224)) { dest = BITMAP_ADDR16(bitmap, ydrawpos, 0); draw_sprite_line(wide, dest, xzoom, xgrow, yoffset, flip, xpos); } ycntdraw++; if (ydrawpos ==224) ycnt = high; } ycnt++; } } static UINT16 *pgm_sprite_source; static void draw_sprites(int priority, mame_bitmap* bitmap) { /* ZZZZ Zxxx xxxx xxxx zzzz z-yy yyyy yyyy -ffp pppp Pvvv vvvv vvvv vvvv vvvv vvvv wwww wwwh hhhh hhhh */ const UINT16 *finish = pgm_spritebufferram+(0xa00/2); while( pgm_sprite_source> 11; int xgrow = (pgm_sprite_source[0] & 0x8000) >> 15; int yzom = (pgm_sprite_source[1] & 0x7800) >> 11; int ygrow = (pgm_sprite_source[1] & 0x8000) >> 15; int palt = (pgm_sprite_source[2] & 0x1f00) >> 8; int flip = (pgm_sprite_source[2] & 0x6000) >> 13; int boff = ((pgm_sprite_source[2] & 0x007f) << 16) | (pgm_sprite_source[3] & 0xffff); int wide = (pgm_sprite_source[4] & 0x7e00) >> 9; int high = pgm_sprite_source[4] & 0x01ff; int pri = (pgm_sprite_source[2] & 0x0080) >> 7; UINT32 xzoom, yzoom; UINT16* pgm_sprite_zoomtable = &pgm_videoregs[0x1000/2]; if (xgrow) { // xzom = 0xf-xzom; // would make more sense but everything gets zoomed slightly in dragon world 2 ?! xzom = 0x10-xzom; // this way it doesn't but there is a bad line when zooming after the level select? } if (ygrow) { // yzom = 0xf-yzom; // see comment above yzom = 0x10-yzom; } xzoom = (pgm_sprite_zoomtable[xzom*2]<<16)|pgm_sprite_zoomtable[xzom*2+1]; yzoom = (pgm_sprite_zoomtable[yzom*2]<<16)|pgm_sprite_zoomtable[yzom*2+1]; boff *= 2; if (xpos > 0x3ff) xpos -=0x800; if (ypos > 0x1ff) ypos -=0x400; if (high == 0) break; /* is this right? */ if ((priority == 1) && (pri == 0)) break; draw_sprite_new_zoomed(wide, high, xpos, ypos, palt, boff, flip, bitmap, xzoom,xgrow, yzoom,ygrow); pgm_sprite_source += 5; } } /* TX Layer */ WRITE16_HANDLER( pgm_tx_videoram_w ) { pgm_tx_videoram[offset] = data; tilemap_mark_tile_dirty(pgm_tx_tilemap,offset/2); } static TILE_GET_INFO( get_pgm_tx_tilemap_tile_info ) { /* 0x904000 - 0x90ffff is the Text Overlay Ram (pgm_tx_videoram) each tile uses 4 bytes, the tilemap is 64x128? the layer uses 4bpp 8x8 tiles from the 'T' roms colours from 0xA01000 - 0xA017FF scroll registers are at 0xB05000 (Y) and 0xB06000 (X) ---- ---- ffpp ppp- nnnn nnnn nnnn nnnn n = tile number p = palette f = flip */ int tileno,colour,flipyx; //,game; tileno = pgm_tx_videoram[tile_index *2] & 0xffff; colour = (pgm_tx_videoram[tile_index*2+1] & 0x3e) >> 1; flipyx = (pgm_tx_videoram[tile_index*2+1] & 0xc0) >> 6; if (tileno > 0xbfff) { tileno -= 0xc000 ; tileno += 0x20000; } /* not sure about this */ SET_TILE_INFO(0,tileno,colour,TILE_FLIPYX(flipyx)); } /* BG Layer */ WRITE16_HANDLER( pgm_bg_videoram_w ) { pgm_bg_videoram[offset] = data; tilemap_mark_tile_dirty(pgm_bg_tilemap,offset/2); } static TILE_GET_INFO( get_pgm_bg_tilemap_tile_info ) { /* pretty much the same as tx layer */ int tileno,colour,flipyx; tileno = pgm_bg_videoram[tile_index *2] & 0xffff; if (tileno > 0x7ff) tileno+=0x1000; /* Tiles 0x800+ come from the GAME Roms */ colour = (pgm_bg_videoram[tile_index*2+1] & 0x3e) >> 1; flipyx = (pgm_bg_videoram[tile_index*2+1] & 0xc0) >> 6; SET_TILE_INFO(1,tileno,colour,TILE_FLIPYX(flipyx)); } /*** Video - Start / Update ****************************************************/ VIDEO_START( pgm ) { pgm_tx_tilemap= tilemap_create(get_pgm_tx_tilemap_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32); tilemap_set_transparent_pen(pgm_tx_tilemap,15); pgm_bg_tilemap = tilemap_create(get_pgm_bg_tilemap_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 32, 32,64,64); tilemap_set_transparent_pen(pgm_bg_tilemap,31); tilemap_set_scroll_rows(pgm_bg_tilemap,64*32); pgm_spritebufferram = auto_malloc (0xa00); /* we render each sprite to a bitmap then copy the bitmap to screen bitmap with zooming */ /* easier this way because of the funky sprite format */ sprite_temp_render = auto_malloc(0x400*0x200*2); } VIDEO_UPDATE( pgm ) { int y; fillbitmap(bitmap,get_black_pen(machine),&machine->screen[0].visarea); pgm_sprite_source = pgm_spritebufferram; draw_sprites(1, bitmap); tilemap_set_scrolly(pgm_bg_tilemap,0, pgm_videoregs[0x2000/2]); for (y = 0; y < 224; y++) tilemap_set_scrollx(pgm_bg_tilemap,(y+pgm_videoregs[0x2000/2])&0x7ff, pgm_videoregs[0x3000/2]+pgm_rowscrollram[y]); tilemap_draw(bitmap,cliprect,pgm_bg_tilemap,0,0); draw_sprites(0, bitmap); tilemap_set_scrolly(pgm_tx_tilemap,0, pgm_videoregs[0x5000/2]); tilemap_set_scrollx(pgm_tx_tilemap,0, pgm_videoregs[0x6000/2]); // Check tilemap_draw(bitmap,cliprect,pgm_tx_tilemap,0,0); return 0; } VIDEO_EOF( pgm ) { /* first 0xa00 of main ram = sprites, seems to be buffered, DMA? */ memcpy(pgm_spritebufferram,pgm_mainram,0xa00); }