diff options
Diffstat (limited to 'src/mame/machine/konamigx.c')
-rw-r--r-- | src/mame/machine/konamigx.c | 2247 |
1 files changed, 2247 insertions, 0 deletions
diff --git a/src/mame/machine/konamigx.c b/src/mame/machine/konamigx.c new file mode 100644 index 00000000000..ba336815a5b --- /dev/null +++ b/src/mame/machine/konamigx.c @@ -0,0 +1,2247 @@ +#define VERBOSE 0 +#define GX_DEBUG 0 + +/************************************************************************** + * + * machine/konamigx.c - contains various System GX hardware abstractions + * + * Currently includes: TMS57002 skipper/simulator to make the sound 68k happy. + * + */ + +#include "driver.h" +#include "video/konamiic.h" +#include "machine/konamigx.h" +#include <math.h> + + +static struct +{ + UINT8 control; + UINT8 program[1024]; + UINT32 tables[256]; + int curpos; + int bytepos; + UINT32 tmp; +} tms57002; + +static int ldw = 0; + + +void tms57002_init(void) +{ + tms57002.control = 0; +} + +static void chk_ldw(void) +{ + ldw = 0; +} + +WRITE8_HANDLER( tms57002_control_w ) +{ + chk_ldw(); + + switch(tms57002.control) + { + case 0xf8: + break; + case 0xf0: + break; + } + + tms57002.control = data; + + switch(data) + { + case 0xf8: // Program write + case 0xf0: // Table write + tms57002.curpos = 0; + tms57002.bytepos = 3; + tms57002.tmp = 0; + break; + case 0xf4: // Entry write + tms57002.curpos = -1; + tms57002.bytepos = 3; + tms57002.tmp = 0; + break; + case 0xfc: // Checksum (?) Status (?) + tms57002.bytepos = 3; + tms57002.tmp = 0; + break; + case 0xff: // Standby + break; + case 0xfe: // Irq + /* (place ack of timer IRQ here) */ + break; + default: + break; + } +} + +READ8_HANDLER( tms57002_status_r ) +{ + chk_ldw(); + return 1; +} + +WRITE8_HANDLER( tms57002_data_w ) +{ + switch(tms57002.control) + { + case 0xf8: + tms57002.program[tms57002.curpos++] = data; + break; + case 0xf0: + tms57002.tmp |= data << (8*tms57002.bytepos); + tms57002.bytepos--; + if (tms57002.bytepos < 0) + { + tms57002.bytepos = 3; + tms57002.tables[tms57002.curpos++] = tms57002.tmp; + tms57002.tmp = 0; + } + break; + case 0xf4: + if (tms57002.curpos == -1) + tms57002.curpos = data; + else + { + tms57002.tmp |= data << (8*tms57002.bytepos); + tms57002.bytepos--; + + if (tms57002.bytepos < 0) + { + tms57002.bytepos = 3; + tms57002.tables[tms57002.curpos] = tms57002.tmp; + tms57002.tmp = 0; + tms57002.curpos = -1; + } + } + break; + default: + ldw++; + break; + } +} + +READ8_HANDLER( tms57002_data_r ) +{ + UINT8 res; + + chk_ldw(); + + switch(tms57002.control) + { + case 0xfc: + res = tms57002.tmp >> (8*tms57002.bytepos); + tms57002.bytepos--; + + if(tms57002.bytepos < 0) tms57002.bytepos = 3; + return res; + } + + return 0; +} + + +READ16_HANDLER( tms57002_data_word_r ) +{ + return(tms57002_data_r(0)); +} + +READ16_HANDLER( tms57002_status_word_r ) +{ + return(tms57002_status_r(0)); +} + +WRITE16_HANDLER( tms57002_control_word_w ) +{ + tms57002_control_w(0, data); +} + +WRITE16_HANDLER( tms57002_data_word_w ) +{ + tms57002_data_w(0, data); +} + + + +/***************************************************************************/ +/* */ +/* 2nd-Tier GX/MW Graphics Functions */ +/* */ +/***************************************************************************/ + +#if GX_DEBUG + #define GX_ZBUFW 512 + #define GX_ZBUFH 384 + #define GX_ZPAGESIZE 0x300000 + #define GX_ZBUFSIZE 0x600000 +#else + #define GX_ZBUFW 384 + #define GX_ZBUFH 224 + #define GX_ZPAGESIZE 0x150000 + #define GX_ZBUFSIZE 0x2a0000 +#endif + +static UINT8 *gx_objzbuf, *gx_shdzbuf; + + +// Localized K053936/ROZ+ +#define K053936_MAX_CHIPS 2 + +static rectangle K053936_cliprect[K053936_MAX_CHIPS] = {{0,0,0,0},{0,0,0,0}}; +static int K053936_offset[K053936_MAX_CHIPS][2] = {{0,0},{0,0}}; +static int K053936_clip_enabled[K053936_MAX_CHIPS] = {0,0}; + + +void K053936GP_set_offset(int chip, int xoffs, int yoffs) { K053936_offset[chip][0] = xoffs; K053936_offset[chip][1] = yoffs; } + +void K053936GP_clip_enable(int chip, int status) { K053936_clip_enabled[chip] = status; } + +void K053936GP_set_cliprect(int chip, int minx, int maxx, int miny, int maxy) +{ + rectangle *cliprect = &K053936_cliprect[chip]; + cliprect->min_x = minx; + cliprect->max_x = maxx; + cliprect->min_y = miny; + cliprect->max_y = maxy; +} + +INLINE void K053936GP_copyroz32clip( mame_bitmap *dst_bitmap, mame_bitmap *src_bitmap, + const rectangle *dst_cliprect, const rectangle *src_cliprect, + UINT32 _startx,UINT32 _starty,int _incxx,int _incxy,int _incyx,int _incyy, + int tilebpp, int blend, int clip ) +{ + static const int colormask[8]={1,3,7,0xf,0x1f,0x3f,0x7f,0xff}; + + int cy, cx; + int ecx; + int src_pitch, incxy, incxx; + int src_minx, src_maxx, src_miny, src_maxy, cmask; + UINT16 *src_base; + const pen_t *pal_base; + UINT32 *dst_ptr; + + int tx, dst_pitch; + UINT32 *dst_base; + int starty, incyy, startx, incyx, ty, sx, sy; + + incxy = _incxy; incxx = _incxx; incyy = _incyy; incyx = _incyx; + starty = _starty; startx = _startx; + + if (src_cliprect && clip) // set source clip range to some extreme values when disabled + { + src_minx = src_cliprect->min_x; + src_maxx = src_cliprect->max_x; + src_miny = src_cliprect->min_y; + src_maxy = src_cliprect->max_y; + } + else { src_minx = src_miny = -0x10000; src_maxx = src_maxy = 0x10000; } + + if (dst_cliprect) // set target clip range + { + sx = dst_cliprect->min_x; + tx = dst_cliprect->max_x - sx + 1; + sy = dst_cliprect->min_y; + ty = dst_cliprect->max_y - sy + 1; + + startx += sx * incxx + sy * incyx; + starty += sx * incxy + sy * incyy; + } + else { sx = sy = 0; tx = dst_bitmap->width; ty = dst_bitmap->height; } + + // adjust entry points and other loop constants + dst_pitch = dst_bitmap->rowpixels; + dst_base = (UINT32*)dst_bitmap->base + sy * dst_pitch + sx + tx; + ecx = tx = -tx; + + tilebpp = (tilebpp-1) & 7; + pal_base = Machine->remapped_colortable; + cmask = colormask[tilebpp]; + + src_pitch = src_bitmap->rowpixels; + src_base = src_bitmap->base; + + dst_ptr = dst_base; + cy = starty; + cx = startx; + + if (blend > 0) + { + dst_base += dst_pitch; // draw blended + starty += incyy; + startx += incyx; + + do { + do { + int srcx = (cx >> 16) & 0x1fff; + int srcy = (cy >> 16) & 0x1fff; + int pixel; + + cx += incxx; + cy += incxy; + if (srcx < src_minx || srcx > src_maxx || srcy < src_miny || srcy > src_maxy) + continue; + + pixel = src_base[srcy * src_pitch + srcx]; + if (!(pixel & cmask)) + continue; + + dst_ptr[ecx] = alpha_blend32(pal_base[pixel], dst_ptr[ecx]); + } + while (++ecx); + + ecx = tx; + dst_ptr = dst_base; dst_base += dst_pitch; + cy = starty; starty += incyy; + cx = startx; startx += incyx; + } while (--ty); + } + else // draw solid + { + if (blend == 0) + { + dst_base += dst_pitch; + starty += incyy; + startx += incyx; + } + else + { + if ((sy & 1) ^ (blend & 1)) + { + if (ty <= 1) return; + + dst_ptr += dst_pitch; + cy += incyy; + cx += incyx; + } + + if (ty > 1) + { + ty >>= 1; + dst_pitch <<= 1; + incyy <<= 1; + incyx <<= 1; + + dst_base = dst_ptr + dst_pitch; + starty = cy + incyy; + startx = cx + incyx; + } + } + + do { + do { + int srcx = (cx >> 16) & 0x1fff; + int srcy = (cy >> 16) & 0x1fff; + int pixel; + + cx += incxx; + cy += incxy; + if (srcx < src_minx || srcx > src_maxx || srcy < src_miny || srcy > src_maxy) + continue; + + pixel = src_base[srcy * src_pitch + srcx]; + if (!(pixel & cmask)) + continue; + + dst_ptr[ecx] = pal_base[pixel]; + } + while (++ecx); + + ecx = tx; + dst_ptr = dst_base; dst_base += dst_pitch; + cy = starty; starty += incyy; + cx = startx; startx += incyx; + } while (--ty); + } +} + +// adpoted from generic K053936_zoom_draw() +static void K053936GP_zoom_draw(int chip, UINT16 *ctrl, UINT16 *linectrl, + mame_bitmap *bitmap, const rectangle *cliprect, tilemap *tmap, + int tilebpp, int blend) +{ + mame_bitmap *src_bitmap; + rectangle *src_cliprect; + UINT16 *lineaddr; + + rectangle my_clip; + UINT32 startx, starty; + int incxx, incxy, incyx, incyy, y, maxy, clip; + + src_bitmap = tilemap_get_pixmap(tmap); + src_cliprect = &K053936_cliprect[chip]; + clip = K053936_clip_enabled[chip]; + + if (ctrl[0x07] & 0x0040) /* "super" mode */ + { + my_clip.min_x = cliprect->min_x; + my_clip.max_x = cliprect->max_x; + y = cliprect->min_y; + maxy = cliprect->max_y; + + while (y <= maxy) + { + lineaddr = linectrl + ( ((y - K053936_offset[chip][1]) & 0x1ff) << 2); + my_clip.min_y = my_clip.max_y = y; + + startx = (INT16)(lineaddr[0] + ctrl[0x00]) << 8; + starty = (INT16)(lineaddr[1] + ctrl[0x01]) << 8; + incxx = (INT16)(lineaddr[2]); + incxy = (INT16)(lineaddr[3]); + + if (ctrl[0x06] & 0x8000) incxx <<= 8; + if (ctrl[0x06] & 0x0080) incxy <<= 8; + + startx -= K053936_offset[chip][0] * incxx; + starty -= K053936_offset[chip][0] * incxy; + + K053936GP_copyroz32clip(bitmap, src_bitmap, &my_clip, src_cliprect, + startx<<5, starty<<5, incxx<<5, incxy<<5, 0, 0, + tilebpp, blend, clip); + y++; + } + } + else /* "simple" mode */ + { + startx = (INT16)(ctrl[0x00]) << 8; + starty = (INT16)(ctrl[0x01]) << 8; + incyx = (INT16)(ctrl[0x02]); + incyy = (INT16)(ctrl[0x03]); + incxx = (INT16)(ctrl[0x04]); + incxy = (INT16)(ctrl[0x05]); + + if (ctrl[0x06] & 0x4000) { incyx <<= 8; incyy <<= 8; } + if (ctrl[0x06] & 0x0040) { incxx <<= 8; incxy <<= 8; } + + startx -= K053936_offset[chip][1] * incyx; + starty -= K053936_offset[chip][1] * incyy; + + startx -= K053936_offset[chip][0] * incxx; + starty -= K053936_offset[chip][0] * incxy; + + K053936GP_copyroz32clip(bitmap, src_bitmap, cliprect, src_cliprect, + startx<<5, starty<<5, incxx<<5, incxy<<5, incyx<<5, incyy<<5, + tilebpp, blend, clip); + } +} + +void K053936GP_0_zoom_draw(mame_bitmap *bitmap, const rectangle *cliprect, + tilemap *tmap, int tilebpp, int blend) +{ + K053936GP_zoom_draw(0,K053936_0_ctrl,K053936_0_linectrl,bitmap,cliprect,tmap,tilebpp,blend); +} + +void K053936GP_1_zoom_draw(mame_bitmap *bitmap, const rectangle *cliprect, + tilemap *tmap, int tilebpp, int blend) +{ + K053936GP_zoom_draw(1,K053936_1_ctrl,K053936_1_linectrl,bitmap,cliprect,tmap,tilebpp,blend); +} + + + +/* + 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) +*/ + +INLINE void zdrawgfxzoom32GP( mame_bitmap *bitmap, const gfx_element *gfx, const rectangle *cliprect, + UINT32 code, UINT32 color, int flipx, int flipy, int sx, int sy, + int scalex, int scaley, int alpha, int drawmode, int zcode, int pri) +{ +#define FP 19 +#define FPONE (1<<FP) +#define FPHALF (1<<(FP-1)) +#define FPENT 0 + + // inner loop + UINT8 *src_ptr; + int src_x; + int eax, ecx; + int src_fx, src_fdx; + int shdpen; + UINT8 z8, db0, p8, db1; + UINT8 *ozbuf_ptr; + UINT8 *szbuf_ptr; + const pen_t *pal_base; + const pen_t *shd_base; + UINT32 *dst_ptr; + + // outter loop + int src_fby, src_fdy, src_fbx; + UINT8 *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 = gfx->color_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 = gfx->gfxdata + (code % gfx->total_elements) * gfx->char_modulo; + + pal_base = Machine->remapped_colortable + gfx->color_base + (color % gfx->total_colors) * granularity; + shd_base = Machine->shadow_table; + + dst_ptr = bitmap->base; + 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; + if ((nozoom = (scalex == 0x10000 && scaley == 0x10000))) + { + 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; + db0 = z8 = (UINT8)zcode; + db1 = p8 = (UINT8)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_blend32(pal_base[eax], dst_ptr[ecx]); + } + 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_blend32(pal_base[eax], dst_ptr[ecx]); + } + 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; + eax = dst_ptr[ecx]; + szbuf_ptr[ecx*2] = z8; + szbuf_ptr[ecx*2+1] = p8; + eax = (eax>>9&0x7c00) | (eax>>6&0x03e0) | (eax>>3&0x001f); + dst_ptr[ecx] = shd_base[eax]; + } + 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_blend32(pal_base[eax], dst_ptr[ecx]); + } + 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_blend32(pal_base[eax], dst_ptr[ecx]); + } + 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; + eax = dst_ptr[ecx]; + szbuf_ptr[ecx*2] = z8; + szbuf_ptr[ecx*2+1] = p8; + eax = (eax>>9&0x7c00) | (eax>>6&0x03e0) | (eax>>3&0x001f); + dst_ptr[ecx] = shd_base[eax]; + } + 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 +} + + + +/***************************************************************************/ +/* */ +/* 1st-Tier GX/MW Variables and Functions */ +/* */ +/***************************************************************************/ + +// global system ports access +UINT8 konamigx_wrport1_0, konamigx_wrport1_1; +UINT16 konamigx_wrport2; + +// frequently used registers +static int K053246_objset1; +static int K053247_vrcbk[4]; +static int K053247_coreg, K053247_coregshift, K053247_opset; +static int opri, oinprion; +static int vcblk[6], ocblk; +static int vinmix, vmixon, osinmix, osmixon; + + +static void konamigx_precache_registers(void) +{ + // (see sprite color coding scheme on p.46 & 47) + static int coregmasks[5] = {0xf,0xe,0xc,0x8,0x0}; + static int coregshifts[5]= {4,5,6,7,8}; + int i; + + K053246_objset1 = K053246_read_register(5); + + i = K053247_read_register(0x8/2); + K053247_vrcbk[0] = (i & 0x000f) << 14; + K053247_vrcbk[1] = (i & 0x0f00) << 6; + i = K053247_read_register(0xa/2); + K053247_vrcbk[2] = (i & 0x000f) << 14; + K053247_vrcbk[3] = (i & 0x0f00) << 6; + + // COREG == OBJSET2+1C == bit8-11 of OPSET ??? (see p.50 last table, needs p.49 to confirm) + K053247_opset = K053247_read_register(0xc/2); + + i = K053247_opset & 7; if (i > 4) i = 4; + + K053247_coreg = K053247_read_register(0xc/2)>>8 & 0xf; + K053247_coreg =(K053247_coreg & coregmasks[i]) << 12; + + K053247_coregshift = coregshifts[i]; + + opri = K055555_read_register(K55_PRIINP_8); + oinprion = K055555_read_register(K55_OINPRI_ON); + vcblk[0] = K055555_read_register(K55_PALBASE_A); + vcblk[1] = K055555_read_register(K55_PALBASE_B); + vcblk[2] = K055555_read_register(K55_PALBASE_C); + vcblk[3] = K055555_read_register(K55_PALBASE_D); + vcblk[4] = K055555_read_register(K55_PALBASE_SUB1); + vcblk[5] = K055555_read_register(K55_PALBASE_SUB2); + ocblk = K055555_read_register(K55_PALBASE_OBJ); + vinmix = K055555_read_register(K55_BLEND_ENABLES); + vmixon = K055555_read_register(K55_VINMIX_ON); + osinmix = K055555_read_register(K55_OSBLEND_ENABLES); + osmixon = K055555_read_register(K55_OSBLEND_ON); +} + +INLINE int K053247GX_combine_c18(int attrib) // (see p.46) +{ + int c18; + + c18 = (attrib & 0xff)<<K053247_coregshift | K053247_coreg; + + if (konamigx_wrport2 & 4) c18 &= 0x3fff; else + if (!(konamigx_wrport2 & 8)) c18 = (c18 & 0x3fff) | (attrib<<6 & 0xc000); + + return(c18); +} + +INLINE int K055555GX_decode_objcolor(int c18) // (see p.59 7.2.2) +{ + int ocb, opon; + + opon = oinprion<<8 | 0xff; + ocb = (ocblk & 7) << 10; + c18 &= opon; + ocb &=~opon; + + return((ocb | c18) >> K053247_coregshift); +} + +INLINE int K055555GX_decode_inpri(int c18) // (see p.59 7.2.2) +{ + int op = opri; + + c18 >>= 8; + op &= oinprion; + c18 &=~oinprion; + + return(c18 | op); +} + +void konamigx_type2_sprite_callback(int *code, int *color, int *priority) +{ + int num = *code; + int c18 = *color; + + *code = K053247_vrcbk[num>>14] | (num & 0x3fff); + c18 = K053247GX_combine_c18(c18); + *color = K055555GX_decode_objcolor(c18); + *priority = K055555GX_decode_inpri(c18); +} + +void konamigx_dragoonj_sprite_callback(int *code, int *color, int *priority) +{ + int num, op, pri, c18; + + num = *code; + *code = K053247_vrcbk[num>>14] | (num & 0x3fff); + + c18 = pri = *color; + op = opri; + pri = (pri & 0x200) ? 4 : pri>>4 & 0xf; + op &= oinprion; + pri &=~oinprion; + *priority = pri | op; + + c18 = K053247GX_combine_c18(c18); + *color = K055555GX_decode_objcolor(c18); +} + +void konamigx_salmndr2_sprite_callback(int *code, int *color, int *priority) +{ + int num, op, pri, c18; + + num = *code; + *code = K053247_vrcbk[num>>14] | (num & 0x3fff); + + c18 = pri = *color; + op = opri; + pri = pri>>4 & 0x3f; + op &= oinprion; + pri &=~oinprion; + *priority = pri | op; + + c18 = K053247GX_combine_c18(c18); + *color = K055555GX_decode_objcolor(c18); +} + +void konamigx_le2_sprite_callback(int *code, int *color, int *priority) +{ + int num, op, pri; + + num = *code; + *code = K053247_vrcbk[num>>14] | (num & 0x3fff); + + pri = *color; + *color &= 0x1f; + + op = opri; + pri &= 0xf0; + op &= oinprion; + pri &=~oinprion; + *priority = pri | op; +} + +int K055555GX_decode_vmixcolor(int layer, int *color) // (see p.62 7.2.6 and p.27 3.3) +{ + int vcb, shift, pal, vmx, von, pl45, emx; + + vcb = vcblk[layer]<<6; + shift = layer<<1; + pal = *color; + vmx = vinmix>>shift & 3; + von = vmixon>>shift & 3; + emx = pl45 = pal>>4 & 3; + pal &= 0xf; + pl45 &= von; + vmx &= von; + pl45 <<= 4; + emx &= ~von; + pal |= pl45; + emx |= vmx; + pal |= vcb; + + if (von == 3) emx = -1; // invalidate external mix code if all bits are from internal + *color = pal; + + return(emx); +} + +int K055555GX_decode_osmixcolor(int layer, int *color) // (see p.63, p.49-50 and p.27 3.3) +{ + int scb, shift, pal, osmx, oson, pl45, emx; + + shift = layer<<1; + pal = *color; + osmx = osinmix>>shift & 3; + oson = osmixon>>shift & 3; + + if (layer) + { + // layer 1-3 are external tile layers + scb = vcblk[layer+3]<<6; + emx = pl45 = pal>>4 & 3; + pal &= 0xf; + pl45 &= oson; + osmx &= oson; + pl45 <<= 4; + emx &= ~oson; + pal |= pl45; + emx |= osmx; + pal |= scb; + + if (oson == 3) emx = -1; // invalidate external mix code if all bits are from internal + *color = pal; + } + else + { + // layer 0 is the sprite layer with different attributes decode; detail on p.49 (missing) + emx = 0; // K053247_read_register(??)>>? & 3; + osmx &= oson; + emx &=~oson; + emx |= osmx; + } + + return(emx); +} + +static void gx_wipezbuf(int noshadow) +{ + UINT8 *zptr; + int w, h; + register int ecx; + + w = Machine->screen[0].visarea.max_x - Machine->screen[0].visarea.min_x + 1; + h = Machine->screen[0].visarea.max_y - Machine->screen[0].visarea.min_y + 1; + + zptr = gx_objzbuf; + ecx = h; + do { memset(zptr, -1, w); zptr += GX_ZBUFW; } while (--ecx); + + if (!noshadow) + { + zptr = gx_shdzbuf; + w <<= 1; + ecx = h; + do { memset(zptr, -1, w); zptr += (GX_ZBUFW<<1); } while (--ecx); + } +} + +/* + * 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. + */ +#define GX_MAX_SPRITES 512 +#define GX_MAX_LAYERS 6 +#define GX_MAX_OBJECTS (GX_MAX_SPRITES + GX_MAX_LAYERS) + +static struct GX_OBJ { int order, offs, code, color; } *gx_objpool; +static UINT16 *gx_spriteram; +static int gx_objdma, gx_primode; + +// mirrored K053247 and K054338 settings +static UINT16 *K053247_ram; +static gfx_element *K053247_gfx; +static void (*K053247_callback)(int *code,int *color,int *priority); +static int K053247_dx, K053247_dy; + +static int *K054338_shdRGB; + + +void K053247GP_set_SpriteOffset(int offsx, int offsy) +{ + K053247_dx = offsx; + K053247_dy = offsy; +} + +void konamigx_mixer_init(int objdma) +{ + gx_objdma = 0; + gx_primode = 0; + + gx_objzbuf = (UINT8 *)priority_bitmap->base; + gx_shdzbuf = auto_malloc(GX_ZBUFSIZE); + gx_objpool = auto_malloc(sizeof(struct GX_OBJ) * (GX_MAX_OBJECTS)); + + K053247_export_config(&K053247_ram, &K053247_gfx, &K053247_callback, &K053247_dx, &K053247_dy); + K054338_export_config(&K054338_shdRGB); + + if (objdma) + { + gx_spriteram = auto_malloc(0x1000); + gx_objdma = 1; + } + else + gx_spriteram = K053247_ram; + + palette_set_shadow_dRGB32(Machine, 3,-80,-80,-80, 0); + K054338_invert_alpha(1); +} + +void konamigx_mixer_primode(int mode) +{ + gx_primode = mode; +} + +void konamigx_objdma(void) +{ + if (gx_objdma && gx_spriteram && K053247_ram) memcpy(gx_spriteram, K053247_ram, 0x1000); +} + +void konamigx_mixer(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, + tilemap *sub1, int sub1flags, + tilemap *sub2, int sub2flags, + int mixerflags) +{ + static int xoffset[8] = { 0, 1, 4, 5, 16, 17, 20, 21 }; + static int yoffset[8] = { 0, 2, 8, 10, 32, 34, 40, 42 }; + static int parity = 0; + + int objbuf[GX_MAX_OBJECTS]; + int shadowon[3], shdpri[3], layerid[6], layerpri[6]; + + struct GX_OBJ *objpool, *objptr; + int wrapsize, xwraplim, ywraplim, cltc_shdpri, prflp, disp; + int xa,ya,ox,oy,zw,zh,flipx,flipy,mirrorx,mirrory,zoomx,zoomy,scalex,scaley,nozoom; + int screenwidth, flipscreenx, flipscreeny, offx, offy; + int nobj, i, j, k, l, temp, temp1, temp2, temp3, temp4, count; + int order, offs, code, color, zcode, pri = 0, spri, spri_min, shdprisel, shadow, alpha, drawmode; + + + // abort if object database failed to initialize + if (!(objpool = gx_objpool)) return; + + // clear screen with backcolor and update flicker pulse + K054338_fill_backcolor(machine, bitmap, konamigx_wrport1_0 & 0x20); + parity ^= 1; + + // abort if video has been disabled + if (!(disp = K055555_read_register(K55_INPUT_ENABLES))) return; + cltc_shdpri = K054338_read_register(K338_REG_CONTROL); + if (!(cltc_shdpri & K338_CTL_KILL)) return; + + // demote shadows by one layer when this bit is set??? (see p.73 8.6) + cltc_shdpri &= K338_CTL_SHDPRI; + + // wipe z-buffer + if (mixerflags & GXMIX_NOZBUF) + mixerflags |= GXMIX_NOSHADOW; + else + gx_wipezbuf(mixerflags & GXMIX_NOSHADOW); + + // cache global parameters + konamigx_precache_registers(); + + // init OBJSET1 parameters (see p.47 6.2) + flipscreenx = K053246_objset1 & 1; + flipscreeny = K053246_objset1 & 2; + + // get "display window" offsets + offx = (K053246_read_register(0)<<8 | K053246_read_register(1)) & 0x3ff; + offy = (K053246_read_register(2)<<8 | K053246_read_register(3)) & 0x3ff; + + // 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; + + if (K053247_opset & 0x40) + { + wrapsize = 512; + xwraplim = 512 - 64; + ywraplim = 512 - 128; + } + else + { + wrapsize = 1024; + xwraplim = 1024 - 384; + ywraplim = 1024 - 512; + } + + // invert layer priority when this flag is set (not used by any GX game?) + prflp = K055555_read_register(K55_CONTROL) & K55_CTL_FLIPPRI; + + layerpri[0] = K055555_read_register(K55_PRIINP_0); + layerpri[1] = K055555_read_register(K55_PRIINP_3); + layerpri[3] = K055555_read_register(K55_PRIINP_7); + layerpri[4] = K055555_read_register(K55_PRIINP_9); + layerpri[5] = K055555_read_register(K55_PRIINP_10); + + if (gx_primode == -1) + { + // Lethal Enforcer hack (requires pixel color comparison) + layerpri[2] = K055555_read_register(K55_PRIINP_3) + 0x20; + shdprisel = 0x3f; + } + else + { + layerpri[2] = K055555_read_register(K55_PRIINP_6); + shdprisel = K055555_read_register(K55_SHD_PRI_SEL); + } + + // SHDPRISEL filters shadows by different priority comparison methods (UNIMPLEMENTED, see detail on p.66) + if (!(shdprisel & 0x03)) shadowon[0] = 0; + if (!(shdprisel & 0x0c)) shadowon[1] = 0; + if (!(shdprisel & 0x30)) shadowon[2] = 0; + + shdpri[0] = K055555_read_register(K55_SHAD1_PRI); + shdpri[1] = K055555_read_register(K55_SHAD2_PRI); + shdpri[2] = K055555_read_register(K55_SHAD3_PRI); + + spri_min = 0; + shadowon[2] = shadowon[1] = shadowon[0] = 0; + + if (!(mixerflags & GXMIX_NOSHADOW)) + { + // only enable shadows beyond a +/-7 RGB threshold + for (j=0,i=0; i<3; j+=3,i++) + { + k = K054338_shdRGB[j ]; if (k < -7 || k > 7) { shadowon[i] = 1; continue; } + k = K054338_shdRGB[j+1]; if (k < -7 || k > 7) { shadowon[i] = 1; continue; } + k = K054338_shdRGB[j+2]; if (k < -7 || k > 7) { shadowon[i] = 1; } + } + + // SHDON specifies layers on which shadows can be projected (see detail on p.65 7.2.8) + temp = K055555_read_register(K55_SHD_ON); + for (i=0; i<4; i++) if (!(temp>>i & 1) && spri_min < layerpri[i]) spri_min = layerpri[i]; // HACK + + // update shadows status + K054338_update_all_shadows(machine); + } + + // pre-sort layers + for (j=0; j<5; j++) + { + temp1 = layerpri[j]; + for (i=j+1; i<6; i++) + { + temp2 = layerpri[i]; + if ((UINT32)temp1 <= (UINT32)temp2) + { + layerpri[i] = temp1; layerpri[j] = temp1 = temp2; + temp2 = layerid[i]; layerid[i] = layerid[j]; layerid[j] = temp2; + } + } + } + + // build object database and create indices + objptr = objpool; + nobj = 0; + + for (i=5; i>=0; i--) + { + code = layerid[i]; + switch (code) + { + /* + Background layers are represented by negative offset values as follow: + + 0+ : normal sprites + -1 : tile layer A - D + -2 : K053936 ROZ+ layer 1 + -3 : K053936 ROZ+ layer 2 + -4 : K053250 LVC layer 1 + -5 : K053250 LVC layer 2 + */ + case 4 : + offs = -128; + if (sub1flags & 0xf) { if (sub1flags & GXSUB_K053250) offs = -4; else if (sub1) offs = -2; } + break; + case 5 : + offs = -128; + if (sub2flags & 0xf) { if (sub2flags & GXSUB_K053250) offs = -5; else if (sub2) offs = -3; } + break; + default: offs = -1; + } + + if (offs != -128) + { + objptr->order = layerpri[i]<<24; + objptr->code = code; + objptr->offs = offs; + objptr++; + + objbuf[nobj] = nobj; + nobj++; + } + } + + i = j = 0xff; + + for (offs=0; offs<0x800; offs+=8) + { + if (!(gx_spriteram[offs] & 0x8000)) continue; + + zcode = gx_spriteram[offs] & 0xff; + + // invert z-order when opset_pri is set (see p.51 OPSET PRI) + if (K053247_opset & 0x10) zcode = 0xff - zcode; + + code = gx_spriteram[offs+1]; + color = k = gx_spriteram[offs+6]; + l = gx_spriteram[offs+7]; + + (*K053247_callback)(&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 + */ + temp4 = temp3 = temp2 = temp1 = spri = shadow = 0; + + 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 + } + else + { + if ((shadow = k>>10 & 3)) // object has shadow? + { + if (shadow != 1 || K053246_objset1 & 0x20) + { + shadow--; + temp1 = 1; // add solid + temp2 = 1; // draw partial solid + if (shadowon[shadow]) + { + temp3 = 1; // add shadow + temp4 = 4; // draw partial shadow + } + } + else + { + // 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 + } + } + else + { + temp1 = 1; // add solid + temp2 = 0; // draw full solid + } + + if (temp1) + { + // tag sprite for alpha blending + if (color>>K055555_MIXSHIFT & 3) temp2 |= 2; + } + + if (temp3) + { + // determine shadow priority + spri = (K053247_opset & 0x20) ? pri : shdpri[shadow]; // (see p.51 OPSET SDSEL) + } + } + + switch (gx_primode & 0xf) + { + // Dadandarn zcode suppression + case 1: + zcode = 0; + break; + + // Daisukiss bad shadow filter + case 4: + if (k & 0x3000 || k == 0x0800) continue; + + // Tokkae shadow masking (INACCURATE) + case 5: + if (spri < spri_min) spri = spri_min; + break; + } + + /* + default sort order: + fedcba9876543210fedcba9876543210 + xxxxxxxx------------------------ (priority) + --------xxxxxxxx---------------- (zcode) + ----------------xxxxxxxx-------- (offset) + ------------------------xxxx---- (shadow mode) + ----------------------------xxxx (shadow code) + */ + if (temp1) + { + // add objects with solid or alpha pens + 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++; + } + + if (temp3 && !(color & K055555_SKIPSHADOW) && !(mixerflags & GXMIX_NOSHADOW)) + { + // add objects with shadows if enabled + 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 (j=0; j<l; j++) + { + temp1 = objbuf[j]; + temp2 = objpool[temp1].order; + for (i=j+1; i<k; i++) + { + temp3 = objbuf[i]; + temp4 = objpool[temp3].order; + if ((UINT32)temp2 <= (UINT32)temp4) { temp2 = temp4; objbuf[i] = temp1; objbuf[j] = temp1 = temp3; } + } + } + + // traverse draw list + screenwidth = Machine->screen[0].width; + + for (count=0; count<nobj; count++) + { + objptr = objpool + objbuf[count]; + order = objptr->order; + offs = objptr->offs; + code = objptr->code; + color = objptr->color; + + if (offs >= 0) + { + if (!(disp & K55_INP_OBJ)) continue; + } + else + { + i = code<<1; + j = mixerflags>>i & 3; + k = 0; + + switch (offs) + { + case -1: + if (disp & (1<<code)) + { + if (j == GXMIX_BLEND_NONE) { temp1 = 0xff; temp2 = temp3 = 0; } else + if (j == GXMIX_BLEND_FORCE) { temp1 = 0x00; temp2 = mixerflags>>(i+16); temp3 = 3; } + else + { + temp1 = vinmix; + temp2 = vinmix>>i & 3; + temp3 = vmixon>>i & 3; + } + + /* blend layer only when: + 1) vinmix != 0xff + 2) its internal mix code is set + 3) all mix code bits are internal(overriden until tile blending has been implemented) + 4) 0 > alpha < 255; + */ + if (temp1!=0xff && temp2 /*&& temp3==3*/) + { + temp4 = K054338_set_alpha_level(temp2); + + if (temp4 <= 0) continue; + if (temp4 < 255) k = TILEMAP_DRAW_ALPHA; + } + + if (mixerflags & 1<<(code+12)) k |= TILE_LINE_DISABLED; + + K056832_tilemap_draw(machine, bitmap, cliprect, code, k, 0); + } + continue; + case -2: + case -4: + if (disp & K55_INP_SUB1) + { + if (j == GXMIX_BLEND_NONE) { temp1 = 0xff; temp2 = temp3 = 0; } else + if (j == GXMIX_BLEND_FORCE) { temp1 = 0x00; temp2 = mixerflags>>24; temp3 = 3; } + else + { + temp1 = osinmix; + temp2 = osinmix>>2 & 3; + temp3 = osmixon>>2 & 3; + } + + if (temp1!=0xff && temp2 /*&& temp3==3*/) + { + temp4 = K054338_set_alpha_level(temp2); + + if (temp4 <= 0) continue; + if (temp4 < 255) k = (j == GXMIX_BLEND_FAST) ? ~parity : 1; + } + + l = sub1flags & 0xf; + + if (offs == -2) + K053936GP_0_zoom_draw(bitmap, cliprect, sub1, l, k); + else + K053250_draw(machine, bitmap, cliprect, 0, vcblk[4]<<l, 0, 0); + } + continue; + case -3: + case -5: + if (disp & K55_INP_SUB2) + { + if (j == GXMIX_BLEND_NONE) { temp1 = 0xff; temp2 = temp3 = 0; } else + if (j == GXMIX_BLEND_FORCE) { temp1 = 0x00; temp2 = mixerflags>>26; temp3 = 3; } + else + { + temp1 = osinmix; + temp2 = osinmix>>4 & 3; + temp3 = osmixon>>4 & 3; + } + + if (temp1!=0xff && temp2 /*&& temp3==3*/) + { + temp4 = K054338_set_alpha_level(temp2); + + if (temp4 <= 0) continue; + if (temp4 < 255) k = (j == GXMIX_BLEND_FAST) ? ~parity : 1; + } + + l = sub2flags & 0xf; + + if (offs == -3) + K053936GP_1_zoom_draw(bitmap, cliprect, sub2, l, k); + else + K053250_draw(machine, bitmap, cliprect, 1, vcblk[5]<<l, 0, 0); + } + continue; + } + continue; + } + + drawmode = order>>4 & 0xf; + + alpha = 255; + if (drawmode & 2) + { + if ((alpha = color>>K055555_MIXSHIFT & 3)) alpha = K054338_set_alpha_level(alpha); + if (alpha <= 0) continue; + } + color &= K055555_COLORMASK; + + if (drawmode >= 4) palette_set_shadow_mode(Machine, order & 0x0f); + + if (!(mixerflags & GXMIX_NOZBUF)) + { + zcode = order>>16 & 0xff; + pri = order>>24 & 0xff; + } + else + zcode = -1; // negative zcode values turn off z-buffering + + xa = ya = 0; + if (code & 0x01) xa += 1; + if (code & 0x02) ya += 1; + if (code & 0x04) xa += 2; + if (code & 0x08) ya += 2; + if (code & 0x10) xa += 4; + if (code & 0x20) ya += 4; + code &= ~0x3f; + + temp4 = gx_spriteram[offs]; + + // mask off the upper 6 bits of coordinate and zoom registers + oy = gx_spriteram[offs+2] & 0x3ff; + ox = gx_spriteram[offs+3] & 0x3ff; + + scaley = zoomy = gx_spriteram[offs+4] & 0x3ff; + if (zoomy) zoomy = (0x400000+(zoomy>>1)) / zoomy; + else zoomy = 0x800000; + if (!(temp4 & 0x4000)) + { + scalex = zoomx = gx_spriteram[offs+5] & 0x3ff; + if (zoomx) zoomx = (0x400000+(zoomx>>1)) / zoomx; + else zoomx = 0x800000; + } + else { zoomx = zoomy; scalex = scaley; } + + nozoom = (scalex == 0x40 && scaley == 0x40); + + flipx = temp4 & 0x1000; + flipy = temp4 & 0x2000; + + temp = gx_spriteram[offs+6]; + mirrorx = temp & 0x4000; + if (mirrorx) flipx = 0; // only applies to x mirror, proven + mirrory = temp & 0x8000; + + // for Escape Kids (GX975) + if ( K053246_objset1 & 8 ) // Check only "Bit #3 is '1'?" + { + zoomx = zoomx>>1; // Fix sprite width to HALF size + ox = (ox>>1) + 1; // Fix sprite draw position + + if (flipscreenx) ox += screenwidth; + } + + if (flipscreenx) { ox = -ox; if (!mirrorx) flipx = !flipx; } + if (flipscreeny) { oy = -oy; if (!mirrory) flipy = !flipy; } + + // apply wrapping and global offsets + temp = wrapsize-1; + ox = ( ox - offx) & temp; + oy = (-oy - offy) & temp; + if (ox >= xwraplim) ox -= wrapsize; + if (oy >= ywraplim) oy -= wrapsize; + ox += K053247_dx; + oy += K053247_dy; + + + temp = temp4>>8 & 0x0f; + k = 1 << (temp & 3); + l = 1 << (temp>>2 & 3); + + ox -= (zoomx * k) >> 13; + oy -= (zoomy * l) >> 13; + + // substitutes: i=x, j=y, k=w, l=h, temp=code, temp1=fx, temp2=fy, temp3=sx, temp4=sy; + for (j=0; j<l; j++) + { + temp4 = oy + ((zoomy * j + (1<<11)) >> 12); + zh = (oy + ((zoomy * (j+1) + (1<<11)) >> 12)) - temp4; + + for (i=0; i<k; i++) + { + temp3 = ox + ((zoomx * i + (1<<11)) >> 12); + zw = (ox + ((zoomx * (i+1) + (1<<11)) >> 12)) - temp3; + temp = code; + + if (mirrorx) + { + if ((!flipx)^((i<<1)<k)) + { + /* mirror left/right */ + temp += xoffset[(k-1-i+xa)&7]; + temp1 = 1; + } + else + { + temp += xoffset[(i+xa)&7]; + temp1 = 0; + } + } + else + { + if (flipx) temp += xoffset[(k-1-i+xa)&7]; + else temp += xoffset[(i+xa)&7]; + temp1 = flipx; + } + + if (mirrory) + { + if ((!flipy)^((j<<1)>=l)) + { + /* mirror top/bottom */ + temp += yoffset[(l-1-j+ya)&7]; + temp2 = 1; + } + else + { + temp += yoffset[(j+ya)&7]; + temp2 = 0; + } + } + else + { + if (flipy) temp += yoffset[(l-1-j+ya)&7]; + else temp += yoffset[(j+ya)&7]; + temp2 = flipy; + } + + if (nozoom) { scaley = scalex = 0x10000; } else { scalex = zw << 12; scaley = zh << 12; }; + + zdrawgfxzoom32GP(bitmap, K053247_gfx, cliprect, + temp, + color, + temp1,temp2, + temp3,temp4, + scalex, scaley, alpha, drawmode, zcode, pri); + } + } + } +} + + + +/***************************************************************************/ +/* */ +/* GX/MW Protections */ +/* */ +/***************************************************************************/ + +// K055550/K053990 protection chips, perform simple memset() and other game logic operations +static UINT16 prot_data[0x20]; + +READ16_HANDLER( K055550_word_r ) +{ + return(prot_data[offset]); +} + +WRITE16_HANDLER( K055550_word_w ) +{ + UINT32 adr, bsize, count, i, lim; + int src, tgt, srcend, tgtend, skip, cx1, sx1, wx1, cy1, sy1, wy1, cz1, sz1, wz1, c2, s2, w2; + int dx, dy, angle; + + COMBINE_DATA(prot_data+offset); + + if (offset == 0 && ACCESSING_MSB) + { + data >>= 8; + switch (data) + { + case 0x97: // memset() (Dadandarn at 0x639dc) + case 0x9f: // memset() (Violent Storm at 0x989c) + adr = (prot_data[7] << 16) | prot_data[8]; + bsize = (prot_data[10] << 16) | prot_data[11]; + count = (prot_data[0] & 0xff) + 1; + + lim = adr+bsize*count; + for(i=adr; i<lim; i+=2) + program_write_word(i, prot_data[0x1a/2]); + break; + + // WARNING: The following cases are speculation based with questionable accuracy!(AAT) + + case 0x87: // unknown memory write (Violent Storm at 0x00b6ea) + // Violent Storm writes the following data to the 55550 in mode 0x87. + // All values are hardcoded and the write happens each frame during + // gameplay. It refers to a 32x8-word list at 0x210e00 and seems to + // be tied with another 13x128-byte table at 0x205080. + // Both tables appear "check-only" and have little effect on gameplay. + count =(prot_data[0] & 0xff) + 1; // unknown ( byte 0x00) + i = prot_data[1]; // unknown ( byte 0x1f) + adr = prot_data[7]<<16 | prot_data[8]; // address (dword 0x210e00) + lim = prot_data[9]; // unknown ( word 0x0010) + src = prot_data[10]<<16 | prot_data[11]; // unknown (dword zero) + tgt = prot_data[12]<<16 | prot_data[13]; // unknown (dword zero) + break; + + case 0xa0: // update collision detection table (Violent Storm at 0x018b42) + count = prot_data[0] & 0xff; // number of objects - 1 + skip = prot_data[1]>>(8-1); // words to skip in each entry to reach the "hit list" + adr = prot_data[2]<<16 | prot_data[3]; // where the table is located + bsize = prot_data[5]<<16 | prot_data[6]; // object entry size in bytes + + srcend = adr + bsize * count; + tgtend = srcend + bsize; + + // let's hope GCC will inline the mem24bew calls + for (src=adr; src<srcend; src+=bsize) + { + cx1 = (short)program_read_word(src); + sx1 = (short)program_read_word(src + 2); + wx1 = (short)program_read_word(src + 4); + + cy1 = (short)program_read_word(src + 6); + sy1 = (short)program_read_word(src + 8); + wy1 = (short)program_read_word(src +10); + + cz1 = (short)program_read_word(src +12); + sz1 = (short)program_read_word(src +14); + wz1 = (short)program_read_word(src +16); + + count = i = src + skip; + tgt = src + bsize; + + for (; count<tgt; count++) program_write_byte(count, 0); + + for (; tgt<tgtend; i++, tgt+=bsize) + { + c2 = (short)program_read_word(tgt); + s2 = (short)program_read_word(tgt + 2); + w2 = (short)program_read_word(tgt + 4); + if (abs((cx1+sx1)-(c2+s2))>=wx1+w2) continue; // X rejection + + c2 = (short)program_read_word(tgt + 6); + s2 = (short)program_read_word(tgt + 8); + w2 = (short)program_read_word(tgt +10); + if (abs((cy1+sy1)-(c2+s2))>=wy1+w2) continue; // Y rejection + + c2 = (short)program_read_word(tgt +12); + s2 = (short)program_read_word(tgt +14); + w2 = (short)program_read_word(tgt +16); + if (abs((cz1+sz1)-(c2+s2))>=wz1+w2) continue; // Z rejection + + program_write_byte(i, 0x80); // collision confirmed + } + } + break; + + case 0xc0: // calculate object "homes-in" vector (Violent Storm at 0x03da9e) + dx = (short)prot_data[0xc]; + dy = (short)prot_data[0xd]; + + // it's not necessary to use lookup tables because Violent Storm + // only calls the service once per enemy per frame. + if (dx) + { + if (dy) + { + angle = (atan((double)dy / dx) * 128.0) / M_PI; + if (dx < 0) angle += 128; + i = (angle - 0x40) & 0xff; + } + else + i = (dx > 0) ? 0xc0 : 0x40; + } + else + if (dy > 0) i = 0; + else + if (dy < 0) i = 0x80; + else + i = mame_rand(Machine) & 0xff; // vector direction indeterminate + + prot_data[0x10] = i; + break; + + default: +// logerror("%06x: unknown K055550 command %02x\n", activecpu_get_pc(), data); + break; + } + } +} + +WRITE16_HANDLER( K053990_martchmp_word_w ) +{ + int src_addr, src_count, src_skip; + int dst_addr, dst_count, dst_skip; + int mod_addr, mod_count, mod_skip, mod_offs; + int mode, i, element_size = 1; + UINT16 mod_val, mod_data; + + COMBINE_DATA(prot_data+offset); + + if (offset == 0x0c && ACCESSING_MSB) + { + mode = (prot_data[0x0d]<<8 & 0xff00) | (prot_data[0x0f] & 0xff); + + switch (mode) + { + case 0xffff: // word copy + element_size = 2; + case 0xff00: // byte copy + src_addr = prot_data[0x0]; + src_addr |= prot_data[0x1]<<16 & 0xff0000; + dst_addr = prot_data[0x2]; + dst_addr |= prot_data[0x3]<<16 & 0xff0000; + src_count = prot_data[0x8]>>8; + dst_count = prot_data[0x9]>>8; + src_skip = prot_data[0xa] & 0xff; + dst_skip = prot_data[0xb] & 0xff; + + if ((prot_data[0x8] & 0xff) == 2) src_count <<= 1; + src_skip += element_size; + dst_skip += element_size; + + if (element_size == 1) + for (i=src_count; i; i--) + { + program_write_byte(dst_addr, program_read_byte(src_addr)); + src_addr += src_skip; + dst_addr += dst_skip; + } + else for (i=src_count; i; i--) + { + program_write_word(dst_addr, program_read_word(src_addr)); + src_addr += src_skip; + dst_addr += dst_skip; + } + break; + + case 0x00ff: // sprite list modifier + src_addr = prot_data[0x0]; + src_addr |= prot_data[0x1]<<16 & 0xff0000; + src_skip = prot_data[0x1]>>8; + dst_addr = prot_data[0x2]; + dst_addr |= prot_data[0x3]<<16 & 0xff0000; + dst_skip = prot_data[0x3]>>8; + mod_addr = prot_data[0x4]; + mod_addr |= prot_data[0x5]<<16 & 0xff0000; + mod_skip = prot_data[0x5]>>8; + mod_offs = prot_data[0x8] & 0xff; + mod_offs<<= 1; + mod_count = 0x100; + + src_addr += mod_offs; + dst_addr += mod_offs; + + for (i=mod_count; i; i--) + { + mod_val = program_read_word(mod_addr); + mod_addr += mod_skip; + + mod_data = program_read_word(src_addr); + src_addr += src_skip; + + mod_data += mod_val; + + program_write_word(dst_addr, mod_data); + dst_addr += dst_skip; + } + break; + + default: + break; + } + } +} + +void konamigx_esc_alert(UINT32 *srcbase, int srcoffs, int count, int mode) // (WARNING: assumed big endianess) +{ + +// hand-filled but should be close +static UINT8 ztable[7][8] = +{ + {5,4,3,2,1,7,6,0}, + {4,3,2,1,0,7,6,5}, + {4,3,2,1,0,7,6,5}, + {3,2,1,0,5,7,4,6}, + {6,5,1,4,3,7,0,2}, + {5,4,3,2,1,7,6,0}, + {5,4,3,2,1,7,6,0} +}; + +static UINT8 ptable[7][8] = +{ + {0x00,0x00,0x00,0x10,0x20,0x00,0x00,0x30}, + {0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x20}, + {0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00}, + {0x10,0x10,0x10,0x20,0x00,0x00,0x10,0x00}, + {0x00,0x00,0x20,0x00,0x10,0x00,0x20,0x20}, + {0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x10}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10} +}; + + INT32 data1, data2, i, j, vpos, hpos, voffs, hoffs, vcorr, hcorr, vmask, hmask, magicid; + UINT32 *src, *srcend, *obj, *objend; + UINT16 *dst; + UINT8 *zcode, *pcode; + + if (!count || !srcbase) return; + + if (mode == 0) + { + src = srcbase + srcoffs; + dst = K053247_ram; + data1 = count<<2; + data2 = count<<3; + src += data1; dst += data2; i = -data1; j = -data2; + do + { + data1 = src[i]; + data2 = src[i+1]; + i += 2; + dst[j+1] = data1; + dst[j+3] = data2; + data1 >>= 16; + data2 >>= 16; + dst[j] = data1; + dst[j+2] = data2; + } + while (j += 4); + } + else + { + +#define EXTRACT_ODD \ +if((data1=obj[0])&0x8000) \ +{ \ + i = data1 & 7; \ + data1 &= 0xff00; \ + dst[0] = data1 | zcode[i];\ + data1 = obj[1]; \ + dst[1] = data1>>16; \ + vpos = data1 & 0xffff; \ + data1 = obj[2]; \ + vpos += voffs; \ + dst[4] = data1; \ + vpos &= vmask; \ + hpos = data1>>16; \ + data1 = obj[3]; \ + hpos += hoffs; \ + dst[2] = vpos; \ + dst[3] = hpos; \ + dst[5] = data1>>16; \ + i = pcode[i]; \ + dst[6] = data1| i<<4; \ + dst += 8; \ + if (!(--j)) return; \ +} + +#define EXTRACT_EVEN \ +if((data1=obj[0])&0x80000000)\ +{ \ + dst[1] = data1; \ + data1>>= 16; \ + i = data1 & 7; \ + data1 &= 0xff00; \ + dst[0] = data1 | zcode[i]; \ + data1 = obj[1]; \ + hpos = data1 & 0xffff; \ + vpos = data1>>16; \ + hpos += hoffs; \ + vpos += voffs; \ + data1 = obj[2]; \ + vpos &= vmask; \ + dst[3] = hpos; \ + dst[2] = vpos; \ + dst[5] = data1; \ + dst[4] = data1>>16; \ + data1 = obj[3]>>16; \ + i = pcode[i]; \ + dst[6] = data1 | i<<4; \ + dst += 8; \ + if (!(--j)) return; \ +} + + // These suspecious looking flags might tell the ESC chip what zcode/priority combos to use. + // At the beginning of each sprite chunk there're at least three pointers to the main ROM but + // I can't make out anything meaningful. + magicid = srcbase[0x71f0/4]; + + hmask = vmask = 0x3ff; + if (magicid != 0x11010111) + { + switch (magicid) + { + case 0x10010801: i = 6; break; + case 0x11010010: i = 5; vmask = 0x1ff; break; + case 0x01111018: i = 4; break; + case 0x10010011: i = 3; + if ((srcbase[0x1c75]&0xff)==32) K055555_write_reg(K55_BLEND_ENABLES,36); // (TEMPORARY) + break; + case 0x11010811: i = 2; break; + case 0x10000010: i = 1; break; + default: i = 0; + } + vcorr = srcbase[0x26a0/4] & 0xffff; + hcorr = srcbase[0x26a4/4] >> 16; + hcorr -= 10; + } + else + hcorr = vcorr = i = 0; + + zcode = ztable[i]; + pcode = ptable[i]; + + dst = K053247_ram; + j = 256; + + // decode Vic-Viper + if (srcbase[0x049c/4] & 0xffff0000) + { + hoffs = srcbase[0x0502/4] & 0xffff; + voffs = srcbase[0x0506/4] & 0xffff; + hoffs -= hcorr; + voffs -= vcorr; + obj = &srcbase[0x049e/4]; + EXTRACT_ODD + obj = &srcbase[0x04ae/4]; + EXTRACT_ODD + obj = &srcbase[0x04be/4]; + EXTRACT_ODD + } + + // decode Lord British (the designer must be a Richard Garriot fan too:) + if (srcbase[0x0848/4] & 0x0000ffff) + { + hoffs = srcbase[0x08b0/4]>>16; + voffs = srcbase[0x08b4/4]>>16; + hoffs -= hcorr; + voffs -= vcorr; + obj = &srcbase[0x084c/4]; + EXTRACT_EVEN + obj = &srcbase[0x085c/4]; + EXTRACT_EVEN + obj = &srcbase[0x086c/4]; + EXTRACT_EVEN + } + + // decode common sprites + src = srcbase + srcoffs; + srcend = src + count * 0x30; + do + { + if (!src[0] || !(i = src[7] & 0xf)) continue; // reject retired or zero-element groups + i <<= 2; + hoffs = src[5]>>16; + voffs = src[6]>>16; + hoffs -= hcorr; + voffs -= vcorr; + obj = src + 8; + objend = obj + i; + + do + { + EXTRACT_EVEN + } + while ((obj+=4)<objend); + } + while ((src+=0x30)<srcend); + + // clear residual data + if (j) do { *dst = 0; dst += 8; } while (--j); + } + +#undef EXTRACT_ODD +#undef EXTRACT_EVEN +} |