// license:BSD-3-Clause
// copyright-holders:Jarek Parchanski, Andrea Mazzoleni
/***************************************************************************
video.c
Functions to emulate the video hardware of the machine.
***************************************************************************/
#include "emu.h"
#include "includes/retofinv.h"
void retofinv_state::retofinv_palette(palette_device &palette) const
{
uint8_t const *const palette_prom = memregion("palette")->base();
uint8_t const *const clut_prom = memregion("clut")->base();
// create a lookup table for the palette
for (int i = 0; i < 0x100; i++)
{
int const r = pal4bit(palette_prom[i | 0x000]);
int const g = pal4bit(palette_prom[i | 0x100]);
int const b = pal4bit(palette_prom[i | 0x200]);
palette.set_indirect_color(i, rgb_t(r, g, b));
}
// fg chars (1bpp)
for (int i = 0; i < 0x200; i++)
{
uint8_t const ctabentry = (i & 0x01) ? (i >> 1) : 0;
palette.set_pen_indirect(i, ctabentry);
}
// sprites and bg tiles clut
for (int i = 0; i < 0x800; i++)
{
// descramble the address
int const j = bitswap<16>(i, 15,14,13,12,11,10,9,8,7,6,5,4,3,0,1,2);
palette.set_pen_indirect(i + 0x200, clut_prom[j]);
}
}
void retofinv_state::retofinv_bl_palette(palette_device &palette) const
{
uint8_t const *const palette_prom = memregion("palette")->base();
uint8_t const *const clut_prom = memregion("clut")->base();
// create a lookup table for the palette
for (int i = 0; i < 0x100; i++)
{
int const r = pal4bit(palette_prom[i | 0x000]);
int const g = pal4bit(palette_prom[i | 0x100]);
int const b = pal4bit(palette_prom[i | 0x200]);
palette.set_indirect_color(i, rgb_t(r, g, b));
}
// fg chars (1bpp)
for (int i = 0; i < 0x200; i++)
{
uint8_t const ctabentry = (i & 0x01) ? (i >> 1) : 0;
palette.set_pen_indirect(i, ctabentry);
}
// sprites and bg tiles clut
for (int i = 0; i < 0x800; i++)
{
// descramble the data
palette.set_pen_indirect(i + 0x200, bitswap<8>(clut_prom[i], 4,5,6,7,3,2,1,0));
}
}
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
/* convert from 32x32 to 36x28 */
TILEMAP_MAPPER_MEMBER(retofinv_state::tilemap_scan)
{
row += 2;
col -= 2;
if (col & 0x20)
return ((col & 0x1f) << 5) + row;
else
return (row << 5) + col;
}
TILE_GET_INFO_MEMBER(retofinv_state::bg_get_tile_info)
{
SET_TILE_INFO_MEMBER(2,
m_bg_videoram[tile_index] + 256 * m_bg_bank,
m_bg_videoram[0x400 + tile_index] & 0x3f,
0);
}
TILE_GET_INFO_MEMBER(retofinv_state::fg_get_tile_info)
{
int color = m_fg_videoram[0x400 + tile_index];
tileinfo.group = color;
SET_TILE_INFO_MEMBER(0,
m_fg_videoram[tile_index] + 256 * m_fg_bank,
color,
0);
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void retofinv_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(retofinv_state::bg_get_tile_info)), tilemap_mapper_delegate(*this, FUNC(retofinv_state::tilemap_scan)), 8, 8, 36, 28);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(retofinv_state::fg_get_tile_info)), tilemap_mapper_delegate(*this, FUNC(retofinv_state::tilemap_scan)), 8, 8, 36, 28);
m_fg_tilemap->configure_groups(*m_gfxdecode->gfx(0), 0);
save_item(NAME(m_fg_bank));
save_item(NAME(m_bg_bank));
}
/***************************************************************************
Memory handlers
***************************************************************************/
WRITE8_MEMBER(retofinv_state::bg_videoram_w)
{
m_bg_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset & 0x3ff);
}
WRITE8_MEMBER(retofinv_state::fg_videoram_w)
{
m_fg_videoram[offset] = data;
m_fg_tilemap->mark_tile_dirty(offset & 0x3ff);
}
WRITE8_MEMBER(retofinv_state::gfx_ctrl_w)
{
switch (offset)
{
case 0:
flip_screen_set(data & 1);
break;
case 1:
if (m_fg_bank != (data & 1))
{
m_fg_bank = data & 1;
m_fg_tilemap->mark_all_dirty();
}
break;
case 2:
if (m_bg_bank != (data & 1))
{
m_bg_bank = data & 1;
m_bg_tilemap->mark_all_dirty();
}
break;
}
}
/***************************************************************************
Display refresh
***************************************************************************/
void retofinv_state::draw_sprites(bitmap_ind16 &bitmap)
{
uint8_t *spriteram = m_sharedram + 0x0780;
uint8_t *spriteram_2 = m_sharedram + 0x0f80;
uint8_t *spriteram_3 = m_sharedram + 0x1780;
int offs;
const rectangle spritevisiblearea(2*8, 34*8-1, 0*8, 28*8-1);
for (offs = 0;offs < 0x80;offs += 2)
{
static const int gfx_offs[2][2] =
{
{ 0, 1 },
{ 2, 3 }
};
int sprite = spriteram[offs];
int color = spriteram[offs+1] & 0x3f;
int sx = ((spriteram_2[offs+1] << 1) + ((spriteram_3[offs+1] & 0x80) >> 7)) - 39;
int sy = 256 - ((spriteram_2[offs] << 1) + ((spriteram_3[offs] & 0x80) >> 7)) + 1;
/* not sure about the flipping, it's hardly ever used (mostly for shots) */
int flipx = (spriteram_3[offs] & 0x01);
int flipy = (spriteram_3[offs] & 0x02) >> 1;
int sizey = (spriteram_3[offs] & 0x04) >> 2;
int sizex = (spriteram_3[offs] & 0x08) >> 3;
int x,y;
sprite &= ~sizex;
sprite &= ~(sizey << 1);
if (flip_screen())
{
flipx ^= 1;
flipy ^= 1;
}
sy -= 16 * sizey;
sy = (sy & 0xff) - 32; // fix wraparound
for (y = 0;y <= sizey;y++)
{
for (x = 0;x <= sizex;x++)
{
m_gfxdecode->gfx(1)->transmask(bitmap,spritevisiblearea,
sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
color,
flipx,flipy,
sx + 16*x,sy + 16*y,
m_palette->transpen_mask(*m_gfxdecode->gfx(1), color, 0xff));
}
}
}
}
uint32_t retofinv_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->draw(screen, bitmap, cliprect, 0,0);
draw_sprites(bitmap);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0,0);
return 0;
}