summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/atlus/cave_v.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/atlus/cave_v.cpp')
-rw-r--r--src/mame/atlus/cave_v.cpp1445
1 files changed, 1445 insertions, 0 deletions
diff --git a/src/mame/atlus/cave_v.cpp b/src/mame/atlus/cave_v.cpp
new file mode 100644
index 00000000000..14b4ad9513e
--- /dev/null
+++ b/src/mame/atlus/cave_v.cpp
@@ -0,0 +1,1445 @@
+// 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 "cave.h"
+
+
+static constexpr u8 CAVE_SPRITETYPE_ZBUF = 0x01;
+static constexpr u8 CAVE_SPRITETYPE_ZOOM = 0x02;
+
+static constexpr u8 SPRITE_FLIPX_CAVE = 0x01;
+static constexpr u8 SPRITE_FLIPY_CAVE = 0x02;
+static constexpr u8 SPRITE_VISIBLE_CAVE = 0x04;
+
+
+/* Sailormn: the lower 2 Megabytes of tiles banked */
+
+void cave_z80_state::sailormn_tilebank_w(int bank)
+{
+ if (m_sailormn_tilebank != bank)
+ {
+ m_sailormn_tilebank = bank;
+ m_tilemap[2]->mark_all_dirty();
+ }
+}
+
+void cave_z80_state::sailormn_get_banked_code(bool tiledim, u32 &color, u32 &pri, u32 &code)
+{
+ if (!tiledim)
+ {
+ if ((code < 0x10000) && (m_sailormn_tilebank))
+ code += 0x40000;
+ }
+}
+
+
+/***************************************************************************
+
+ 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::vh_start(u16 sprcol_granularity)
+{
+ m_sprite_granularity = sprcol_granularity;
+
+ sprite_init();
+
+ 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[0] = m_gfxdecode[0]->gfx(0)->colorbase() +
+ (m_gfxdecode[0]->gfx(0)->colors() - 1) *
+ m_gfxdecode[0]->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[0] = m_gfxdecode[0]->gfx(0)->colorbase() - m_gfxdecode[0]->gfx(0)->granularity();
+ break;
+ case 4: /* pwrinst2 */
+ m_background_pen[0] = m_gfxdecode[0]->gfx(0)->colorbase() - m_gfxdecode[0]->gfx(0)->granularity();
+ m_layers_offs_y++;
+ break;
+ }
+}
+
+// 4 bit sprite granularity
+VIDEO_START_MEMBER(cave_state,spr_4bpp)
+{
+ vh_start(16);
+}
+
+// 8 bit sprite granularity
+VIDEO_START_MEMBER(cave_state,spr_8bpp)
+{
+ vh_start(256);
+}
+
+// ppsatan (3 screen)
+void ppsatan_state::video_start()
+{
+ vh_start(16);
+ for (int chip = 1; chip < 3; chip++)
+ {
+ m_background_pen[chip] = m_gfxdecode[chip]->gfx(0)->colorbase() +
+ (m_gfxdecode[chip]->gfx(0)->colors() - 1) *
+ m_gfxdecode[chip]->gfx(0)->granularity();
+
+ switch (m_kludge)
+ {
+ case 2: /* uopoko dfeveron */
+ case 4: /* pwrinst2 */
+ m_background_pen[chip] = m_gfxdecode[chip]->gfx(0)->colorbase() - m_gfxdecode[chip]->gfx(0)->granularity();
+ break;
+ }
+ }
+}
+
+/***************************************************************************
+
+ Zoomed Sprites Drawing
+
+ Sprite format with zoom, 16 bytes per each sprites
+
+ Offset: Bits: Value:
+
+ 00.w X Position*
+
+ 02.w Y Position*
+
+ 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
+
+ * S.9.6 Fixed point or 10 bit signed integer,
+ Configured from videoregs
+
+
+ Sprites Drawing
+
+ Sprite format without zoom, 16 bytes per each sprites
+
+ Offset: Bits: Value:
+
+ 00.w fe-- ---- ---- ----
+ --dc ba98 ---- ---- Color
+ ---- ---- 76-- ----
+ ---- ---- --54 ---- Priority
+ ---- ---- ---- 3--- Flip X
+ ---- ---- ---- -2-- Flip Y
+ ---- ---- ---- --10 Code High Bit(s?)
+
+ 02.w Code Low Bits
+
+ 04.w fedc ba-- ---- ----
+ ---- --98 7654 3210 X Position**
+
+ 06.w fedc ba-- ---- ----
+ ---- --98 7654 3210 Y Position**
+
+ 08.w fedc ba98 ---- ---- Tile Size X
+ ---- ---- 7654 3210 Tile Size Y
+
+ 0A.w Unused
+
+ 0C.w Unused
+
+ 0E.w Unused
+
+ ** 10 bit signed only? need verifications.
+
+***************************************************************************/
+
+void cave_state::get_sprite_info_cave(int chip)
+{
+ chip %= 4;
+
+ if (m_sprite[chip] == nullptr)
+ return;
+
+ gfx_element *gfx = m_spr_gfxdecode[chip]->gfx(0);
+ sprite_cave *sprite = m_sprite[chip].get();
+
+ const int glob_flipx = m_videoregs[chip][0] & 0x8000;
+ const int glob_flipy = m_videoregs[chip][1] & 0x8000;
+
+ const int max_x = m_screen[chip]->width();
+ const int max_y = m_screen[chip]->height();
+
+ const u16 *source = &m_spriteram[chip][(0x4000 / 2) * m_spriteram_bank[chip]];
+ const u16 *finish = source + (0x4000 / 2);
+ u32 clk = 0; // used clock cycle for sprites
+
+ for (; source < finish; source += 8)
+ {
+ clk += 32; // 32 clock per each sprites
+ if (clk > m_max_sprite_clk[chip])
+ break;
+
+ int x, y;
+ int total_width_f, total_height_f;
+
+ if ((m_videoregs[chip][5] & 0x3000) == 0) // if bit 12/13 is 0 (or separated per X and Y?)
+ {
+ x = (source[0] & 0x3ff) << 8;
+ y = (source[1] & 0x3ff) << 8;
+ }
+ else
+ {
+ x = source[0] << 2;
+ y = source[1] << 2;
+ }
+ const u16 attr = source[2];
+ u32 code = source[3] + ((attr & 3) << 16);
+ int zoomx = source[4];
+ int zoomy = source[5];
+ const u16 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;
+
+ clk += sprite->tile_width * sprite->tile_height; // 256 clock per each sprite blocks
+ if (clk > m_max_sprite_clk[chip])
+ break;
+
+ /* Bound checking */
+ sprite->pen_data = &m_sprite_gfx[chip][(code << 8) & m_sprite_gfx_mask[chip]];
+
+ int flipx = attr & 0x0008;
+ int 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_videoregs[chip][5] & 0x3000) == 0)
+ {
+ 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 = gfx->colorbase() + (((attr & 0x3f00) >> 8) * gfx->granularity()); // 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;
+
+ if (m_sprite[chip] == nullptr)
+ return;
+
+ gfx_element *gfx = m_spr_gfxdecode[chip]->gfx(0);
+ sprite_cave *sprite = m_sprite[chip].get();
+
+ const int glob_flipx = m_videoregs[chip][0] & 0x8000;
+ const int glob_flipy = m_videoregs[chip][1] & 0x8000;
+
+ const int max_x = m_screen[chip]->width();
+ const int max_y = m_screen[chip]->height();
+
+ const u16 *source = &m_spriteram[chip][(0x4000 / 2) * m_spriteram_bank[chip]];
+ const u16 *finish = source + (0x4000 / 2);
+ u32 clk = 0; // used clock cycle for sprites
+
+ for (; source < finish; source += 8)
+ {
+ clk += 32; // 32 clock per each sprites
+ if (clk > m_max_sprite_clk[chip])
+ break;
+
+ int y;
+
+ const u16 attr = source[0];
+ u32 code = source[1] + ((attr & 3) << 16);
+ int x = source[2] & 0x3ff;
+
+ if (m_spritetype[0] & TYPE_ISPWRINST2) /* pwrinst2 */
+ y = (source[3] + 1) & 0x3ff;
+ else
+ y = source[3] & 0x3ff;
+
+ const u16 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 */
+ sprite->pen_data = &m_sprite_gfx[chip][(code << 8) & m_sprite_gfx_mask[chip]];
+
+ 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;}
+
+ clk += sprite->tile_width * sprite->tile_height; // 256 clock per each sprite blocks
+ if (clk > m_max_sprite_clk[chip])
+ break;
+
+ int flipx = attr & 0x0008;
+ int flipy = attr & 0x0004;
+
+ if (m_spritetype[0] & TYPE_ISPWRINST2) /* pwrinst2 */
+ {
+ sprite->priority = ((attr & 0x0010) >> 4) + 2;
+ sprite->base_pen = gfx->colorbase() + ((((attr & 0x3f00) >> 8) + ((attr & 0x0020) << 1)) * gfx->granularity());
+ }
+ else
+ {
+ sprite->priority = (attr & 0x0030) >> 4;
+ sprite->base_pen = gfx->colorbase() + (((attr & 0x3f00) >> 8) * gfx->granularity()); // 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()
+{
+ if ((m_spritetype[0] & TYPE_NOZOOM) == 0) // 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;
+ for (int screen = 0; screen < 4; screen++)
+ {
+ if (m_screen[screen])
+ {
+ m_screen[screen]->register_screen_bitmap(m_sprite_zbuf[screen]);
+
+ save_item(NAME(m_sprite_zbuf[screen]), screen);
+ }
+ }
+
+ for (int chip = 0; chip < 4; chip++)
+ {
+ m_max_sprite_clk[chip] = 0;
+ if (m_videoregs[chip] && m_spr_gfxdecode[chip])
+ {
+ for (int screen = 0; screen < 4; screen++)
+ {
+ if (m_screen[screen])
+ {
+ const u32 new_clk = (m_screen[screen]->visible_area().width() > 360 ? 512 : 448) * 272 * 2; // whole screen size related?
+ if (m_max_sprite_clk[chip] < new_clk)
+ {
+ m_max_sprite_clk[chip] = new_clk;
+ }
+ }
+ }
+ m_num_sprites[chip] = m_spriteram[chip].bytes() / 0x10 / 2;
+ m_sprite[chip] = std::make_unique<sprite_cave []>(m_num_sprites[chip]);
+ m_spr_gfxdecode[chip]->gfx(0)->set_granularity(m_sprite_granularity);
+ }
+ else
+ {
+ m_num_sprites[chip] = 0;
+ m_sprite[chip] = nullptr;
+ }
+ 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_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));
+}
+
+void cave_state::sprite_check(int chip, int screen_no, screen_device &screen, const rectangle &clip)
+{
+ if (m_sprite[chip] == nullptr)
+ return;
+
+ { /* set clip */
+ const int left = clip.min_x;
+ const int top = clip.min_y;
+ const int right = clip.max_x + 1;
+ const 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[screen_no].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[screen_no].fill(0, visarea);
+ }
+ break;
+
+ default:
+ case 0:
+ m_sprite_draw = &cave_state::sprite_draw_donpachi;
+ }
+ }
+}
+
+void cave_state::do_blit_zoom32(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 u8 *pen_data = sprite->pen_data -1 -sprite->line_offset;
+ const pen_t base_pen = sprite->base_pen;
+ const int pitch = m_blit.line_offset * dy / 4;
+ u32 *dest = (u32 *)(m_blit.baseaddr + m_blit.line_offset * y1);
+ int ycount = ycount0;
+
+ for (int y = y1; y != y2; y += dy)
+ {
+ if (ycount & 0xffff0000)
+ {
+ int xcount = xcount0;
+ pen_data += sprite->line_offset * (ycount >> 16);
+ ycount &= 0xffff;
+ const u8 *source = pen_data;
+ for (int x = x1; x != x2; x += dx)
+ {
+ if (xcount & 0xffff0000)
+ {
+ source += xcount >> 16;
+ xcount &= 0xffff;
+ const u8 pen = *source;
+ if (pen)
+ dest[x] = m_palette[chip]->pen_color(base_pen + pen);
+ }
+ xcount += sprite->zoomx_re;
+ }
+ }
+ ycount += sprite->zoomy_re;
+ dest += pitch;
+ }
+ }
+}
+
+
+void cave_state::do_blit_zoom32_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 u8 *pen_data = sprite->pen_data - 1 - sprite->line_offset;
+ const pen_t base_pen = sprite->base_pen;
+ const int pitch = m_blit.line_offset * dy / 4;
+ u32 *dest = (u32 *)(m_blit.baseaddr + m_blit.line_offset * y1);
+ const int pitchz = m_blit.line_offset_zbuf * dy / 2;
+ u16 *zbf = (u16 *)(m_blit.baseaddr_zbuf + m_blit.line_offset_zbuf * y1);
+ const u16 pri_sp = (u16)(sprite - m_sprite[chip].get()) + m_sprite_zbuf_baseval;
+ int ycount = ycount0;
+
+ for (int y = y1; y != y2; y += dy)
+ {
+ if (ycount & 0xffff0000)
+ {
+ int xcount = xcount0;
+ pen_data += sprite->line_offset * (ycount >> 16);
+ ycount &= 0xffff;
+ const u8 *source = pen_data;
+ for (int x = x1; x != x2; x += dx)
+ {
+ if (xcount & 0xffff0000)
+ {
+ source += xcount >> 16;
+ xcount &= 0xffff;
+ const u8 pen = *source;
+ if (pen && (zbf[x] <= pri_sp))
+ {
+ dest[x] = m_palette[chip]->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(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 u8 *pen_data = sprite->pen_data;
+ const pen_t base_pen = sprite->base_pen;
+ const int pitch = m_blit.line_offset * dy / 4;
+ u32 *dest = (u32 *)(m_blit.baseaddr + m_blit.line_offset * y1);
+
+ pen_data += sprite->line_offset * ycount0 + xcount0;
+ for (int y = y1; y != y2; y += dy)
+ {
+ const u8 *source = pen_data;
+ for (int x = x1; x != x2; x += dx)
+ {
+ const u8 pen = *source;
+ if (pen)
+ dest[x] = m_palette[chip]->pen_color(base_pen + pen);
+ source++;
+ }
+ pen_data += sprite->line_offset;
+ dest += pitch;
+ }
+ }
+}
+
+
+void cave_state::do_blit_32_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 u8 *pen_data = sprite->pen_data;
+ const pen_t base_pen = sprite->base_pen;
+ const int pitch = m_blit.line_offset * dy / 4;
+ u32 *dest = (u32 *)(m_blit.baseaddr + m_blit.line_offset * y1);
+ const int pitchz = m_blit.line_offset_zbuf * dy / 2;
+ u16 *zbf = (u16 *)(m_blit.baseaddr_zbuf + m_blit.line_offset_zbuf * y1);
+ const u16 pri_sp = (u16)(sprite - m_sprite[chip].get()) + m_sprite_zbuf_baseval;
+
+ pen_data += sprite->line_offset * ycount0 + xcount0;
+ for (int y = y1; y != y2; y += dy)
+ {
+ const u8 *source;
+ source = pen_data;
+ for (int x = x1; x != x2; x += dx)
+ {
+ const u8 pen = *source;
+ if (pen && (zbf[x] <= pri_sp))
+ {
+ dest[x] = m_palette[chip]->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)
+{
+ if (m_sprite[chip] == nullptr)
+ return;
+
+ 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(chip, sprite);
+ else
+ do_blit_zoom32(chip, sprite);
+ }
+}
+
+void cave_state::sprite_draw_cave_zbuf(int chip, int priority)
+{
+ if (m_sprite[chip] == nullptr)
+ return;
+
+ 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_zb(chip, sprite);
+ else
+ do_blit_zoom32_zb(chip, sprite);
+ }
+}
+
+void cave_state::sprite_draw_donpachi(int chip, int priority)
+{
+ if (m_sprite[chip] == nullptr)
+ return;
+
+ int i = 0;
+ while (m_sprite_table[chip][priority][i])
+ do_blit_32(chip, m_sprite_table[chip][priority][i++]);
+}
+
+void cave_state::sprite_draw_donpachi_zbuf(int chip, int priority)
+{
+ if (m_sprite[chip] == nullptr)
+ return;
+
+ int i = 0;
+ while (m_sprite_table[chip][priority][i])
+ do_blit_32_zb(chip, m_sprite_table[chip][priority][i++]);
+}
+
+
+/***************************************************************************
+
+ Screen Drawing
+
+
+ Layers Control Registers (vctrl_0..3)
+
+
+ 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 (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,
+ u32 flags, u32 priority, u32 priority2, int GFX)
+{
+ tilemap038_device *TILEMAP = m_tilemap[GFX];
+
+ /* Bail out if ... */
+
+ if (!TILEMAP) /* no tilemap; */
+ return;
+
+ if (((TILEMAP->external() & 0x0003) != priority2) || /* tilemap's global priority not the requested one; */
+ ((!TILEMAP->enable()))) /* tilemap's disabled. */
+ return;
+
+ const bool flipx = TILEMAP->flipx();
+ const bool flipy = TILEMAP->flipy();
+ TILEMAP->set_flip((flipx ? TILEMAP_FLIPX : 0) | (flipy ? TILEMAP_FLIPY : 0));
+
+ int offs_x = m_layers_offs_x;
+ const int offs_y = m_layers_offs_y;
+
+ const int 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 -= (TILEMAP->tile_is_16x16() ? 1 : (1 + 8));
+ else if (TILEMAP == m_tilemap[1]) offs_x -= (TILEMAP->tile_is_16x16() ? 2 : (2 + 8));
+ else if (TILEMAP == m_tilemap[2]) offs_x -= (TILEMAP->tile_is_16x16() ? 3 : (3 + 8));
+ else if (TILEMAP == m_tilemap[3]) offs_x -= (TILEMAP->tile_is_16x16() ? 4 : (4 + 8));
+
+ const int sx = TILEMAP->scrollx() - m_videoregs[chip][0] + (flipx ? (offs_x + 2) : -offs_x);
+ const int sy = TILEMAP->scrolly() - m_videoregs[chip][1] + (flipy ? (offs_y + 2) : -offs_y);
+
+ if (TILEMAP->rowselect_en()) // row-select
+ {
+ rectangle clip;
+ int 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 (int startline = cliprect.min_y; startline <= cliprect.max_y;)
+ {
+ /* Find the largest slice */
+ vramdata0 = (vramdata1 = TILEMAP->rowselect(sy + offs_row + startline));
+ for (endline = startline + 1; endline <= cliprect.max_y; endline++)
+ if ((++vramdata1) != TILEMAP->rowselect(sy + offs_row + endline)) break;
+
+ TILEMAP->set_scrolly(0, vramdata0 - startline);
+
+ if (TILEMAP->rowscroll_en()) // row-scroll, row-select
+ {
+ /*
+ 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 (int line = startline; line < endline; line++)
+ TILEMAP->set_scrollx((vramdata0 - startline + line) & 511,
+ sx + TILEMAP->rowscroll(sy + offs_row + line));
+ }
+ 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 (TILEMAP->rowscroll_en()) // row-scroll, no row-select
+ {
+ TILEMAP->set_scroll_rows(512);
+ for (int line = cliprect.min_y; line <= cliprect.max_y; line++)
+ TILEMAP->set_scrollx((line + sy) & 511,
+ sx + TILEMAP->rowscroll(sy + offs_row + line));
+ TILEMAP->set_scrolly(0, sy);
+ TILEMAP->draw(screen, bitmap, cliprect, flags, priority);
+ }
+ else
+ {
+ /* 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);
+ }
+}
+
+
+u32 cave_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ int layers_ctrl = -1;
+
+ m_blit.baseaddr = reinterpret_cast<u8 *>(bitmap.raw_pixptr(0));
+ m_blit.line_offset = bitmap.rowbytes();
+ m_blit.baseaddr_zbuf = reinterpret_cast<u8 *>(m_sprite_zbuf[0].raw_pixptr(0));
+ m_blit.line_offset_zbuf = m_sprite_zbuf[0].rowbytes();
+
+ for (int GFX = 0; GFX < 4; GFX++)
+ {
+ if (m_tilemap[GFX])
+ m_tilemap[GFX]->prepare();
+ }
+
+#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_tilemap[0]->vregs(0),m_tilemap[0]->vregs(1),m_tilemap[0]->vregs(2));
+ if ((m_tilemap[1]) && (msk & 0x00f0)) popmessage("x:%04X y:%04X f:%04X", m_tilemap[1]->vregs(0),m_tilemap[1]->vregs(1),m_tilemap[1]->vregs(2));
+ if ((m_tilemap[2]) && (msk & 0x0f00)) popmessage("x:%04X y:%04X f:%04X", m_tilemap[2]->vregs(0),m_tilemap[2]->vregs(1),m_tilemap[2]->vregs(2));
+ if ((m_tilemap[3]) && (msk & 0xf000)) popmessage("x:%04X y:%04X f:%04X", m_tilemap[3]->vregs(0),m_tilemap[3]->vregs(1),m_tilemap[3]->vregs(2));
+ }
+
+ /* Show the row / "column" scroll enable flags, when they change state */
+ m_rasflag = 0;
+ for (int GFX = 0; GFX < 4; GFX++)
+ {
+ if (m_tilemap[GFX])
+ {
+ m_rasflag |= (m_tilemap[GFX]->vregs(0) & 0x4000) ? 0x0001 << (4*GFX) : 0;
+ m_rasflag |= (m_tilemap[GFX]->vregs(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
+
+ sprite_check(0, 0, screen, cliprect);
+
+ bitmap.fill(m_palette[0]->pen_color(m_background_pen[0]), 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 (int pri = 0; pri <= 3; pri++) // tile / sprite priority
+ {
+ if (layers_ctrl & (1 << (pri + 16))) (this->*m_sprite_draw)(0, pri);
+
+ for (int 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::get_sprite_info(int chip)
+{
+ if (m_videoregs[chip] == nullptr)
+ return;
+
+ const int spriteram_bankmax = m_spriteram[chip].bytes() / 0x4000;
+
+ 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::device_post_load()
+{
+ for (int chip = 0; chip < 4; chip++)
+ get_sprite_info(chip);
+}
+
+
+// Poka Poka Satan: 3 screens * (1 Sprite chip + 1 Tilemap chip)
+
+u32 ppsatan_state::screen_update_ppsatan_core(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int chip)
+{
+ m_blit.baseaddr = reinterpret_cast<u8 *>(bitmap.raw_pixptr(0));
+ m_blit.line_offset = bitmap.rowbytes();
+ m_blit.baseaddr_zbuf = reinterpret_cast<u8 *>(m_sprite_zbuf[chip].raw_pixptr(0));
+ m_blit.line_offset_zbuf = m_sprite_zbuf[chip].rowbytes();
+
+ m_tilemap[chip]->prepare();
+
+ sprite_check(chip, chip, screen, cliprect);
+
+ bitmap.fill(m_palette[chip]->pen_color(m_background_pen[chip]), 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;
+}
+
+u32 ppsatan_state::screen_update_ppsatan_top(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ return screen_update_ppsatan_core(screen, bitmap, cliprect, 0);
+}
+u32 ppsatan_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);
+}
+u32 ppsatan_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);
+}