/***************************************************************************
video.c
Functions to emulate the video hardware of the machine.
***************************************************************************/
#include "emu.h"
#include "includes/popeye.h"
static const size_t popeye_bitmapram_size = 0x2000;
enum { TYPE_SKYSKIPR, TYPE_POPEYE };
/***************************************************************************
Convert the color PROMs into a more useable format.
Popeye has four color PROMS:
- 32x8 char palette
- 32x8 background palette
- two 256x4 sprite palette
The char and sprite PROMs are connected to the RGB output this way:
bit 7 -- 220 ohm resistor -- BLUE (inverted)
-- 470 ohm resistor -- BLUE (inverted)
-- 220 ohm resistor -- GREEN (inverted)
-- 470 ohm resistor -- GREEN (inverted)
-- 1 kohm resistor -- GREEN (inverted)
-- 220 ohm resistor -- RED (inverted)
-- 470 ohm resistor -- RED (inverted)
bit 0 -- 1 kohm resistor -- RED (inverted)
The background PROM is connected to the RGB output this way:
bit 7 -- 470 ohm resistor -- BLUE (inverted)
-- 680 ohm resistor -- BLUE (inverted) (1300 ohm in Sky Skipper)
-- 470 ohm resistor -- GREEN (inverted)
-- 680 ohm resistor -- GREEN (inverted)
-- 1.2kohm resistor -- GREEN (inverted)
-- 470 ohm resistor -- RED (inverted)
-- 680 ohm resistor -- RED (inverted)
bit 0 -- 1.2kohm resistor -- RED (inverted)
The bootleg is the same, but the outputs are not inverted.
***************************************************************************/
static void convert_color_prom(running_machine &machine,const UINT8 *color_prom)
{
popeye_state *state = machine.driver_data<popeye_state>();
int i;
/* palette entries 0-15 are directly used by the background and changed at runtime */
color_prom += 32;
/* characters */
for (i = 0;i < 16;i++)
{
int prom_offs = i | ((i & 8) << 1); /* address bits 3 and 4 are tied together */
int bit0,bit1,bit2,r,g,b;
/* red component */
bit0 = ((color_prom[prom_offs] ^ state->m_invertmask) >> 0) & 0x01;
bit1 = ((color_prom[prom_offs] ^ state->m_invertmask) >> 1) & 0x01;
bit2 = ((color_prom[prom_offs] ^ state->m_invertmask) >> 2) & 0x01;
r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
/* green component */
bit0 = ((color_prom[prom_offs] ^ state->m_invertmask) >> 3) & 0x01;
bit1 = ((color_prom[prom_offs] ^ state->m_invertmask) >> 4) & 0x01;
bit2 = ((color_prom[prom_offs] ^ state->m_invertmask) >> 5) & 0x01;
g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
/* blue component */
bit0 = 0;
bit1 = ((color_prom[prom_offs] ^ state->m_invertmask) >> 6) & 0x01;
bit2 = ((color_prom[prom_offs] ^ state->m_invertmask) >> 7) & 0x01;
b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
palette_set_color(machine,16 + (2 * i) + 1,MAKE_RGB(r,g,b));
}
color_prom += 32;
/* sprites */
for (i = 0;i < 256;i++)
{
int bit0,bit1,bit2,r,g,b;
/* red component */
bit0 = ((color_prom[0] ^ state->m_invertmask) >> 0) & 0x01;
bit1 = ((color_prom[0] ^ state->m_invertmask) >> 1) & 0x01;
bit2 = ((color_prom[0] ^ state->m_invertmask) >> 2) & 0x01;
r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
/* green component */
bit0 = ((color_prom[0] ^ state->m_invertmask) >> 3) & 0x01;
bit1 = ((color_prom[256] ^ state->m_invertmask) >> 0) & 0x01;
bit2 = ((color_prom[256] ^ state->m_invertmask) >> 1) & 0x01;
g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
/* blue component */
bit0 = 0;
bit1 = ((color_prom[256] ^ state->m_invertmask) >> 2) & 0x01;
bit2 = ((color_prom[256] ^ state->m_invertmask) >> 3) & 0x01;
b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
palette_set_color(machine,48+i,MAKE_RGB(r,g,b));
color_prom++;
}
}
PALETTE_INIT( popeye )
{
popeye_state *state = machine.driver_data<popeye_state>();
state->m_invertmask = 0xff;
convert_color_prom(machine,color_prom);
}
PALETTE_INIT( popeyebl )
{
popeye_state *state = machine.driver_data<popeye_state>();
state->m_invertmask = 0x00;
convert_color_prom(machine,color_prom);
}
static void set_background_palette(running_machine &machine,int bank)
{
popeye_state *state = machine.driver_data<popeye_state>();
int i;
UINT8 *color_prom = machine.region("proms")->base() + 16 * bank;
for (i = 0;i < 16;i++)
{
int bit0,bit1,bit2;
int r,g,b;
/* red component */
bit0 = ((*color_prom ^ state->m_invertmask) >> 0) & 0x01;
bit1 = ((*color_prom ^ state->m_invertmask) >> 1) & 0x01;
bit2 = ((*color_prom ^ state->m_invertmask) >> 2) & 0x01;
r = 0x1c * bit0 + 0x31 * bit1 + 0x47 * bit2;
/* green component */
bit0 = ((*color_prom ^ state->m_invertmask) >> 3) & 0x01;
bit1 = ((*color_prom ^ state->m_invertmask) >> 4) & 0x01;
bit2 = ((*color_prom ^ state->m_invertmask) >> 5) & 0x01;
g = 0x1c * bit0 + 0x31 * bit1 + 0x47 * bit2;
/* blue component */
bit0 = 0;
bit1 = ((*color_prom ^ state->m_invertmask) >> 6) & 0x01;
bit2 = ((*color_prom ^ state->m_invertmask) >> 7) & 0x01;
if (state->m_bitmap_type == TYPE_SKYSKIPR)
{
/* Sky Skipper has different weights */
bit0 = bit1;
bit1 = 0;
}
b = 0x1c * bit0 + 0x31 * bit1 + 0x47 * bit2;
palette_set_color(machine,i,MAKE_RGB(r,g,b));
color_prom++;
}
}
WRITE8_HANDLER( popeye_videoram_w )
{
popeye_state *state = space->machine().driver_data<popeye_state>();
state->m_videoram[offset] = data;
tilemap_mark_tile_dirty(state->m_fg_tilemap, offset);
}
WRITE8_HANDLER( popeye_colorram_w )
{
popeye_state *state = space->machine().driver_data<popeye_state>();
state->m_colorram[offset] = data;
tilemap_mark_tile_dirty(state->m_fg_tilemap, offset);
}
WRITE8_HANDLER( popeye_bitmap_w )
{
popeye_state *state = space->machine().driver_data<popeye_state>();
int sx,sy,x,y,colour;
state->m_bitmapram[offset] = data;
if (state->m_bitmap_type == TYPE_SKYSKIPR)
{
sx = 8 * (offset % 128);
sy = 8 * (offset / 128);
if (flip_screen_get(space->machine()))
sy = 512-8 - sy;
colour = data & 0x0f;
for (y = 0; y < 8; y++)
{
for (x = 0; x < 8; x++)
{
*BITMAP_ADDR16(state->m_tmpbitmap2, sy+y, sx+x) = colour;
}
}
}
else
{
sx = 8 * (offset % 64);
sy = 4 * (offset / 64);
if (flip_screen_get(space->machine()))
sy = 512-4 - sy;
colour = data & 0x0f;
for (y = 0; y < 4; y++)
{
for (x = 0; x < 8; x++)
{
*BITMAP_ADDR16(state->m_tmpbitmap2, sy+y, sx+x) = colour;
}
}
}
}
WRITE8_HANDLER( skyskipr_bitmap_w )
{
offset = ((offset & 0xfc0) << 1) | (offset & 0x03f);
if (data & 0x80)
offset |= 0x40;
popeye_bitmap_w(space,offset,data);
}
static TILE_GET_INFO( get_fg_tile_info )
{
popeye_state *state = machine.driver_data<popeye_state>();
int code = state->m_videoram[tile_index];
int color = state->m_colorram[tile_index] & 0x0f;
SET_TILE_INFO(0, code, color, 0);
}
VIDEO_START( skyskipr )
{
popeye_state *state = machine.driver_data<popeye_state>();
state->m_bitmapram = auto_alloc_array(machine, UINT8, popeye_bitmapram_size);
state->m_tmpbitmap2 = auto_bitmap_alloc(machine,1024,1024,machine.primary_screen->format()); /* actually 1024x512 but not rolling over vertically? */
state->m_bitmap_type = TYPE_SKYSKIPR;
state->m_fg_tilemap = tilemap_create(machine, get_fg_tile_info, tilemap_scan_rows, 16, 16, 32, 32);
tilemap_set_transparent_pen(state->m_fg_tilemap, 0);
state->m_lastflip = 0;
state_save_register_global(machine, state->m_lastflip);
state_save_register_global_bitmap(machine, state->m_tmpbitmap2);
state_save_register_global_pointer(machine, state->m_bitmapram, popeye_bitmapram_size);
}
VIDEO_START( popeye )
{
popeye_state *state = machine.driver_data<popeye_state>();
state->m_bitmapram = auto_alloc_array(machine, UINT8, popeye_bitmapram_size);
state->m_tmpbitmap2 = auto_bitmap_alloc(machine,512,512,machine.primary_screen->format());
state->m_bitmap_type = TYPE_POPEYE;
state->m_fg_tilemap = tilemap_create(machine, get_fg_tile_info, tilemap_scan_rows, 16, 16, 32, 32);
tilemap_set_transparent_pen(state->m_fg_tilemap, 0);
state->m_lastflip = 0;
state_save_register_global(machine, state->m_lastflip);
state_save_register_global_bitmap(machine, state->m_tmpbitmap2);
state_save_register_global_pointer(machine, state->m_bitmapram, popeye_bitmapram_size);
}
static void draw_background(running_machine &machine, bitmap_t *bitmap, const rectangle *cliprect)
{
popeye_state *state = machine.driver_data<popeye_state>();
int offs;
address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
if (state->m_lastflip != flip_screen_get(machine))
{
for (offs = 0;offs < popeye_bitmapram_size;offs++)
popeye_bitmap_w(space,offs,state->m_bitmapram[offs]);
state->m_lastflip = flip_screen_get(machine);
}
set_background_palette(machine, (*state->m_palettebank & 0x08) >> 3);
if (state->m_background_pos[1] == 0) /* no background */
bitmap_fill(bitmap,cliprect,0);
else
{
/* copy the background graphics */
int scrollx = 200 - state->m_background_pos[0] - 256*(state->m_background_pos[2]&1); /* ??? */
int scrolly = 2 * (256 - state->m_background_pos[1]);
if (state->m_bitmap_type == TYPE_SKYSKIPR)
scrollx = 2*scrollx - 512;
if (flip_screen_get(machine))
{
if (state->m_bitmap_type == TYPE_POPEYE)
scrollx = -scrollx;
scrolly = -scrolly;
}
copyscrollbitmap(bitmap,state->m_tmpbitmap2,1,&scrollx,1,&scrolly,cliprect);
}
}
static void draw_sprites(running_machine &machine, bitmap_t *bitmap, const rectangle *cliprect)
{
popeye_state *state = machine.driver_data<popeye_state>();
UINT8 *spriteram = state->m_spriteram;
int offs;
for (offs = 0;offs < state->m_spriteram_size;offs += 4)
{
int code,color,flipx,flipy,sx,sy;
/*
* offs+3:
* bit 7 ?
* bit 6 ?
* bit 5 ?
* bit 4 MSB of sprite code
* bit 3 vertical flip
* bit 2 sprite bank
* bit 1 \ color (with bit 2 as well)
* bit 0 /
*/
code = (spriteram[offs + 2] & 0x7f) + ((spriteram[offs + 3] & 0x10) << 3)
+ ((spriteram[offs + 3] & 0x04) << 6);
color = (spriteram[offs + 3] & 0x07) + 8*(*state->m_palettebank & 0x07);
if (state->m_bitmap_type == TYPE_SKYSKIPR)
{
/* Two of the PROM address pins are tied together and one is not connected... */
color = (color & 0x0f) | ((color & 0x08) << 1);
}
flipx = spriteram[offs + 2] & 0x80;
flipy = spriteram[offs + 3] & 0x08;
sx = 2*(spriteram[offs])-8;
sy = 2*(256-spriteram[offs + 1]);
if (flip_screen_get(machine))
{
flipx = !flipx;
flipy = !flipy;
sx = 496 - sx;
sy = 496 - sy;
}
if (spriteram[offs] != 0)
drawgfx_transpen(bitmap,cliprect,machine.gfx[1],
code ^ 0x1ff,
color,
flipx,flipy,
sx,sy,0);
}
}
SCREEN_UPDATE( popeye )
{
popeye_state *state = screen->machine().driver_data<popeye_state>();
draw_background(screen->machine(), bitmap, cliprect);
draw_sprites(screen->machine(), bitmap, cliprect);
tilemap_draw(bitmap, cliprect, state->m_fg_tilemap, 0, 0);
return 0;
}