// license:BSD-3-Clause // copyright-holders:Mike Coates, Couriersud /*************************************************************************** video\cvs.c Functions to emulate the video hardware of the machine. ***************************************************************************/ #include "emu.h" #include "cpu/s2650/s2650.h" #include "includes/cvs.h" #define SPRITE_PEN_BASE (0x820) #define BULLET_STAR_PEN (0x828) /****************************************************** * Convert Colour prom to format for Mame Colour Map * * * * There is a prom used for colour mapping and plane * * priority. This is converted to a colour table here * * * * colours are taken from SRAM and are programmable * ******************************************************/ PALETTE_INIT_MEMBER(cvs_state,cvs) { const uint8_t *color_prom = memregion("proms")->base(); int i, attr; /* color mapping PROM */ for (attr = 0; attr < 0x100; attr++) { for (i = 0; i < 8; i++) { uint8_t ctabentry = color_prom[(i << 8) | attr] & 0x07; /* bits 0 and 2 are swapped */ ctabentry = bitswap<8>(ctabentry,7,6,5,4,3,0,1,2); palette.set_pen_indirect((attr << 3) | i, ctabentry); } } /* background collision map */ for (i = 0; i < 8; i++) { palette.set_pen_indirect(0x800 + i, 0); palette.set_pen_indirect(0x808 + i, i & 0x04); palette.set_pen_indirect(0x810 + i, i & 0x02); palette.set_pen_indirect(0x818 + i, i & 0x06); } /* sprites */ for (i = 0; i < 8; i++) palette.set_pen_indirect(SPRITE_PEN_BASE + i, i | 0x08); /* bullet */ palette.set_pen_indirect(BULLET_STAR_PEN, 7); } void cvs_state::set_pens( ) { int i; for (i = 0; i < 0x10; i++) { int r = pal2bit(~m_palette_ram[i] >> 0); int g = pal3bit(~m_palette_ram[i] >> 2); int b = pal3bit(~m_palette_ram[i] >> 5); m_palette->set_indirect_color(i, rgb_t(r, g, b)); } } WRITE8_MEMBER(cvs_state::cvs_video_fx_w) { if (data & 0xce) logerror("%4x : CVS: Unimplemented CVS video fx = %2x\n",m_maincpu->pc(), data & 0xce); m_stars_on = data & 0x01; if (data & 0x02) logerror(" SHADE BRIGHTER TO RIGHT\n"); if (data & 0x04) logerror(" SCREEN ROTATE\n"); if (data & 0x08) logerror(" SHADE BRIGHTER TO LEFT\n"); m_lamps[0] = BIT(data, 4); /* lamp 1 */ m_lamps[1] = BIT(data, 5); /* lamp 2 */ if (data & 0x40) logerror(" SHADE BRIGHTER TO BOTTOM\n"); if (data & 0x80) logerror(" SHADE BRIGHTER TO TOP\n"); } READ8_MEMBER(cvs_state::cvs_collision_r) { return m_collision_register; } READ8_MEMBER(cvs_state::cvs_collision_clear) { m_collision_register = 0; return 0; } WRITE8_MEMBER(cvs_state::cvs_scroll_w) { m_scroll_reg = 255 - data; } VIDEO_START_MEMBER(cvs_state,cvs) { cvs_init_stars(); /* create helper bitmaps */ m_screen->register_screen_bitmap(m_background_bitmap); m_screen->register_screen_bitmap(m_collision_background); m_screen->register_screen_bitmap(m_scrolled_collision_background); /* register save */ save_item(NAME(m_background_bitmap)); save_item(NAME(m_collision_background)); save_item(NAME(m_scrolled_collision_background)); } uint32_t cvs_state::screen_update_cvs(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { static const int ram_based_char_start_indices[] = { 0xe0, 0xc0, 0x100, 0x80 }; offs_t offs; int scroll[8]; set_pens(); /* draw the background */ for (offs = 0; offs < 0x0400; offs++) { int collision_color = 0x100; uint8_t code = m_video_ram[offs]; uint8_t color = m_color_ram[offs]; uint8_t x = offs << 3; uint8_t y = offs >> 5 << 3; int gfxnum = (code < ram_based_char_start_indices[m_character_banking_mode]) ? 0 : 1; m_gfxdecode->gfx(gfxnum)->opaque(m_background_bitmap,m_background_bitmap.cliprect(), code, color, 0, 0, x, y); /* foreground for collision detection */ if (color & 0x80) collision_color = 0x103; else { if ((color & 0x03) == 0x03) collision_color = 0x101; else if ((color & 0x01) == 0) collision_color = 0x102; } m_gfxdecode->gfx(gfxnum)->opaque(m_collision_background,m_collision_background.cliprect(), code, collision_color, 0, 0, x, y); } /* Update screen - 8 regions, fixed scrolling area */ scroll[0] = 0; scroll[1] = m_scroll_reg; scroll[2] = m_scroll_reg; scroll[3] = m_scroll_reg; scroll[4] = m_scroll_reg; scroll[5] = m_scroll_reg; scroll[6] = 0; scroll[7] = 0; copyscrollbitmap(bitmap, m_background_bitmap, 0, nullptr, 8, scroll, cliprect); copyscrollbitmap(m_scrolled_collision_background, m_collision_background, 0, nullptr, 8, scroll, cliprect); /* update the S2636 chips */ bitmap_ind16 const &s2636_0_bitmap = m_s2636_0->update(cliprect); bitmap_ind16 const &s2636_1_bitmap = m_s2636_1->update(cliprect); bitmap_ind16 const &s2636_2_bitmap = m_s2636_2->update(cliprect); /* Bullet Hardware */ for (offs = 8; offs < 256; offs++ ) { if (m_bullet_ram[offs] != 0) { int ct; for (ct = 0; ct < 4; ct++) { int bx = 255 - 7 - m_bullet_ram[offs] - ct; /* Bullet/Object Collision */ if ((s2636_0_bitmap.pix16(offs, bx) != 0) || (s2636_1_bitmap.pix16(offs, bx) != 0) || (s2636_2_bitmap.pix16(offs, bx) != 0)) m_collision_register |= 0x08; /* Bullet/Background Collision */ if (m_palette->pen_indirect(m_scrolled_collision_background.pix16(offs, bx))) m_collision_register |= 0x80; bitmap.pix16(offs, bx) = BULLET_STAR_PEN; } } } /* mix and copy the S2636 images into the main bitmap, also check for collision */ { int y; for (y = cliprect.min_y; y <= cliprect.max_y; y++) { int x; for (x = cliprect.min_x; x <= cliprect.max_x; x++) { int pixel0 = s2636_0_bitmap.pix16(y, x); int pixel1 = s2636_1_bitmap.pix16(y, x); int pixel2 = s2636_2_bitmap.pix16(y, x); int pixel = pixel0 | pixel1 | pixel2; if (S2636_IS_PIXEL_DRAWN(pixel)) { bitmap.pix16(y, x) = SPRITE_PEN_BASE + S2636_PIXEL_COLOR(pixel); /* S2636 vs. S2636 collision detection */ if (S2636_IS_PIXEL_DRAWN(pixel0) && S2636_IS_PIXEL_DRAWN(pixel1)) m_collision_register |= 0x01; if (S2636_IS_PIXEL_DRAWN(pixel1) && S2636_IS_PIXEL_DRAWN(pixel2)) m_collision_register |= 0x02; if (S2636_IS_PIXEL_DRAWN(pixel0) && S2636_IS_PIXEL_DRAWN(pixel2)) m_collision_register |= 0x04; /* S2636 vs. background collision detection */ if (m_palette->pen_indirect(m_scrolled_collision_background.pix16(y, x))) { if (S2636_IS_PIXEL_DRAWN(pixel0)) m_collision_register |= 0x10; if (S2636_IS_PIXEL_DRAWN(pixel1)) m_collision_register |= 0x20; if (S2636_IS_PIXEL_DRAWN(pixel2)) m_collision_register |= 0x40; } } } } } /* stars circuit */ if (m_stars_on) cvs_update_stars(bitmap, cliprect, BULLET_STAR_PEN, 0); return 0; } /* cvs stars hardware */ void cvs_state::cvs_scroll_stars( ) { m_stars_scroll++; } void cvs_state::cvs_init_stars( ) { int generator = 0; int x, y; /* precalculate the star background */ m_total_stars = 0; for (y = 255; y >= 0; y--) { for (x = 511; x >= 0; x--) { int bit1, bit2; generator <<= 1; bit1 = (~generator >> 17) & 1; bit2 = (generator >> 5) & 1; if (bit1 ^ bit2) generator |= 1; if (((~generator >> 16) & 1) && (generator & 0xfe) == 0xfe) { if(((~(generator >> 12)) & 0x01) && ((~(generator >> 13)) & 0x01)) { if (m_total_stars < CVS_MAX_STARS) { m_stars[m_total_stars].x = x; m_stars[m_total_stars].y = y; m_stars[m_total_stars].code = 1; m_total_stars++; } } } } } } void cvs_state::cvs_update_stars(bitmap_ind16 &bitmap, const rectangle &cliprect, const pen_t star_pen, bool update_always) { for (int offs = 0; offs < m_total_stars; offs++) { uint8_t x = (m_stars[offs].x + m_stars_scroll) >> 1; uint8_t y = m_stars[offs].y + ((m_stars_scroll + m_stars[offs].x) >> 9); if ((y & 1) ^ ((x >> 4) & 1)) { if (flip_screen_x()) x = ~x; if (flip_screen_y()) y = ~y; if ((y >= cliprect.min_y) && (y <= cliprect.max_y) && (update_always || (m_palette->pen_indirect(bitmap.pix16(y, x)) == 0))) bitmap.pix16(y, x) = star_pen; } } }