// license:BSD-3-Clause
// copyright-holders:Bryan McPhail, David Haywood
/*
Deco MXC06 sprite generator:
used by:
madmotor.cpp
dec0.cpp
stadhero.cpp
thedeep.cpp
actfancr.cpp
vaportra.cpp
dec8.cpp
Notes (dec0.cpp)
Sprite data: The unknown bits seem to be unused.
Byte 0:
Bit 0 : Y co-ord hi bit
Bit 1,2 : Sprite width (1x, 2x, 4x, 8x)
Bit 3,4 : Sprite height (1x, 2x, 4x, 8x)
Bit 5 - X flip
Bit 6 - Y flip
Bit 7 - Only display Sprite if set
Byte 1: Y-coords
Byte 2:
Bit 0,1,2,3: Hi bits of sprite number
Bit 4,5,6,7: (Probably unused MSB's of sprite)
Byte 3: Low bits of sprite number
Byte 4:
Bit 0 : X co-ords hi bit
Bit 1,2: ??
Bit 3: Sprite flash (sprite is displayed every other frame)
Bit 4,5,6,7: - Colour
Byte 5: X-coords
*/
#include "emu.h"
#include "decmxc06.h"
#include "screen.h"
DEFINE_DEVICE_TYPE(DECO_MXC06, deco_mxc06_device, "deco_mxc06", "DECO MXC06 Sprite")
deco_mxc06_device::deco_mxc06_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, DECO_MXC06, tag, owner, clock)
, device_video_interface(mconfig, *this)
, m_colpri_cb(*this)
{
}
/* this implementation was originally from Mad Motor */
void deco_mxc06_device::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, gfx_element *gfx, u16* spriteram, int size)
{
const bool priority = !m_colpri_cb.isnull();
struct sprite_t *sprite_ptr = m_spritelist.get();
for (int offs = 0; offs < size;)
{
u32 pri_mask = 0;
int flipy, incy, mult, parentFlipY;
const u16 data0 = spriteram[offs];
const u16 data2 = spriteram[offs + 2];
u32 colour = data2 >> 12;
if (priority)
m_colpri_cb(colour, pri_mask);
const bool flash = data2 & 0x800;
int flipx = data0 & 0x2000;
parentFlipY = flipy = data0 & 0x4000;
const int h = (1 << ((data0 & 0x1800) >> 11)); /* 1x, 2x, 4x, 8x height */
const int w = (1 << ((data0 & 0x0600) >> 9)); /* 1x, 2x, 4x, 8x width */
int sx = data2 & 0x01ff;
int sy = data0 & 0x01ff;
if (sx >= 256) sx -= 512;
if (sy >= 256) sy -= 512;
sx = 240 - sx;
sy = 240 - sy;
if (m_flip_screen)
{
sy = 240 - sy;
sx = 240 - sx;
if (flipx) flipx = 0; else flipx = 1;
if (flipy) flipy = 0; else flipy = 1;
mult = 16;
}
else
mult = -16;
// thedeep strongly suggests that this check goes here, otherwise the radar breaks
if (!(spriteram[offs] & 0x8000))
{
offs += 4;
continue;
}
for (int x = 0; x < w; x++)
{
if (offs < size)
{
// maybe, birdie try appears to specify the base code for each part..
u16 code = spriteram[offs + 1] & 0x1fff;
code &= ~(h - 1);
// not affected by flipscreen
if (parentFlipY) // in the case of multi-width sprites the y flip bit is set by the parent
incy = -1;
else
{
code += h - 1;
incy = 1;
}
if (!flash || (screen.frame_number() & 1))
{
sprite_ptr->height = h;
sprite_ptr->colour = colour;
sprite_ptr->flipx = flipx;
sprite_ptr->flipy = flipy;
if (priority)
{
sprite_ptr->pri_mask = pri_mask;
for (int y = 0; y < h; y++)
{
sprite_ptr->code[y] = code - y * incy;
sprite_ptr->x[y] = sx + (mult * x);
sprite_ptr->y[y] = sy + (mult * y);
}
sprite_ptr++;
}
else
{
for (int y = 0; y < h; y++)
{
sprite_ptr->code[y] = code - y * incy;
sprite_ptr->x[y] = sx + (mult * x);
sprite_ptr->y[y] = sy + (mult * y);
gfx->transpen(bitmap, cliprect,
sprite_ptr->code[y],
sprite_ptr->colour,
sprite_ptr->flipx, sprite_ptr->flipy,
sprite_ptr->x[y], sprite_ptr->y[y], 0);
}
}
}
}
offs += 4;
}
}
if (priority)
{
while (sprite_ptr != m_spritelist.get())
{
sprite_ptr--;
for (int y = 0; y < sprite_ptr->height; y++)
{
gfx->prio_transpen(bitmap, cliprect,
sprite_ptr->code[y],
sprite_ptr->colour,
sprite_ptr->flipx, sprite_ptr->flipy,
sprite_ptr->x[y], sprite_ptr->y[y], screen.priority(), sprite_ptr->pri_mask, 0);
};
}
}
}
/* this is used by the automat bootleg, it seems to have greatly simplified sprites compared to the real chip */
/* spriteram is twice the size tho! */
void deco_mxc06_device::draw_sprites_bootleg(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, gfx_element *gfx, u16* spriteram, int size)
{
const bool priority = !m_colpri_cb.isnull();
struct sprite_t *sprite_ptr = m_spritelist.get();
for (int offs = 0; offs < size; offs += 4)
{
u32 pri_mask = 0;
u32 code = spriteram[offs];
int sy = 240-spriteram[offs + 1]; // 241- will align robocop with the ground but causes other issues too
int sx = spriteram[offs + 2];
code |= (spriteram[offs + 3] &0x0f)<<8;
const bool flipx = !(spriteram[offs + 3] &0x20);
const bool flipy = (spriteram[offs + 3] &0x40);
u32 colour = (spriteram[offs + 0x400] & 0xf0) >> 4;
if (priority)
m_colpri_cb(colour, pri_mask);
sx |= (spriteram[offs + 0x400] & 0x01) << 8;
sx -= 16;
sx &=0x1ff;
sx -= 0x100;
sprite_ptr->colour = colour;
sprite_ptr->flipx = flipx;
sprite_ptr->flipy = flipy;
sprite_ptr->code[0] = code;
sprite_ptr->x[0] = sx;
sprite_ptr->y[0] = sy;
if (priority)
{
sprite_ptr->pri_mask = pri_mask;
sprite_ptr++;
}
else
{
gfx->transpen(bitmap,cliprect,
sprite_ptr->code[0],
sprite_ptr->colour,
sprite_ptr->flipx,sprite_ptr->flipy,
sprite_ptr->x[0],sprite_ptr->y[0],0);
}
}
if (priority)
{
while (sprite_ptr != m_spritelist.get())
{
sprite_ptr--;
gfx->prio_transpen(bitmap, cliprect,
sprite_ptr->code[0],
sprite_ptr->colour,
sprite_ptr->flipx, sprite_ptr->flipy,
sprite_ptr->x[0], sprite_ptr->y[0], screen.priority(), sprite_ptr->pri_mask, 0);
}
}
}
void deco_mxc06_device::device_start()
{
m_colpri_cb.resolve();
m_flip_screen = false;
m_spritelist = make_unique_clear<struct sprite_t[]>(0x400);
save_item(NAME(m_flip_screen));
}
void deco_mxc06_device::device_reset()
{
}