// license:BSD-3-Clause
// copyright-holders:David Haywood
/***************************************************************************/
/* */
/* 053246 */
/* with 053247 or 055673 */
/* is the 053247 / 055673 choice just a BPP change like the tilemaps? */
/* */
/* */
/***************************************************************************/
/* later Konami GX board replaces the 053246 with a 058142 */
/*
053247/053246
-------------
Sprite generators. Nothing is known about their external interface.
The sprite RAM format is very similar to the 053245.
053246 memory map (but the 053247 sees and processes them too):
000-001 W global X offset
002-003 W global Y offset
004 W low 8 bits of the ROM address to read
005 W bit 0 = flip screen X
bit 1 = flip screen Y
bit 2 = unknown
bit 4 = interrupt enable
bit 5 = unknown
006-007 W high 16 bits of the ROM address to read
???-??? R reads data from the gfx ROMs (16 bits in total). The address of the
data is determined by the registers above
*/
#include "emu.h"
#include "k053246_k053247_k055673.h"
#include "konami_helper.h"
#define VERBOSE 0
#include "logmacro.h"
/*****************************************************************************
DEVICE HANDLERS
*****************************************************************************/
void k053247_device::clear_all()
{
m_ram = nullptr;
m_gfx = nullptr;
for (auto & elem : m_kx46_regs)
elem = 0;
for (auto & elem : m_kx47_regs)
elem = 0;
m_objcha_line = 0;
m_z_rejection = 0;
m_memory_region = nullptr;
}
void k053247_device::k053247_get_ram( uint16_t **ram )
{
*ram = m_ram.get();
}
int k053247_device::k053247_get_dx( void )
{
return m_dx;
}
int k053247_device::k053247_get_dy( void )
{
return m_dy;
}
int k053247_device::k053246_read_register( int regnum )
{
return(m_kx46_regs[regnum]);
}
int k053247_device::k053247_read_register( int regnum )
{
return(m_kx47_regs[regnum]);
}
WRITE16_MEMBER( k053247_device::k055673_reg_word_w ) // write-only OBJSET2 registers (see p.43 table 6.1)
{
COMBINE_DATA(m_kx47_regs + offset);
}
READ16_MEMBER( k053247_device::k053247_word_r )
{
return m_ram[offset];
}
WRITE16_MEMBER( k053247_device::k053247_word_w )
{
COMBINE_DATA(m_ram.get() + offset);
}
READ8_MEMBER( k053247_device::k053247_r )
{
int offs = offset >> 1;
if (offset & 1)
return(m_ram[offs] & 0xff);
else
return(m_ram[offs] >> 8);
}
WRITE8_MEMBER( k053247_device::k053247_w )
{
int offs = offset >> 1;
if (offset & 1)
m_ram[offs] = (m_ram[offs] & 0xff00) | data;
else
m_ram[offs] = (m_ram[offs] & 0x00ff) | (data << 8);
}
// The K055673 supports a non-objcha based ROM readback
// write the address to the 246 as usual, but there's a completely separate ROM
// window that works without needing an objcha line.
// in this window, +0 = 32 bits from one set of ROMs, and +8 = 32 bits from another set
// FIXME: rearrange ROM loading so this can be merged with the 4/6/8bpp version
READ16_MEMBER( k053247_device::k055673_5bpp_rom_word_r ) // 5bpp
{
uint8_t *ROM8 = (uint8_t *)machine().root_device().memregion(m_memory_region)->base();
uint16_t *ROM = (uint16_t *)machine().root_device().memregion(m_memory_region)->base();
int size4 = (machine().root_device().memregion(m_memory_region)->bytes() / (1024 * 1024)) / 5;
int romofs;
size4 *= 4 * 1024 * 1024; // get offset to 5th bit
ROM8 += size4;
romofs = m_kx46_regs[6] << 16 | m_kx46_regs[7] << 8 | m_kx46_regs[4];
switch (offset)
{
case 0: // 20k / 36u
return ROM[romofs + 2];
case 1: // 17k / 36y
return ROM[romofs + 3];
case 2: // 10k / 32y
case 3:
romofs /= 2;
return ROM8[romofs + 1];
case 4: // 22k / 34u
return ROM[romofs];
case 5: // 19k / 34y
return ROM[romofs + 1];
case 6: // 12k / 29y
case 7:
romofs /= 2;
return ROM8[romofs];
default:
LOG("55673_rom_word_r: Unknown read offset %x\n", offset);
break;
}
return 0;
}
READ16_MEMBER( k053247_device::k055673_rom_word_r )
{
if (m_bpp == 5)
return k055673_5bpp_rom_word_r(space, offset, mem_mask);
uint16_t *ROM = (uint16_t *)machine().root_device().memregion(m_memory_region)->base();
int romofs;
romofs = m_kx46_regs[6] << 16 | m_kx46_regs[7] << 8 | m_kx46_regs[4];
romofs = (romofs >> 2) * m_bpp;
if ((offset & 0x4) == 0) romofs += m_bpp >> 1;
return ROM[romofs + (offset & 0x3)];
}
READ16_MEMBER( k053247_device::k055673_ps_rom_word_r )
{
uint8_t *ROM = (uint8_t *)machine().root_device().memregion(m_memory_region)->base();
int romofs;
int magic = (offset & 1);
romofs = m_kx46_regs[6] << 16 | m_kx46_regs[7] << 8 | m_kx46_regs[4];
offset = ((offset & 4) >> 1);
int finoffs = (romofs * 2) + (offset * 2) + magic;
return ROM[finoffs+2] | (ROM[finoffs]<<8);
}
READ8_MEMBER( k053247_device::k053246_r )
{
if (m_objcha_line == ASSERT_LINE)
{
int addr;
addr = (m_kx46_regs[6] << 17) | (m_kx46_regs[7] << 9) | (m_kx46_regs[4] << 1) | ((offset & 1) ^ 1);
addr &= machine().root_device().memregion(m_memory_region)->bytes() - 1;
return machine().root_device().memregion(m_memory_region)->base()[addr];
}
else
{
return 0;
}
}
WRITE8_MEMBER( k053247_device::k053246_w )
{
m_kx46_regs[offset] = data;
}
READ16_MEMBER( k053247_device::k053246_word_r )
{
offset <<= 1;
return k053246_r( space, offset + 1) | (k053246_r( space, offset) << 8);
}
WRITE16_MEMBER( k053247_device::k053246_word_w )
{
if (ACCESSING_BITS_8_15)
k053246_w( space, offset << 1,(data >> 8) & 0xff);
if (ACCESSING_BITS_0_7)
k053246_w( space, (offset << 1) + 1,data & 0xff);
}
void k053247_device::k053246_set_objcha_line( int state )
{
m_objcha_line = state;
}
int k053247_device::k053246_is_irq_enabled( void )
{
// This bit enables obj DMA rather than obj IRQ even though the two functions usually coincide.
return m_kx46_regs[5] & 0x10;
}
/*
* Sprite Format
* ------------------
*
* Word | Bit(s) | Use
* -----+-fedcba9876543210-+----------------
* 0 | x--------------- | active (show this sprite)
* 0 | -x-------------- | maintain aspect ratio (when set, zoom y acts on both axis)
* 0 | --x------------- | flip y
* 0 | ---x------------ | flip x
* 0 | ----xxxx-------- | sprite size (see below)
* 0 | --------xxxxxxxx | zcode
* 1 | xxxxxxxxxxxxxxxx | sprite code
* 2 | ------xxxxxxxxxx | y position
* 3 | ------xxxxxxxxxx | x position
* 4 | xxxxxxxxxxxxxxxx | zoom y (0x40 = normal, <0x40 = enlarge, >0x40 = reduce)
* 5 | xxxxxxxxxxxxxxxx | zoom x (0x40 = normal, <0x40 = enlarge, >0x40 = reduce)
* 6 | x--------------- | mirror y (top half is drawn as mirror image of the bottom)
* 6 | -x-------------- | mirror x (right half is drawn as mirror image of the left)
* 6 | --xx------------ | reserved (sprites with these two bits set don't seem to be graphics data at all)
* 6 | ----xx---------- | shadow code: 0=off, 0x400=preset1, 0x800=preset2, 0xc00=preset3
* 6 | ------xx-------- | effect code: flicker, upper palette, full shadow...etc. (game dependent)
* 6 | --------xxxxxxxx | "color", but depends on external connections (implies priority)
* 7 | xxxxxxxxxxxxxxxx | game dependent
*
* shadow enables transparent shadows. Note that it applies to the last sprite pen ONLY.
* The rest of the sprite remains normal.
*/
template<class _BitmapClass>
void k053247_device::k053247_sprites_draw_common( _BitmapClass &bitmap, const rectangle &cliprect )
{
#define NUM_SPRITES 256
int code, color, x, y, shadow, shdmask, count, temp, primask;
int sortedlist[NUM_SPRITES];
int offs,zcode;
uint8_t drawmode_table[256];
uint8_t shadowmode_table[256];
memset(drawmode_table, DRAWMODE_SOURCE, sizeof(drawmode_table));
drawmode_table[0] = DRAWMODE_NONE;
memset(shadowmode_table, DRAWMODE_SHADOW, sizeof(shadowmode_table));
shadowmode_table[0] = DRAWMODE_NONE;
/*
safeguard older drivers missing any of the following video attributes:
VIDEO_HAS_SHADOWS | VIDEO_HAS_HIGHLIGHTS
*/
if (palette().shadows_enabled())
{
if (sizeof(typename _BitmapClass::pixel_t) == 4 && (palette().hilights_enabled()))
shdmask = 3; // enable all shadows and highlights
else
shdmask = 0; // enable default shadows
}
else
shdmask = -1; // disable everything
/*
The k053247 does not draw pixels on top of those with equal or smaller Z-values
regardless of priority. Embedded shadows inherit Z-values from their host sprites
but do not assume host priorities unless explicitly told. In other words shadows
can have priorities different from that of normal pens in the same sprite,
in addition to the ability of masking themselves from specific layers or pixels
on the other sprites.
In front-to-back rendering, sprites cannot sandwich between alpha blended layers
or the draw code will have to figure out the percentage opacities of what is on
top and beneath each sprite pixel and blend the target accordingly. The process
is overly demanding for realtime software and is thus another shortcoming of
pdrawgfx and pixel based mixers. Even mahjong games with straight forward video
subsystems are feeling the impact by which the girls cannot appear under
translucent dialogue boxes.
These are a small part of the k053247's feature set but many games expect them
to be the minimum compliances. The specification will undoubtedly require
redesigning the priority system from the ground up. Drawgfx.c and tilemap.c must
also undergo heavy facelifts but in the end the changes could hurt simpler games
more than they help complex systems; therefore the new engine should remain
completely stand alone and self-contained. Implementation details are being
hammered down but too early to make propositions.
*/
// Prebuild a sorted table by descending Z-order.
zcode = m_z_rejection;
offs = count = 0;
if (zcode == -1)
{
for (; offs < 0x800; offs += 8)
if (m_ram[offs] & 0x8000)
sortedlist[count++] = offs;
}
else
{
for (; offs < 0x800; offs += 8)
if ((m_ram[offs] & 0x8000) && ((m_ram[offs] & 0xff) != zcode))
sortedlist[count++] = offs;
}
int w = count;
count--;
int h = count;
if (!(m_kx47_regs[0xc / 2] & 0x10))
{
// sort objects in decending order(smaller z closer) when OPSET PRI is clear
for (y = 0; y < h; y++)
{
offs = sortedlist[y];
zcode = m_ram[offs] & 0xff;
for (x = y + 1; x < w; x++)
{
temp = sortedlist[x];
code = m_ram[temp] & 0xff;
if (zcode <= code)
{
zcode = code;
sortedlist[x] = offs;
sortedlist[y] = offs = temp;
}
}
}
}
else
{
// sort objects in ascending order(bigger z closer) when OPSET PRI is set
for (y = 0; y < h; y++)
{
offs = sortedlist[y];
zcode = m_ram[offs] & 0xff;
for (x = y + 1; x < w; x++)
{
temp = sortedlist[x];
code = m_ram[temp] & 0xff;
if (zcode >= code)
{
zcode = code;
sortedlist[x] = offs;
sortedlist[y] = offs = temp;
}
}
}
}
for (; count >= 0; count--)
{
offs = sortedlist[count];
code = m_ram[offs + 1];
shadow = color = m_ram[offs + 6];
primask = 0;
m_k053247_cb(&code, &color, &primask);
k053247_draw_single_sprite_gxcore( bitmap, cliprect,
nullptr, nullptr,
code, m_ram.get(), offs,
color,
/* gx only */
0, 0, 0, 0,
/* non-gx only */
primask,shadow,drawmode_table,shadowmode_table,shdmask
);
} // end of sprite-list loop
#undef NUM_SPRITES
}
void k053247_device::k053247_sprites_draw( bitmap_ind16 &bitmap, const rectangle &cliprect )
{ k053247_sprites_draw_common( bitmap, cliprect); }
void k053247_device::k053247_sprites_draw( bitmap_rgb32 &bitmap, const rectangle &cliprect )
{ k053247_sprites_draw_common( bitmap, cliprect); }
/*
Parameter Notes
---------------
clip : *caller must supply a pointer to target clip rectangle
alpha : 0 = invisible, 255 = solid
drawmode:
0 = all pens solid
1 = solid pens only
2 = all pens solid with alpha blending
3 = solid pens only with alpha blending
4 = shadow pens only
5 = all pens shadow
zcode : 0 = closest, 255 = furthest (pixel z-depth), -1 = disable depth buffers and shadows
pri : 0 = topmost, 255 = backmost (pixel priority)
*/
void k053247_device::zdrawgfxzoom32GP(
bitmap_rgb32 &bitmap, const rectangle &cliprect,
uint32_t code, uint32_t color, int flipx, int flipy, int sx, int sy,
int scalex, int scaley, int alpha, int drawmode, int zcode, int pri, uint8_t* gx_objzbuf, uint8_t* gx_shdzbuf)
{
#define FP 19
#define FPONE (1<<FP)
#define FPHALF (1<<(FP-1))
#define FPENT 0
// inner loop
const uint8_t *src_ptr;
int src_x;
int eax, ecx;
int src_fx, src_fdx;
int shdpen;
uint8_t z8 = 0, p8 = 0;
uint8_t *ozbuf_ptr;
uint8_t *szbuf_ptr;
const pen_t *pal_base;
const pen_t *shd_base;
uint32_t *dst_ptr;
// outter loop
int src_fby, src_fdy, src_fbx;
const uint8_t *src_base;
int dst_w, dst_h;
// one-time
int nozoom, granularity;
int src_fw, src_fh;
int dst_minx, dst_maxx, dst_miny, dst_maxy;
int dst_skipx, dst_skipy, dst_x, dst_y, dst_lastx, dst_lasty;
int src_pitch, dst_pitch;
// cull illegal and transparent objects
if (!scalex || !scaley) return;
// find shadow pens and cull invisible shadows
granularity = shdpen = m_gfx->granularity();
shdpen--;
if (zcode >= 0)
{
if (drawmode == 5) { drawmode = 4; shdpen = 1; }
}
else
if (drawmode >= 4) return;
// alpha blend necessary?
if (drawmode & 2)
{
if (alpha <= 0) return;
if (alpha >= 255) drawmode &= ~2;
}
// fill internal data structure with default values
ozbuf_ptr = gx_objzbuf;
szbuf_ptr = gx_shdzbuf;
src_pitch = 16;
src_fw = 16;
src_fh = 16;
src_base = m_gfx->get_data(code % m_gfx->elements());
pal_base = palette().pens() + m_gfx->colorbase() + (color % m_gfx->colors()) * granularity;
shd_base = palette().shadow_table();
dst_ptr = &bitmap.pix32(0);
dst_pitch = bitmap.rowpixels();
dst_minx = cliprect.min_x;
dst_maxx = cliprect.max_x;
dst_miny = cliprect.min_y;
dst_maxy = cliprect.max_y;
dst_x = sx;
dst_y = sy;
// cull off-screen objects
if (dst_x > dst_maxx || dst_y > dst_maxy) return;
nozoom = (scalex == 0x10000 && scaley == 0x10000);
if (nozoom)
{
dst_h = dst_w = 16;
src_fdy = src_fdx = 1;
}
else
{
dst_w = ((scalex<<4)+0x8000)>>16;
dst_h = ((scaley<<4)+0x8000)>>16;
if (!dst_w || !dst_h) return;
src_fw <<= FP;
src_fh <<= FP;
src_fdx = src_fw / dst_w;
src_fdy = src_fh / dst_h;
}
dst_lastx = dst_x + dst_w - 1;
if (dst_lastx < dst_minx) return;
dst_lasty = dst_y + dst_h - 1;
if (dst_lasty < dst_miny) return;
// clip destination
dst_skipx = 0;
eax = dst_minx; if ((eax -= dst_x) > 0) { dst_skipx = eax; dst_w -= eax; dst_x = dst_minx; }
eax = dst_lastx; if ((eax -= dst_maxx) > 0) dst_w -= eax;
dst_skipy = 0;
eax = dst_miny; if ((eax -= dst_y) > 0) { dst_skipy = eax; dst_h -= eax; dst_y = dst_miny; }
eax = dst_lasty; if ((eax -= dst_maxy) > 0) dst_h -= eax;
// calculate zoom factors and clip source
if (nozoom)
{
if (!flipx) src_fbx = 0; else { src_fbx = src_fw - 1; src_fdx = -src_fdx; }
if (!flipy) src_fby = 0; else { src_fby = src_fh - 1; src_fdy = -src_fdy; src_pitch = -src_pitch; }
}
else
{
if (!flipx) src_fbx = FPENT; else { src_fbx = src_fw - FPENT - 1; src_fdx = -src_fdx; }
if (!flipy) src_fby = FPENT; else { src_fby = src_fh - FPENT - 1; src_fdy = -src_fdy; }
}
src_fbx += dst_skipx * src_fdx;
src_fby += dst_skipy * src_fdy;
// adjust insertion points and pre-entry constants
eax = (dst_y - dst_miny) * GX_ZBUFW + (dst_x - dst_minx) + dst_w;
z8 = (uint8_t)zcode;
p8 = (uint8_t)pri;
ozbuf_ptr += eax;
szbuf_ptr += eax << 1;
dst_ptr += dst_y * dst_pitch + dst_x + dst_w;
dst_w = -dst_w;
if (!nozoom)
{
ecx = src_fby; src_fby += src_fdy;
ecx >>= FP; src_fx = src_fbx;
src_x = src_fbx; src_fx += src_fdx;
ecx <<= 4; src_ptr = src_base;
src_x >>= FP; src_ptr += ecx;
ecx = dst_w;
if (zcode < 0) // no shadow and z-buffering
{
do {
do {
eax = src_ptr[src_x];
src_x = src_fx;
src_fx += src_fdx;
src_x >>= FP;
if (!eax || eax >= shdpen) continue;
dst_ptr [ecx] = pal_base[eax];
}
while (++ecx);
ecx = src_fby; src_fby += src_fdy;
dst_ptr += dst_pitch;
ecx >>= FP; src_fx = src_fbx;
src_x = src_fbx; src_fx += src_fdx;
ecx <<= 4; src_ptr = src_base;
src_x >>= FP; src_ptr += ecx;
ecx = dst_w;
}
while (--dst_h);
}
else
{
switch (drawmode)
{
case 0: // all pens solid
do {
do {
eax = src_ptr[src_x];
src_x = src_fx;
src_fx += src_fdx;
src_x >>= FP;
if (!eax || ozbuf_ptr[ecx] < z8) continue;
eax = pal_base[eax];
ozbuf_ptr[ecx] = z8;
dst_ptr [ecx] = eax;
}
while (++ecx);
ecx = src_fby; src_fby += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx >>= FP; src_fx = src_fbx;
src_x = src_fbx; src_fx += src_fdx;
ecx <<= 4; src_ptr = src_base;
src_x >>= FP; src_ptr += ecx;
ecx = dst_w;
}
while (--dst_h);
break;
case 1: // solid pens only
do {
do {
eax = src_ptr[src_x];
src_x = src_fx;
src_fx += src_fdx;
src_x >>= FP;
if (!eax || eax >= shdpen || ozbuf_ptr[ecx] < z8) continue;
eax = pal_base[eax];
ozbuf_ptr[ecx] = z8;
dst_ptr [ecx] = eax;
}
while (++ecx);
ecx = src_fby; src_fby += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx >>= FP; src_fx = src_fbx;
src_x = src_fbx; src_fx += src_fdx;
ecx <<= 4; src_ptr = src_base;
src_x >>= FP; src_ptr += ecx;
ecx = dst_w;
}
while (--dst_h);
break;
case 2: // all pens solid with alpha blending
do {
do {
eax = src_ptr[src_x];
src_x = src_fx;
src_fx += src_fdx;
src_x >>= FP;
if (!eax || ozbuf_ptr[ecx] < z8) continue;
ozbuf_ptr[ecx] = z8;
dst_ptr[ecx] = alpha_blend_r32(pal_base[eax], dst_ptr[ecx], alpha);
}
while (++ecx);
ecx = src_fby; src_fby += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx >>= FP; src_fx = src_fbx;
src_x = src_fbx; src_fx += src_fdx;
ecx <<= 4; src_ptr = src_base;
src_x >>= FP; src_ptr += ecx;
ecx = dst_w;
}
while (--dst_h);
break;
case 3: // solid pens only with alpha blending
do {
do {
eax = src_ptr[src_x];
src_x = src_fx;
src_fx += src_fdx;
src_x >>= FP;
if (!eax || eax >= shdpen || ozbuf_ptr[ecx] < z8) continue;
ozbuf_ptr[ecx] = z8;
dst_ptr[ecx] = alpha_blend_r32(pal_base[eax], dst_ptr[ecx], alpha);
}
while (++ecx);
ecx = src_fby; src_fby += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx >>= FP; src_fx = src_fbx;
src_x = src_fbx; src_fx += src_fdx;
ecx <<= 4; src_ptr = src_base;
src_x >>= FP; src_ptr += ecx;
ecx = dst_w;
}
while (--dst_h);
break;
case 4: // shadow pens only
do {
do {
eax = src_ptr[src_x];
src_x = src_fx;
src_fx += src_fdx;
src_x >>= FP;
if (eax < shdpen || szbuf_ptr[ecx*2] < z8 || szbuf_ptr[ecx*2+1] <= p8) continue;
rgb_t pix = dst_ptr[ecx];
szbuf_ptr[ecx*2] = z8;
szbuf_ptr[ecx*2+1] = p8;
// the shadow tables are 15-bit lookup tables which accept RGB15... lossy, nasty, yuck!
dst_ptr[ecx] = shd_base[pix.as_rgb15()];
//dst_ptr[ecx] =(eax>>3&0x001f);lend_r32( eax, 0x00000000, 128);
}
while (++ecx);
ecx = src_fby; src_fby += src_fdy;
szbuf_ptr += (GX_ZBUFW<<1);
dst_ptr += dst_pitch;
ecx >>= FP; src_fx = src_fbx;
src_x = src_fbx; src_fx += src_fdx;
ecx <<= 4; src_ptr = src_base;
src_x >>= FP; src_ptr += ecx;
ecx = dst_w;
}
while (--dst_h);
break;
} // switch (drawmode)
} // if (zcode < 0)
} // if (!nozoom)
else
{
src_ptr = src_base + (src_fby<<4) + src_fbx;
src_fdy = src_fdx * dst_w + src_pitch;
ecx = dst_w;
if (zcode < 0) // no shadow and z-buffering
{
do {
do {
eax = *src_ptr;
src_ptr += src_fdx;
if (!eax || eax >= shdpen) continue;
dst_ptr[ecx] = pal_base[eax];
}
while (++ecx);
src_ptr += src_fdy;
dst_ptr += dst_pitch;
ecx = dst_w;
}
while (--dst_h);
}
else
{
switch (drawmode)
{
case 0: // all pens solid
do {
do {
eax = *src_ptr;
src_ptr += src_fdx;
if (!eax || ozbuf_ptr[ecx] < z8) continue;
eax = pal_base[eax];
ozbuf_ptr[ecx] = z8;
dst_ptr[ecx] = eax;
}
while (++ecx);
src_ptr += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx = dst_w;
}
while (--dst_h);
break;
case 1: // solid pens only
do {
do {
eax = *src_ptr;
src_ptr += src_fdx;
if (!eax || eax >= shdpen || ozbuf_ptr[ecx] < z8) continue;
eax = pal_base[eax];
ozbuf_ptr[ecx] = z8;
dst_ptr[ecx] = eax;
}
while (++ecx);
src_ptr += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx = dst_w;
}
while (--dst_h);
break;
case 2: // all pens solid with alpha blending
do {
do {
eax = *src_ptr;
src_ptr += src_fdx;
if (!eax || ozbuf_ptr[ecx] < z8) continue;
ozbuf_ptr[ecx] = z8;
dst_ptr[ecx] = alpha_blend_r32(pal_base[eax], dst_ptr[ecx], alpha);
}
while (++ecx);
src_ptr += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx = dst_w;
}
while (--dst_h);
break;
case 3: // solid pens only with alpha blending
do {
do {
eax = *src_ptr;
src_ptr += src_fdx;
if (!eax || eax >= shdpen || ozbuf_ptr[ecx] < z8) continue;
ozbuf_ptr[ecx] = z8;
dst_ptr[ecx] = alpha_blend_r32(pal_base[eax], dst_ptr[ecx], alpha);
}
while (++ecx);
src_ptr += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx = dst_w;
}
while (--dst_h);
break;
case 4: // shadow pens only
do {
do {
eax = *src_ptr;
src_ptr += src_fdx;
if (eax < shdpen || szbuf_ptr[ecx*2] < z8 || szbuf_ptr[ecx*2+1] <= p8) continue;
rgb_t pix = dst_ptr[ecx];
szbuf_ptr[ecx*2] = z8;
szbuf_ptr[ecx*2+1] = p8;
// the shadow tables are 15-bit lookup tables which accept RGB15... lossy, nasty, yuck!
dst_ptr[ecx] = shd_base[pix.as_rgb15()];
}
while (++ecx);
src_ptr += src_fdy;
szbuf_ptr += (GX_ZBUFW<<1);
dst_ptr += dst_pitch;
ecx = dst_w;
}
while (--dst_h);
break;
}
}
}
#undef FP
#undef FPONE
#undef FPHALF
#undef FPENT
}
void k053247_device::zdrawgfxzoom32GP(
bitmap_ind16 &bitmap, const rectangle &cliprect,
uint32_t code, uint32_t color, int flipx, int flipy, int sx, int sy,
int scalex, int scaley, int alpha, int drawmode, int zcode, int pri, uint8_t* gx_objzbuf, uint8_t* gx_shdzbuf)
{
fatalerror("no zdrawgfxzoom32GP for bitmap_ind16\n");
}
/*****************************************************************************
DEVICE INTERFACE
*****************************************************************************/
DEFINE_DEVICE_TYPE(K055673, k055673_device, "k055673", "K055673 Sprite Generator")
k055673_device::k055673_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: k053247_device(mconfig, K055673, tag, owner, clock)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void k055673_device::device_start()
{
if (!palette().device().started())
throw device_missing_dependencies();
int gfx_index = 0;
uint32_t total;
static const gfx_layout spritelayout = /* System GX sprite layout */
{
16,16,
0,
5,
{ 32, 24, 16, 8, 0 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 40, 41, 42, 43, 44, 45, 46, 47 },
{ 0, 10*8, 10*8*2, 10*8*3, 10*8*4, 10*8*5, 10*8*6, 10*8*7, 10*8*8,
10*8*9, 10*8*10, 10*8*11, 10*8*12, 10*8*13, 10*8*14, 10*8*15 },
16*16*5
};
static const gfx_layout spritelayout2 = /* Run and Gun sprite layout */
{
16,16,
0,
4,
{ 24, 16, 8, 0 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 32, 33, 34, 35, 36, 37, 38, 39 },
{ 0, 64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960 },
16*16*4
};
static const gfx_layout spritelayout3 = /* Lethal Enforcers II sprite layout */
{
16,16,
0,
8,
{ 56, 48, 40, 32, 24, 16, 8, 0 },
{ 0,1,2,3,4,5,6,7,64+0,64+1,64+2,64+3,64+4,64+5,64+6,64+7 },
{ 128*0, 128*1, 128*2, 128*3, 128*4, 128*5, 128*6, 128*7,
128*8, 128*9, 128*10, 128*11, 128*12, 128*13, 128*14, 128*15 },
16*16*8
};
static const gfx_layout spritelayout4 = /* System GX 6bpp sprite layout */
{
16,16,
0,
6,
{ 40, 32, 24, 16, 8, 0 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 48, 49, 50, 51, 52, 53, 54, 55 },
{ 0, 12*8, 12*8*2, 12*8*3, 12*8*4, 12*8*5, 12*8*6, 12*8*7, 12*8*8,
12*8*9, 12*8*10, 12*8*11, 12*8*12, 12*8*13, 12*8*14, 12*8*15 },
16*16*6
};
static const gfx_layout spritelayout5 = /* Pirate Ship layout */
{
16,16,
0,
4,
{ 24, 8, 16, 0 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 32, 33, 34, 35, 36, 37, 38, 39 },
{ 0, 64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960 },
16*16*4
};
uint8_t *s1, *s2, *d;
long i;
uint16_t *alt_k055673_rom;
int size4;
alt_k055673_rom = (uint16_t *)machine().root_device().memregion(m_memory_region)->base();
/* decode the graphics */
switch (m_bpp)
{
case K055673_LAYOUT_GX:
size4 = (machine().root_device().memregion(m_memory_region)->bytes()/(1024*1024))/5;
size4 *= 4*1024*1024;
/* set the # of tiles based on the 4bpp section */
alt_k055673_rom = auto_alloc_array(machine(), uint16_t, size4 * 5 / 2);
d = (uint8_t *)alt_k055673_rom;
// now combine the graphics together to form 5bpp
s1 = machine().root_device().memregion(m_memory_region)->base(); // 4bpp area
s2 = s1 + (size4); // 1bpp area
for (i = 0; i < size4; i+= 4)
{
*d++ = *s1++;
*d++ = *s1++;
*d++ = *s1++;
*d++ = *s1++;
*d++ = *s2++;
}
total = size4 / 128;
konami_decode_gfx(*this, gfx_index, (uint8_t *)alt_k055673_rom, total, &spritelayout, 5);
break;
case K055673_LAYOUT_RNG:
total = machine().root_device().memregion(m_memory_region)->bytes() / (16*16/2);
konami_decode_gfx(*this, gfx_index, (uint8_t *)alt_k055673_rom, total, &spritelayout2, 4);
break;
case K055673_LAYOUT_PS:
total = machine().root_device().memregion(m_memory_region)->bytes() / (16*16/2);
konami_decode_gfx(*this, gfx_index, (uint8_t *)alt_k055673_rom, total, &spritelayout5, 4);
break;
case K055673_LAYOUT_LE2:
total = machine().root_device().memregion(m_memory_region)->bytes() / (16*16);
konami_decode_gfx(*this, gfx_index, (uint8_t *)alt_k055673_rom, total, &spritelayout3, 8);
break;
case K055673_LAYOUT_GX6:
total = machine().root_device().memregion(m_memory_region)->bytes() / (16*16*6/8);
konami_decode_gfx(*this, gfx_index, (uint8_t *)alt_k055673_rom, total, &spritelayout4, 6);
break;
default:
fatalerror("Unsupported layout\n");
}
if (VERBOSE && !(palette().shadows_enabled()))
popmessage("driver should use VIDEO_HAS_SHADOWS");
m_z_rejection = -1;
m_gfx = gfx(gfx_index);
m_objcha_line = CLEAR_LINE;
m_ram = std::make_unique<uint16_t[]>(0x1000/2);
memset(m_ram.get(), 0, 0x1000);
memset(m_kx46_regs, 0, 8);
memset(m_kx47_regs, 0, 32);
save_pointer(NAME(m_ram), 0x800);
save_item(NAME(m_kx46_regs));
save_item(NAME(m_kx47_regs));
save_item(NAME(m_objcha_line));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
DEFINE_DEVICE_TYPE(K053247, k053247_device, "k053247", "K053246/K053247 Sprite Generator")
decltype(K053247) K053246 = K053247;
k053247_device::k053247_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: k053247_device(mconfig, K053247, tag, owner, clock)
{
}
k053247_device::k053247_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock),
device_video_interface(mconfig, *this),
device_gfx_interface(mconfig, *this, nullptr),
m_gfx_num(0)
{
clear_all();
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void k053247_device::device_start()
{
if (!palette().device().started())
throw device_missing_dependencies();
uint32_t total;
static const gfx_layout spritelayout =
{
16,16,
0,
4,
{ 0, 1, 2, 3 },
{ 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4,
10*4, 11*4, 8*4, 9*4, 14*4, 15*4, 12*4, 13*4 },
{ 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64,
8*64, 9*64, 10*64, 11*64, 12*64, 13*64, 14*64, 15*64 },
128*8
};
/* decode the graphics */
switch (m_bpp)
{
case NORMAL_PLANE_ORDER:
total = machine().root_device().memregion(m_memory_region)->bytes() / 128;
konami_decode_gfx(*this, m_gfx_num, machine().root_device().memregion(m_memory_region)->base(), total, &spritelayout, 4);
break;
default:
fatalerror("Unsupported plane_order\n");
}
if (VERBOSE)
{
if (screen().format() == BITMAP_FORMAT_RGB32)
{
if (!palette().shadows_enabled() || !palette().hilights_enabled())
popmessage("driver missing SHADOWS or HIGHLIGHTS flag");
}
else
{
if (!(palette().shadows_enabled()))
popmessage("driver should use VIDEO_HAS_SHADOWS");
}
}
m_gfx = gfx(m_gfx_num);
m_ram = make_unique_clear<uint16_t[]>(0x1000 / 2);
save_pointer(NAME(m_ram), 0x1000 / 2);
save_item(NAME(m_kx46_regs));
save_item(NAME(m_kx47_regs));
save_item(NAME(m_objcha_line));
save_item(NAME(m_z_rejection));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void k053247_device::device_reset()
{
m_z_rejection = -1;
m_objcha_line = CLEAR_LINE;
memset(m_kx46_regs, 0, 8);
memset(m_kx47_regs, 0, 32);
}
/*
In a K053247+K055555 setup objects with Z-code 0x00 should be ignored
when PRFLIP is cleared, while objects with Z-code 0xff should be
ignored when PRFLIP is set.
These behaviors can also be seen in older K053245(6)+K053251 setups.
Bucky'O Hare, The Simpsons and Sunset Riders rely on their implications
to prepare and retire sprites. They probably apply to many other Konami
games but it's hard to tell because most artifacts have been filtered
by exclusion sort.
A driver may call K05324x_set_z_rejection() to set which zcode to ignore.
Parameter:
-1 = accept all(default)
0x00-0xff = zcode to ignore
*/
void k053247_device::k053247_set_z_rejection( int zcode )
{
m_z_rejection = zcode;
}
READ16_MEMBER( k053247_device::k053246_reg_word_r )
{
return(m_kx46_regs[offset * 2] << 8 | m_kx46_regs[offset * 2 + 1]);
} // OBJSET1