// license:BSD-3-Clause
// copyright-holders:Jarek Parchanski
/***************************************************************************
Psychic 5
Bombs Away
Functions to emulate the video hardware of the machine.
***************************************************************************/
#include "emu.h"
#include "includes/psychic5.h"
#define BG_PAL_INTENSITY_RG 0x1fe
#define BG_PAL_INTENSITY_BU 0x1ff
/***************************************************************************
Palette color
***************************************************************************/
void psychic5_state::change_palette(int offset, uint8_t* palram, int palbase)
{
uint8_t lo = palram[(offset) & ~1];
uint8_t hi = palram[(offset) | 1];
int color = offset >> 1;
if (m_blend)
m_blend->set(palbase + color, hi & 0x0f);
m_palette->set_pen_color(palbase + color, pal4bit(lo >> 4), pal4bit(lo), pal4bit(hi >> 4));
}
void psychic5_state::change_bg_palette(int color, int lo_offs, int hi_offs)
{
uint8_t r,g,b,lo,hi,ir,ig,ib,ix;
rgb_t irgb;
/* red,green,blue intensities */
ir = pal4bit(m_palette_intensity >> 12);
ig = pal4bit(m_palette_intensity >> 8);
ib = pal4bit(m_palette_intensity >> 4);
ix = m_palette_intensity & 0x0f;
irgb = rgb_t(ir,ig,ib);
lo = m_ps5_palette_ram_bg[lo_offs];
hi = m_ps5_palette_ram_bg[hi_offs];
/* red,green,blue component */
r = pal4bit(lo >> 4);
g = pal4bit(lo);
b = pal4bit(hi >> 4);
/* Grey background enable */
if (m_bg_control[4] & 2)
{
uint8_t val = (r + g + b) / 3; /* Grey */
/* Just leave plain grey */
m_palette->set_pen_color(color,m_blend->func(rgb_t(val,val,val),irgb,ix));
}
else
{
/* Seems fishy, but the title screen would be black otherwise... */
if (!(m_title_screen & 1))
{
/* Leave the world as-is */
m_palette->set_pen_color(color,m_blend->func(rgb_t(r,g,b),irgb,ix));
}
}
}
void psychic5_state::set_background_palette_intensity()
{
int i;
m_palette_intensity = m_ps5_palette_ram_sp[BG_PAL_INTENSITY_BU] |
(m_ps5_palette_ram_sp[BG_PAL_INTENSITY_RG]<<8);
/* for all of the background palette */
for (i = 0; i < 0x100; i++)
change_bg_palette(i+0x100,i*2,i*2+1);
}
/***************************************************************************
Memory handler
***************************************************************************/
READ8_MEMBER(psychic5_state::vram_page_select_r)
{
return m_ps5_vram_page;
}
WRITE8_MEMBER(psychic5_state::vram_page_select_w)
{
m_ps5_vram_page = data & 1;
m_vrambank->set_bank(data);
}
WRITE8_MEMBER(psychic5_state::psychic5_title_screen_w)
{
m_title_screen = data;
}
WRITE8_MEMBER(psychic5_state::sprite_col_w)
{
m_ps5_palette_ram_sp[offset] = data;
change_palette(offset,m_ps5_palette_ram_sp, 0x000);
}
WRITE8_MEMBER(psychic5_state::bg_col_w)
{
m_ps5_palette_ram_bg[offset] = data;
change_palette(offset,m_ps5_palette_ram_bg, 0x100);
}
WRITE8_MEMBER(psychic5_state::tx_col_w)
{
m_ps5_palette_ram_tx[offset] = data;
change_palette(offset,m_ps5_palette_ram_tx, 0x200);
}
WRITE8_MEMBER(psychic5_state::fg_videoram_w)
{
m_fg_videoram[offset] = data;
m_fg_tilemap->mark_tile_dirty(offset >> 1);
}
WRITE8_MEMBER( psychic5_state::bg_videoram_w )
{
m_bg_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset >> 1);
}
WRITE8_MEMBER(psychic5_state::bombsa_unknown_w)
{
m_bombsa_unknown = data;
}
/***************************************************************************
Callbacks for the tilemap code
***************************************************************************/
TILE_GET_INFO_MEMBER(psychic5_state::get_bg_tile_info)
{
int offs = tile_index << 1;
int attr = m_bg_videoram[offs + 1];
int code = m_bg_videoram[offs] | ((attr & 0xc0) << 2);
int color = attr & 0x0f;
int flags = TILE_FLIPYX((attr & 0x30) >> 4);
SET_TILE_INFO_MEMBER(1, code, color, flags);
}
TILE_GET_INFO_MEMBER(psychic5_state::get_fg_tile_info)
{
int offs = tile_index << 1;
int attr = m_fg_videoram[offs + 1];
int code = m_fg_videoram[offs] | ((attr & 0xc0) << 2);
int color = attr & 0x0f;
int flags = TILE_FLIPYX((attr & 0x30) >> 4);
SET_TILE_INFO_MEMBER(2, code, color, flags);
}
/***************************************************************************
Initialize and destroy video hardware emulation
***************************************************************************/
void psychic5_state::video_start()
{
save_item(NAME(m_ps5_vram_page));
save_item(NAME(m_bg_clip_mode));
save_item(NAME(m_palette_intensity));
save_item(NAME(m_sx1));
save_item(NAME(m_sy1));
save_item(NAME(m_sy2));
}
VIDEO_START_MEMBER(psychic5_state,psychic5)
{
video_start();
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(psychic5_state::get_bg_tile_info),this), TILEMAP_SCAN_COLS, 16, 16, 64, 32);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(psychic5_state::get_fg_tile_info),this), TILEMAP_SCAN_COLS, 8, 8, 32, 32);
m_fg_tilemap->set_transparent_pen(15);
save_item(NAME(m_title_screen));
}
VIDEO_START_MEMBER(psychic5_state,bombsa)
{
video_start();
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(psychic5_state::get_bg_tile_info),this), TILEMAP_SCAN_COLS, 16, 16, 128, 32);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(psychic5_state::get_fg_tile_info),this), TILEMAP_SCAN_COLS, 8, 8, 32, 32);
m_fg_tilemap->set_transparent_pen(15);
save_item(NAME(m_bombsa_unknown));
}
VIDEO_RESET_MEMBER(psychic5_state,psychic5)
{
m_bg_clip_mode = 0;
m_ps5_vram_page = 0;
m_title_screen = 0;
m_palette_intensity = 0;
}
/***************************************************************************
Screen refresh
***************************************************************************/
#define DRAW_SPRITE(code, sx, sy) \
if (m_blend) \
m_blend->drawgfx(*m_palette, bitmap, cliprect, m_gfxdecode->gfx(0), code, color, flipx, flipy, sx, sy, 15); \
else \
m_gfxdecode->gfx(0)->transpen(bitmap, cliprect, code, color, flipx, flipy, sx, sy, 15);
void psychic5_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
/* Draw the sprites */
for (int offs = 0; offs < m_spriteram.bytes(); offs += 16)
{
int attr = m_spriteram[offs + 13];
if(attr & 2) // Bombs Away: disable sprite if enabled
continue;
int code = m_spriteram[offs + 14] | ((attr & 0xc0) << 2);
int color = m_spriteram[offs + 15] & 0x0f;
int flipx = attr & 0x10;
int flipy = attr & 0x20;
int sx = m_spriteram[offs + 12];
int sy = m_spriteram[offs + 11];
int size = (attr & 0x08) ? 32:16;
if (attr & 0x01) sx -= 256;
if (attr & 0x04) sy -= 256;
if (flip_screen())
{
sx = 224 - sx;
sy = 224 - sy;
flipx = !flipx;
flipy = !flipy;
}
if (size == 32)
{
int x0,x1,y0,y1;
if (flipx) { x0 = 2; x1 = 0; }
else { x0 = 0; x1 = 2; }
if (flipy) { y0 = 1; y1 = 0; }
else { y0 = 0; y1 = 1; }
DRAW_SPRITE(code + x0 + y0, sx, sy)
DRAW_SPRITE(code + x0 + y1, sx, sy + 16)
DRAW_SPRITE(code + x1 + y0, sx + 16, sy)
DRAW_SPRITE(code + x1 + y1, sx + 16, sy + 16)
}
else
{
if (flip_screen())
DRAW_SPRITE(code, sx + 16, sy + 16)
else
DRAW_SPRITE(code, sx, sy)
}
}
}
void psychic5_state::draw_background(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
rectangle clip = cliprect;
set_background_palette_intensity();
if (!(m_title_screen & 1))
{
m_bg_clip_mode = 0;
m_sx1 = m_sy1 = m_sy2 = 0;
}
else
{
int sy1_old = m_sy1;
int sx1_old = m_sx1;
int sy2_old = m_sy2;
m_sy1 = m_spriteram[11]; /* sprite 0 */
m_sx1 = m_spriteram[12];
m_sy2 = m_spriteram[11+128]; /* sprite 8 */
switch (m_bg_clip_mode)
{
case 0: case 4: if (sy1_old != m_sy1) m_bg_clip_mode++; break;
case 2: case 6: if (sy2_old != m_sy2) m_bg_clip_mode++; break;
case 8: case 10:
case 12: case 14: if (sx1_old != m_sx1) m_bg_clip_mode++; break;
case 1: case 5: if (m_sy1 == 0xf0) m_bg_clip_mode++; break;
case 3: case 7: if (m_sy2 == 0xf0) m_bg_clip_mode++; break;
case 9: case 11: if (m_sx1 == 0xf0) m_bg_clip_mode++; break;
case 13: case 15: if (sx1_old == 0xf0) m_bg_clip_mode++;
case 16: if (m_sy1 != 0x00) m_bg_clip_mode = 0; break;
}
switch (m_bg_clip_mode)
{
case 0: case 4: case 8: case 12: case 16:
clip.set(0, 0, 0, 0);
break;
case 1: clip.min_y = m_sy1; break;
case 3: clip.max_y = m_sy2; break;
case 5: clip.max_y = m_sy1; break;
case 7: clip.min_y = m_sy2; break;
case 9: case 15: clip.min_x = m_sx1; break;
case 11: case 13: clip.max_x = m_sx1; break;
}
if (flip_screen())
clip.set(255 - clip.max_x, 255 - clip.min_x, 255 - clip.max_y, 255 - clip.min_y);
}
m_bg_tilemap->draw(screen, bitmap, clip, 0, 0);
}
uint32_t psychic5_state::screen_update_psychic5(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
uint16_t bg_scrollx = m_bg_control[0] | (m_bg_control[1] << 8);
m_bg_tilemap->set_scrollx(0, bg_scrollx);
uint16_t bg_scrolly = m_bg_control[2] | (m_bg_control[3] << 8);
m_bg_tilemap->set_scrolly(0, bg_scrolly);
bitmap.fill(m_palette->black_pen(), cliprect);
if (m_bg_control[4] & 1) /* Backgound enable */
draw_background(screen, bitmap, cliprect);
if (!(m_title_screen & 1))
draw_sprites(bitmap, cliprect);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
uint32_t psychic5_state::screen_update_bombsa(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
uint16_t bg_scrollx = m_bg_control[0] | (m_bg_control[1] << 8);
m_bg_tilemap->set_scrollx(0, bg_scrollx);
uint16_t bg_scrolly = m_bg_control[2] | (m_bg_control[3] << 8);
m_bg_tilemap->set_scrolly(0, bg_scrolly);
bitmap.fill(m_palette->black_pen(), cliprect);
if (m_bg_control[4] & 1) /* Backgound enable */
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
else
bitmap.fill(m_palette->pen(0x0ff), cliprect);
draw_sprites(bitmap, cliprect);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}