/***************************************************************************
video\cvs.c
Functions to emulate the video hardware of the machine.
***************************************************************************/
#include "emu.h"
#include "cpu/s2650/s2650.h"
#include "includes/cvs.h"
#include "video/s2636.h"
#define SPRITE_PEN_BASE (0x820)
#define BULLET_STAR_PEN (0x828)
#define STARS_COLOR_BASE 16
/******************************************************
* 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( cvs )
{
int i, attr;
/* allocate the colortable */
machine.colortable = colortable_alloc(machine, 0x10);
/* color mapping PROM */
for (attr = 0; attr < 0x100; attr++)
{
for (i = 0; i < 8; i++)
{
UINT8 ctabentry = color_prom[(i << 8) | attr] & 0x07;
/* bits 0 and 2 are swapped */
ctabentry = BITSWAP8(ctabentry,7,6,5,4,3,0,1,2);
colortable_entry_set_value(machine.colortable, (attr << 3) | i, ctabentry);
}
}
/* background collision map */
for (i = 0; i < 8; i++)
{
colortable_entry_set_value(machine.colortable, 0x800 + i, 0);
colortable_entry_set_value(machine.colortable, 0x808 + i, i & 0x04);
colortable_entry_set_value(machine.colortable, 0x810 + i, i & 0x02);
colortable_entry_set_value(machine.colortable, 0x818 + i, i & 0x06);
}
/* sprites */
for (i = 0; i < 8; i++)
colortable_entry_set_value(machine.colortable, SPRITE_PEN_BASE + i, i | 0x08);
/* bullet */
colortable_entry_set_value(machine.colortable, BULLET_STAR_PEN, 7);
}
static void set_pens( running_machine &machine )
{
cvs_state *state = machine.driver_data<cvs_state>();
int i;
for (i = 0; i < 0x10; i++)
{
int r = pal2bit(~state->m_palette_ram[i] >> 0);
int g = pal3bit(~state->m_palette_ram[i] >> 2);
int b = pal3bit(~state->m_palette_ram[i] >> 5);
colortable_palette_set_color(machine.colortable, i, MAKE_RGB(r, g, b));
}
}
WRITE8_HANDLER( cvs_video_fx_w )
{
cvs_state *state = space->machine().driver_data<cvs_state>();
if (data & 0xce)
logerror("%4x : CVS: Unimplemented CVS video fx = %2x\n",cpu_get_pc(&space->device()), data & 0xce);
state->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");
set_led_status(space->machine(), 1, data & 0x10); /* lamp 1 */
set_led_status(space->machine(), 2, data & 0x20); /* lamp 2 */
if (data & 0x40) logerror(" SHADE BRIGHTER TO BOTTOM\n");
if (data & 0x80) logerror(" SHADE BRIGHTER TO TOP\n");
}
READ8_HANDLER( cvs_collision_r )
{
cvs_state *state = space->machine().driver_data<cvs_state>();
return state->m_collision_register;
}
READ8_HANDLER( cvs_collision_clear )
{
cvs_state *state = space->machine().driver_data<cvs_state>();
state->m_collision_register = 0;
return 0;
}
WRITE8_HANDLER( cvs_scroll_w )
{
cvs_state *state = space->machine().driver_data<cvs_state>();
state->m_scroll_reg = 255 - data;
}
VIDEO_START( cvs )
{
cvs_state *state = machine.driver_data<cvs_state>();
int generator = 0;
int y;
/* precalculate the star background */
state->m_total_stars = 0;
for (y = 255; y >= 0; y--)
{
int x;
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 (state->m_total_stars < CVS_MAX_STARS)
{
state->m_stars[state->m_total_stars].x = x;
state->m_stars[state->m_total_stars].y = y;
state->m_stars[state->m_total_stars].code = 1;
state->m_total_stars++;
}
}
}
}
}
/* create helper bitmaps */
state->m_background_bitmap = machine.primary_screen->alloc_compatible_bitmap();
state->m_collision_background = machine.primary_screen->alloc_compatible_bitmap();
state->m_scrolled_collision_background = machine.primary_screen->alloc_compatible_bitmap();
/* register save */
state->save_item(NAME(*state->m_background_bitmap));
state->save_item(NAME(*state->m_collision_background));
state->save_item(NAME(*state->m_scrolled_collision_background));
}
void cvs_scroll_stars( running_machine &machine )
{
cvs_state *state = machine.driver_data<cvs_state>();
state->m_stars_scroll++;
}
SCREEN_UPDATE( cvs )
{
cvs_state *state = screen->machine().driver_data<cvs_state>();
static const int ram_based_char_start_indices[] = { 0xe0, 0xc0, 0x100, 0x80 };
offs_t offs;
int scroll[8];
bitmap_t *s2636_0_bitmap, *s2636_1_bitmap, *s2636_2_bitmap;
set_pens(screen->machine());
/* draw the background */
for (offs = 0; offs < 0x0400; offs++)
{
int collision_color = 0x100;
UINT8 code = state->m_video_ram[offs];
UINT8 color = state->m_color_ram[offs];
UINT8 x = offs << 3;
UINT8 y = offs >> 5 << 3;
int gfxnum = (code < ram_based_char_start_indices[state->m_character_banking_mode]) ? 0 : 1;
drawgfx_opaque(state->m_background_bitmap, 0, screen->machine().gfx[gfxnum],
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;
}
drawgfx_opaque(state->m_collision_background, 0, screen->machine().gfx[gfxnum],
code, collision_color,
0, 0,
x, y);
}
/* Update screen - 8 regions, fixed scrolling area */
scroll[0] = 0;
scroll[1] = state->m_scroll_reg;
scroll[2] = state->m_scroll_reg;
scroll[3] = state->m_scroll_reg;
scroll[4] = state->m_scroll_reg;
scroll[5] = state->m_scroll_reg;
scroll[6] = 0;
scroll[7] = 0;
copyscrollbitmap(bitmap, state->m_background_bitmap, 0, 0, 8, scroll, cliprect);
copyscrollbitmap(state->m_scrolled_collision_background, state->m_collision_background, 0, 0, 8, scroll, cliprect);
/* update the S2636 chips */
s2636_0_bitmap = s2636_update(state->m_s2636_0, cliprect);
s2636_1_bitmap = s2636_update(state->m_s2636_1, cliprect);
s2636_2_bitmap = s2636_update(state->m_s2636_2, cliprect);
/* Bullet Hardware */
for (offs = 8; offs < 256; offs++ )
{
if (state->m_bullet_ram[offs] != 0)
{
int ct;
for (ct = 0; ct < 4; ct++)
{
int bx = 255 - 7 - state->m_bullet_ram[offs] - ct;
/* Bullet/Object Collision */
if ((*BITMAP_ADDR16(s2636_0_bitmap, offs, bx) != 0) ||
(*BITMAP_ADDR16(s2636_1_bitmap, offs, bx) != 0) ||
(*BITMAP_ADDR16(s2636_2_bitmap, offs, bx) != 0))
state->m_collision_register |= 0x08;
/* Bullet/Background Collision */
if (colortable_entry_get_value(screen->machine().colortable, *BITMAP_ADDR16(state->m_scrolled_collision_background, offs, bx)))
state->m_collision_register |= 0x80;
*BITMAP_ADDR16(bitmap, 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 = *BITMAP_ADDR16(s2636_0_bitmap, y, x);
int pixel1 = *BITMAP_ADDR16(s2636_1_bitmap, y, x);
int pixel2 = *BITMAP_ADDR16(s2636_2_bitmap, y, x);
int pixel = pixel0 | pixel1 | pixel2;
if (S2636_IS_PIXEL_DRAWN(pixel))
{
*BITMAP_ADDR16(bitmap, 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)) state->m_collision_register |= 0x01;
if (S2636_IS_PIXEL_DRAWN(pixel1) && S2636_IS_PIXEL_DRAWN(pixel2)) state->m_collision_register |= 0x02;
if (S2636_IS_PIXEL_DRAWN(pixel0) && S2636_IS_PIXEL_DRAWN(pixel2)) state->m_collision_register |= 0x04;
/* S2636 vs. background collision detection */
if (colortable_entry_get_value(screen->machine().colortable, *BITMAP_ADDR16(state->m_scrolled_collision_background, y, x)))
{
if (S2636_IS_PIXEL_DRAWN(pixel0)) state->m_collision_register |= 0x10;
if (S2636_IS_PIXEL_DRAWN(pixel1)) state->m_collision_register |= 0x20;
if (S2636_IS_PIXEL_DRAWN(pixel2)) state->m_collision_register |= 0x40;
}
}
}
}
}
/* stars circuit */
if (state->m_stars_on)
{
for (offs = 0; offs < state->m_total_stars; offs++)
{
UINT8 x = (state->m_stars[offs].x + state->m_stars_scroll) >> 1;
UINT8 y = state->m_stars[offs].y + ((state->m_stars_scroll + state->m_stars[offs].x) >> 9);
if ((y & 1) ^ ((x >> 4) & 1))
{
if (flip_screen_x_get(screen->machine()))
x = ~x;
if (flip_screen_y_get(screen->machine()))
y = ~y;
if ((y >= cliprect->min_y) && (y <= cliprect->max_y) &&
(colortable_entry_get_value(screen->machine().colortable, *BITMAP_ADDR16(bitmap, y, x)) == 0))
*BITMAP_ADDR16(bitmap, y, x) = BULLET_STAR_PEN;
}
}
}
return 0;
}