// license:BSD-3-Clause
// copyright-holders:Luca Elia
/***************************************************************************
-= Cave Hardware =-
driver by Luca Elia (l.elia@tin.it)
Note: if MAME_DEBUG is defined, pressing:
X/C/V/B/Z with Q shows layer 0 (tiles with priority 0/1/2/3/All)
X/C/V/B/Z with W shows layer 1 (tiles with priority 0/1/2/3/All)
X/C/V/B/Z with E shows layer 2 (tiles with priority 0/1/2/3/All)
X/C/V/B/Z with R shows layer 3 (tiles with priority 0/1/2/3/All)
X/C/V/B/Z with A shows sprites (tiles with priority 0/1/2/3/All)
Keys can be used together!
[ 1 Layer per chip (games use as many as 4 chips) ]
Layer Size: 512 x 512
Tiles: 8 x 8 & 16 x 16.
There are 2 tilemaps in memory, one per tiles dimension.
A bit decides which one gets displayed.
The tiles depth varies with games, from 16 to 256 colors.
A per layer row-scroll / row-select effect can be enabled:
a different scroll value is fetched (from tile RAM) for each
scan line, and a different tilemap line for each scan line
[ 1024 Zooming Sprites ]
There are 2 or 4 0x4000 Sprite RAM Areas. A hardware register's
bit selects an area to display (sprites double buffering).
The sprites are NOT tile based: the "tile" size and start address
is selectable for each sprite with a 16 pixel granularity.
Also note that the zoom is of a peculiar type: pixels are never
drawn more than once. So shrinking works as usual (some pixels are
just not drawn) while enlarging adds some transparent pixels to
the image, uniformly, to reach the final size.
**************************************************************************/
#include "emu.h"
#include "crsshair.h"
#include "includes/cave.h"
#define CAVE_SPRITETYPE_ZBUF 0x01
#define CAVE_SPRITETYPE_ZOOM 0x02
#define SPRITE_FLIPX_CAVE 0x01
#define SPRITE_FLIPY_CAVE 0x02
#define SPRITE_VISIBLE_CAVE 0x04
/***************************************************************************
Palette Init Routines
Function needed for games with 4 bit sprites, rather than 8 bit,
or games with an odd colors mapping for the layers.
***************************************************************************/
PALETTE_INIT_MEMBER(cave_state,cave)
{
for (int chip = 0; chip < 4; chip++)
{
/* create a 1:1 palette map covering everything */
m_palette_map[chip] = std::make_unique<uint16_t[]>(palette.entries());
int maxpens = m_paletteram[chip].bytes() / 2;
if (!maxpens)
continue;
for (int pen = 0; pen < palette.entries(); pen++)
m_palette_map[chip][pen] = pen % maxpens;
}
}
PALETTE_INIT_MEMBER(cave_state,dfeveron)
{
int color, pen;
/* Fill the 0-3fff range, used by sprites ($40 color codes * $100 pens)
Here sprites have 16 pens, but the sprite drawing routine always
multiplies the color code by $100 (for consistency).
That's why we need this function. */
PALETTE_INIT_NAME(cave)(palette);
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x10; pen++)
m_palette_map[0][(color << 8) | pen] = (color << 4) | pen;
}
PALETTE_INIT_MEMBER(cave_state,ddonpach)
{
int color, pen;
/* Fill the 8000-83ff range ($40 color codes * $10 pens) for
layers 0 & 1 which are 4 bits deep rather than 8 bits deep
like layer 2, but use the first 16 color of every 256 for
any given color code. */
PALETTE_INIT_NAME(cave)(palette);
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x10; pen++)
m_palette_map[0][0x8000 | (color << 4) | pen] = 0x4000 | (color << 8) | pen;
}
PALETTE_INIT_MEMBER(cave_state,mazinger)
{
int color, pen;
PALETTE_INIT_NAME(cave)(palette);
/* sprites (encrypted) are 4 bit deep */
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x100; pen++)
m_palette_map[0][(color << 8) | pen] = (color << 4) + pen; /* yes, PLUS, not OR */
/* layer 0 is 6 bit deep, there are 64 color codes but only $400
colors are actually addressable */
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x40; pen++)
m_palette_map[0][0x4400 + ((color << 6) | pen)] = 0x400 | ((color & 0x0f) << 6) | pen;
}
PALETTE_INIT_MEMBER(cave_state,sailormn)
{
int color, pen;
PALETTE_INIT_NAME(cave)(palette);
/* sprites (encrypted) are 4 bit deep */
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x100; pen++)
m_palette_map[0][(color << 8) | pen] = (color << 4) + pen; /* yes, PLUS, not OR */
/* layer 2 is 6 bit deep, there are 64 color codes but only $400
colors are actually addressable */
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x40; pen++)
m_palette_map[0][0x4c00 + ((color << 6) | pen)] = 0xc00 | ((color & 0x0f) << 6) | pen;
}
PALETTE_INIT_MEMBER(cave_state,pwrinst2)
{
int color, pen;
PALETTE_INIT_NAME(cave)(palette);
for (color = 0; color < 0x80; color++)
for (pen = 0; pen < 0x10; pen++)
m_palette_map[0][(color << 8) | pen] = (color << 4) | pen;
for (pen = 0x8000; pen < 0xa800; pen++)
m_palette_map[0][pen] = pen - 0x8000;
}
PALETTE_INIT_MEMBER(cave_state,korokoro)
{
int color, pen;
PALETTE_INIT_NAME(cave)(palette);
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x10; pen++)
m_palette_map[0][(color << 8) | pen] = 0x3c00 | (color << 4) | pen;
}
void cave_state::set_pens(int chip)
{
int pen;
for (pen = 0; pen < m_palette->entries(); pen++)
{
uint16_t data = m_paletteram[chip][m_palette_map[chip][pen]];
rgb_t color = rgb_t(pal5bit(data >> 5), pal5bit(data >> 10), pal5bit(data >> 0));
m_palette->set_pen_color(pen, color);
}
}
/***************************************************************************
Tiles Format
Offset: Bits: Value:
0.w fe-- ---- ---- --- Priority
--dc ba98 ---- ---- Color
---- ---- 7654 3210
2.w Code
When a row-scroll / row-select effect is enabled, the scroll values are
fetched starting from tile RAM + $1000, 4 bytes per scan line:
Offset: Value:
0.w Tilemap line to display
2.w X Scroll value
***************************************************************************/
template<int Chip>
TILE_GET_INFO_MEMBER(cave_state::get_tile_info)
{
uint16_t *VRAM = m_vram[Chip];
int TDIM = m_tiledim[Chip];
uint32_t code, color, pri, tile;
if (TDIM)
{
tile = (tile_index % (512 / 8)) / 2 + ((tile_index / (512 / 8)) / 2) * (512 / 16);
code = (VRAM[tile * 2 + 0x0000 / 2] << 16) + VRAM[tile * 2 + 0x0002 / 2];
color = (code & 0x3f000000) >> (32-8);
pri = (code & 0xc0000000) >> (32-2);
code = (code & 0x00ffffff) * 4;
code += tile_index & 1;
code += ((tile_index / (512 / 8)) & 1) * 2;
}
else
{
code = (VRAM[tile_index * 2 + 0x4000 / 2] << 16) + VRAM[tile_index * 2 + 0x4002 / 2];
color = (code & 0x3f000000) >> (32 - 8);
pri = (code & 0xc0000000) >> (32 - 2);
code = (code & 0x00ffffff);
}
SET_TILE_INFO_MEMBER(Chip, code, color, 0 );
tileinfo.category = pri;
}
/* Sailormn: the lower 2 Megabytes of tiles banked */
void cave_state::sailormn_tilebank_w(int bank)
{
if (m_sailormn_tilebank != bank)
{
m_sailormn_tilebank = bank;
m_tilemap[2]->mark_all_dirty();
}
}
TILE_GET_INFO_MEMBER(cave_state::sailormn_get_tile_info_2)
{
uint32_t code, color, pri;
if (m_tiledim[2])
{
uint32_t tile;
tile = (tile_index % (512 / 8)) / 2 + ((tile_index / (512 / 8)) / 2) * (512 / 16);
code = (m_vram[2][tile * 2 + 0x0000 / 2] << 16) + m_vram[2][tile * 2 + 0x0002 / 2];
color = (code & 0x3f000000) >> (32 - 8);
pri = (code & 0xc0000000) >> (32 - 2);
code = (code & 0x00ffffff) * 4;
code += tile_index & 1;
code += ((tile_index / (512 / 8)) & 1) * 2;
}
else
{
code = (m_vram[2][tile_index * 2 + 0x4000 / 2] << 16) + m_vram[2][tile_index * 2 + 0x4002 / 2];
color = (code & 0x3f000000) >> (32 - 8);
pri = (code & 0xc0000000) >> (32 - 2);
code = (code & 0x00ffffff);
if ((code < 0x10000) && (m_sailormn_tilebank))
code += 0x40000;
}
SET_TILE_INFO_MEMBER(2, code, color, 0 );
tileinfo.category = pri;
}
/***************************************************************************
Video Init Routines
Depending on the game, there can be from 1 to 4 layers and the
tile sizes can be 8x8 or 16x16.
***************************************************************************/
void cave_state::cave_vh_start( int num )
{
assert(m_palette_map != nullptr);
m_tilemap[0] = nullptr;
m_tilemap[1] = nullptr;
m_tilemap[2] = nullptr;
m_tilemap[3] = nullptr;
m_tiledim[0] = 0;
m_tiledim[1] = 0;
m_tiledim[2] = 0;
m_tiledim[3] = 0;
m_old_tiledim[0] = 0;
m_old_tiledim[1] = 0;
m_old_tiledim[2] = 0;
m_old_tiledim[3] = 0;
assert((num >= 1) && (num <= 4));
switch (num)
{
case 4:
m_tilemap[3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(cave_state::get_tile_info<3>),this), TILEMAP_SCAN_ROWS, 8, 8, 512 / 8, 512 / 8);
m_tilemap[3]->set_transparent_pen(0);
m_tilemap[3]->set_scroll_rows(1);
m_tilemap[3]->set_scroll_cols(1);
save_item(NAME(m_tiledim[3]));
save_item(NAME(m_old_tiledim[3]));
case 3:
m_tilemap[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(cave_state::get_tile_info<2>),this), TILEMAP_SCAN_ROWS, 8, 8, 512 / 8, 512 / 8);
m_tilemap[2]->set_transparent_pen(0);
m_tilemap[2]->set_scroll_rows(1);
m_tilemap[2]->set_scroll_cols(1);
save_item(NAME(m_tiledim[2]));
save_item(NAME(m_old_tiledim[2]));
case 2:
m_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(cave_state::get_tile_info<1>),this), TILEMAP_SCAN_ROWS, 8, 8, 512 / 8, 512 / 8);
m_tilemap[1]->set_transparent_pen(0);
m_tilemap[1]->set_scroll_rows(1);
m_tilemap[1]->set_scroll_cols(1);
save_item(NAME(m_tiledim[1]));
save_item(NAME(m_old_tiledim[1]));
case 1:
m_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(cave_state::get_tile_info<0>),this), TILEMAP_SCAN_ROWS, 8, 8, 512 / 8, 512 / 8);
m_tilemap[0]->set_transparent_pen(0);
m_tilemap[0]->set_scroll_rows(1);
m_tilemap[0]->set_scroll_cols(1);
save_item(NAME(m_tiledim[0]));
save_item(NAME(m_old_tiledim[0]));
break;
}
sprite_init_cave();
m_layers_offs_x = 0x13;
m_layers_offs_y = -0x12;
m_row_effect_offs_n = -1;
m_row_effect_offs_f = 1;
m_background_pen = m_gfxdecode->gfx(0)->colorbase() +
(m_gfxdecode->gfx(0)->colors() - 1) *
m_gfxdecode->gfx(0)->granularity();
switch (m_kludge)
{
case 1: /* sailormn */
m_row_effect_offs_n = -1;
m_row_effect_offs_f = -1;
break;
case 2: /* uopoko dfeveron */
m_background_pen = 0x3f00;
break;
case 4: /* pwrinst2 */
m_background_pen = 0x7f00;
m_layers_offs_y++;
break;
}
}
VIDEO_START_MEMBER(cave_state,cave_1_layer){ cave_vh_start(1); }
VIDEO_START_MEMBER(cave_state,cave_2_layers){ cave_vh_start(2); }
VIDEO_START_MEMBER(cave_state,cave_3_layers){ cave_vh_start(3); }
VIDEO_START_MEMBER(cave_state,cave_4_layers){ cave_vh_start(4); }
VIDEO_START_MEMBER(cave_state,sailormn_3_layers)
{
cave_vh_start(2);
/* Layer 2 (8x8) needs to be handled differently */
m_tilemap[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(cave_state::sailormn_get_tile_info_2),this), TILEMAP_SCAN_ROWS, 8, 8, 512 / 8, 512 / 8 );
m_tilemap[2]->set_transparent_pen(0);
m_tilemap[2]->set_scroll_rows(1);
m_tilemap[2]->set_scroll_cols(1);
}
/***************************************************************************
Sprites Drawing
Offset: Bits: Value:
00.w fedc ba98 76-- ---- X Position
---- ---- --54 3210
02.w fedc ba98 76-- ---- Y Position
---- ---- --54 3210
04.w fe-- ---- ---- ----
--dc ba98 ---- ---- Color
---- ---- 76-- ----
---- ---- --54 ---- Priority
---- ---- ---- 3--- Flip X
---- ---- ---- -2-- Flip Y
---- ---- ---- --10 Code High Bit(s?)
06.w Code Low Bits
08/0A.w Zoom X / Y
0C.w fedc ba98 ---- ---- Tile Size X
---- ---- 7654 3210 Tile Size Y
0E.w Unused
***************************************************************************/
void cave_state::get_sprite_info_cave(int chip)
{
chip %= 4;
pen_t base_pal = 0;
const uint8_t *base_gfx = m_spriteregion[chip]->base();
int code_max = m_spriteregion[chip]->bytes() / (16*16);
uint16_t *source;
uint16_t *finish;
sprite_cave *sprite = m_sprite[chip].get();
int glob_flipx = m_videoregs[chip][0] & 0x8000;
int glob_flipy = m_videoregs[chip][1] & 0x8000;
int max_x = m_screen->width();
int max_y = m_screen->height();
source = m_spriteram[chip] + (0x4000 / 2) * m_spriteram_bank[chip];
finish = source + (0x4000 / 2);
for (; source < finish; source += 8)
{
int x, y, attr, code, zoomx, zoomy, size, flipx, flipy;
int total_width_f, total_height_f;
if (m_spritetype[0] == 2) /* Hot Dog Storm */
{
x = (source[0] & 0x3ff) << 8;
y = (source[1] & 0x3ff) << 8;
}
else /* all others */
{
x = source[0] << 2;
y = source[1] << 2;
}
attr = source[2];
code = source[3] + ((attr & 3) << 16);
zoomx = source[4];
zoomy = source[5];
size = source[6];
sprite->tile_width = ((size >> 8) & 0x1f) * 16;
sprite->tile_height = ((size >> 0) & 0x1f) * 16;
if (!sprite->tile_width || !sprite->tile_height)
continue;
/* Bound checking */
code %= code_max;
sprite->pen_data = base_gfx + (16 * 16) * code;
flipx = attr & 0x0008;
flipy = attr & 0x0004;
sprite->total_width = (total_width_f = sprite->tile_width * zoomx) / 0x100;
sprite->total_height = (total_height_f = sprite->tile_height * zoomy) / 0x100;
if (sprite->total_width <= 1)
{
sprite->total_width = 1;
sprite->zoomx_re = sprite->tile_width << 16;
sprite->xcount0 = sprite->zoomx_re / 2;
x -= 0x80;
}
else
{
sprite->zoomx_re = 0x1000000 / zoomx;
sprite->xcount0 = sprite->zoomx_re - 1;
}
if (sprite->total_height <= 1)
{
sprite->total_height = 1;
sprite->zoomy_re = sprite->tile_height << 16;
sprite->ycount0 = sprite->zoomy_re / 2;
y -= 0x80;
}
else
{
sprite->zoomy_re = 0x1000000 / zoomy;
sprite->ycount0 = sprite->zoomy_re - 1;
}
if (m_spritetype[0] == 2)
{
x >>= 8;
y >>= 8;
if (flipx && (zoomx != 0x100)) x += sprite->tile_width - sprite->total_width;
if (flipy && (zoomy != 0x100)) y += sprite->tile_height - sprite->total_height;
}
else
{
if (flipx && (zoomx != 0x100)) x += (sprite->tile_width << 8) - total_width_f - 0x80;
if (flipy && (zoomy != 0x100)) y += (sprite->tile_height << 8) - total_height_f - 0x80;
x >>= 8;
y >>= 8;
}
if (x > 0x1ff) x -= 0x400;
if (y > 0x1ff) y -= 0x400;
if (x + sprite->total_width <= 0 || x >= max_x || y + sprite->total_height <= 0 || y >= max_y )
{continue;}
sprite->priority = (attr & 0x0030) >> 4;
sprite->flags = SPRITE_VISIBLE_CAVE;
sprite->line_offset = sprite->tile_width;
sprite->base_pen = base_pal + (attr & 0x3f00); // first 0x4000 colors
if (glob_flipx) { x = max_x - x - sprite->total_width; flipx = !flipx; }
if (glob_flipy) { y = max_y - y - sprite->total_height; flipy = !flipy; }
sprite->x = x;
sprite->y = y;
if (flipx) sprite->flags |= SPRITE_FLIPX_CAVE;
if (flipy) sprite->flags |= SPRITE_FLIPY_CAVE;
sprite++;
}
m_num_sprites[chip] = sprite - m_sprite[chip].get();
}
void cave_state::get_sprite_info_donpachi(int chip)
{
chip %= 4;
pen_t base_pal = 0;
const uint8_t *base_gfx = m_spriteregion[chip]->base();
int code_max = m_spriteregion[chip]->bytes() / (16*16);
uint16_t *source;
uint16_t *finish;
sprite_cave *sprite = m_sprite[chip].get();
int glob_flipx = m_videoregs[chip][0] & 0x8000;
int glob_flipy = m_videoregs[chip][1] & 0x8000;
int max_x = m_screen->width();
int max_y = m_screen->height();
source = m_spriteram[chip] + (0x4000 / 2) * m_spriteram_bank[chip];
finish = source + (0x4000 / 2);
for (; source < finish; source += 8)
{
int x, y, attr, code, size, flipx, flipy;
attr = source[0];
code = source[1] + ((attr & 3) << 16);
x = source[2] & 0x3ff;
if (m_spritetype[0] == 3) /* pwrinst2 */
y = (source[3] + 1) & 0x3ff;
else
y = source[3] & 0x3ff;
size = source[4];
sprite->tile_width = sprite->total_width = ((size >> 8) & 0x1f) * 16;
sprite->tile_height = sprite->total_height = ((size >> 0) & 0x1f) * 16;
/* Bound checking */
code %= code_max;
sprite->pen_data = base_gfx + (16*16) * code;
if (x > 0x1ff) x -= 0x400;
if (y > 0x1ff) y -= 0x400;
if (!sprite->tile_width || !sprite->tile_height ||
x + sprite->total_width <= 0 || x >= max_x || y + sprite->total_height <= 0 || y >= max_y )
{continue;}
flipx = attr & 0x0008;
flipy = attr & 0x0004;
if (m_spritetype[0] == 3) /* pwrinst2 */
{
sprite->priority = ((attr & 0x0010) >> 4) + 2;
sprite->base_pen = base_pal + (attr & 0x3f00) + 0x4000 * ((attr & 0x0020) >> 5);
}
else
{
sprite->priority = (attr & 0x0030) >> 4;
sprite->base_pen = base_pal + (attr & 0x3f00); // first 0x4000 colors
}
sprite->flags = SPRITE_VISIBLE_CAVE;
sprite->line_offset = sprite->tile_width;
if (glob_flipx) { x = max_x - x - sprite->total_width; flipx = !flipx; }
if (glob_flipy) { y = max_y - y - sprite->total_height; flipy = !flipy; }
sprite->x = x;
sprite->y = y;
if (flipx) sprite->flags |= SPRITE_FLIPX_CAVE;
if (flipy) sprite->flags |= SPRITE_FLIPY_CAVE;
sprite++;
}
m_num_sprites[chip] = sprite - m_sprite[chip].get();
}
void cave_state::sprite_init_cave()
{
if (m_spritetype[0] == 0 || m_spritetype[0] == 2) // most of the games
{
m_get_sprite_info = &cave_state::get_sprite_info_cave;
m_spritetype[1] = CAVE_SPRITETYPE_ZOOM;
}
else // donpachi ddonpach
{
m_get_sprite_info = &cave_state::get_sprite_info_donpachi;
m_spritetype[1] = 0;
}
m_sprite_zbuf_baseval = 0x10000 - MAX_SPRITE_NUM;
m_screen->register_screen_bitmap(m_sprite_zbuf);
for (int chip = 0; chip < 4; chip++)
{
m_num_sprites[chip] = m_spriteram[chip].bytes() / 0x10 / 2;
m_sprite[chip] = std::make_unique<sprite_cave []>(m_num_sprites[chip]);
for (auto &prio : m_sprite_table[chip])
for (sprite_cave *&spr : prio)
spr = nullptr;
m_spriteram_bank[chip] = m_spriteram_bank_delay[chip] = 0;
}
m_sprite_draw = &cave_state::sprite_draw_donpachi;
save_item(NAME(m_sprite_zbuf));
save_item(NAME(m_sprite_zbuf_baseval));
save_item(NAME(m_num_sprites));
save_item(NAME(m_spriteram_bank));
save_item(NAME(m_spriteram_bank_delay));
save_item(NAME(m_blit.clip_left));
save_item(NAME(m_blit.clip_right));
save_item(NAME(m_blit.clip_top));
save_item(NAME(m_blit.clip_bottom));
machine().save().register_postload(save_prepost_delegate(FUNC(cave_state::cave_get_sprite_info_all), this));
}
void cave_state::cave_sprite_check(int chip, screen_device &screen, const rectangle &clip)
{
{ /* set clip */
int left = clip.min_x;
int top = clip.min_y;
int right = clip.max_x + 1;
int bottom = clip.max_y + 1;
m_blit.clip_left = left;
m_blit.clip_top = top;
m_blit.clip_right = right;
m_blit.clip_bottom = bottom;
}
{ /* check priority & sprite type */
sprite_cave *sprite = m_sprite[chip].get();
const sprite_cave *const finish = &sprite[m_num_sprites[chip]];
int i[4] = {0,0,0,0};
int priority_check = 0;
int spritetype = m_spritetype[1];
const rectangle &visarea = screen.visible_area();
while (sprite < finish)
{
if (sprite->x + sprite->total_width > m_blit.clip_left && sprite->x < m_blit.clip_right &&
sprite->y + sprite->total_height > m_blit.clip_top && sprite->y < m_blit.clip_bottom )
{
m_sprite_table[chip][sprite->priority][i[sprite->priority]++] = sprite;
if(!(spritetype & CAVE_SPRITETYPE_ZBUF))
{
if (priority_check > sprite->priority)
spritetype |= CAVE_SPRITETYPE_ZBUF;
else
priority_check = sprite->priority;
}
}
sprite++;
}
m_sprite_table[chip][0][i[0]] = nullptr;
m_sprite_table[chip][1][i[1]] = nullptr;
m_sprite_table[chip][2][i[2]] = nullptr;
m_sprite_table[chip][3][i[3]] = nullptr;
switch (spritetype)
{
case CAVE_SPRITETYPE_ZOOM:
m_sprite_draw = &cave_state::sprite_draw_cave;
break;
case CAVE_SPRITETYPE_ZOOM | CAVE_SPRITETYPE_ZBUF:
m_sprite_draw = &cave_state::sprite_draw_cave_zbuf;
if (clip.min_y == visarea.min_y)
{
if(!(m_sprite_zbuf_baseval += MAX_SPRITE_NUM))
m_sprite_zbuf.fill(0, visarea);
}
break;
case CAVE_SPRITETYPE_ZBUF:
m_sprite_draw = &cave_state::sprite_draw_donpachi_zbuf;
if (clip.min_y == visarea.min_y)
{
if(!(m_sprite_zbuf_baseval += MAX_SPRITE_NUM))
m_sprite_zbuf.fill(0, visarea);
}
break;
default:
case 0:
m_sprite_draw = &cave_state::sprite_draw_donpachi;
}
}
}
void cave_state::do_blit_zoom32_cave( int chip, const sprite_cave *sprite )
{
/* assumes SPRITE_LIST_RAW_DATA flag is set */
int x1, x2, y1, y2, dx, dy;
int xcount0 = 0x10000 + sprite->xcount0, ycount0 = 0x10000 + sprite->ycount0;
if (sprite->flags & SPRITE_FLIPX_CAVE)
{
x2 = sprite->x;
x1 = x2 + sprite->total_width;
dx = -1;
if (x2 < m_blit.clip_left)
x2 = m_blit.clip_left;
if (x1 > m_blit.clip_right)
{
xcount0 += (x1 - m_blit.clip_right) * sprite->zoomx_re;
x1 = m_blit.clip_right;
while ((xcount0 & 0xffff) >= sprite->zoomx_re)
{
xcount0 += sprite->zoomx_re;
x1--;
}
}
if (x2 >= x1)
return;
x1--; x2--;
}
else
{
x1 = sprite->x;
x2 = x1 + sprite->total_width;
dx = 1;
if (x1 < m_blit.clip_left)
{
xcount0 += (m_blit.clip_left - x1) * sprite->zoomx_re;
x1 = m_blit.clip_left;
while ((xcount0 & 0xffff) >= sprite->zoomx_re)
{
xcount0 += sprite->zoomx_re;
x1++;
}
}
if (x2 > m_blit.clip_right)
x2 = m_blit.clip_right;
if (x1 >= x2)
return;
}
if (sprite->flags & SPRITE_FLIPY_CAVE )
{
y2 = sprite->y;
y1 = y2 + sprite->total_height;
dy = -1;
if (y2 < m_blit.clip_top)
y2 = m_blit.clip_top;
if (y1 > m_blit.clip_bottom)
{
ycount0 += (y1 - m_blit.clip_bottom) * sprite->zoomy_re;
y1 = m_blit.clip_bottom;
while ((ycount0 & 0xffff) >= sprite->zoomy_re)
{
ycount0 += sprite->zoomy_re;
y1--;
}
}
if (y2 >= y1)
return;
y1--; y2--;
}
else
{
y1 = sprite->y;
y2 = y1 + sprite->total_height;
dy = 1;
if (y1 < m_blit.clip_top)
{
ycount0 += (m_blit.clip_top - y1) * sprite->zoomy_re;
y1 = m_blit.clip_top;
while ((ycount0 & 0xffff) >= sprite->zoomy_re)
{
ycount0 += sprite->zoomy_re;
y1++;
}
}
if (y2 > m_blit.clip_bottom )
y2 = m_blit.clip_bottom;
if (y1 >= y2)
return;
}
{
const uint8_t *pen_data = sprite->pen_data -1 -sprite->line_offset;
pen_t base_pen = sprite->base_pen;
int x, y;
uint8_t pen;
int pitch = m_blit.line_offset * dy / 4;
uint32_t *dest = (uint32_t *)(m_blit.baseaddr + m_blit.line_offset * y1);
int ycount = ycount0;
for (y = y1; y != y2; y += dy)
{
int xcount;
const uint8_t *source;
if (ycount & 0xffff0000)
{
xcount = xcount0;
pen_data += sprite->line_offset * (ycount >> 16);
ycount &= 0xffff;
source = pen_data;
for (x = x1; x != x2; x += dx)
{
if (xcount & 0xffff0000)
{
source += xcount >> 16;
xcount &= 0xffff;
pen = *source;
if (pen)
dest[x] = m_palette->pen_color(base_pen + pen);
}
xcount += sprite->zoomx_re;
}
}
ycount += sprite->zoomy_re;
dest += pitch;
}
}
}
void cave_state::do_blit_zoom32_cave_zb( int chip, const sprite_cave *sprite )
{
/* assumes SPRITE_LIST_RAW_DATA flag is set */
int x1, x2, y1, y2, dx, dy;
int xcount0 = 0x10000 + sprite->xcount0, ycount0 = 0x10000 + sprite->ycount0;
if (sprite->flags & SPRITE_FLIPX_CAVE)
{
x2 = sprite->x;
x1 = x2 + sprite->total_width;
dx = -1;
if (x2 < m_blit.clip_left)
x2 = m_blit.clip_left;
if (x1 > m_blit.clip_right)
{
xcount0 += (x1 - m_blit.clip_right) * sprite->zoomx_re;
x1 = m_blit.clip_right;
while ((xcount0 & 0xffff) >= sprite->zoomx_re)
{
xcount0 += sprite->zoomx_re;
x1--;
}
}
if (x2 >= x1)
return;
x1--; x2--;
}
else
{
x1 = sprite->x;
x2 = x1 + sprite->total_width;
dx = 1;
if (x1 < m_blit.clip_left)
{
xcount0 += (m_blit.clip_left - x1) * sprite->zoomx_re;
x1 = m_blit.clip_left;
while ((xcount0 & 0xffff) >= sprite->zoomx_re)
{
xcount0 += sprite->zoomx_re;
x1++;
}
}
if (x2 > m_blit.clip_right)
x2 = m_blit.clip_right;
if (x1 >= x2)
return;
}
if (sprite->flags & SPRITE_FLIPY_CAVE)
{
y2 = sprite->y;
y1 = y2 + sprite->total_height;
dy = -1;
if (y2 < m_blit.clip_top)
y2 = m_blit.clip_top;
if (y1 > m_blit.clip_bottom)
{
ycount0 += (y1 - m_blit.clip_bottom) * sprite->zoomy_re;
y1 = m_blit.clip_bottom;
while ((ycount0 & 0xffff) >= sprite->zoomy_re)
{
ycount0 += sprite->zoomy_re;
y1--;
}
}
if (y2 >= y1)
return;
y1--; y2--;
}
else
{
y1 = sprite->y;
y2 = y1 + sprite->total_height;
dy = 1;
if (y1 < m_blit.clip_top)
{
ycount0 += (m_blit.clip_top - y1) * sprite->zoomy_re;
y1 = m_blit.clip_top;
while ((ycount0 & 0xffff) >= sprite->zoomy_re)
{
ycount0 += sprite->zoomy_re;
y1++;
}
}
if (y2 > m_blit.clip_bottom)
y2 = m_blit.clip_bottom;
if (y1 >= y2)
return;
}
{
const uint8_t *pen_data = sprite->pen_data - 1 - sprite->line_offset;
pen_t base_pen = sprite->base_pen;
int x, y;
uint8_t pen;
int pitch = m_blit.line_offset * dy / 4;
uint32_t *dest = (uint32_t *)(m_blit.baseaddr + m_blit.line_offset * y1);
int pitchz = m_blit.line_offset_zbuf * dy / 2;
uint16_t *zbf = (uint16_t *)(m_blit.baseaddr_zbuf + m_blit.line_offset_zbuf * y1);
uint16_t pri_sp = (uint16_t)(sprite - m_sprite[chip].get()) + m_sprite_zbuf_baseval;
int ycount = ycount0;
for (y = y1; y != y2; y += dy)
{
int xcount;
const uint8_t *source;
if (ycount & 0xffff0000)
{
xcount = xcount0;
pen_data += sprite->line_offset * (ycount >> 16);
ycount &= 0xffff;
source = pen_data;
for (x = x1; x != x2; x += dx)
{
if (xcount & 0xffff0000)
{
source += xcount >> 16;
xcount &= 0xffff;
pen = *source;
if (pen && (zbf[x] <= pri_sp))
{
dest[x] = m_palette->pen_color(base_pen + pen);
zbf[x] = pri_sp;
}
}
xcount += sprite->zoomx_re;
}
}
ycount += sprite->zoomy_re;
dest += pitch;
zbf += pitchz;
}
}
}
void cave_state::do_blit_32_cave( int chip, const sprite_cave *sprite )
{
/* assumes SPRITE_LIST_RAW_DATA flag is set */
int x1, x2, y1, y2, dx, dy;
int xcount0 = 0, ycount0 = 0;
if (sprite->flags & SPRITE_FLIPX_CAVE)
{
x2 = sprite->x;
x1 = x2 + sprite->total_width;
dx = -1;
if (x2 < m_blit.clip_left)
x2 = m_blit.clip_left;
if (x1 > m_blit.clip_right)
{
xcount0 = x1 - m_blit.clip_right;
x1 = m_blit.clip_right;
}
if (x2 >= x1)
return;
x1--; x2--;
}
else
{
x1 = sprite->x;
x2 = x1 + sprite->total_width;
dx = 1;
if (x1 < m_blit.clip_left)
{
xcount0 = m_blit.clip_left - x1;
x1 = m_blit.clip_left;
}
if (x2 > m_blit.clip_right)
x2 = m_blit.clip_right;
if (x1 >= x2)
return;
}
if (sprite->flags & SPRITE_FLIPY_CAVE)
{
y2 = sprite->y;
y1 = y2 + sprite->total_height;
dy = -1;
if (y2 < m_blit.clip_top)
y2 = m_blit.clip_top;
if (y1 > m_blit.clip_bottom)
{
ycount0 = y1 - m_blit.clip_bottom;
y1 = m_blit.clip_bottom;
}
if (y2 >= y1)
return;
y1--; y2--;
}
else {
y1 = sprite->y;
y2 = y1 + sprite->total_height;
dy = 1;
if (y1 < m_blit.clip_top )
{
ycount0 = m_blit.clip_top - y1;
y1 = m_blit.clip_top;
}
if (y2 > m_blit.clip_bottom)
y2 = m_blit.clip_bottom;
if (y1 >= y2)
return;
}
{
const uint8_t *pen_data = sprite->pen_data;
pen_t base_pen = sprite->base_pen;
int x, y;
uint8_t pen;
int pitch = m_blit.line_offset * dy / 4;
uint32_t *dest = (uint32_t *)(m_blit.baseaddr + m_blit.line_offset * y1);
pen_data += sprite->line_offset * ycount0 + xcount0;
for (y = y1; y != y2; y += dy)
{
const uint8_t *source;
source = pen_data;
for (x = x1; x != x2; x += dx)
{
pen = *source;
if (pen)
dest[x] = m_palette->pen_color(base_pen + pen);
source++;
}
pen_data += sprite->line_offset;
dest += pitch;
}
}
}
void cave_state::do_blit_32_cave_zb( int chip, const sprite_cave *sprite )
{
/* assumes SPRITE_LIST_RAW_DATA flag is set */
int x1, x2, y1, y2, dx, dy;
int xcount0 = 0, ycount0 = 0;
if (sprite->flags & SPRITE_FLIPX_CAVE)
{
x2 = sprite->x;
x1 = x2 + sprite->total_width;
dx = -1;
if (x2 < m_blit.clip_left)
x2 = m_blit.clip_left;
if (x1 > m_blit.clip_right)
{
xcount0 = x1 - m_blit.clip_right;
x1 = m_blit.clip_right;
}
if (x2 >= x1)
return;
x1--; x2--;
}
else
{
x1 = sprite->x;
x2 = x1 + sprite->total_width;
dx = 1;
if (x1 < m_blit.clip_left)
{
xcount0 = m_blit.clip_left - x1;
x1 = m_blit.clip_left;
}
if (x2 > m_blit.clip_right)
x2 = m_blit.clip_right;
if (x1 >= x2)
return;
}
if (sprite->flags & SPRITE_FLIPY_CAVE)
{
y2 = sprite->y;
y1 = y2 + sprite->total_height;
dy = -1;
if (y2 < m_blit.clip_top)
y2 = m_blit.clip_top;
if (y1 > m_blit.clip_bottom)
{
ycount0 = y1 - m_blit.clip_bottom;
y1 = m_blit.clip_bottom;
}
if (y2 >= y1)
return;
y1--; y2--;
}
else
{
y1 = sprite->y;
y2 = y1 + sprite->total_height;
dy = 1;
if (y1 < m_blit.clip_top)
{
ycount0 = m_blit.clip_top - y1;
y1 = m_blit.clip_top;
}
if (y2 > m_blit.clip_bottom)
y2 = m_blit.clip_bottom;
if (y1 >= y2)
return;
}
{
const uint8_t *pen_data = sprite->pen_data;
pen_t base_pen = sprite->base_pen;
int x, y;
uint8_t pen;
int pitch = m_blit.line_offset * dy / 4;
uint32_t *dest = (uint32_t *)(m_blit.baseaddr + m_blit.line_offset * y1);
int pitchz = m_blit.line_offset_zbuf * dy / 2;
uint16_t *zbf = (uint16_t *)(m_blit.baseaddr_zbuf + m_blit.line_offset_zbuf * y1);
uint16_t pri_sp = (uint16_t)(sprite - m_sprite[chip].get()) + m_sprite_zbuf_baseval;
pen_data += sprite->line_offset * ycount0 + xcount0;
for (y = y1; y != y2; y += dy)
{
const uint8_t *source;
source = pen_data;
for (x = x1; x != x2; x += dx)
{
pen = *source;
if (pen && (zbf[x] <= pri_sp))
{
dest[x] = m_palette->pen_color(base_pen + pen);
zbf[x] = pri_sp;
}
source++;
}
pen_data += sprite->line_offset;
dest += pitch;
zbf += pitchz;
}
}
}
void cave_state::sprite_draw_cave( int chip, int priority )
{
int i = 0;
while (m_sprite_table[chip][priority][i])
{
const sprite_cave *sprite = m_sprite_table[chip][priority][i++];
if ((sprite->tile_width == sprite->total_width) && (sprite->tile_height == sprite->total_height))
do_blit_32_cave(chip, sprite);
else
do_blit_zoom32_cave(chip, sprite);
}
}
void cave_state::sprite_draw_cave_zbuf( int chip, int priority )
{
int i = 0;
while (m_sprite_table[chip][priority][i])
{
const sprite_cave *sprite = m_sprite_table[chip][priority][i++];
if ((sprite->tile_width == sprite->total_width) && (sprite->tile_height == sprite->total_height))
do_blit_32_cave_zb(chip, sprite);
else
do_blit_zoom32_cave_zb(chip, sprite);
}
}
void cave_state::sprite_draw_donpachi( int chip, int priority )
{
int i = 0;
while (m_sprite_table[chip][priority][i])
do_blit_32_cave(chip, m_sprite_table[chip][priority][i++]);
}
void cave_state::sprite_draw_donpachi_zbuf( int chip, int priority )
{
int i = 0;
while (m_sprite_table[chip][priority][i])
do_blit_32_cave_zb(chip, m_sprite_table[chip][priority][i++]);
}
/***************************************************************************
Screen Drawing
Layers Control Registers (cave_vctrl_0..2)
Offset: Bits: Value:
0.w f--- ---- ---- ---- 0 = Layer Flip X
-e-- ---- ---- ---- Activate Row-scroll
--d- ---- ---- ----
---c ba9- ---- ----
---- ---8 7654 3210 Scroll X
2.w f--- ---- ---- ---- 0 = Layer Flip Y
-e-- ---- ---- ---- Activate Row-select
--d- ---- ---- ---- 0 = 8x8 tiles, 1 = 16x16 tiles
---c ba9- ---- ----
---- ---8 7654 3210 Scroll Y
4.w fedc ba98 765- ----
---- ---- ---4 ---- Layer Disable
---- ---- ---- 32--
---- ---- ---- --10 Layer Priority (decides the order
of the layers for tiles with the
same tile priority)
Row-scroll / row-select data is fetched from tile RAM + $1000.
Row-select: a tilemap line is specified for each scan line.
Row-scroll: a different scroll value is specified for each scan line.
Sprites Registers (cave_videoregs)
Offset: Bits: Value:
0.w f--- ---- ---- ---- Sprites Flip X
-edc ba98 7654 3210 Sprites Offset X
2.w f--- ---- ---- ---- Sprites Flip Y
-edc ba98 7654 3210 Sprites Offset Y
..
8.w fedc ba98 7654 32--
---- ---- ---- --10 Sprite RAM Bank
There are more!
***************************************************************************/
inline void cave_state::tilemap_draw( int chip,
screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect,
uint32_t flags, uint32_t priority, uint32_t priority2, int GFX )
{
tilemap_t *TILEMAP = m_tilemap[GFX];
uint16_t *VRAM = m_vram[GFX];
uint16_t *VCTRL = m_vctrl[GFX];
int sx, sy, flipx, flipy, offs_x, offs_y, offs_row;
/* Bail out if ... */
if ( (!TILEMAP) || /* no tilemap; */
((VCTRL[2] & 0x0003) != priority2) || /* tilemap's global priority not the requested one; */
((VCTRL[2] & 0x0010)) ) /* tilemap's disabled. */
return;
flipx = ~VCTRL[0] & 0x8000;
flipy = ~VCTRL[1] & 0x8000;
TILEMAP->set_flip((flipx ? TILEMAP_FLIPX : 0) | (flipy ? TILEMAP_FLIPY : 0) );
offs_x = m_layers_offs_x;
offs_y = m_layers_offs_y;
offs_row = flipy ? m_row_effect_offs_f : m_row_effect_offs_n;
/* An additional 8 pixel offset for layers with 8x8 tiles. Plus
Layer 0 is displaced by 1 pixel wrt Layer 1, so is Layer 2 wrt
Layer 1 */
if (TILEMAP == m_tilemap[0]) offs_x -= (m_tiledim[0] ? 1 : (1 + 8));
else if (TILEMAP == m_tilemap[1]) offs_x -= (m_tiledim[1] ? 2 : (2 + 8));
else if (TILEMAP == m_tilemap[2]) offs_x -= (m_tiledim[2] ? 3 : (3 + 8));
else if (TILEMAP == m_tilemap[3]) offs_x -= (m_tiledim[3] ? 4 : (4 + 8));
sx = VCTRL[0] - m_videoregs[chip][0] + (flipx ? (offs_x + 2) : -offs_x);
sy = VCTRL[1] - m_videoregs[chip][1] + (flipy ? (offs_y + 2) : -offs_y);
if (VCTRL[1] & 0x4000) // row-select
{
rectangle clip;
int startline, endline, vramdata0, vramdata1;
/*
Row-select:
A tilemap line is specified for each scan line. This is handled
using many horizontal clipping regions (slices) and calling
tilemap_draw multiple times.
*/
clip.min_x = cliprect.min_x;
clip.max_x = cliprect.max_x;
for (startline = cliprect.min_y; startline <= cliprect.max_y;)
{
/* Find the largest slice */
vramdata0 = (vramdata1 = VRAM[(0x1002 + (((sy + offs_row + startline) * 4) & 0x7ff)) / 2]);
for(endline = startline + 1; endline <= cliprect.max_y; endline++)
if((++vramdata1) != VRAM[(0x1002 + (((sy + offs_row + endline) * 4) & 0x7ff)) / 2]) break;
TILEMAP->set_scrolly(0, vramdata0 - startline);
if (VCTRL[0] & 0x4000) // row-scroll, row-select
{
int line;
/*
Row-scroll:
A different scroll value is specified for each scan line.
This is handled using tilemap_set_scroll_rows and calling
tilemap_draw just once.
*/
TILEMAP->set_scroll_rows(512);
for(line = startline; line < endline; line++)
TILEMAP->set_scrollx((vramdata0 - startline + line) & 511,
sx + VRAM[(0x1000 + (((sy + offs_row + line) * 4) & 0x7ff)) / 2]);
}
else // no row-scroll, row-select
{
TILEMAP->set_scroll_rows(1);
TILEMAP->set_scrollx(0, sx);
}
if (flipy)
{
clip.min_y = cliprect.max_y - (endline - 1 - cliprect.min_y);
clip.max_y = cliprect.max_y - (startline - cliprect.min_y);
}
else
{
clip.min_y = startline;
clip.max_y = endline - 1;
}
TILEMAP->draw(screen, bitmap, clip, flags, priority);
startline = endline;
}
}
else if (VCTRL[0] & 0x4000) // row-scroll, no row-select
{
int line;
TILEMAP->set_scroll_rows(512);
for(line = cliprect.min_y; line <= cliprect.max_y; line++)
TILEMAP->set_scrollx((line + sy) & 511,
sx + VRAM[(0x1000+(((sy + offs_row + line) * 4) & 0x7ff)) / 2] );
TILEMAP->set_scrolly(0, sy);
TILEMAP->draw(screen, bitmap, cliprect, flags, priority);
}
else
{
/* DEF_STR( Normal ) scrolling */
TILEMAP->set_scroll_rows(1);
TILEMAP->set_scroll_cols(1);
TILEMAP->set_scrollx(0, sx);
TILEMAP->set_scrolly(0, sy);
TILEMAP->draw(screen, bitmap, cliprect, flags, priority);
}
}
uint32_t cave_state::screen_update_cave(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
int pri, pri2, GFX;
int layers_ctrl = -1;
set_pens(0);
m_blit.baseaddr = reinterpret_cast<uint8_t *>(bitmap.raw_pixptr(0));
m_blit.line_offset = bitmap.rowbytes();
m_blit.baseaddr_zbuf = reinterpret_cast<uint8_t *>(m_sprite_zbuf.raw_pixptr(0));
m_blit.line_offset_zbuf = m_sprite_zbuf.rowbytes();
/* Choose the tilemap to display (8x8 tiles or 16x16 tiles) */
for (GFX = 0; GFX < 4; GFX++)
{
if (m_tilemap[GFX])
{
m_tiledim[GFX] = m_vctrl[GFX][1] & 0x2000;
if (m_tiledim[GFX] != m_old_tiledim[GFX])
m_tilemap[GFX]->mark_all_dirty();
m_old_tiledim[GFX] = m_tiledim[GFX];
}
}
#ifdef MAME_DEBUG
{
if ( machine().input().code_pressed(KEYCODE_Z) || machine().input().code_pressed(KEYCODE_X) || machine().input().code_pressed(KEYCODE_C) ||
machine().input().code_pressed(KEYCODE_V) || machine().input().code_pressed(KEYCODE_B) )
{
int msk = 0, val = 0;
if (machine().input().code_pressed(KEYCODE_X)) val = 1; // priority 0 only
if (machine().input().code_pressed(KEYCODE_C)) val = 2; // "" 1
if (machine().input().code_pressed(KEYCODE_V)) val = 4; // "" 2
if (machine().input().code_pressed(KEYCODE_B)) val = 8; // "" 3
if (machine().input().code_pressed(KEYCODE_Z)) val = 1|2|4|8; // All of the above priorities
if (machine().input().code_pressed(KEYCODE_Q)) msk |= val << 0; // for layer 0
if (machine().input().code_pressed(KEYCODE_W)) msk |= val << 4; // for layer 1
if (machine().input().code_pressed(KEYCODE_E)) msk |= val << 8; // for layer 2
if (machine().input().code_pressed(KEYCODE_R)) msk |= val << 12; // for layer 3
if (machine().input().code_pressed(KEYCODE_A)) msk |= val << 16; // for sprites
if (msk != 0) layers_ctrl &= msk;
#if 1
/* Show the video registers (cave_videoregs) */
popmessage("%04X %04X %04X %04X %04X %04X %04X %04X",
m_videoregs[0][0], m_videoregs[0][1], m_videoregs[0][2], m_videoregs[0][3],
m_videoregs[0][4], m_videoregs[0][5], m_videoregs[0][6], m_videoregs[0][7] );
#endif
/* Show the scroll / flags registers of the selected layer */
if ((m_tilemap[0]) && (msk & 0x000f)) popmessage("x:%04X y:%04X f:%04X", m_vctrl[0][0],m_vctrl[0][1],m_vctrl[0][2]);
if ((m_tilemap[1]) && (msk & 0x00f0)) popmessage("x:%04X y:%04X f:%04X", m_vctrl[1][0],m_vctrl[1][1],m_vctrl[1][2]);
if ((m_tilemap[2]) && (msk & 0x0f00)) popmessage("x:%04X y:%04X f:%04X", m_vctrl[2][0],m_vctrl[2][1],m_vctrl[2][2]);
if ((m_tilemap[3]) && (msk & 0xf000)) popmessage("x:%04X y:%04X f:%04X", m_vctrl[3][0],m_vctrl[3][1],m_vctrl[3][2]);
}
/* Show the row / "column" scroll enable flags, when they change state */
m_rasflag = 0;
for (GFX = 0; GFX < 4; GFX++)
{
if (m_tilemap[GFX])
{
m_rasflag |= (m_vctrl[GFX][0] & 0x4000) ? 0x0001 << (4*GFX) : 0;
m_rasflag |= (m_vctrl[GFX][1] & 0x4000) ? 0x0002 << (4*GFX) : 0;
}
}
if (m_rasflag != m_old_rasflag)
{
popmessage("Line Effect: 0:%c%c 1:%c%c 2:%c%c 3:%c%c",
(m_rasflag & 0x0001) ? 'x' : ' ', (m_rasflag & 0x0002) ? 'y' : ' ',
(m_rasflag & 0x0010) ? 'x' : ' ', (m_rasflag & 0x0020) ? 'y' : ' ',
(m_rasflag & 0x0100) ? 'x' : ' ', (m_rasflag & 0x0200) ? 'y' : ' ',
(m_rasflag & 0x1000) ? 'x' : ' ', (m_rasflag & 0x2000) ? 'y' : ' ' );
m_old_rasflag = m_rasflag;
}
}
#endif
cave_sprite_check(0, screen, cliprect);
bitmap.fill(m_palette->pen_color(m_background_pen), cliprect);
/*
Tiles and sprites are ordered by priority (0 back, 3 front) with
sprites going below tiles of their same priority.
Sprites with the same priority are ordered by their place in
sprite RAM (last sprite is the frontmost).
Tiles with the same priority are ordered by the priority of their layer.
Tiles with the same priority *and* the same priority of their layer
are ordered by layer (0 back, 2 front)
*/
for (pri = 0; pri <= 3; pri++) // tile / sprite priority
{
if (layers_ctrl & (1 << (pri + 16))) (this->*m_sprite_draw)(0, pri);
for (pri2 = 0; pri2 <= 3; pri2++) // priority of the whole layer
{
if (layers_ctrl & (1 << (pri + 0))) tilemap_draw(0, screen, bitmap, cliprect, pri, 0, pri2, 0);
if (layers_ctrl & (1 << (pri + 4))) tilemap_draw(0, screen, bitmap, cliprect, pri, 0, pri2, 1);
if (layers_ctrl & (1 << (pri + 8))) tilemap_draw(0, screen, bitmap, cliprect, pri, 0, pri2, 2);
if (layers_ctrl & (1 << (pri + 12))) tilemap_draw(0, screen, bitmap, cliprect, pri, 0, pri2, 3);
}
}
return 0;
}
/**************************************************************/
void cave_state::cave_get_sprite_info(int chip)
{
int spriteram_bankmax = m_spriteram[chip].bytes() / 0x4000;
if (m_videoregs[chip] == nullptr)
return;
if (m_kludge == 3) /* mazinger metmqstr */
{
if (machine().video().skip_this_frame() == 0)
{
m_spriteram_bank[chip] = m_spriteram_bank_delay[chip];
(this->*m_get_sprite_info)(chip);
}
m_spriteram_bank_delay[chip] = (m_videoregs[chip][4] & 3) % spriteram_bankmax;
}
else
{
if (machine().video().skip_this_frame() == 0)
{
m_spriteram_bank[chip] = (m_videoregs[chip][4] & 3) % spriteram_bankmax;
(this->*m_get_sprite_info)(chip);
}
}
}
void cave_state::cave_get_sprite_info_all()
{
for (int chip = 0; chip < 4; chip++)
cave_get_sprite_info(chip);
}
// Poka Poka Satan: 3 screens * (1 Sprite chip + 1 Tilemap chip)
PALETTE_INIT_MEMBER(cave_state,ppsatan)
{
int color, pen;
PALETTE_INIT_NAME(cave)(palette);
for (int chip = 0; chip < 3; chip++)
{
// Sprites: 0x987800 - 0x988fff
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x10; pen++)
m_palette_map[chip][(color << 8) | pen] = 0x7800/2 + ((color << 4) | pen);
// Tiles: 0x980000 - 0x9803ff
for (color = 0; color < 0x40; color++)
for (pen = 0; pen < 0x10; pen++)
m_palette_map[chip][0x4000 + ((color << 4) | pen)] = ((color << 4) | pen);
}
}
uint32_t cave_state::screen_update_ppsatan_core(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int chip)
{
set_pens(chip);
m_blit.baseaddr = reinterpret_cast<uint8_t *>(bitmap.raw_pixptr(0));
m_blit.line_offset = bitmap.rowbytes();
m_blit.baseaddr_zbuf = reinterpret_cast<uint8_t *>(m_sprite_zbuf.raw_pixptr(0));
m_blit.line_offset_zbuf = m_sprite_zbuf.rowbytes();
m_tiledim[chip] = m_vctrl[chip][1] & 0x2000;
if (m_tiledim[chip] != m_old_tiledim[chip])
m_tilemap[chip]->mark_all_dirty();
m_old_tiledim[chip] = m_tiledim[chip];
cave_sprite_check(chip, screen, cliprect);
bitmap.fill(m_palette->pen_color(m_background_pen), cliprect);
for (int pri = 0; pri <= 3; pri++) // tile / sprite priority
{
(this->*m_sprite_draw)(chip, pri);
for (int pri2 = 0; pri2 <= 3; pri2++) // priority of the whole layer
tilemap_draw(chip, screen, bitmap, cliprect, pri, 0, pri2, chip);
}
return 0;
}
uint32_t cave_state::screen_update_ppsatan_top(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
return screen_update_ppsatan_core(screen, bitmap, cliprect, 0);
}
uint32_t cave_state::screen_update_ppsatan_left(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
machine().crosshair().get_crosshair(1).set_screen(&screen);
return screen_update_ppsatan_core(screen, bitmap, cliprect, 1);
}
uint32_t cave_state::screen_update_ppsatan_right(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
machine().crosshair().get_crosshair(0).set_screen(&screen);
return screen_update_ppsatan_core(screen, bitmap, cliprect, 2);
}