/*************************************************************************** COSMIC.C emulation of video hardware of cosmic machines of 1979-1980(ish) ***************************************************************************/ #include "driver.h" static pen_t (*map_color)(UINT8 x, UINT8 y); static int color_registers[3]; static int background_enable; static int magspot_pen_mask; WRITE8_HANDLER( cosmic_color_register_w ) { color_registers[offset] = data ? 1 : 0; } static pen_t panic_map_color(UINT8 x, UINT8 y) { offs_t offs; pen_t pen; offs = (color_registers[0] << 9) | (color_registers[2] << 10) | ((x >> 4) << 5) | (y >> 3); pen = memory_region(REGION_USER1)[offs]; if (color_registers[1]) pen >>= 4; return pen & 0x0f; } static pen_t cosmica_map_color(UINT8 x, UINT8 y) { offs_t offs; pen_t pen; offs = (color_registers[0] << 9) | ((x >> 4) << 5) | (y >> 3); pen = memory_region(REGION_USER1)[offs]; if (color_registers[0]) /* yes, 0 again according to the schematics */ pen >>= 4; return pen & 0x07; } static pen_t cosmicg_map_color(UINT8 x, UINT8 y) { offs_t offs; pen_t pen; offs = (color_registers[0] << 8) | (color_registers[1] << 9) | ((y >> 4) << 4) | (x >> 4); pen = memory_region(REGION_USER1)[offs]; /* the upper 4 bits are for cocktail mode support */ return pen & 0x0f; } static pen_t magspot2_map_color(UINT8 x, UINT8 y) { offs_t offs; pen_t pen; offs = (color_registers[0] << 9) | ((x >> 3) << 4) | (y >> 4); pen = memory_region(REGION_USER1)[offs]; if (color_registers[1]) pen >>= 4; return pen & magspot_pen_mask; } /* * Panic Color table setup * * Bit 0 = RED, Bit 1 = GREEN, Bit 2 = BLUE * * First 8 colors are normal intensities * * But, bit 3 can be used to pull Blue via a 2k resistor to 5v * (1k to ground) so second version of table has blue set to 2/3 */ PALETTE_INIT( panic ) { int i; #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity) #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs]) for (i = 0;i < machine->drv->total_colors;i++) { int r = 0xff * ((i >> 0) & 1); int g = 0xff * ((i >> 1) & 1); int b; if ((i & 0x0c) == 0x08) b = 0xaa; else b = 0xff * ((i >> 2) & 1); palette_set_color(machine,i,MAKE_RGB(r,g,b)); } for (i = 0;i < TOTAL_COLORS(0);i++) COLOR(0,i) = *(color_prom++) & 0x07; map_color = panic_map_color; } /* * Cosmic Alien Color table setup * * 8 colors, 16 sprite color codes * * Bit 0 = RED, Bit 1 = GREEN, Bit 2 = BLUE * */ PALETTE_INIT( cosmica ) { int i; #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity) #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs]) for (i = 0;i < machine->drv->total_colors;i++) palette_set_color_rgb(machine,i,pal1bit(i >> 0),pal1bit(i >> 1),pal1bit(i >> 2)); for (i = 0;i < TOTAL_COLORS(0)/2;i++) { COLOR(0,i) = * color_prom & 0x07; COLOR(0,i+(TOTAL_COLORS(0)/2)) = (*(color_prom++) >> 4) & 0x07; } map_color = cosmica_map_color; } /* * Cosmic guerilla table setup * * Use AA for normal, FF for Full Red * Bit 0 = R, bit 1 = G, bit 2 = B, bit 4 = High Red * * It's possible that the background is dark gray and not black, as the * resistor chain would never drop to zero, Anybody know ? */ PALETTE_INIT( cosmicg ) { int i; for (i = 0;i < machine->drv->total_colors;i++) { int r,g,b; if (i > 8) r = 0xff; else r = 0xaa * ((i >> 0) & 1); g = 0xaa * ((i >> 1) & 1); b = 0xaa * ((i >> 2) & 1); palette_set_color(machine,i,MAKE_RGB(r,g,b)); } map_color = cosmicg_map_color; } PALETTE_INIT( magspot2 ) { int i; #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity) #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs]) for (i = 0;i < machine->drv->total_colors;i++) { int r,g,b; if ((i & 0x09) == 0x08) r = 0xaa; else r = 0xff * ((i >> 0) & 1); g = 0xff * ((i >> 1) & 1); b = 0xff * ((i >> 2) & 1); palette_set_color(machine,i,MAKE_RGB(r,g,b)); } for (i = 0;i < TOTAL_COLORS(0);i++) { COLOR(0,i) = *(color_prom++) & 0x0f; } map_color = magspot2_map_color; magspot_pen_mask = 0x0f; } PALETTE_INIT( nomnlnd ) { int i; #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity) #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs]) for (i = 0;i < machine->drv->total_colors;i++) palette_set_color_rgb(machine,i,pal1bit(i >> 0),pal1bit(i >> 1),pal1bit(i >> 2)); for (i = 0;i < TOTAL_COLORS(0);i++) { COLOR(0,i) = *(color_prom++) & 0x07; } map_color = magspot2_map_color; magspot_pen_mask = 0x07; } WRITE8_HANDLER( cosmic_background_enable_w ) { background_enable = data; } static void draw_bitmap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) { offs_t offs; for (offs = 0; offs < videoram_size; offs++) { UINT8 data = videoram[offs]; if (data != 0) /* optimization, not absolutely neccessary */ { int i; UINT8 x = offs << 3; UINT8 y = offs >> 5; pen_t pen = machine->pens[map_color(x, y)]; for (i = 0; i < 8; i++) { if (data & 0x80) { if (flip_screen) *BITMAP_ADDR16(bitmap, 255-y, 255-x) = pen; else *BITMAP_ADDR16(bitmap, y, x) = pen; } x++; data <<= 1; } } } } static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int color_mask, int extra_sprites) { int offs; for (offs = spriteram_size - 4;offs >= 0;offs -= 4) { if (spriteram[offs] != 0) { int code, color; code = ~spriteram[offs ] & 0x3f; color = ~spriteram[offs+3] & color_mask; if (extra_sprites) { code |= (spriteram[offs+3] & 0x08) << 3; } if (spriteram[offs] & 0x80) { /* 16x16 sprite */ drawgfx(bitmap,machine->gfx[0], code, color, 0, ~spriteram[offs] & 0x40, 256-spriteram[offs+2],spriteram[offs+1], cliprect,TRANSPARENCY_PEN,0); } else { /* 32x32 sprite */ drawgfx(bitmap,machine->gfx[1], code >> 2, color, 0, ~spriteram[offs] & 0x40, 256-spriteram[offs+2],spriteram[offs+1], cliprect,TRANSPARENCY_PEN,0); } } } } static void cosmica_draw_starfield(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) { UINT8 y = 0; UINT8 map = 0; UINT8 *PROM = memory_region(REGION_USER2); while (1) { int va = y & 0x01; int vb = (y >> 1) & 0x01; UINT8 x = 0; while (1) { UINT8 x1; int hc, hb_; if (flip_screen) x1 = x - cpu_getcurrentframe(); else x1 = x + cpu_getcurrentframe(); hc = (x1 >> 2) & 0x01; hb_ = (x >> 5) & 0x01; /* not a bug, this one is the real x */ if ((x1 & 0x1f) == 0) { // flip-flop at IC11 is clocked map = PROM[(x1 >> 5) | (y >> 1 << 3)]; } if ((!(hc & va) & (vb ^ hb_)) && /* right network */ (((x1 ^ map) & (hc | 0x1e)) == 0x1e)) /* left network */ { /* RGB order is reversed -- bit 7=R, 6=G, 5=B */ int col = (map >> 7) | ((map >> 5) & 0x02) | ((map >> 3) & 0x04); *BITMAP_ADDR16(bitmap, y, x) = machine->pens[col]; } x++; if (x == 0) break; } y++; if (y == 0) break; } } static void devzone_draw_grid(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) { UINT8 y; UINT8 *horz_PROM = memory_region(REGION_USER2); UINT8 *vert_PROM = memory_region(REGION_USER3); offs_t horz_addr = 0; UINT8 count = 0; UINT8 horz_data = 0; UINT8 vert_data; for (y = 32; y < 224; y++) { UINT8 x = 0; while (1) { int x1; /* for the vertical lines, each bit indicates if there should be a line at the x position */ vert_data = vert_PROM[x >> 3]; /* the horizontal (perspective) lines are RLE encoded. When the screen is flipped, the address should be decrementing. But since it's just a mirrored image, this is easier. */ if (count == 0) { count = horz_PROM[horz_addr++]; } count++; if (count == 0) { horz_data = horz_PROM[horz_addr++]; } for (x1 = 0; x1 < 8; x1++) { if (!(vert_data & horz_data & 0x80)) /* NAND gate */ { pen_t pen = machine->pens[4]; /* blue */ if (flip_screen) *BITMAP_ADDR16(bitmap, 255-y, 255-x) = pen; else *BITMAP_ADDR16(bitmap, y, x) = pen; } horz_data = (horz_data << 1) | 0x01; vert_data = (vert_data << 1) | 0x01; x++; } if (x == 0) break; } } } static void nomnlnd_draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) { UINT8 y = 0; UINT8 water = cpu_getcurrentframe(); UINT8 *PROM = memory_region(REGION_USER2); /* all positioning is via logic gates: tree is displayed where __ __ HD' ^ HC' ^ HB' and __ __ __ (VB' ^ VC' ^ VD') X (VB' ^ VC' ^ VD') water is displayed where __ __ HD' ^ HC' ^ HB ^ HA' and vertically the same equation as the trees, but final result inverted. The colors are coded in logic gates: trees: P1 P2 BGR R = Plane1 ^ Plane2 0 0 000 G = Plane2 0 1 010 B = Plane1 ^ ~Plane2 1 0 100 1 1 011 water: P1 P2 BGR or R = Plane1 ^ Plane2 0 0 100 000 G = Plane2 v Plane2 0 1 110 010 B = ~Plane1 or 1 0 010 010 0 based oh HD 1 1 011 011 Not sure about B, the logic seems convulated for such a simple result. */ while (1) { int vb_ = (y >> 5) & 0x01; int vc_ = (y >> 6) & 0x01; int vd_ = y >> 7; UINT8 x = 0; while (1) { int color = 0; int hd = (x >> 3) & 0x01; int ha_ = (x >> 4) & 0x01; int hb_ = (x >> 5) & 0x01; int hc_ = (x >> 6) & 0x01; int hd_ = x >> 7; if ((!vb_ & vc_ & !vd_) ^ (vb_ & !vc_ & vd_)) { /* tree */ if (!hd_ & hc_ & !hb_) { offs_t offs = ((x >> 3) & 0x03) | ((y & 0x1f) << 2) | (flip_screen ? 0x80 : 0); UINT8 plane1 = PROM[offs ] << (x & 0x07); UINT8 plane2 = PROM[offs | 0x0400] << (x & 0x07); plane1 >>= 7; plane2 >>= 7; color = (plane1 & plane2) | // R (plane2 ) << 1 | // G (plane1 & !plane2) << 2; // B } } else { /* water */ if (hd_ & !hc_ & hb_ & !ha_) { offs_t offs = hd | (water << 1) | 0x0200; UINT8 plane1 = PROM[offs ] << (x & 0x07); UINT8 plane2 = PROM[offs | 0x0400] << (x & 0x07); plane1 >>= 7; plane2 >>= 7; color = ( plane1 & plane2) | // R ( plane1 | plane2) << 1 | // G (!plane1 & hd) << 2; // B - see above } } if (color != 0) { pen_t pen = machine->pens[color]; if (flip_screen) *BITMAP_ADDR16(bitmap, 255-y, 255-x) = pen; else *BITMAP_ADDR16(bitmap, y, x) = pen; } x++; if (x == 0) break; } // this is obviously wrong // if (vb_) // { water++; // } y++; if (y == 0) break; } } VIDEO_UPDATE( cosmicg ) { fillbitmap(bitmap, machine->pens[0], cliprect); draw_bitmap(machine, bitmap, cliprect); return 0; } VIDEO_UPDATE( panic ) { fillbitmap(bitmap, machine->pens[0], cliprect); draw_bitmap(machine, bitmap, cliprect); draw_sprites(machine, bitmap, cliprect, 0x07, 1); return 0; } VIDEO_UPDATE( cosmica ) { fillbitmap(bitmap, machine->pens[0], cliprect); cosmica_draw_starfield(machine, bitmap, cliprect); draw_bitmap(machine, bitmap, cliprect); draw_sprites(machine, bitmap, cliprect, 0x0f, 0); return 0; } VIDEO_UPDATE( magspot2 ) { fillbitmap(bitmap, machine->pens[0], cliprect); draw_bitmap(machine, bitmap, cliprect); draw_sprites(machine, bitmap, cliprect, 0x07, 0); return 0; } VIDEO_UPDATE( devzone ) { fillbitmap(bitmap, machine->pens[0], cliprect); if (background_enable) { devzone_draw_grid(machine, bitmap, cliprect); } draw_bitmap(machine, bitmap, cliprect); draw_sprites(machine, bitmap, cliprect, 0x07, 0); return 0; } VIDEO_UPDATE( nomnlnd ) { /* according to the video summation logic on pg4, the trees and river have the highest priority */ fillbitmap(bitmap, machine->pens[0], cliprect); draw_bitmap(machine, bitmap, cliprect); draw_sprites(machine, bitmap, cliprect, 0x07, 0); if (background_enable) { nomnlnd_draw_background(machine, bitmap, cliprect); } return 0; }