diff options
Diffstat (limited to 'src/mame/video/exidy.c')
-rw-r--r-- | src/mame/video/exidy.c | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/src/mame/video/exidy.c b/src/mame/video/exidy.c new file mode 100644 index 00000000000..a72cb0ea231 --- /dev/null +++ b/src/mame/video/exidy.c @@ -0,0 +1,502 @@ +/************************************************************************* + + Exidy 6502 hardware + +*************************************************************************/ + +#include "driver.h" +#include "exidy.h" + +UINT8 *exidy_characterram; + +UINT8 exidy_collision_mask; +UINT8 exidy_collision_invert; + +UINT8 *exidy_palette; +UINT16 *exidy_colortable; + +static mame_bitmap *motion_object_1_vid; +static mame_bitmap *motion_object_2_vid; +static mame_bitmap *motion_object_2_clip; + +static UINT8 chardirty[256]; +static UINT8 update_complete; + +static UINT8 int_condition; + +static UINT8 spriteno; +static UINT8 sprite_enable; +static UINT8 sprite1_xpos; +static UINT8 sprite1_ypos; +static UINT8 sprite2_xpos; +static UINT8 sprite2_ypos; + +static UINT8 color_latch[3]; + + + +/************************************* + * + * Hard coded palettes + * + *************************************/ + +/* Sidetrack/Targ/Spectar don't have a color PROM; colors are changed by the means of 8x3 */ +/* dip switches on the board. Here are the colors they map to. */ +UINT8 sidetrac_palette[PALETTE_LEN*3] = +{ + 0x00,0x00,0x00, /* BACKGND */ + 0x00,0x00,0x00, /* CSPACE0 */ + 0x00,0xff,0x00, /* CSPACE1 */ + 0xff,0xff,0xff, /* CSPACE2 */ + 0xff,0xff,0xff, /* CSPACE3 */ + 0xff,0x00,0xff, /* 5LINES (unused?) */ + 0xff,0xff,0x00, /* 5MO2VID */ + 0xff,0xff,0xff /* 5MO1VID */ +}; + +/* Targ has different colors */ +UINT8 targ_palette[PALETTE_LEN*3] = +{ + /* color use */ + 0x00,0x00,0xff, /* blue background */ + 0x00,0xff,0xff, /* cyan characters 192-255 */ + 0xff,0xff,0x00, /* yellow characters 128-191 */ + 0xff,0xff,0xff, /* white characters 64-127 */ + 0xff,0x00,0x00, /* red characters 0- 63 */ + 0x00,0xff,0xff, /* cyan not used */ + 0xff,0xff,0xff, /* white bullet sprite */ + 0x00,0xff,0x00, /* green wummel sprite */ +}; + +/* Spectar has different colors */ +UINT8 spectar_palette[PALETTE_LEN*3] = +{ + /* color use */ + 0x00,0x00,0xff, /* blue background */ + 0x00,0xff,0x00, /* green characters 192-255 */ + 0x00,0xff,0x00, /* green characters 128-191 */ + 0xff,0xff,0xff, /* white characters 64-127 */ + 0xff,0x00,0x00, /* red characters 0- 63 */ + 0x00,0xff,0x00, /* green not used */ + 0xff,0xff,0x00, /* yellow bullet sprite */ + 0x00,0xff,0x00, /* green wummel sprite */ +}; + + + +/************************************* + * + * Hard coded color tables + * + *************************************/ + +UINT16 exidy_1bpp_colortable[COLORTABLE_LEN] = +{ + /* one-bit characters */ + 0, 4, /* chars 0x00-0x3F */ + 0, 3, /* chars 0x40-0x7F */ + 0, 2, /* chars 0x80-0xBF */ + 0, 1, /* chars 0xC0-0xFF */ + + /* Motion Object 1 */ + 0, 7, + + /* Motion Object 2 */ + 0, 6, +}; + +UINT16 exidy_2bpp_colortable[COLORTABLE_LEN] = +{ + /* two-bit characters */ + /* (Because this is 2-bit color, the colorspace is only divided + in half instead of in quarters. That's why 00-3F = 40-7F and + 80-BF = C0-FF) */ + 0, 0, 4, 3, /* chars 0x00-0x3F */ + 0, 0, 4, 3, /* chars 0x40-0x7F */ + 0, 0, 2, 1, /* chars 0x80-0xBF */ + 0, 0, 2, 1, /* chars 0xC0-0xFF */ + + /* Motion Object 1 */ + 0, 7, + + /* Motion Object 2 */ + 0, 6, +}; + + + +/************************************* + * + * Palettes and colors + * + *************************************/ + +PALETTE_INIT( exidy ) +{ + if (exidy_palette) + { + int i; + + for (i = 0; i < PALETTE_LEN; i++) + palette_set_color_rgb(machine,i,exidy_palette[i*3+0],exidy_palette[i*3+1],exidy_palette[i*3+2]); + } + memcpy(colortable, exidy_colortable, COLORTABLE_LEN * sizeof(colortable[0])); +} + + + +/************************************* + * + * Video startup + * + *************************************/ + +VIDEO_START( exidy ) +{ + video_start_generic(machine); + + motion_object_1_vid = auto_bitmap_alloc(16, 16, machine->screen[0].format); + motion_object_2_vid = auto_bitmap_alloc(16, 16, machine->screen[0].format); + motion_object_2_clip = auto_bitmap_alloc(16, 16, machine->screen[0].format); +} + + + +/************************************* + * + * Interrupt generation + * + *************************************/ + +INLINE void latch_condition(int collision) +{ + collision ^= exidy_collision_invert; + int_condition = (readinputportbytag("INTSOURCE") & ~0x1c) | (collision & exidy_collision_mask); +} + + +INTERRUPT_GEN( exidy_vblank_interrupt ) +{ + /* latch the current condition */ + latch_condition(0); + int_condition &= ~0x80; + + /* set the IRQ line */ + cpunum_set_input_line(0, 0, ASSERT_LINE); +} + + +INTERRUPT_GEN( teetert_vblank_interrupt ) +{ + /* standard stuff */ + if (cpu_getiloops() == 0) + exidy_vblank_interrupt(); + + /* plus a pulse on the NMI line */ + cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE); +} + + +READ8_HANDLER( exidy_interrupt_r ) +{ + /* clear any interrupts */ + cpunum_set_input_line(0, 0, CLEAR_LINE); + + /* return the latched condition */ + return int_condition; +} + + + +/************************************* + * + * Character RAM + * + *************************************/ + +WRITE8_HANDLER( exidy_characterram_w ) +{ + if (exidy_characterram[offset] != data) + { + exidy_characterram[offset] = data; + chardirty[offset / 8 % 256] = 1; + } +} + + + +/************************************* + * + * Palette RAM + * + *************************************/ + +WRITE8_HANDLER( exidy_color_w ) +{ + int i; + + color_latch[offset] = data; + + for (i = 0; i < 8; i++) + palette_set_color_rgb(Machine, i, pal1bit(color_latch[2] >> i), pal1bit(color_latch[1] >> i), pal1bit(color_latch[0] >> i)); +} + + + +/************************************* + * + * Sprite controls + * + *************************************/ + +WRITE8_HANDLER( exidy_sprite1_xpos_w ) +{ + sprite1_xpos = data; +} + +WRITE8_HANDLER( exidy_sprite1_ypos_w ) +{ + sprite1_ypos = data; +} + +WRITE8_HANDLER( exidy_sprite2_xpos_w ) +{ + sprite2_xpos = data; +} + +WRITE8_HANDLER( exidy_sprite2_ypos_w ) +{ + sprite2_ypos = data; +} + +WRITE8_HANDLER( exidy_spriteno_w ) +{ + spriteno = data; +} + +WRITE8_HANDLER( exidy_sprite_enable_w ) +{ + sprite_enable = data; +} + + + +/************************************* + * + * Background update + * + *************************************/ + +static void update_background(running_machine *machine) +{ + int x, y, offs; + + /* update the background and any dirty characters in it */ + for (y = offs = 0; y < 32; y++) + for (x = 0; x < 32; x++, offs++) + { + int code = videoram[offs]; + + /* see if the character is dirty */ + if (chardirty[code] == 1) + { + decodechar(machine->gfx[0], code, exidy_characterram, machine->drv->gfxdecodeinfo[0].gfxlayout); + chardirty[code] = 2; + } + + /* see if the bitmap is dirty */ + if (dirtybuffer[offs] || chardirty[code]) + { + int color = code >> 6; + drawgfx(tmpbitmap, machine->gfx[0], code, color, 0, 0, x * 8, y * 8, NULL, TRANSPARENCY_NONE, 0); + dirtybuffer[offs] = 0; + } + } + + /* reset the char dirty array */ + for (y = 0; y < 256; y++) + if (chardirty[y] == 2) + chardirty[y] = 0; +} + + + +static TIMER_CALLBACK( collision_irq_callback ) +{ + /* latch the collision bits */ + latch_condition(param); + + /* set the IRQ line */ + cpunum_set_input_line(0, 0, ASSERT_LINE); +} + + + +/************************************* + * + * End-of-frame callback + * + *************************************/ + +/*************************************************************************** + + Exidy hardware checks for two types of collisions based on the video + signals. If the Motion Object 1 and Motion Object 2 signals are on at + the same time, an M1M2 collision bit gets set. If the Motion Object 1 + and Background Character signals are on at the same time, an M1CHAR + collision bit gets set. So effectively, there's a pixel-by-pixel + collision check comparing Motion Object 1 (the player) to the + background and to the other Motion Object (typically a bad guy). + +***************************************************************************/ + +INLINE int sprite_1_enabled(void) +{ + /* if the exidy_collision_mask is 0x00, then we are on old hardware that always has */ + /* sprite 1 enabled regardless */ + return (!(sprite_enable & 0x80) || (sprite_enable & 0x10) || (exidy_collision_mask == 0x00)); +} + +INLINE int sprite_2_enabled(void) +{ + return (!(sprite_enable & 0x40)); +} + +VIDEO_EOF( exidy ) +{ + UINT8 enable_set = ((sprite_enable & 0x20) != 0); + static const rectangle clip = { 0, 15, 0, 15 }; + int pen0 = machine->pens[0]; + int org_1_x = 0, org_1_y = 0; + int org_2_x = 0, org_2_y = 0; + int sx, sy; + int count = 0; + + /* if there is nothing to detect, bail */ + if (exidy_collision_mask == 0) + return; + + /* if the sprites aren't enabled, we can't collide */ + if (!sprite_1_enabled() && !sprite_2_enabled()) + { + update_complete = 0; + return; + } + + /* update the background if necessary */ + if (!update_complete) + update_background(machine); + update_complete = 0; + + /* draw sprite 1 */ + if (sprite_1_enabled()) + { + org_1_x = 236 - sprite1_xpos - 4; + org_1_y = 244 - sprite1_ypos - 4; + drawgfx(motion_object_1_vid, machine->gfx[1], + (spriteno & 0x0f) + 16 * enable_set, 0, + 0, 0, 0, 0, &clip, TRANSPARENCY_NONE, 0); + } + else + fillbitmap(motion_object_1_vid, pen0, &clip); + + /* draw sprite 2 */ + if (sprite_2_enabled()) + { + org_2_x = 236 - sprite2_xpos - 4; + org_2_y = 244 - sprite2_ypos - 4; + drawgfx(motion_object_2_vid, machine->gfx[1], + ((spriteno >> 4) & 0x0f) + 32, 0, + 0, 0, 0, 0, &clip, TRANSPARENCY_NONE, 0); + } + else + fillbitmap(motion_object_2_vid, pen0, &clip); + + /* draw sprite 2 clipped to sprite 1's location */ + fillbitmap(motion_object_2_clip, pen0, &clip); + if (sprite_1_enabled() && sprite_2_enabled()) + { + sx = org_2_x - org_1_x; + sy = org_2_y - org_1_y; + drawgfx(motion_object_2_clip, machine->gfx[1], + ((spriteno >> 4) & 0x0f) + 32, 0, + 0, 0, sx, sy, &clip, TRANSPARENCY_NONE, 0); + } + + /* scan for collisions */ + for (sy = 0; sy < 16; sy++) + for (sx = 0; sx < 16; sx++) + { + if (*BITMAP_ADDR16(motion_object_1_vid, sy, sx) != pen0) + { + UINT8 collision_mask = 0; + + /* check for background collision (M1CHAR) */ + if (*BITMAP_ADDR16(tmpbitmap, org_1_y + sy, org_1_x + sx) != pen0) + collision_mask |= 0x04; + + /* check for motion object collision (M1M2) */ + if (*BITMAP_ADDR16(motion_object_2_clip, sy, sx) != pen0) + collision_mask |= 0x10; + + /* if we got one, trigger an interrupt */ + if ((collision_mask & exidy_collision_mask) && count++ < 128) + timer_set(video_screen_get_time_until_pos(0, org_1_x + sx, org_1_y + sy), collision_mask, collision_irq_callback); + } + if (*BITMAP_ADDR16(motion_object_2_vid, sy, sx) != pen0) + { + /* check for background collision (M2CHAR) */ + if (*BITMAP_ADDR16(tmpbitmap, org_2_y + sy, org_2_x + sx) != pen0) + if ((exidy_collision_mask & 0x08) && count++ < 128) + timer_set(video_screen_get_time_until_pos(0, org_2_x + sx, org_2_y + sy), 0x08, collision_irq_callback); + } + } +} + + + +/************************************* + * + * Standard screen refresh callback + * + *************************************/ + +VIDEO_UPDATE( exidy ) +{ + int sx, sy; + + /* update the background and draw it */ + update_background(machine); + copybitmap(bitmap, tmpbitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_NONE, 0); + + /* draw sprite 2 first */ + if (sprite_2_enabled()) + { + sx = 236 - sprite2_xpos - 4; + sy = 244 - sprite2_ypos - 4; + + drawgfx(bitmap, machine->gfx[1], + ((spriteno >> 4) & 0x0f) + 32, 1, + 0, 0, sx, sy, cliprect, TRANSPARENCY_PEN, 0); + } + + /* draw sprite 1 next */ + if (sprite_1_enabled()) + { + UINT8 enable_set = ((sprite_enable & 0x20) != 0); + + sx = 236 - sprite1_xpos - 4; + sy = 244 - sprite1_ypos - 4; + + if (sy < 0) sy = 0; + + drawgfx(bitmap, machine->gfx[1], + (spriteno & 0x0f) + 16 * enable_set, 0, + 0, 0, sx, sy, cliprect, TRANSPARENCY_PEN, 0); + } + + /* indicate that we already updated the background */ + update_complete = 1; + return 0; +} |