summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/gaelco2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/gaelco2.c')
-rw-r--r--src/mame/video/gaelco2.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/src/mame/video/gaelco2.c b/src/mame/video/gaelco2.c
new file mode 100644
index 00000000000..fb74193927c
--- /dev/null
+++ b/src/mame/video/gaelco2.c
@@ -0,0 +1,510 @@
+/***************************************************************************
+
+ Gaelco Type CG-1V/GAE1 Video Hardware
+
+ Functions to emulate the video hardware of the machine
+
+ CG-1V/GAE1 (Gaelco custom GFX & Sound chip):
+ The CG-1V works with 16x16, 5 bpp gfx.
+ It can handle:
+ * 2 1024x512 tilemaps with linescroll.
+ * 2 banks of 512 sprites (sprites can be grouped up to 16x16).
+ Sprites can make the background darker or brighter.
+
+ Memory map:
+ ===========
+ 0x000000-0x000fff Sprite bank #1 (1)
+ 0x001000-0x001fff Sprite bank #2 (1)
+ 0x002000-0x0023ff Linescroll tilemap #1 (2)
+ 0x002400-0x0027ff Linescroll tilemap #2 (2)
+ Linescroll entries are like this:
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ i | xxxxxx-- -------- | not used?
+ i | ------xx xxxxxxxx | line i x scroll register
+
+ 0x002800-0x002807 Scroll registers
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | xxxxxxx- -------- | not used?
+ 0 | -------x xxxxxxxx | tilemap #1 y scroll register
+ 1 | xxxxxx-- -------- | not used?
+ 1 | ------xx xxxxxxxx | tilemap #1 x scroll register
+ 2 | xxxxxxx- -------- | not used?
+ 2 | -------x xxxxxxxx | tilemap #2 y scroll register
+ 3 | xxxxxx-- -------- | not used?
+ 3 | ------xx xxxxxxxx | tilemap #2 x scroll register
+ 0x002890-0x0028ff Sound registers (3)
+ 0x000000-0x00ffff Video RAM
+ 0x010000-0x011fff Palette (xRRRRRGGGGGBBBBB)
+ 0x018004-0x018007 Video Registers
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | x------- -------- | tilemap #1 linescroll enable
+ 0 | -xxx---- -------- | not used?
+ 0 | ----xxx- -------- | tilemap #1 video RAM bank? (4, 5)
+ 0 | -------x -------- | not used?
+ 0 | -------- x------- | unknown
+ 0 | -------- -x------ | not used?
+ 0 | -------- --xx---- | visible area size? (=0,480x240;=1,384x240;=2,320x240)
+ 0 | -------- ----xxxx | not used?
+ 1 | x------- -------- | tilemap #2 linescroll enable
+ 1 | -xxx---- -------- | not used?
+ 1 | ----xxx- -------- | tilemap #2 video RAM bank? (4, 5)
+ 1 | -------x xxx----- | not used?
+ 1 | -------- ---x---- | sprite bank select
+ 1 | -------- ----xxxx | not used?
+ 0x018008-0x018009 Clear video int?
+
+Notes:
+ (1) See sprite format in the sprite section
+ (2) x scroll register is not taken into account when doing line scroll
+ (3) See sound/gaelco.c for the sound register layout
+ (4) tilemaps use the memory [0x2000*bank .. 0x2000*bank + 0x1fff]
+ (5) See tile format in the tilemap section
+
+Multi monitor notes:
+ Some games have two RGB outputs to allow two or four simultaneous
+ players linking two cabinets (World Rally 2, Touch & Go).
+
+ In 2 monitors mode, the hardware maps one tilemap to a monitor and the
+ other tilemap to the other monitor. The game palette is splitted, using
+ the first half for one monitor and the second half for the other monitor.
+ The sprite RAM has one bit that selects the sprite's target monitor. The
+ sound is splitted too, right channel for cabinet 1 and the left channel
+ for the other cabinet.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *gaelco2_vregs;
+static UINT16 *gaelco2_videoram;
+
+/* tilemaps */
+static tilemap *pant[2];
+
+static int dual_monitor;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code (single monitor games)
+
+ Tile format
+ -----------
+
+ Screen 0 & 1: (1024*512, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- -----xxx | code (bits 18-16)
+ 0 | -------- --xxx--- | not used?
+ 0 | -------- -x------ | flip y
+ 0 | -------- x------- | flip x
+ 0 | -------x -------- | not used?
+ 0 | xxxxxxx- -------- | color
+ 1 | xxxxxxxx xxxxxxxx | code (bits 15-0)
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_gaelco2_screen0 )
+{
+ int data = gaelco2_videoram[(((gaelco2_vregs[0] >> 9) & 0x07)*0x2000/2) + (tile_index << 1)];
+ int data2 = gaelco2_videoram[(((gaelco2_vregs[0] >> 9) & 0x07)*0x2000/2) + ((tile_index << 1) + 1)];
+ int code = ((data & 0x07) << 16) | (data2 & 0xffff);
+
+ SET_TILE_INFO(0, code, ((data >> 9) & 0x7f), TILE_FLIPXY((data >> 6) & 0x03));
+}
+
+static TILE_GET_INFO( get_tile_info_gaelco2_screen1 )
+{
+ int data = gaelco2_videoram[(((gaelco2_vregs[1] >> 9) & 0x07)*0x2000/2) + (tile_index << 1)];
+ int data2 = gaelco2_videoram[(((gaelco2_vregs[1] >> 9) & 0x07)*0x2000/2) + ((tile_index << 1) + 1)];
+ int code = ((data & 0x07) << 16) | (data2 & 0xffff);
+
+ SET_TILE_INFO(0, code, ((data >> 9) & 0x7f), TILE_FLIPXY((data >> 6) & 0x03));
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code (dual monitor games)
+
+ Tile format
+ -----------
+
+ Screen 0 & 1: (1024*512, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- -----xxx | code (bits 18-16)
+ 0 | -------- --xxx--- | not used?
+ 0 | -------- -x------ | flip y
+ 0 | -------- x------- | flip x
+ 0 | -------x -------- | not used?
+ 0 | -xxxxxx- -------- | color
+ 0 | x------- -------- | unknown
+ 1 | xxxxxxxx xxxxxxxx | code (bits 15-0)
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_gaelco2_screen0_dual )
+{
+ int data = gaelco2_videoram[(((gaelco2_vregs[0] >> 9) & 0x07)*0x2000/2) + (tile_index << 1)];
+ int data2 = gaelco2_videoram[(((gaelco2_vregs[0] >> 9) & 0x07)*0x2000/2) + ((tile_index << 1) + 1)];
+ int code = ((data & 0x07) << 16) | (data2 & 0xffff);
+
+ SET_TILE_INFO(0, code, ((data >> 9) & 0x3f), TILE_FLIPXY((data >> 6) & 0x03));
+}
+
+static TILE_GET_INFO( get_tile_info_gaelco2_screen1_dual )
+{
+ int data = gaelco2_videoram[(((gaelco2_vregs[1] >> 9) & 0x07)*0x2000/2) + (tile_index << 1)];
+ int data2 = gaelco2_videoram[(((gaelco2_vregs[1] >> 9) & 0x07)*0x2000/2) + ((tile_index << 1) + 1)];
+ int code = ((data & 0x07) << 16) | (data2 & 0xffff);
+
+ SET_TILE_INFO(0, code, 0x40 + ((data >> 9) & 0x3f), TILE_FLIPXY((data >> 6) & 0x03));
+}
+
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( gaelco2_vram_w )
+{
+ int pant0_start = ((gaelco2_vregs[0] >> 9) & 0x07)*0x1000;
+ int pant0_end = pant0_start + 0x1000;
+ int pant1_start = ((gaelco2_vregs[1] >> 9) & 0x07)*0x1000;
+ int pant1_end = pant1_start + 0x1000;
+
+ COMBINE_DATA(&gaelco2_videoram[offset]);
+
+ /* tilemap 0 writes */
+ if ((offset >= pant0_start) && (offset < pant0_end)){
+ tilemap_mark_tile_dirty(pant[0], ((offset << 1) & 0x1fff) >> 2);
+ }
+
+ /* tilemap 1 writes */
+ if ((offset >= pant1_start) && (offset < pant1_end)){
+ tilemap_mark_tile_dirty(pant[1], ((offset << 1) & 0x1fff) >> 2);
+ }
+}
+
+/***************************************************************************
+
+ Palette (paletteram16_xRRRRRGGGGGBBBBB_word_w)
+
+ The game's palette uses colors 0-4095, but we need 15 aditional palettes
+ to handle shadows and highlights properly. After a color write to the
+ game's palette we update the other palettes with a darker/brighter color.
+
+ Sprites use last palette entry for shadows and highlights
+ (in order to make some pixels darker or brighter).
+
+ The sprite's pens define the color adjustment:
+
+ 0x00 -> Transparent
+ 0x01-0x07 -> Shadow level (0x01 = min, 0x07 = max)
+ 0x08-0x0f -> Highlight level (0x08 = max, 0x0f = min)
+ 0x10-0x1f -> not used?
+
+***************************************************************************/
+
+#define RGB_CHG 0x08
+#define ADJUST_COLOR(c) ((c < 0) ? 0 : ((c > 255) ? 255 : c))
+
+/* table used for color adjustment */
+static int pen_color_adjust[16] = {
+ +RGB_CHG*0, -RGB_CHG*1, -RGB_CHG*2, -RGB_CHG*3, -RGB_CHG*4, -RGB_CHG*5, -RGB_CHG*6, -RGB_CHG*7,
+ +RGB_CHG*8, +RGB_CHG*7, +RGB_CHG*6, +RGB_CHG*5, +RGB_CHG*4, +RGB_CHG*3, +RGB_CHG*2, +RGB_CHG*1
+};
+
+
+WRITE16_HANDLER( gaelco2_palette_w )
+{
+ int i, color, r, g, b, auxr, auxg, auxb;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ color = paletteram16[offset];
+
+ /* extract RGB components */
+ r = (color >> 10) & 0x1f;
+ g = (color >> 5) & 0x1f;
+ b = (color >> 0) & 0x1f;
+
+ r = pal5bit(r);
+ g = pal5bit(g);
+ b = pal5bit(b);
+
+ /* update game palette */
+ palette_set_color(Machine, 4096*0 + offset, MAKE_RGB(r, g, b));
+
+ /* update shadow/highligh palettes */
+ for (i = 1; i < 16; i++){
+ /* because the last palette entry is reserved for shadows and highlights, we
+ don't use it and that way we save some colors so the UI looks fine ;-) */
+ if ((offset >= 0xff0) && (offset <= 0xfff)) return;
+
+ auxr = ADJUST_COLOR(r + pen_color_adjust[i]);
+ auxg = ADJUST_COLOR(g + pen_color_adjust[i]);
+ auxb = ADJUST_COLOR(b + pen_color_adjust[i]);
+
+ palette_set_color(Machine, 4096*i + offset, MAKE_RGB(auxr, auxg, auxb));
+ }
+}
+
+/***************************************************************************
+
+ Start/Stop the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gaelco2 )
+{
+ gaelco2_videoram = spriteram16;
+
+ /* create tilemaps */
+ pant[0] = tilemap_create(get_tile_info_gaelco2_screen0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pant[1] = tilemap_create(get_tile_info_gaelco2_screen1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+
+ /* set tilemap properties */
+ tilemap_set_transparent_pen(pant[0],0);
+ tilemap_set_transparent_pen(pant[1],0);
+
+ tilemap_set_scroll_rows(pant[0], 512);
+ tilemap_set_scroll_cols(pant[0], 1);
+ tilemap_set_scroll_rows(pant[1], 512);
+ tilemap_set_scroll_cols(pant[1], 1);
+
+ dual_monitor = 0;
+}
+
+VIDEO_START( gaelco2_dual )
+{
+ gaelco2_videoram = spriteram16;
+
+ /* create tilemaps */
+ pant[0] = tilemap_create(get_tile_info_gaelco2_screen0_dual,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pant[1] = tilemap_create(get_tile_info_gaelco2_screen1_dual,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+
+ /* set tilemap properties */
+ tilemap_set_transparent_pen(pant[0],0);
+ tilemap_set_transparent_pen(pant[1],0);
+
+ tilemap_set_scroll_rows(pant[0], 512);
+ tilemap_set_scroll_cols(pant[0], 1);
+ tilemap_set_scroll_rows(pant[1], 512);
+ tilemap_set_scroll_cols(pant[1], 1);
+
+ dual_monitor = 1;
+}
+
+/***************************************************************************
+
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------x xxxxxxxx | sprite bank (sprite number bits 18-10)
+ 0 | xxxxxxx- -------- | sprite color (bits 6-0)
+ 1 | -------x xxxxxxxx | y position
+ 1 | ------x- -------- | sprite enable
+ 1 | -----x-- -------- | flipy
+ 1 | ----x--- -------- | flipx
+ 1 | xxxx---- -------- | sprite y size
+ 2 | ------xx xxxxxxxx | x position
+ 2 | ----xx-- -------- | not used?
+ 2 | xxxx---- -------- | sprite x size
+ 3 | xxxxxxxx xxxxxxxx | pointer to more sprite data
+
+ Each sprite entry has a pointer to more sprite data.
+ The length of data depends on the sprite size (xsize*ysize).
+ Each entry has the following format:
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | ----xxxx xxxxxxxx | sprite number offset (sprite number bits 11-0)
+ 0 | xxxx---- -------- | sprite color offset (bits 3-0)
+
+ In dual monitor games, the configuration is the same, but MSB of
+ word 0 is used to select target monitor for the sprite, and the
+ palette is splitted for each monitor.
+
+ Last sprite color entry is used for shadows/highlights
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int mask, int xoffs)
+{
+ int j, x, y, ex, ey, px, py;
+ const gfx_element *gfx = machine->gfx[0];
+
+ /* get sprite ram start and end offsets */
+ int start_offset = (gaelco2_vregs[1] & 0x10)*0x100;
+ int end_offset = start_offset + 0x1000;
+
+ /* sprite offset is based on the visible area */
+ int spr_x_adjust = (machine->screen[0].visarea.max_x - 320 + 1) - (511 - 320 - 1) - ((gaelco2_vregs[0] >> 4) & 0x01) + xoffs;
+
+ for (j = start_offset; j < end_offset; j += 8){
+ int data = buffered_spriteram16[(j/2) + 0];
+ int data2 = buffered_spriteram16[(j/2) + 1];
+ int data3 = buffered_spriteram16[(j/2) + 2];
+ int data4 = buffered_spriteram16[(j/2) + 3];
+
+ int sx = data3 & 0x3ff;
+ int sy = data2 & 0x1ff;
+
+ int xflip = data2 & 0x800;
+ int yflip = data2 & 0x400;
+
+ int xsize = ((data3 >> 12) & 0x0f) + 1;
+ int ysize = ((data2 >> 12) & 0x0f) + 1;
+
+ if (dual_monitor && ((data & 0x8000) != mask)) continue;
+
+ /* if it's enabled, draw it */
+ if ((data2 & 0x0200) != 0){
+ for (y = 0; y < ysize; y++){
+ for (x = 0; x < xsize; x++){
+ /* for each x,y of the sprite, fetch the sprite data */
+ int data5 = buffered_spriteram16[((data4/2) + (y*xsize + x)) & 0x7fff];
+ int number = ((data & 0x1ff) << 10) + (data5 & 0x0fff);
+ int color = ((data >> 9) & 0x7f) + ((data5 >> 12) & 0x0f);
+ int color_effect = dual_monitor ? ((color & 0x3f) == 0x3f) : (color == 0x7f);
+
+ ex = xflip ? (xsize - 1 - x) : x;
+ ey = yflip ? (ysize - 1 - y) : y;
+
+ /* normal sprite, pen 0 transparent */
+ if (color_effect == 0){
+ drawgfx(bitmap, gfx, number,
+ color, xflip, yflip,
+ ((sx + ex*16) & 0x3ff) + spr_x_adjust,
+ ((sy + ey*16) & 0x1ff),
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ } else { /* last palette entry is reserved for shadows and highlights */
+
+ /* get a pointer to the current sprite's gfx data */
+ UINT8 *gfx_src = gfx->gfxdata + (number % gfx->total_elements)*gfx->char_modulo;
+
+ for (py = 0; py < gfx->height; py++){
+ /* get a pointer to the current line in the screen bitmap */
+ int ypos = ((sy + ey*16 + py) & 0x1ff);
+ UINT16 *srcy = BITMAP_ADDR16(bitmap, ypos, 0);
+
+ int gfx_py = yflip ? (gfx->height - 1 - py) : py;
+
+ if ((ypos < cliprect->min_y) || (ypos > cliprect->max_y)) continue;
+
+ for (px = 0; px < gfx->width; px++){
+ /* get current pixel */
+ int xpos = (((sx + ex*16 + px) & 0x3ff) + spr_x_adjust) & 0x3ff;
+ UINT16 *pixel = srcy + xpos;
+ int src_color = *pixel;
+
+ int gfx_px = xflip ? (gfx->width - 1 - px) : px;
+
+ /* get asociated pen for the current sprite pixel */
+ int gfx_pen = gfx_src[gfx->line_modulo*gfx_py + gfx_px];
+
+ if ((gfx_pen == 0) || (gfx_pen >= 16)) continue;
+
+ if ((xpos < cliprect->min_x) || (xpos > cliprect->max_x)) continue;
+
+ /* make background color darker or brighter */
+ *pixel = src_color + 4096*gfx_pen;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( gaelco2 )
+{
+ int i;
+
+ /* read scroll values */
+ int scroll0x = gaelco2_videoram[0x2802/2] + 0x14;
+ int scroll1x = gaelco2_videoram[0x2806/2] + 0x10;
+ int scroll0y = gaelco2_videoram[0x2800/2] + 0x01;
+ int scroll1y = gaelco2_videoram[0x2804/2] + 0x01;
+
+ /* set y scroll registers */
+ tilemap_set_scrolly(pant[0], 0, scroll0y & 0x1ff);
+ tilemap_set_scrolly(pant[1], 0, scroll1y & 0x1ff);
+
+ /* set x linescroll registers */
+ for (i = 0; i < 512; i++){
+ tilemap_set_scrollx(pant[0], i & 0x1ff, (gaelco2_vregs[0] & 0x8000) ? (gaelco2_videoram[(0x2000/2) + i] + 0x14) & 0x3ff : scroll0x & 0x3ff);
+ tilemap_set_scrollx(pant[1], i & 0x1ff, (gaelco2_vregs[1] & 0x8000) ? (gaelco2_videoram[(0x2400/2) + i] + 0x10) & 0x3ff : scroll1x & 0x3ff);
+ }
+
+ /* draw screen */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ tilemap_draw(bitmap, cliprect, pant[1], 0, 0);
+ tilemap_draw(bitmap, cliprect, pant[0], 0, 0);
+ draw_sprites(machine, bitmap, cliprect, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( gaelco2_dual )
+{
+ int i;
+
+ /* read scroll values */
+ int scroll0x = gaelco2_videoram[0x2802/2] + 0x14;
+ int scroll1x = gaelco2_videoram[0x2806/2] + 0x10;
+ int scroll0y = gaelco2_videoram[0x2800/2] + 0x01;
+ int scroll1y = gaelco2_videoram[0x2804/2] + 0x01;
+
+ /* set y scroll registers */
+ tilemap_set_scrolly(pant[0], 0, scroll0y & 0x1ff);
+ tilemap_set_scrolly(pant[1], 0, scroll1y & 0x1ff);
+
+ /* set x linescroll registers */
+ for (i = 0; i < 512; i++){
+ tilemap_set_scrollx(pant[0], i & 0x1ff, (gaelco2_vregs[0] & 0x8000) ? (gaelco2_videoram[(0x2000/2) + i] + 0x14) & 0x3ff : scroll0x & 0x3ff);
+ tilemap_set_scrollx(pant[1], i & 0x1ff, (gaelco2_vregs[1] & 0x8000) ? (gaelco2_videoram[(0x2400/2) + i] + 0x10) & 0x3ff : scroll1x & 0x3ff);
+ }
+
+ /* draw screen */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ if (screen==1)
+ {
+ /* monitor 2 output */
+ tilemap_draw(bitmap,cliprect,pant[1], 0, 0);
+ draw_sprites(machine,bitmap,cliprect, 0x8000, 0);
+ }
+ else if (screen==0)
+ {
+ /* monitor 1 output */
+ tilemap_draw(bitmap,cliprect,pant[0], 0, 0);
+ draw_sprites(machine,bitmap,cliprect, 0x0000, 0);
+ }
+
+ return 0;
+}
+
+
+VIDEO_EOF( gaelco2 )
+{
+ /* sprites are one frame ahead */
+ buffer_spriteram16_w(0, 0, 0);
+}