/***************************************************************************
video.c
Functions to emulate the video hardware of the machine.
***************************************************************************/
#include "emu.h"
#include "video/resnet.h"
#include "includes/ladybug.h"
/***************************************************************************
Convert the color PROMs into a more useable format.
Lady Bug has a 32 bytes palette PROM and a 32 bytes sprite color lookup
table PROM.
The palette PROM is connected to the RGB output this way:
bit 7 -- inverter -- 220 ohm resistor -- BLUE
-- inverter -- 220 ohm resistor -- GREEN
-- inverter -- 220 ohm resistor -- RED
-- inverter -- 470 ohm resistor -- BLUE
-- unused
-- inverter -- 470 ohm resistor -- GREEN
-- unused
bit 0 -- inverter -- 470 ohm resistor -- RED
***************************************************************************/
static void palette_init_common( running_machine &machine, const UINT8 *color_prom, int colortable_size,
int r_bit0, int r_bit1, int g_bit0, int g_bit1, int b_bit0, int b_bit1 )
{
static const int resistances[2] = { 470, 220 };
double rweights[2], gweights[2], bweights[2];
int i;
/* compute the color output resistor weights */
compute_resistor_weights(0, 255, -1.0,
2, resistances, rweights, 470, 0,
2, resistances, gweights, 470, 0,
2, resistances, bweights, 470, 0);
/* allocate the colortable */
machine.colortable = colortable_alloc(machine, colortable_size);
/* create a lookup table for the palette */
for (i = 0; i < 0x20; i++)
{
int bit0, bit1;
int r, g, b;
/* red component */
bit0 = (~color_prom[i] >> r_bit0) & 0x01;
bit1 = (~color_prom[i] >> r_bit1) & 0x01;
r = combine_2_weights(rweights, bit0, bit1);
/* green component */
bit0 = (~color_prom[i] >> g_bit0) & 0x01;
bit1 = (~color_prom[i] >> g_bit1) & 0x01;
g = combine_2_weights(gweights, bit0, bit1);
/* blue component */
bit0 = (~color_prom[i] >> b_bit0) & 0x01;
bit1 = (~color_prom[i] >> b_bit1) & 0x01;
b = combine_2_weights(bweights, bit0, bit1);
colortable_palette_set_color(machine.colortable, i, MAKE_RGB(r, g, b));
}
/* color_prom now points to the beginning of the lookup table */
color_prom += 0x20;
/* characters */
for (i = 0; i < 0x20; i++)
{
UINT8 ctabentry = ((i << 3) & 0x18) | ((i >> 2) & 0x07);
colortable_entry_set_value(machine.colortable, i, ctabentry);
}
/* sprites */
for (i = 0x20; i < 0x40; i++)
{
UINT8 ctabentry = color_prom[(i - 0x20) >> 1];
ctabentry = BITSWAP8((color_prom[i - 0x20] >> 0) & 0x0f, 7,6,5,4,0,1,2,3);
colortable_entry_set_value(machine.colortable, i + 0x00, ctabentry);
ctabentry = BITSWAP8((color_prom[i - 0x20] >> 4) & 0x0f, 7,6,5,4,0,1,2,3);
colortable_entry_set_value(machine.colortable, i + 0x20, ctabentry);
}
}
PALETTE_INIT( ladybug )
{
palette_init_common(machine, color_prom, 0x20, 0, 5, 2, 6, 4, 7);
}
PALETTE_INIT( sraider )
{
int i;
/* the resistor net may be probably different than Lady Bug */
palette_init_common(machine, color_prom, 0x41, 3, 0, 5, 4, 7, 6);
/* star colors */
for (i = 0x20; i < 0x40; i++)
{
int bit0, bit1;
int r, g, b;
/* red component */
bit0 = ((i - 0x20) >> 3) & 0x01;
bit1 = ((i - 0x20) >> 4) & 0x01;
b = 0x47 * bit0 + 0x97 * bit1;
/* green component */
bit0 = ((i - 0x20) >> 1) & 0x01;
bit1 = ((i - 0x20) >> 2) & 0x01;
g = 0x47 * bit0 + 0x97 * bit1;
/* blue component */
bit0 = ((i - 0x20) >> 0) & 0x01;
r = 0x47 * bit0;
colortable_palette_set_color(machine.colortable, i, MAKE_RGB(r, g, b));
}
for (i = 0x60; i < 0x80; i++)
colortable_entry_set_value(machine.colortable, i, (i - 0x60) + 0x20);
/* stationary part of grid */
colortable_entry_set_value(machine.colortable, 0x81, 0x40);
}
WRITE8_HANDLER( ladybug_videoram_w )
{
ladybug_state *state = space->machine().driver_data<ladybug_state>();
state->m_videoram[offset] = data;
tilemap_mark_tile_dirty(state->m_bg_tilemap, offset);
}
WRITE8_HANDLER( ladybug_colorram_w )
{
ladybug_state *state = space->machine().driver_data<ladybug_state>();
state->m_colorram[offset] = data;
tilemap_mark_tile_dirty(state->m_bg_tilemap, offset);
}
WRITE8_HANDLER( ladybug_flipscreen_w )
{
if (flip_screen_get(space->machine()) != (data & 0x01))
{
flip_screen_set(space->machine(), data & 0x01);
tilemap_mark_all_tiles_dirty_all(space->machine());
}
}
WRITE8_HANDLER( sraider_io_w )
{
ladybug_state *state = space->machine().driver_data<ladybug_state>();
// bit7 = flip
// bit6 = grid red
// bit5 = grid green
// bit4 = grid blue
// bit3 = enable stars
// bit210 = stars speed/dir
if (flip_screen_get(space->machine()) != (data & 0x80))
{
flip_screen_set(space->machine(), data & 0x80);
tilemap_mark_all_tiles_dirty_all(space->machine());
}
state->m_grid_color = data & 0x70;
redclash_set_stars_enable(space->machine(), (data & 0x08) >> 3);
/*
* There must be a subtle clocking difference between
* Space Raider and the other games using this star generator,
* hence the -1 here
*/
redclash_set_stars_speed(space->machine(), (data & 0x07) - 1);
}
static TILE_GET_INFO( get_bg_tile_info )
{
ladybug_state *state = machine.driver_data<ladybug_state>();
int code = state->m_videoram[tile_index] + 32 * (state->m_colorram[tile_index] & 0x08);
int color = state->m_colorram[tile_index] & 0x07;
SET_TILE_INFO(0, code, color, 0);
}
static TILE_GET_INFO( get_grid_tile_info )
{
if (tile_index < 512)
SET_TILE_INFO(3, tile_index, 0, 0);
else
{
int temp = tile_index / 32;
tile_index = (31 - temp) * 32 + (tile_index % 32);
SET_TILE_INFO(4, tile_index, 0, 0);
}
}
VIDEO_START( ladybug )
{
ladybug_state *state = machine.driver_data<ladybug_state>();
state->m_bg_tilemap = tilemap_create(machine, get_bg_tile_info, tilemap_scan_rows, 8, 8, 32, 32);
tilemap_set_scroll_rows(state->m_bg_tilemap, 32);
tilemap_set_transparent_pen(state->m_bg_tilemap, 0);
}
VIDEO_START( sraider )
{
ladybug_state *state = machine.driver_data<ladybug_state>();
state->m_grid_tilemap = tilemap_create(machine, get_grid_tile_info, tilemap_scan_rows, 8, 8, 32, 32);
tilemap_set_scroll_rows(state->m_grid_tilemap, 32);
tilemap_set_transparent_pen(state->m_grid_tilemap, 0);
state->m_bg_tilemap = tilemap_create(machine, get_bg_tile_info, tilemap_scan_rows, 8, 8, 32, 32);
tilemap_set_scroll_rows(state->m_bg_tilemap, 32);
tilemap_set_transparent_pen(state->m_bg_tilemap, 0);
}
static void draw_sprites( running_machine &machine, bitmap_t *bitmap, const rectangle *cliprect )
{
ladybug_state *state = machine.driver_data<ladybug_state>();
UINT8 *spriteram = state->m_spriteram;
int offs;
for (offs = state->m_spriteram_size - 2 * 0x40; offs >= 2 * 0x40; offs -= 0x40)
{
int i = 0;
while (i < 0x40 && spriteram[offs + i] != 0)
i += 4;
while (i > 0)
{
/*
abccdddd eeeeeeee fffghhhh iiiiiiii
a enable?
b size (0 = 8x8, 1 = 16x16)
cc flip
dddd y offset
eeeeeeee sprite code (shift right 2 bits for 16x16 sprites)
fff unknown
g sprite bank
hhhh color
iiiiiiii x position
*/
i -= 4;
if (spriteram[offs + i] & 0x80)
{
if (spriteram[offs + i] & 0x40) /* 16x16 */
drawgfx_transpen(bitmap,cliprect,machine.gfx[1],
(spriteram[offs + i + 1] >> 2) + 4 * (spriteram[offs + i + 2] & 0x10),
spriteram[offs + i + 2] & 0x0f,
spriteram[offs + i] & 0x20,spriteram[offs + i] & 0x10,
spriteram[offs + i + 3],
offs / 4 - 8 + (spriteram[offs + i] & 0x0f),0);
else /* 8x8 */
drawgfx_transpen(bitmap,cliprect,machine.gfx[2],
spriteram[offs + i + 1] + 16 * (spriteram[offs + i + 2] & 0x10),
spriteram[offs + i + 2] & 0x0f,
spriteram[offs + i] & 0x20,spriteram[offs + i] & 0x10,
spriteram[offs + i + 3],
offs / 4 + (spriteram[offs + i] & 0x0f),0);
}
}
}
}
SCREEN_UPDATE( ladybug )
{
ladybug_state *state = screen->machine().driver_data<ladybug_state>();
int offs;
// clear the bg bitmap
bitmap_fill(bitmap, cliprect, 0);
for (offs = 0; offs < 32; offs++)
{
int sx = offs % 4;
int sy = offs / 4;
if (flip_screen_get(screen->machine()))
tilemap_set_scrollx(state->m_bg_tilemap, offs, -state->m_videoram[32 * sx + sy]);
else
tilemap_set_scrollx(state->m_bg_tilemap, offs, state->m_videoram[32 * sx + sy]);
}
tilemap_draw(bitmap, cliprect, state->m_bg_tilemap, 0, 0);
draw_sprites(screen->machine(), bitmap, cliprect);
return 0;
}
SCREEN_EOF( sraider ) /* update starfield position */
{
redclash_update_stars_state(machine);
}
SCREEN_UPDATE( sraider )
{
ladybug_state *state = screen->machine().driver_data<ladybug_state>();
// this part is boilerplate from ladybug, not sure if hardware does this,
// since it's not used
int offs;
int i;
for (offs = 0; offs < 32; offs++)
{
int sx = offs % 4;
int sy = offs / 4;
if (flip_screen_get(screen->machine()))
tilemap_set_scrollx(state->m_bg_tilemap, offs, -state->m_videoram[32 * sx + sy]);
else
tilemap_set_scrollx(state->m_bg_tilemap, offs, state->m_videoram[32 * sx + sy]);
}
// clear the bg bitmap
bitmap_fill(bitmap, cliprect, 0);
// draw the stars
if (flip_screen_get(screen->machine()))
redclash_draw_stars(screen->machine(), bitmap, cliprect, 0x60, 1, 0x27, 0xff);
else
redclash_draw_stars(screen->machine(), bitmap, cliprect, 0x60, 1, 0x00, 0xd8);
// draw the gridlines
colortable_palette_set_color(screen->machine().colortable, 0x40, MAKE_RGB(state->m_grid_color & 0x40 ? 0xff : 0,
state->m_grid_color & 0x20 ? 0xff : 0,
state->m_grid_color & 0x10 ? 0xff : 0));
tilemap_draw(bitmap, cliprect, state->m_grid_tilemap, 0, flip_screen_get(screen->machine()));
for (i = 0; i < 0x100; i++)
{
if (state->m_grid_data[i] != 0)
{
UINT8 x = i;
int height = cliprect->max_y - cliprect->min_y + 1;
if (flip_screen_get(screen->machine()))
x = ~x;
plot_box(bitmap, x, cliprect->min_y, 1, height, 0x81);
}
}
// now the chars
tilemap_draw(bitmap, cliprect, state->m_bg_tilemap, 0, flip_screen_get(screen->machine()));
// now the sprites
draw_sprites(screen->machine(), bitmap, cliprect);
return 0;
}