Radica 6502: some hacks to improve the video, (#3074)

* Radica 6502: some hacks to improve the video, lack of test cases / makes these tricky to figure out properly

* at least these aren't *my* bugs.. (nw)
This commit is contained in:
David Haywood 2018-01-16 21:11:20 +00:00 committed by R. Belmont
parent 0f59e5b720
commit c97f56c83f

View File

@ -128,6 +128,7 @@
Flaws (NOT emulation bugs, happen on hardware): Flaws (NOT emulation bugs, happen on hardware):
--
In QIX the sprites lag behind the line drawing, so you see the line infront of your player until you stop moving In QIX the sprites lag behind the line drawing, so you see the line infront of your player until you stop moving
@ -137,6 +138,19 @@
Colony 7 has a typo in the instructions Colony 7 has a typo in the instructions
The fake 'colour band' effect does not apply to the thruster (and several other elements) in Lunar Rescue
Enemies in Phoenix are rendered above the score panel
The 200pt right facing bird on the Phoenix score table is corrupt
Uncertain (to check)
Space Invaders seems to be using a darker than expected palette, there are lighter colours in the palette but
they don't seem to be used. It's difficult to judge from hardware videos, although it definitely isn't as
white as the menu, so this might also be a non-bug.
*/ */
#include "emu.h" #include "emu.h"
@ -306,6 +320,8 @@ private:
void handle_sound_1_w(int which, int offset, uint8_t data); void handle_sound_1_w(int which, int offset, uint8_t data);
uint8_t handle_sound_1_r(int which, int offset); uint8_t handle_sound_1_r(int which, int offset);
bool get_tile_data(int base, int drawpri, int& tile, int &attr, int &unk2);
void draw_tilemaps(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int drawpri);
void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
}; };
@ -325,14 +341,15 @@ void radica_6502_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap
/* /*
Sprites Sprites
AA yy xx ?? XX YY aa bb AA yy xx cc XX YY aa bb
yy = y position yy = y position
xx = x position xx = x position
XX = texture x start XX = texture x start
YY = texture y start YY = texture y start
aa = same as final param on tiles? aa = same as unk2 on tiles
bb = sometimes set in invaders bb = sometimes set in invaders
cc = same as attr on tiles (colour / priority?)
AA = attributes AA = attributes
e--- fFsS e--- fFsS
@ -349,23 +366,60 @@ void radica_6502_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap
uint8_t x = m_spriteram[i + 2]; uint8_t x = m_spriteram[i + 2];
uint8_t y = m_spriteram[i + 1]; uint8_t y = m_spriteram[i + 1];
/*
Space Invaders draws the player base with this specific y value before the start of each life
and expects it to NOT wrap around. There are no high priority tiles or anything else to hide
and it doesn't appear on real hardware.
it's possible sprites don't wrap around at all (but then you couldn't have smooth entry at the
top of the screen - there are no extra y co-ordinate bits. However there would have been easier
ways to hide this tho as there are a bunch of unseen lines at the bottom of the screen anyway!
needs further investigation.
*/
if (y==255)
continue;
uint8_t tex_x = m_spriteram[i + 4]; uint8_t tex_x = m_spriteram[i + 4];
uint8_t tex_y = m_spriteram[i + 5]; uint8_t tex_y = m_spriteram[i + 5];
uint8_t attrs = m_spriteram[i + 0]; uint8_t flags = m_spriteram[i + 0];
uint8_t attr = m_spriteram[i + 3];
uint8_t unk2 = m_spriteram[i + 6];
if (!(attrs & 0x80))
//int priority = attr & 0x0f;
int colour = attr & 0xf0;
// ? game select has this set to 0xff, but clearly doesn't want the palette to change!
// while in Space Invaders this has to be palette for the UFO to be red.
if (colour & 0x80)
colour = 0;
int transpen = 0;
/* HACK - how is this calculated
phoenix and the game select need it like this
it isn't a simple case of unk2 being transpen either because Qix has some elements set to 0x07
where the transpen needs to be 0x00 and Space Invaders has it set to 0x04
it could be a global register rather than something in the spritelist?
*/
if ((attr == 0xff) && (unk2 == 0xff))
transpen = 0xff;
if (!(flags & 0x80))
continue; continue;
int sizex = 8; int sizex = 8;
int sizey = 8; int sizey = 8;
if (attrs & 0x01) if (flags & 0x01)
{ {
sizex = 16; sizex = 16;
} }
if (attrs & 0x02) if (flags & 0x02)
{ {
sizey = 16; sizey = 16;
} }
@ -375,8 +429,8 @@ void radica_6502_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap
for (int yy = 0; yy < sizey; yy++) for (int yy = 0; yy < sizey; yy++)
{ {
uint16_t* row; uint16_t* row;
if (attrs & 0x08) // guess flipy if (flags & 0x08) // guess flipy
{ {
row = &bitmap.pix16((y + (sizey - 1 - yy)) & 0xff); row = &bitmap.pix16((y + (sizey - 1 - yy)) & 0xff);
} }
@ -387,20 +441,20 @@ void radica_6502_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap
for (int xx = 0; xx < sizex; xx++) for (int xx = 0; xx < sizex; xx++)
{ {
int realaddr = base + ((tex_x+xx)&0xff); int realaddr = base + ((tex_x + xx) & 0xff);
realaddr += ((tex_y+yy)&0xff) * 256; realaddr += ((tex_y + yy) & 0xff) * 256;
uint8_t pix = fullbankspace.read_byte(realaddr); uint8_t pix = fullbankspace.read_byte(realaddr);
if (pix) if (pix != transpen)
{ {
if (attrs & 0x04) // flipx if (flags & 0x04) // flipx
{ {
row[(x + (sizex - 1 - xx)) & 0xff] = pix;// + attr; row[(x + (sizex - 1 - xx)) & 0xff] = (pix + ((colour & 0x70) << 1)) & 0xff;
} }
else else
{ {
row[(x + xx) & 0xff] = pix;// + attr; row[(x + xx) & 0xff] = (pix + ((colour & 0x70) << 1)) & 0xff;
} }
} }
} }
@ -418,6 +472,160 @@ double hue2rgb(double p, double q, double t)
return p; return p;
} }
// a hacky mess for now
bool radica_6502_state::get_tile_data(int base, int drawpri, int& tile, int &attr, int &unk2)
{
tile = m_vram[base * 4] + (m_vram[(base * 4) + 1] << 8);
// these seem to be the basically the same as attr/unk2 in the sprites, which also make
// very little sense.
attr = m_vram[(base * 4) + 2];
unk2 = m_vram[(base * 4) + 3];
/* hack for phoenix title screens.. the have attr set to 0x3f which change the colour bank in ways we don't want
and also by our interpretation of 0x0f bits sets the tiles to priority over sprites (although in this case
that might tbe ok, because it looks like the sprites also have that set */
if (unk2 == 0x07)
attr = 0;
int priority = attr & 0x0f;
// likely wrong
if ((drawpri == 0 && priority == 0x0f) || (drawpri == 1 && priority != 0x0f))
return false;
return true;
}
void radica_6502_state::draw_tilemaps(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int drawpri)
{
/* this doesn't handle 8x8 4bpp, haven't seen it used
nor is there support for horizontal scrolling etc.
for the same reasons
*/
int scroll = (m_bg_scroll[1] << 8) | m_bg_scroll[0];
address_space& fullbankspace = m_bank->space(AS_PROGRAM);
if (m_5027_data & 0x40) // 16x16 tiles
{
int startrow = (scroll >> 4) & 0x1f;
for (int y = 0; y < 16; y++)
{
for (int x = 0; x < 16; x++)
{
int realstartrow = (startrow + y);
if (realstartrow >= 28)
realstartrow -= 28;
int base = (((realstartrow + y) & 0x1f) * 8) + x;
int tile,attr,unk2;
if (!get_tile_data(base, drawpri, tile,attr,unk2))
continue;
int colour = attr & 0xf0;
if (m_5027_data & 0x20) // 4bpp mode
{
tile = (tile & 0xf) + ((tile & ~0xf) * 16);
tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
}
else
{
tile = (tile & 0xf) + ((tile & ~0xf) * 16);
tile <<= 1;
tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
}
for (int i = 0; i < 16; i++)
{
int drawline = (y * 16) + i;
drawline -= scroll & 0xf;
if ((drawline >= 0) && (drawline < 256))
{
uint16_t* row = &bitmap.pix16(drawline);
if (m_5027_data & 0x20) // 4bpp
{
for (int xx = 0; xx < 16; xx += 2)
{
int realaddr = ((tile + i * 16) << 3) + (xx >> 1);
uint8_t pix = fullbankspace.read_byte(realaddr);
row[x * 16 + xx + 0] = ((pix & 0xf0) >> 4) + colour;
row[x * 16 + xx + 1] = ((pix & 0x0f) >> 0) + colour;
}
}
else // 8bpp
{
for (int xx = 0; xx < 16; xx++)
{
int realaddr = ((tile + i * 32) << 3) + xx;
uint8_t pix = fullbankspace.read_byte(realaddr);
row[x * 16 + xx] = (pix + ((colour & 0x70) << 1)) & 0xff;
}
}
}
}
}
}
}
else // 8x8 tiles
{
// Phoenix scrolling actually skips a pixel, jumping from 0x001 to 0x1bf, scroll 0x000 isn't used, maybe it has other meanings?
int startrow = (scroll >> 3) & 0x3f;
for (int y = 0; y < 32; y++)
{
for (int x = 0; x < 32; x++)
{
int realstartrow = (startrow + y);
if (realstartrow >= 56)
realstartrow -= 56;
int base = (((realstartrow) & 0x3f) * 32) + x;
int tile,attr,unk2;
if (!get_tile_data(base, drawpri, tile,attr,unk2))
continue;
int colour = attr & 0xf0;
tile = (tile & 0x1f) + ((tile & ~0x1f) * 8);
tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
for (int i = 0; i < 8; i++)
{
int drawline = (y * 8) + i;
drawline -= scroll & 0x7;
if ((drawline >= 0) && (drawline < 256))
{
uint16_t* row = &bitmap.pix16(drawline);
for (int xx = 0; xx < 8; xx++)
{
int realaddr = ((tile + i * 32) << 3) + xx;
uint8_t pix = fullbankspace.read_byte(realaddr);
row[x * 8 + xx] = (pix + ((colour & 0x70) << 1)) & 0xff;
}
}
}
}
}
}
}
uint32_t radica_6502_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) uint32_t radica_6502_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{ {
bitmap.fill(0, cliprect); bitmap.fill(0, cliprect);
@ -457,119 +665,10 @@ uint32_t radica_6502_state::screen_update(screen_device &screen, bitmap_ind16 &b
m_palette->set_pen_color(index, r_real, g_real, b_real); m_palette->set_pen_color(index, r_real, g_real, b_real);
} }
// Tilemaps
int scroll = (m_bg_scroll[1] << 8) | m_bg_scroll[0];
address_space& fullbankspace = m_bank->space(AS_PROGRAM);
if (m_5027_data & 0x40) // 16x16 tiles
{
int startrow = (scroll >> 4) & 0x1f;
for (int y = 0; y < 16; y++)
{
for (int x = 0; x < 16; x++)
{
int realstartrow = (startrow + y);
if (realstartrow >= 28)
realstartrow -= 28;
int base = (((realstartrow + y)&0x1f)*8)+x;
int tile = m_vram[base * 4] + (m_vram[(base * 4)+1] << 8);
int attr = m_vram[(base * 4)+ 2];
if (m_5027_data & 0x20) // 4bpp mode
{
tile = (tile & 0xf) + ((tile & ~0xf) * 16);
tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
}
else
{
tile = (tile & 0xf) + ((tile & ~0xf) * 16);
tile <<= 1;
tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
}
for (int i = 0; i < 16; i++)
{
int drawline = (y * 16) + i;
drawline -= scroll & 0xf;
if ((drawline >= 0) && (drawline < 256))
{
uint16_t* row = &bitmap.pix16(drawline);
if (m_5027_data & 0x20) // 4bpp
{
for (int xx = 0; xx < 16; xx += 2)
{
int realaddr = ((tile + i * 16) << 3) + (xx >> 1);
uint8_t pix = fullbankspace.read_byte(realaddr);
row[x * 16 + xx + 0] = ((pix & 0xf0) >> 4) + attr;
row[x * 16 + xx + 1] = ((pix & 0x0f) >> 0) + attr;
}
}
else // 8bpp
{
for (int xx = 0; xx < 16; xx++)
{
int realaddr = ((tile + i * 32) << 3) + xx;
uint8_t pix = fullbankspace.read_byte(realaddr);
row[x * 16 + xx] = pix;// + attr;
}
}
}
}
}
}
}
else // 8x8 tiles
{
// Phoenix scrolling actually skips a pixel, jumping from 0x001 to 0x1bf, scroll 0x000 isn't used, maybe it has other meanings?
int startrow = (scroll >> 3) & 0x3f;
for (int y = 0; y < 32; y++)
{
for (int x = 0; x < 32; x++)
{
int realstartrow = (startrow + y);
if (realstartrow >= 56)
realstartrow -= 56;
int base = (((realstartrow)&0x3f)*32)+x;
int tile = m_vram[base * 4] + (m_vram[(base * 4)+1] << 8);
//int attr = m_vram[(base * 4)+ 2];
tile = (tile & 0x1f) + ((tile & ~0x1f) * 8);
tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
for (int i = 0; i < 8; i++)
{
int drawline = (y * 8) + i;
drawline -= scroll & 0x7;
if ((drawline >= 0) && (drawline < 256))
{
uint16_t* row = &bitmap.pix16(drawline);
for (int xx = 0; xx < 8; xx++)
{
int realaddr = ((tile + i * 32) << 3) + xx;
uint8_t pix = fullbankspace.read_byte(realaddr);
row[x * 8 + xx] = pix;// + attr;
}
}
}
}
}
}
draw_tilemaps(screen,bitmap,cliprect,0);
draw_sprites(screen,bitmap,cliprect); draw_sprites(screen,bitmap,cliprect);
draw_tilemaps(screen,bitmap,cliprect,1);
return 0; return 0;
} }
@ -1327,7 +1426,7 @@ static MACHINE_CONFIG_START( radicasi )
MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 28*8-1) MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 28*8-1)
MCFG_SCREEN_PALETTE("palette") MCFG_SCREEN_PALETTE("palette")
MCFG_PALETTE_ADD("palette", 1024) MCFG_PALETTE_ADD("palette", 256)
MCFG_GFXDECODE_ADD("gfxdecode", "palette", radicasi_fake) MCFG_GFXDECODE_ADD("gfxdecode", "palette", radicasi_fake)