Konami (GX) blending - additive sprite blending, improved tile blending (#13473)

k053246_k053247_k055673.cpp, k053246_k053247_k055673.h:
I went back to update zdrawgfxzoom32GP(), now down to a third of its original size before I started changing it. As a thinly veiled excuse for reworking the whole function, I went ahead and added additive sprite blending (to the now singular alpha call site).

Remarks: the mix priority setting is not yet handled. It seems simple enough (flip dst and src), but I would like to find an example of this before I implement it.

k054156_k054157_k056832.cpp:
The attr variable holds what appear to be the elusive tile (external) mix codes. Attach it to the flags variable so these bits can be accessed in the tile callback functions. Tiles with mix codes gets their own tilemap category.

Remarks: I've now changed the callback to include an attr param.

k054338.cpp:
Update set_alpha_level. This function now returns a level, an additive blend bool and a mixpri bool. Minor style changes to the overall file.

Remarks: set_alpha_level doesn't actually set anything. Maybe rename to get_alpha_level?

moo.cpp, xexex.cpp:
Mask out the new additive & mixpri bits from set_alpha_level calls for now, until it's known if / how they should be used over there.

mystwarr_v.cpp, mystwarr.h:
Remove mystwarr water hack.
Update mystwarr_tile_callback (and add viostorm_tile_callback) to read tile mix codes, store last read mix code in a new m_last_alpha_tile_mix_code variable.
Attach m_last_alpha_tile_mix_code to mixerflags, which happens to have two unused bits.

Remarks: I updated the mixerflags documentation to mention the usage of the last two bits.

konamigx_v.cpp, konamigx.cpp, konamigx.h:
Shrink GX_MAX_SPRITES, which to the best of my ability seems to be oversized. There does seem to be several oversized arrays / defs in these files, so I think this is one of them.
The usual FredYeye updates to konamigx_mixer - move declarations closer to use, more suited types, rename temp vars, etc.
Change objpool to a vector, simplifying usage (push_back, size).
Replace sorting loop with reverse + stable_sort.
Improve gx_draw_basic_tilemaps - read internal / external alpha mix codes based on vinmix_on. Tiles with mixcodes get drawn in a separate pass for per-tile blending.
Update alpha_tile_callback and add salmndr2_tile_callback, same as the mystwarr_v callbacks.

What started out as trying to sort out konamigx_mixer() to look at shadow/priority issues instead ended up with me finally getting a foot into the figurative tile blending door. The mystwarr water hack is gone, and sexyparo gets transparent windows. This might affect many GX and related games. Alpha blending might be broken in some games now, and needs to get their mix codes attached in their respective callbacks. salmndr2 got tagged in my automatic video comparison for differing from earlier versions, that's why I managed to fix it already.

Known problems:
metamrph: stained glass windows are near-transparent at the moment. I think additive tile blending will fix it...
viostorm: character names fade in in reverse. This also uses additive blending, so this might also get fixed once that's in.
fantjour: the top & bottom flames at the captain kebab ship go missing. Uses additive blending.
This commit is contained in:
Fredrik Sandkvist 2025-04-01 13:03:25 +02:00 committed by GitHub
parent cfa56c0d33
commit 7feaa6968d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 386 additions and 544 deletions

View File

@ -439,12 +439,11 @@ void k053247_device::k053247_sprites_draw(bitmap_rgb32 &bitmap, const rectangle
void k053247_device::zdrawgfxzoom32GP(
bitmap_rgb32 &bitmap, const rectangle &cliprect,
u32 code, u32 color, bool flipx, bool flipy, int sx, int sy,
int scalex, int scaley, int alpha, int drawmode, int zcode, int pri, u8* gx_objzbuf, u8* gx_shdzbuf)
int scalex, int scaley, int alpha, int drawmode, int zcode, u8 pri, u8* gx_objzbuf, u8* gx_shdzbuf)
{
constexpr int FP = 19;
constexpr int FPENT = 0;
constexpr u8 FP = 19; // 13.19 fixed point
// cull illegal and transparent objects
// cull objects with invalid scale
if (!scalex || !scaley) return;
// find shadow pens and cull invisible shadows
@ -453,267 +452,145 @@ void k053247_device::zdrawgfxzoom32GP(
if (zcode >= 0)
{
if (drawmode == 5) { drawmode = 4; shdpen = 1; }
if (drawmode == 5)
{
drawmode = 4;
shdpen = 1;
}
}
else
if (drawmode >= 4) return;
else if (drawmode >= 4) return;
// alpha blend necessary?
// alpha blend check: cull if 0% opaque, or skip alpha blending if 100% opaque
if (drawmode & 2)
{
if (alpha <= 0) return;
if (alpha >= 255) drawmode &= ~2;
if (!alpha) return;
if (alpha == 255) drawmode &= ~2;
}
// cull off-screen objects
if (sx > cliprect.max_x || sy > cliprect.max_y) return;
rectangle dst_rect = rectangle {sx, 0, sy, 0};
dst_rect.set_size(((scalex << 4) + 0x8000) >> 16, ((scaley << 4) + 0x8000) >> 16);
// fill internal data structure with default values
u8 *ozbuf_ptr = gx_objzbuf;
u8 *szbuf_ptr = gx_shdzbuf;
// cull off-screen and zero height/width objects
if (dst_rect.left() > cliprect.right() || dst_rect.right() < cliprect.left()) return;
if (dst_rect.top() > cliprect.bottom() || dst_rect.bottom() < cliprect.top()) return;
if (!dst_rect.width() || !dst_rect.height()) return;
constexpr u8 src_size = 16;
const int src_stride_x = (src_size << FP) / dst_rect.width();
const int src_stride_y = (src_size << FP) / dst_rect.height();
const int src_offset_x = std::max(cliprect.left() - dst_rect.left(), 0);
const int src_offset_y = std::max(cliprect.top() - dst_rect.top(), 0);
const int src_base_x = src_offset_x * src_stride_x;
const int src_base_y = src_offset_y * src_stride_y;
// exclude dst_rect area outside cliprect
dst_rect &= cliprect;
// invert src x/y offsets if flip enabled
u8 flip_mask = 0;
if (flipx) flip_mask |= src_size - 1;
if (flipy) flip_mask |= (src_size - 1) << 4;
const int dst_pitch = bitmap.rowpixels();
u32 *dst_ptr = &bitmap.pix(0) + dst_rect.left() + dst_rect.top() * dst_pitch;
const u8 *src_base = m_gfx->get_data(code % m_gfx->elements());
const pen_t *pal_base = palette().pens() + m_gfx->colorbase() + (color % m_gfx->colors()) * granularity;
const pen_t *shd_base = palette().shadow_table();
u32 *dst_ptr = &bitmap.pix(0);
const int dst_pitch = bitmap.rowpixels();
int dst_x = sx;
int dst_y = sy;
const int z_buffer_offset = (dst_rect.top() - cliprect.top()) * GX_ZBUFW + (dst_rect.left() - cliprect.left());
u8 *ozbuf_ptr = gx_objzbuf + z_buffer_offset;
int dst_w, dst_h;
int src_fdx, src_fdy;
int src_pitch = 16, src_fw = 16, src_fh = 16;
const bool 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;
}
const int dst_lastx = dst_x + dst_w - 1;
const int dst_lasty = dst_y + dst_h - 1;
if (dst_lastx < cliprect.min_x || dst_lasty < cliprect.min_y) return;
// clip destination
int dst_skipx = 0;
if (int delta_min_x = cliprect.min_x - dst_x; delta_min_x > 0)
{
dst_skipx = delta_min_x;
dst_w -= delta_min_x;
dst_x = cliprect.min_x;
}
if (int delta_max_x = dst_lastx - cliprect.max_x; delta_max_x > 0) dst_w -= delta_max_x;
int dst_skipy = 0;
if (int delta_min_y = cliprect.min_y - dst_y; delta_min_y > 0)
{
dst_skipy = delta_min_y;
dst_h -= delta_min_y;
dst_y = cliprect.min_y;
}
if (int delta_max_y = dst_lasty - cliprect.max_y; delta_max_y > 0) dst_h -= delta_max_y;
int src_fby, src_fbx;
// 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
const int offset = (dst_y - cliprect.min_y) * GX_ZBUFW + (dst_x - cliprect.min_x) + dst_w;
ozbuf_ptr += offset;
szbuf_ptr += offset << 1;
const u8 z8 = (u8)zcode;
const u8 p8 = (u8)pri;
dst_ptr += dst_y * dst_pitch + dst_x + dst_w;
dst_w = -dst_w;
int src_fx, src_x, ecx;
const u8 *src_ptr;
if (!nozoom)
if (zcode < 0)
{
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;
// no shadow and z-buffering
if (zcode < 0) // no shadow and z-buffering
for (int y = 0; y < dst_rect.height(); ++y)
{
do {
do {
const u8 pal_idx = src_ptr[src_x];
src_x = src_fx >> FP;
src_fx += src_fdx;
if (!pal_idx || pal_idx >= shdpen) continue;
dst_ptr[ecx] = pal_base[pal_idx];
}
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;
for (int x = 0; x < dst_rect.width(); ++x)
{
const int x_off = (src_base_x + x * src_stride_x) >> FP;
const int y_off = (src_base_y + y * src_stride_y) >> FP;
const u8 pal_idx = src_base[(x_off + y_off * 16) ^ flip_mask];
if (!pal_idx || pal_idx >= shdpen) continue;
ozbuf_ptr[x + y * GX_ZBUFW] = z8;
dst_ptr[x + y * dst_pitch] = pal_base[pal_idx];
}
while (--dst_h);
}
else if (drawmode < 4)
}
else if (drawmode < 4)
{
// 0: all pens solid
// 1: solid pens only
// 2: all pens solid with alpha blending
// 3: solid pens only with alpha blending
for (int y = 0; y < dst_rect.height(); ++y)
{
// 0: all pens solid
// 1: solid pens only
// 2: all pens solid with alpha blending
// 3: solid pens only with alpha blending
do {
do {
const u8 pal_idx = src_ptr[src_x];
src_x = src_fx >> FP;
src_fx += src_fdx;
if (!pal_idx || (drawmode & 0b01 && pal_idx >= shdpen) || ozbuf_ptr[ecx] < z8) continue;
ozbuf_ptr[ecx] = z8;
dst_ptr[ecx] = (drawmode & 0b10) ? alpha_blend_r32(dst_ptr[ecx], pal_base[pal_idx], alpha) : pal_base[pal_idx];
for (int x = 0; x < dst_rect.width(); ++x)
{
const int x_off = (src_base_x + x * src_stride_x) >> FP;
const int y_off = (src_base_y + y * src_stride_y) >> FP;
const u8 pal_idx = src_base[(x_off + y_off * 16) ^ flip_mask];
if (!pal_idx || (drawmode & 0b01 && pal_idx >= shdpen) || ozbuf_ptr[x + y * GX_ZBUFW] < z8) continue;
ozbuf_ptr[x + y * GX_ZBUFW] = z8;
if ((drawmode & 0b10) == 0) // solid sprite
{
dst_ptr[x + y * dst_pitch] = pal_base[pal_idx];
}
while (++ecx);
else // alpha blended sprite
{
const u8 alpha_level = alpha;
const bool additive_mode = alpha & (1 << 8);
// mix_pri flips src & dst
// todo: find a game that exhibits this behavior
// const bool mix_pri = alpha & (1 << 9);
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);
}
else
{
// 4: shadow pens only
do {
do {
const u8 pal_idx = src_ptr[src_x];
src_x = src_fx >> FP;
src_fx += src_fdx;
if (pal_idx < 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;
const u32 src = pal_base[pal_idx];
const u32 dst = dst_ptr[x + y * dst_pitch];
// 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);
if (additive_mode)
{
// todo: improve additive blend calculation
const u32 temp = alpha_blend_r32(src, 0, alpha_level);
dst_ptr[x + y * dst_pitch] = add_blend_r32(dst, temp);
}
else
{
dst_ptr[x + y * dst_pitch] = alpha_blend_r32(dst, src, alpha_level);
}
}
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);
}
} // if (!nozoom)
}
else
{
src_ptr = src_base + (src_fby<<4) + src_fbx;
src_fdy = src_fdx * dst_w + src_pitch;
ecx = dst_w;
// 4: shadow pens only
if (zcode < 0) // no shadow and z-buffering
const pen_t *shd_base = palette().shadow_table();
u8 *szbuf_ptr = gx_shdzbuf + z_buffer_offset * 2;
for (int y = 0; y < dst_rect.height(); ++y)
{
do {
do {
const u8 pal_idx = *src_ptr;
src_ptr += src_fdx;
if (!pal_idx || pal_idx >= shdpen) continue;
dst_ptr[ecx] = pal_base[pal_idx];
}
while (++ecx);
for (int x = 0; x < dst_rect.width(); ++x)
{
const int x_off = (src_base_x + x * src_stride_x) >> FP;
const int y_off = (src_base_y + y * src_stride_y) >> FP;
const u8 pal_idx = src_base[(x_off + y_off * 16) ^ flip_mask];
const int szbuf_offset = x * 2 + y * GX_ZBUFW * 2;
if (pal_idx < shdpen || szbuf_ptr[szbuf_offset] < z8 || szbuf_ptr[szbuf_offset + 1] <= pri) continue;
szbuf_ptr[szbuf_offset] = z8;
szbuf_ptr[szbuf_offset + 1] = pri;
src_ptr += src_fdy;
dst_ptr += dst_pitch;
ecx = dst_w;
rgb_t pix = dst_ptr[x + y * dst_pitch];
// the shadow tables are 15-bit lookup tables which accept RGB15... lossy, nasty, yuck!
dst_ptr[x + y * dst_pitch] = shd_base[pix.as_rgb15()];
//dst_ptr[ecx] =(eax>>3&0x001f);lend_r32(eax, 0x00000000, 128);
}
while (--dst_h);
}
else if (drawmode < 4)
{
// 0: all pens solid
// 1: solid pens only
// 2: all pens solid with alpha blending
// 3: solid pens only with alpha blending
do {
do {
const u8 pal_idx = *src_ptr;
src_ptr += src_fdx;
if (!pal_idx || (drawmode & 0b01 && pal_idx >= shdpen) || ozbuf_ptr[ecx] < z8) continue;
ozbuf_ptr[ecx] = z8;
dst_ptr[ecx] = (drawmode & 0b10) ? alpha_blend_r32(dst_ptr[ecx], pal_base[pal_idx], alpha) : pal_base[pal_idx];
}
while (++ecx);
src_ptr += src_fdy;
ozbuf_ptr += GX_ZBUFW;
dst_ptr += dst_pitch;
ecx = dst_w;
}
while (--dst_h);
}
else
{
// 4: shadow pens only
do {
do {
const u8 pal_idx = *src_ptr;
src_ptr += src_fdx;
if (pal_idx < 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);
}
}
}

View File

@ -112,7 +112,7 @@ public:
void zdrawgfxzoom32GP(
bitmap_rgb32 &bitmap, const rectangle &cliprect,
u32 code, u32 color, bool flipx, bool flipy, int sx, int sy,
int scalex, int scaley, int alpha, int drawmode, int zcode, int pri, u8* gx_objzbuf, u8* gx_shdzbuf);
int scalex, int scaley, int alpha, int drawmode, int zcode, u8 pri, u8* gx_objzbuf, u8* gx_shdzbuf);
void zdrawgfxzoom32GP(
bitmap_ind16 &bitmap, const rectangle &cliprect,

View File

@ -506,7 +506,7 @@ void k056832_device::get_tile_info( tile_data &tileinfo, int tile_index, int pa
color = (attr & smptr->palm1) | (attr >> smptr->pals2 & smptr->palm2);
flags = TILE_FLIPYX(flip);
m_k056832_cb(layer, &code, &color, &flags, &priority);
m_k056832_cb(layer, &code, &color, &flags, &priority, attr);
tileinfo.set(m_gfx_num,
code,

View File

@ -8,7 +8,7 @@
#include "k055555.h" // still needs k055555_get_palette_index
#include "tilemap.h"
#define K056832_CB_MEMBER(_name) void _name(int layer, int *code, int *color, int *flags, int *priority)
#define K056832_CB_MEMBER(_name) void _name(int layer, int *code, int *color, int *flags, int *priority, u16 attr)
#define K056832_PAGE_COUNT 16
@ -31,7 +31,7 @@ class k055555_device;
class k056832_device : public device_t, public device_gfx_interface
{
public:
using tile_delegate = device_delegate<void (int layer, int *code, int *color, int *flags, int *priority)>;
using tile_delegate = device_delegate<void (int layer, int *code, int *color, int *flags, int *priority, u16 attr)>;
template <typename T> k056832_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&mixer_tag)
: k056832_device(mconfig, tag, owner, clock)

View File

@ -65,7 +65,7 @@ u16 k054338_device::register_r(offs_t offset)
return m_regs[offset];
}
void k054338_device::update_all_shadows( int rushingheroes_hack, palette_device &palette )
void k054338_device::update_all_shadows(int rushingheroes_hack, palette_device &palette)
{
int i, d;
int noclip = m_regs[K338_REG_CONTROL] & K338_CTL_CLIPSL;
@ -73,8 +73,7 @@ void k054338_device::update_all_shadows( int rushingheroes_hack, palette_device
for (i = 0; i < 9; i++)
{
d = m_regs[K338_REG_SHAD1R + i] & 0x1ff;
if (d >= 0x100)
d -= 0x200;
if (d >= 0x100) d -= 0x200;
m_shd_rgb[i] = d;
}
@ -93,7 +92,7 @@ void k054338_device::update_all_shadows( int rushingheroes_hack, palette_device
}
// k054338 BG color fill
void k054338_device::fill_solid_bg( bitmap_rgb32 &bitmap, const rectangle &cliprect )
void k054338_device::fill_solid_bg(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
uint32_t bgcolor = (register_r(K338_REG_BGC_R) & 0xff) << 16;
bgcolor |= register_r(K338_REG_BGC_GB);
@ -142,60 +141,43 @@ void k054338_device::fill_backcolor(bitmap_rgb32 &bitmap, const rectangle &clipr
}
// addition blending unimplemented (requires major changes to drawgfx and tilemap.cpp)
int k054338_device::set_alpha_level( int pblend )
int k054338_device::set_alpha_level(int pblend)
{
uint16_t *regs;
int ctrl, mixpri, mixset, mixlv;
if (pblend > 3) logerror("mixing mode index out of range: %d (valid range: 0-3)", pblend);
if (pblend <= 0 || pblend > 3)
{
return (255);
}
if (!pblend) return 255;
regs = m_regs;
ctrl = m_regs[K338_REG_CONTROL];
mixpri = ctrl & K338_CTL_MIXPRI;
mixset = regs[K338_REG_PBLEND + (pblend >> 1 & 1)] >> (~pblend << 3 & 8);
mixlv = mixset & 0x1f;
// sanitize input
pblend &= 0b11;
if (m_alpha_inv)
mixlv = 0x1f - mixlv;
const u8 mixset = m_regs[K338_REG_PBLEND + (pblend >> 1 & 1)] >> (~pblend << 3 & 8);
int mixlv = mixset & 0x1f;
if (!(mixset & 0x20))
{
mixlv = (mixlv << 3) | (mixlv >> 2);
}
else
{
if (!mixpri)
{
// source x alpha + target (clipped at 255)
}
else
{
// source + target x alpha (clipped at 255)
}
if (m_alpha_inv) mixlv = 0x1f - mixlv;
// DUMMY
if (mixlv && mixlv < 0x1f)
mixlv = 0x10;
// expand mix level (5 bits -> 8)
mixlv = (mixlv << 3) | (mixlv >> 2);
mixlv = (mixlv << 3) | (mixlv >> 2);
const bool additive_mode = mixset & 0x20;
const bool mixpri = m_regs[K338_REG_CONTROL] & K338_CTL_MIXPRI;
if (VERBOSE)
popmessage("MIXSET%1d %s addition mode: %02x", pblend, (mixpri) ? "dst" : "src", mixset & 0x1f);
}
mixlv |= additive_mode << 8;
mixlv |= mixpri << 9;
// returns 10 bits: pa llll llll
// p: MI (mixpri)
// a: additive mode
// l: alpha level (expanded)
return mixlv;
}
void k054338_device::invert_alpha( int invert )
void k054338_device::invert_alpha(int invert)
{
m_alpha_inv = invert;
}
void k054338_device::export_config( int **shd_rgb )
void k054338_device::export_config(int **shd_rgb)
{
*shd_rgb = m_shd_rgb;
}

View File

@ -1860,6 +1860,8 @@ void konamigx_state::salmndr2(machine_config &config)
konamigx(config);
m_k056832->set_config(K056832_BPP_6, 1, 0);
m_k056832->set_tile_callback(FUNC(konamigx_state::salmndr2_tile_callback));
m_k055673->set_sprite_callback(FUNC(konamigx_state::salmndr2_sprite_callback));
m_k055673->set_config(K055673_LAYOUT_GX6, -48, -23);
}

View File

@ -115,13 +115,18 @@ public:
TIMER_CALLBACK_MEMBER(boothack_callback);
double adc0834_callback(uint8_t input);
K056832_CB_MEMBER(type2_tile_callback);
K056832_CB_MEMBER(salmndr2_tile_callback);
K056832_CB_MEMBER(alpha_tile_callback);
K055673_CB_MEMBER(type2_sprite_callback);
K055673_CB_MEMBER(dragoonj_sprite_callback);
K055673_CB_MEMBER(salmndr2_sprite_callback);
K055673_CB_MEMBER(le2_sprite_callback);
struct GX_OBJ { int order = 0, offs = 0, code = 0, color = 0; };
struct GX_OBJ
{
u32 order = 0;
int offs = 0, code = 0, color = 0;
};
void common_init();
uint32_t k_6bpp_rom_long_r(offs_t offset, uint32_t mem_mask = ~0);
@ -130,13 +135,11 @@ public:
tilemap_t *sub1, int sub1flags,
tilemap_t *sub2, int sub2flags,
int mixerflags, bitmap_ind16 *extra_bitmap, int rushingheroes_hack,
GX_OBJ *objpool,
int *objbuf,
int nobj
const std::vector<GX_OBJ> &objpool
);
void gx_draw_basic_tilemaps(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, int code);
void gx_draw_basic_tilemaps(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, uint8_t layer);
void gx_draw_basic_extended_tilemaps_1(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, int code, tilemap_t *sub1, int sub1flags, int rushingheroes_hack, int offs);
void gx_draw_basic_extended_tilemaps_2(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, int code, tilemap_t *sub2, int sub2flags, bitmap_ind16 *extra_bitmap, int offs);
@ -253,6 +256,8 @@ protected:
u8 m_current_brightness = 0xff;
u8 m_brightness[3]{};
u8 m_last_alpha_tile_mix_code = 0;
// mirrored K054338 settings
int *m_K054338_shdRGB = nullptr;
@ -303,8 +308,6 @@ protected:
std::unique_ptr<bitmap_ind16> m_gxtype1_roz_dstbitmap2;
rectangle m_gxtype1_roz_dstbitmapclip;
std::unique_ptr<GX_OBJ[]> m_gx_objpool;
u8 m_type3_psac2_bank = 0;
u8 m_type3_spriteram_bank = 0;
//int m_konamigx_type3_psac2_actual_last_bank = 0;
@ -339,6 +342,7 @@ protected:
----FFEEDDCCBBAA---------------- (layer A-F mix codes in forced blending)
---x---------------------------- (disable shadows)
--x----------------------------- (disable z-buffering)
yy------------------------------ (last encountered tile mix code)
*/
#define GXMIX_BLEND_AUTO 0 // emulate all blend effects
#define GXMIX_BLEND_NONE 1 // disable all blend effects

View File

@ -55,9 +55,9 @@ void konamigx_state::konamigx_precache_registers(void)
m_osinmix = m_k055555->K055555_read_register(K55_OSBLEND_ENABLES);
m_osmixon = m_k055555->K055555_read_register(K55_OSBLEND_ON);
m_brightness[0] = u8(m_k054338->register_r(K338_REG_BRI3));
m_brightness[1] = u8(m_k054338->register_r(K338_REG_BRI3 + 1) >> 8);
m_brightness[2] = u8(m_k054338->register_r(K338_REG_BRI3 + 1));
m_brightness[0] = uint8_t(m_k054338->register_r(K338_REG_BRI3));
m_brightness[1] = uint8_t(m_k054338->register_r(K338_REG_BRI3 + 1) >> 8);
m_brightness[2] = uint8_t(m_k054338->register_r(K338_REG_BRI3 + 1));
}
inline int konamigx_state::K053247GX_combine_c18(int attrib) // (see p.46)
@ -249,9 +249,9 @@ void konamigx_state::wipezbuf(int noshadow)
void konamigx_state::set_brightness(int layer)
{
const u8 bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
const uint8_t bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
const u8 new_brightness = bri_mode ? m_brightness[bri_mode - 1] : 0xff;
const uint8_t new_brightness = bri_mode ? m_brightness[bri_mode - 1] : 0xff;
if (m_current_brightness != new_brightness)
{
@ -291,7 +291,7 @@ void konamigx_state::set_brightness(int layer)
* shadow enables transparent shadows. Note that it applies to the last sprite pen ONLY.
* The rest of the sprite remains normal.
*/
#define GX_MAX_SPRITES 512*2
#define GX_MAX_SPRITES 256*2 // 256 sprites + 256 shadows
#define GX_MAX_LAYERS 6
#define GX_MAX_OBJECTS (GX_MAX_SPRITES + GX_MAX_LAYERS)
@ -302,7 +302,6 @@ void konamigx_state::konamigx_mixer_init(screen_device &screen, int objdma)
m_gx_objzbuf = &screen.priority().pix(0);
m_gx_shdzbuf = std::make_unique<uint8_t[]>(GX_ZBUFSIZE);
m_gx_objpool = std::make_unique<GX_OBJ[]>(GX_MAX_OBJECTS);
m_k054338->export_config(&m_K054338_shdRGB);
@ -337,19 +336,11 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
tilemap_t *sub2, int sub2flags,
int mixerflags, bitmap_ind16 *extra_bitmap, int rushingheroes_hack)
{
int objbuf[GX_MAX_OBJECTS];
int shadowon[3], shdpri[3], layerid[6], layerpri[6];
GX_OBJ *objpool, *objptr;
int cltc_shdpri, /*prflp,*/ disp;
// int prflp;
// buffer can move when it's resized, so refresh the pointer
m_gx_objzbuf = &screen.priority().pix(0);
// abort if object database failed to initialize
objpool = m_gx_objpool.get();
if (!objpool) return;
// clear screen with backcolor and update flicker pulse
if (m_gx_wrport1_0 & 0x20)
m_k054338->fill_backcolor(bitmap,
@ -360,9 +351,9 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
m_k054338->fill_solid_bg(bitmap, cliprect);
// abort if video has been disabled
disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
const uint8_t disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
if (!disp) return;
cltc_shdpri = m_k054338->register_r(K338_REG_CONTROL);
uint16_t cltc_shdpri = m_k054338->register_r(K338_REG_CONTROL);
if (!rushingheroes_hack) // Slam Dunk 2 never sets this. It's either part of the protection, or type4 doesn't use it
@ -384,12 +375,13 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
konamigx_precache_registers();
// init OBJSET2 and mixer parameters (see p.51 and chapter 7)
layerid[0] = 0; layerid[1] = 1; layerid[2] = 2; layerid[3] = 3; layerid[4] = 4; layerid[5] = 5;
uint8_t layerid[6] = {0, 1, 2, 3, 4, 5};
// invert layer priority when this flag is set (not used by any GX game?)
//prflp = K055555_read_register(K55_CONTROL) & K55_CTL_FLIPPRI;
uint8_t layerpri[6];
layerpri[0] = m_k055555->K055555_read_register(K55_PRIINP_0);
layerpri[1] = m_k055555->K055555_read_register(K55_PRIINP_3);
layerpri[3] = m_k055555->K055555_read_register(K55_PRIINP_7);
@ -411,10 +403,12 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
}
// SHDPRISEL filters shadows by different priority comparison methods (UNIMPLEMENTED, see detail on p.66)
bool shadowon[3];
if (!(shdprisel & 0x03)) shadowon[0] = 0;
if (!(shdprisel & 0x0c)) shadowon[1] = 0;
if (!(shdprisel & 0x30)) shadowon[2] = 0;
uint8_t shdpri[3];
shdpri[0] = m_k055555->K055555_read_register(K55_SHAD1_PRI);
shdpri[1] = m_k055555->K055555_read_register(K55_SHAD2_PRI);
shdpri[2] = m_k055555->K055555_read_register(K55_SHAD3_PRI);
@ -446,27 +440,24 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
// pre-sort layers
for (int j=0; j<5; j++)
{
int temp1 = layerpri[j];
for (int i=j+1; i<6; i++)
{
int temp2 = layerpri[i];
if ((uint32_t)temp1 <= (uint32_t)temp2)
if (layerpri[j] <= layerpri[i])
{
layerpri[i] = temp1; layerpri[j] = temp1 = temp2;
temp2 = layerid[i]; layerid[i] = layerid[j]; layerid[j] = temp2;
std::swap(layerpri[j], layerpri[i]);
std::swap(layerid[j], layerid[i]);
}
}
}
// build object database and create indices
objptr = objpool;
int nobj = 0;
std::vector<GX_OBJ> objpool; // max size: 6 layers + 256 sprites + 256 shadows
for (int i=5; i>=0; i--)
{
int offs;
int code = layerid[i];
const uint8_t code = layerid[i];
switch (code)
{
/*
@ -493,61 +484,45 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
if (offs != -128)
{
objptr->order = layerpri[i]<<24;
objptr->code = code;
objptr->offs = offs;
objptr++;
objbuf[nobj] = nobj;
nobj++;
const uint32_t order = layerpri[i] << 24;
const int color = 0;
objpool.push_back(GX_OBJ{order, offs, code, color});
}
}
// i = j = 0xff;
int l = 0;
const uint32_t start_addr = m_type3_spriteram_bank ? 0x800 : 0;
u32 start_addr = m_type3_spriteram_bank ? 0x800 : 0;
u32 end_addr = start_addr + 0x800;
for (int offs=start_addr; offs<end_addr; offs+=8)
for (int x = 0; x < 256; ++x)
{
const uint16_t offs = start_addr + x * 8;
int pri = 0;
if (!(m_gx_spriteram[offs] & 0x8000)) continue;
int zcode = m_gx_spriteram[offs] & 0xff;
uint8_t zcode = m_gx_spriteram[offs] & 0xff;
// invert z-order when opset_pri is set (see p.51 OPSET PRI)
if (m_k053247_opset & 0x10) zcode = 0xff - zcode;
int code = m_gx_spriteram[offs+1];
int color = k = m_gx_spriteram[offs+6];
l = m_gx_spriteram[offs+7];
// int l = m_gx_spriteram[offs+7];
m_k055673->m_k053247_cb(&code, &color, &pri);
/*
shadow = shadow code
spri = shadow priority
temp1 = add solid object
temp2 = solid pens draw mode
temp3 = add shadow object
temp4 = shadow pens draw mode
*/
int temp4 = 0;
int temp3 = 0;
int temp2 = 0;
int temp1 = 0;
int spri = 0;
int shadow = 0;
uint8_t shadow_draw_mode = 0; // shadow pens draw mode (4-5)
bool add_shadow = 0; // add shadow object
uint8_t solid_draw_mode = 0; // solid pens draw mode (0-3)
bool add_solid = 0; // add solid object
uint8_t spri = 0; // shadow priority
uint8_t shadow = 0; // shadow code
if (color & K055555_FULLSHADOW)
{
shadow = 3; // use default intensity and color
spri = pri; // retain host priority
temp3 = 1; // add shadow
temp4 = 5; // draw full shadow
add_shadow = 1;
shadow_draw_mode = 5; // draw full shadow
}
else
{
@ -558,12 +533,12 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
if (shadow != 1 || k053246_objset1 & 0x20)
{
shadow--;
temp1 = 1; // add solid
temp2 = 1; // draw partial solid
add_solid = 1;
solid_draw_mode = 1; // draw partial solid
if (shadowon[shadow])
{
temp3 = 1; // add shadow
temp4 = 4; // draw partial shadow
add_shadow = 1;
shadow_draw_mode = 4; // draw partial shadow
}
}
else
@ -571,23 +546,23 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
// drop the entire sprite to shadow if its shadow code is 1 and SD0EN is off (see p.48)
shadow = 0;
if (!shadowon[0]) continue;
temp3 = 1; // add shadow
temp4 = 5; // draw full shadow
add_shadow = 1;
shadow_draw_mode = 5; // draw full shadow
}
}
else
{
temp1 = 1; // add solid
temp2 = 0; // draw full solid
add_solid = 1;
solid_draw_mode = 0; // draw full solid
}
if (temp1)
if (add_solid)
{
// tag sprite for alpha blending
if (color>>K055555_MIXSHIFT & 3) temp2 |= 2;
if (color>>K055555_MIXSHIFT & 3) solid_draw_mode |= 2;
}
if (temp3)
if (add_shadow)
{
// determine shadow priority
spri = (m_k053247_opset & 0x20) ? pri : shdpri[shadow]; // (see p.51 OPSET SDSEL)
@ -621,97 +596,171 @@ void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap,
------------------------xxxx---- (shadow mode)
----------------------------xxxx (shadow code)
*/
if (temp1)
if (add_solid)
{
// add objects with solid or alpha pens
int order = pri<<24 | zcode<<16 | offs<<(8-3) | temp2<<4;
objptr->order = order;
objptr->offs = offs;
objptr->code = code;
objptr->color = color;
objptr++;
objbuf[nobj] = nobj;
nobj++;
uint32_t order = pri<<24 | zcode<<16 | offs<<(8-3) | solid_draw_mode<<4;
objpool.push_back(GX_OBJ{order, offs, code, color});
}
if (temp3 && !(color & K055555_SKIPSHADOW) && !(mixerflags & GXMIX_NOSHADOW))
if (add_shadow && !(color & K055555_SKIPSHADOW) && !(mixerflags & GXMIX_NOSHADOW))
{
// add objects with shadows if enabled
int order = spri<<24 | zcode<<16 | offs<<(8-3) | temp4<<4 | shadow;
objptr->order = order;
objptr->offs = offs;
objptr->code = code;
objptr->color = color;
objptr++;
objbuf[nobj] = nobj;
nobj++;
}
}
// sort objects in decending order (SLOW)
k = nobj;
l = nobj - 1;
for (int j=0; j<l; j++)
{
int temp1 = objbuf[j];
int temp2 = objpool[temp1].order;
for (int i=j+1; i<k; i++)
{
int temp3 = objbuf[i];
int temp4 = objpool[temp3].order;
if ((uint32_t)temp2 <= (uint32_t)temp4) { temp2 = temp4; objbuf[i] = temp1; objbuf[j] = temp1 = temp3; }
uint32_t order = spri<<24 | zcode<<16 | offs<<(8-3) | shadow_draw_mode<<4 | shadow;
objpool.push_back(GX_OBJ{ order, offs, code, color});
}
}
// sort objects in descending order (SLOW)
// reverse objpool to retain order in case of ties
std::reverse(objpool.begin(), objpool.end());
std::stable_sort(objpool.begin(), objpool.end(), [](const GX_OBJ &a, const GX_OBJ &b){
return a.order > b.order;
});
konamigx_mixer_draw(screen,bitmap,cliprect,sub1,sub1flags,sub2,sub2flags,mixerflags,extra_bitmap,rushingheroes_hack,
objpool,
objbuf,
nobj
objpool
);
}
void konamigx_state::gx_draw_basic_tilemaps(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, int code)
void konamigx_state::konamigx_mixer_draw(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect,
tilemap_t *sub1, int sub1flags,
tilemap_t *sub2, int sub2flags,
int mixerflags, bitmap_ind16 *extra_bitmap, int rushingheroes_hack,
/* passed from above function */
const std::vector<GX_OBJ> &objpool
)
{
int temp1,temp2,temp3,temp4;
int i = code<<1;
int j = mixerflags>>i & 3;
int k = 0;
// traverse draw list
const uint8_t disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
int disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
if (disp & (1<<code))
for (int count=0; count<objpool.size(); count++)
{
set_brightness(code);
const uint32_t order = objpool[count].order;
const int offs = objpool[count].offs;
const int code = objpool[count].code;
int color = objpool[count].color;
if (j == GXMIX_BLEND_NONE) { temp1 = 0xff; temp2 = temp3 = 0; } else
if (j == GXMIX_BLEND_FORCE) { temp1 = 0x00; temp2 = mixerflags>>(i+16); temp3 = 3; }
/* entries >=0 in our list are sprites */
if (offs >= 0)
{
if (!(disp & K55_INP_OBJ)) continue;
int drawmode = order>>4 & 0xf;
int alpha = 255;
int pri = 0;
int zcode = -1; // negative zcode values turn off z-buffering
if (drawmode & 2)
{
alpha = color>>K055555_MIXSHIFT & 3;
if (alpha) alpha = m_k054338->set_alpha_level(alpha);
if (alpha <= 0) continue;
}
color &= K055555_COLORMASK;
if (drawmode >= 4) m_palette->set_shadow_mode(order & 0x0f);
if (!(mixerflags & GXMIX_NOZBUF))
{
zcode = order>>16 & 0xff;
pri = order>>24 & 0xff;
}
m_k055673->k053247_draw_single_sprite_gxcore(bitmap, cliprect,
m_gx_objzbuf, m_gx_shdzbuf.get(), code, m_gx_spriteram, offs,
color, alpha, drawmode, zcode, pri,
/* non-gx only */
0,0,nullptr,nullptr,0
);
}
/* the rest are tilemaps of various kinda */
else
{
temp1 = m_vinmix;
temp2 = m_vinmix>>i & 3;
temp3 = m_vmixon>>i & 3;
switch (offs)
{
case -1:
gx_draw_basic_tilemaps(screen, bitmap, cliprect, mixerflags, code);
continue;
case -2:
case -4:
gx_draw_basic_extended_tilemaps_1(screen, bitmap, cliprect, mixerflags, code, sub1, sub1flags, rushingheroes_hack, offs);
continue;
case -3:
case -5:
gx_draw_basic_extended_tilemaps_2(screen, bitmap, cliprect, mixerflags, code, sub2, sub2flags, extra_bitmap, offs);
continue;
}
continue;
}
}
}
/* blend layer only when:
1) m_vinmix != 0xff
2) its internal mix code is set
3) all mix code bits are internal(overridden until tile blending has been implemented)
4) 0 > alpha < 255;
*/
if (temp1!=0xff && temp2 /*&& temp3==3*/)
void konamigx_state::gx_draw_basic_tilemaps(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, uint8_t layer)
{
const uint8_t disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
if (disp & (1 << layer))
{
set_brightness(layer);
const uint8_t layer2 = layer << 1;
const uint8_t j = mixerflags >> layer2 & 0b11;
// keep internal and external mix codes separated, so the external mix code can be applied to category 1 tiles
uint8_t mix_mode_internal = 0;
uint8_t mix_mode_external = 0;
if (j == GXMIX_BLEND_FORCE) mix_mode_internal = mixerflags >> (layer2 + 16) & 0b11; // hack
else
{
temp4 = m_k054338->set_alpha_level(temp2);
const uint8_t v_inmix_on_layer = m_vmixon >> layer2 & 0b11;
const uint8_t v_inmix_layer = m_vinmix >> layer2 & 0b11;
const uint8_t tile_mix_code = uint32_t(mixerflags) >> 30;
if (temp4 <= 0) return;
if (temp4 < 255) k = TILEMAP_DRAW_ALPHA(temp4);
mix_mode_internal = v_inmix_layer & v_inmix_on_layer;
mix_mode_external = tile_mix_code & ~v_inmix_on_layer;
}
if (mixerflags & 1<<(code+12)) k |= K056382_DRAW_FLAG_FORCE_XYSCROLL;
int flags = TILEMAP_DRAW_CATEGORY(0);
int flags2 = TILEMAP_DRAW_CATEGORY(1);
m_k056832->m_tilemap_draw(screen, bitmap, cliprect, code, k, 0);
if (mixerflags & 1 << (layer + 12))
{
flags |= K056382_DRAW_FLAG_FORCE_XYSCROLL;
flags2 |= K056382_DRAW_FLAG_FORCE_XYSCROLL;
}
// hack: mask out mixpri bit. if additive bit set, mask it out and invert alpha.
// this makes additive alpha effects look OK until they are properly handled.
int alpha = m_k054338->set_alpha_level(mix_mode_internal) & 0x1ff;
if (alpha & 0x100)
{
alpha &= 0xff;
if (alpha) alpha = ~alpha & 0xff;
}
int alpha2 = m_k054338->set_alpha_level(mix_mode_external) & 0x1ff;
if (alpha2 & 0x100) alpha2 = ~alpha2 & 0xff;
if (alpha < 255) flags |= TILEMAP_DRAW_ALPHA(alpha);
if (alpha2 < 255)
{
// tiles with mix codes are put into category 1.
// draw them in a separate pass for per-tile blending if necessary.
flags2 |= TILEMAP_DRAW_ALPHA(alpha2);
m_k056832->m_tilemap_draw(screen, bitmap, cliprect, layer, flags2, 0);
}
else
{
// if no alpha is being applied to category 1 (tile mix code) tiles,
// draw all tiles with one m_tilemap_draw call
flags |= TILEMAP_DRAW_ALL_CATEGORIES;
}
m_k056832->m_tilemap_draw(screen, bitmap, cliprect, layer, flags, 0);
}
}
@ -738,7 +787,7 @@ void konamigx_state::gx_draw_basic_extended_tilemaps_1(screen_device &screen, bi
if (temp1!=0xff && temp2 /*&& temp3==3*/)
{
alpha = temp4 = m_k054338->set_alpha_level(temp2);
alpha = temp4 = m_k054338->set_alpha_level(temp2) & 0xff;
if (temp4 <= 0) return;
if (temp4 < 255) k = 1;
@ -786,7 +835,7 @@ void konamigx_state::gx_draw_basic_extended_tilemaps_2(screen_device &screen, bi
if (temp1!=0xff && temp2 /*&& temp3==3*/)
{
//alpha =
temp4 = m_k054338->set_alpha_level(temp2);
temp4 = m_k054338->set_alpha_level(temp2) & 0xff;
if (temp4 <= 0) return;
//if (temp4 < 255) k = 1;
@ -831,91 +880,6 @@ void konamigx_state::gx_draw_basic_extended_tilemaps_2(screen_device &screen, bi
}
}
void konamigx_state::konamigx_mixer_draw(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect,
tilemap_t *sub1, int sub1flags,
tilemap_t *sub2, int sub2flags,
int mixerflags, bitmap_ind16 *extra_bitmap, int rushingheroes_hack,
/* passed from above function */
GX_OBJ *objpool,
int *objbuf,
int nobj
)
{
// traverse draw list
int disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
for (int count=0; count<nobj; count++)
{
GX_OBJ *objptr = objpool + objbuf[count];
int order = objptr->order;
int offs = objptr->offs;
int code = objptr->code;
int color = objptr->color;
/* entries >=0 in our list are sprites */
if (offs >= 0)
{
if (!(disp & K55_INP_OBJ)) continue;
int drawmode = order>>4 & 0xf;
int alpha = 255;
int pri = 0;
int zcode = -1; // negative zcode values turn off z-buffering
if (drawmode & 2)
{
alpha = color>>K055555_MIXSHIFT & 3;
if (alpha) alpha = m_k054338->set_alpha_level(alpha);
if (alpha <= 0) continue;
}
color &= K055555_COLORMASK;
if (drawmode >= 4) m_palette->set_shadow_mode(order & 0x0f);
if (!(mixerflags & GXMIX_NOZBUF))
{
zcode = order>>16 & 0xff;
pri = order>>24 & 0xff;
}
m_k055673->k053247_draw_single_sprite_gxcore(bitmap, cliprect,
m_gx_objzbuf, m_gx_shdzbuf.get(), code, m_gx_spriteram, offs,
color, alpha, drawmode, zcode, pri,
/* non-gx only */
0,0,nullptr,nullptr,0
);
}
/* the rest are tilemaps of various kinda */
else
{
switch (offs)
{
case -1:
gx_draw_basic_tilemaps(screen, bitmap, cliprect, mixerflags, code);
continue;
case -2:
case -4:
gx_draw_basic_extended_tilemaps_1(screen, bitmap, cliprect, mixerflags, code, sub1, sub1flags, rushingheroes_hack, offs);
continue;
case -3:
case -5:
gx_draw_basic_extended_tilemaps_2(screen, bitmap, cliprect, mixerflags, code, sub2, sub2flags, extra_bitmap, offs);
continue;
}
continue;
}
}
}
/* Run and Gun 2 / Rushing Heroes */
TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac_tile_info)
{
@ -1083,25 +1047,31 @@ K056832_CB_MEMBER(konamigx_state::type2_tile_callback)
K055555GX_decode_vmixcolor(layer, color);
}
K056832_CB_MEMBER(konamigx_state::alpha_tile_callback)
K056832_CB_MEMBER(konamigx_state::salmndr2_tile_callback)
{
int mixcode;
const uint8_t mix_code = attr >> 4 & 0b11;
if (mix_code) {
*priority = 1;
m_last_alpha_tile_mix_code = mix_code;
}
int d = *code;
mixcode = K055555GX_decode_vmixcolor(layer, color);
*code = (m_gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
K055555GX_decode_vmixcolor(layer, color);
}
if (mixcode < 0)
*code = (m_gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
else
{
/* save mixcode and mark tile alpha (unimplemented) */
// Daisu-Kiss stage presentation
// Sexy Parodius level 3b
*code = (m_gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
if (VERBOSE)
popmessage("skipped alpha tile(layer=%d mix=%d)", layer, mixcode);
K056832_CB_MEMBER(konamigx_state::alpha_tile_callback)
{
const uint8_t mix_code = attr >> 6 & 0b11;
if (mix_code) {
*priority = 1;
m_last_alpha_tile_mix_code = mix_code;
}
int d = *code;
*code = (m_gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
K055555GX_decode_vmixcolor(layer, color);
}
/*
@ -1489,7 +1459,8 @@ uint32_t konamigx_state::screen_update_konamigx(screen_device &screen, bitmap_rg
}
else
{
konamigx_mixer(screen, bitmap, cliprect, nullptr, 0, nullptr, 0, 0, nullptr, m_gx_rushingheroes_hack);
int mixerflags = m_last_alpha_tile_mix_code << 30;
konamigx_mixer(screen, bitmap, cliprect, nullptr, 0, nullptr, 0, mixerflags, nullptr, m_gx_rushingheroes_hack);
}
// HACK: draw type-1 roz layer here for testing purposes only

View File

@ -333,7 +333,7 @@ uint32_t moo_state::screen_update_moo(screen_device &screen, bitmap_rgb32 &bitma
// There is probably a control bit somewhere to turn off alpha blending.
m_alpha_enabled = m_k054338->register_r(K338_REG_CONTROL) & K338_CTL_MIXPRI; // DUMMY
alpha = (m_alpha_enabled) ? m_k054338->set_alpha_level(1) : 255;
alpha = (m_alpha_enabled) ? m_k054338->set_alpha_level(1) & 0xff : 255;
if (alpha > 0)
m_k056832->tilemap_draw(screen, bitmap, cliprect, layers[2], TILEMAP_DRAW_ALPHA(alpha), 4);

View File

@ -1034,7 +1034,7 @@ void mystwarr_state::viostorm(machine_config &config)
m_screen->set_size(64*8, 32*8);
m_screen->set_visarea(40, 40+384-1, 16, 16+224-1);
m_k056832->set_tile_callback(FUNC(mystwarr_state::game4bpp_tile_callback));
m_k056832->set_tile_callback(FUNC(mystwarr_state::viostorm_tile_callback));
m_k055673->set_sprite_callback(FUNC(mystwarr_state::metamrph_sprite_callback));
m_k055673->set_config(K055673_LAYOUT_RNG, -62, -23);
@ -1082,7 +1082,7 @@ void mystwarr_state::metamrph(machine_config &config)
m_screen->set_size(64*8, 32*8);
m_screen->set_visarea(24, 24+288-1, 15, 15+224-1);
m_k056832->set_tile_callback(FUNC(mystwarr_state::game4bpp_tile_callback));
m_k056832->set_tile_callback(FUNC(mystwarr_state::viostorm_tile_callback));
m_k055673->set_sprite_callback(FUNC(mystwarr_state::metamrph_sprite_callback));
m_k055673->set_config(K055673_LAYOUT_RNG, -51, -24);

View File

@ -55,6 +55,8 @@ private:
uint8_t m_sound_ctrl = 0;
uint8_t m_sound_nmi_clk = 0;
uint8_t m_last_alpha_tile_mix_code = 0;
uint16_t eeprom_r(offs_t offset, uint16_t mem_mask = ~0);
void mweeprom_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t dddeeprom_r(offs_t offset, uint16_t mem_mask = ~0);
@ -103,6 +105,7 @@ private:
TIMER_DEVICE_CALLBACK_MEMBER(metamrph_interrupt);
TIMER_DEVICE_CALLBACK_MEMBER(mchamp_interrupt);
K056832_CB_MEMBER(mystwarr_tile_callback);
K056832_CB_MEMBER(viostorm_tile_callback);
K056832_CB_MEMBER(game5bpp_tile_callback);
K056832_CB_MEMBER(game4bpp_tile_callback);
K055673_CB_MEMBER(mystwarr_sprite_callback);

View File

@ -59,16 +59,27 @@ void mystwarr_state::decode_tiles()
// Mystic Warriors requires tile based blending.
K056832_CB_MEMBER(mystwarr_state::mystwarr_tile_callback)
{
if (layer == 1)
const uint8_t mix_code = attr >> 2 & 0b11;
if (mix_code)
{
//* water hack (TEMPORARY)
if ((*code & 0xff00) + (*color) == 0x4101)
m_cbparam++;
else
m_cbparam--;
*priority = 1;
m_last_alpha_tile_mix_code = mix_code;
}
*color = m_layer_colorbase[layer] | (*color >> 1 & 0x1e);
*color = m_layer_colorbase[layer] | (*color >> 1 & 0x0f);
}
K056832_CB_MEMBER(mystwarr_state::viostorm_tile_callback)
{
// metamrph either uses bits 0-1 or 4-5, not sure which
const uint8_t mix_code = attr & 0b11;
if (mix_code)
{
*priority = 1;
m_last_alpha_tile_mix_code = mix_code;
}
*color = m_layer_colorbase[layer] | (*color >> 2 & 0x0f);
}
// for games with 5bpp tile data
@ -209,8 +220,6 @@ VIDEO_START_MEMBER(mystwarr_state, mystwarr)
m_k056832->set_layer_offs(1, 0-3, 0);
m_k056832->set_layer_offs(2, 2-3, 0);
m_k056832->set_layer_offs(3, 3-3, 0);
m_cbparam = 0;
}
VIDEO_START_MEMBER(mystwarr_state, metamrph)
@ -262,14 +271,6 @@ VIDEO_START_MEMBER(mystwarr_state, martchmp)
uint32_t mystwarr_state::screen_update_mystwarr(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
int blendmode = 0;
//* water hack (TEMPORARY)
if (m_cbparam < 0)
m_cbparam = 0;
else if (m_cbparam >= 32)
blendmode = (1 << 16 | GXMIX_BLEND_FORCE) << 2;
for (int i = 0; i < 4; i++)
{
int old = m_layer_colorbase[i];
@ -279,7 +280,8 @@ uint32_t mystwarr_state::screen_update_mystwarr(screen_device &screen, bitmap_rg
m_sprite_colorbase = m_k055555->K055555_get_palette_index(4) << 5;
konamigx_mixer(screen, bitmap, cliprect, nullptr, 0, nullptr, 0, blendmode, nullptr, 0);
int mixerflags = m_last_alpha_tile_mix_code << 30;
konamigx_mixer(screen, bitmap, cliprect, nullptr, 0, nullptr, 0, mixerflags, nullptr, 0);
return 0;
}
@ -294,7 +296,8 @@ uint32_t mystwarr_state::screen_update_metamrph(screen_device &screen, bitmap_rg
m_sprite_colorbase = m_k055555->K055555_get_palette_index(4) << 4;
konamigx_mixer(screen, bitmap, cliprect, nullptr, GXSUB_K053250 | GXSUB_4BPP, nullptr, 0, 0, nullptr, 0);
int mixerflags = m_last_alpha_tile_mix_code << 30;
konamigx_mixer(screen, bitmap, cliprect, nullptr, GXSUB_K053250 | GXSUB_4BPP, nullptr, 0, mixerflags, nullptr, 0);
return 0;
}

View File

@ -364,7 +364,7 @@ uint32_t xexex_state::screen_update_xexex(screen_device &screen, bitmap_rgb32 &b
if (m_cur_alpha)
{
alpha = m_k054338->set_alpha_level(1);
alpha = m_k054338->set_alpha_level(1) & 0xff;
if (alpha > 0)
{