// license:BSD-3-Clause
// copyright-holders:Manuel Abadia, Mike Coates, Nicola Salmoria, Miguel Angel Horna, Luca Elia, David Haywood
#include "emu.h"
#include "gaelco_wrally_sprites.h"
DEFINE_DEVICE_TYPE(GAELCO_WRALLY_SPRITES, gaelco_wrally_sprites_device, "gaelco_wrally_sprites", "Gaelco World Rally Sprites")
DEFINE_DEVICE_TYPE(BLMBYCAR_SPRITES, blmbycar_sprites_device, "blmbycar_sprites", "Blomby Car Sprites")
gaelco_wrally_sprites_device::gaelco_wrally_sprites_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, m_gfxdecode(*this, finder_base::DUMMY_TAG)
, m_screen(*this, finder_base::DUMMY_TAG)
{
}
gaelco_wrally_sprites_device::gaelco_wrally_sprites_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: gaelco_wrally_sprites_device(mconfig, GAELCO_WRALLY_SPRITES, tag, owner, clock)
{
}
void gaelco_wrally_sprites_device::device_start()
{
m_screen->register_screen_bitmap(m_temp_bitmap_sprites);
}
void gaelco_wrally_sprites_device::device_reset()
{
}
/*
Sprite Format
-------------
Offs | Bit(s) | Description
-----+-FEDCBA98-76543210-+--------------------------
0 | -------- xxxxxxxx | y position
0 | --xxxxxx -------- | not used?
0 | -x------ -------- | flipx
0 | x------- -------- | flipy
1 | xxxxxxxx xxxxxxxx | unknown
2 | ------xx xxxxxxxx | x position
2 | --xxxx-- -------- | sprite color (low 4 bits)
2 | -x------ -------- | shadows/highlights (see below)
2 | x------- -------- | not used?
3 | --xxxxxx xxxxxxxx | sprite code
3 | xx------ -------- | not used?
For shadows/highlights, the tile color below the sprite will be set using a
palette (from the 8 available) based on the gfx pen of the sprite. Only pens
in the range 0x8-0xf are used.
*/
void gaelco_wrally_sprites_device::get_sprites_info(uint16_t* spriteram, int& sx, int& sy, int& number, int& color, int& color_effect, int& attr, int& high_priority, int &end)
{
sx = spriteram[2] & 0x03ff;
sy = (240 - (spriteram[0] & 0x00ff)) & 0x00ff;
number = spriteram[3] & 0x3fff;
color = (spriteram[2] & 0x7c00) >> 10;
color_effect = (color & 0x10) >> 4;
attr = (spriteram[0] & 0xfe00) >> 9;
high_priority = number >= 0x3700; // HACK! this is almost certainly not how the priority is determined
end = 0;
}
void gaelco_wrally_sprites_device::draw_sprites(const rectangle &cliprect, uint16_t* spriteram, int flip_screen)
{
m_temp_bitmap_sprites.fill(0, cliprect);
int i;
gfx_element *gfx = m_gfxdecode->gfx(0);
for (i = 6 / 2; i < (0x1000 - 6) / 2; i += 4)
{
int sx, sy, number, color, attr, end, color_effect, high_priority;
get_sprites_info(spriteram + i, sx, sy, number, color, color_effect, attr, high_priority, end);
if (end)
break;
int xflip = attr & 0x20;
int yflip = attr & 0x40;
color = color & 0x0f;
if (flip_screen)
{
sy = sy + 248;
}
// wrally adjusts sx by 0x0f, blmbycar implementation was 0x10
const uint8_t *gfx_src = gfx->get_data(number % gfx->elements());
for (int py = 0; py < gfx->height(); py++)
{
/* get a pointer to the current line in the screen bitmap */
int ypos = ((sy + py) & 0x1ff);
uint16_t *srcy = &m_temp_bitmap_sprites.pix16(ypos);
int gfx_py = yflip ? (gfx->height() - 1 - py) : py;
if ((ypos < cliprect.min_y) || (ypos > cliprect.max_y)) continue;
for (int px = 0; px < gfx->width(); px++)
{
/* get current pixel */
int xpos = (((sx + px) & 0x3ff) - 0x0f) & 0x3ff;
uint16_t *pixel = srcy + xpos;
int gfx_px = xflip ? (gfx->width() - 1 - px) : px;
/* get asociated pen for the current sprite pixel */
int gfx_pen = gfx_src[gfx->rowbytes()*gfx_py + gfx_px];
if ((xpos < cliprect.min_x) || (xpos > cliprect.max_x)) continue;
if (!color_effect)
{
if (gfx_pen)
{
*pixel = gfx_pen | (color << 4) | (high_priority << 8);
}
}
else
{
int src_color = *pixel;
/* pens 8..15 are used to select a palette */
if ((gfx_pen < 8) || (gfx_pen >= 16)) continue;
// if there's already a sprite pixel use the existing priority value? (or you get a glitch against the start line arch at the start of a night stage) possibly because existing priority scheme is bogus?
// this causes a slight shadow of your car to be visible as you pass through the arch instead, but looking at 14:01 in this video seems to show the same on a PCB https://www.youtube.com/watch?v=vZUUK8c-GZ0
if (src_color != 0)
{
*pixel = src_color |= ((gfx_pen - 8) << 12) | 0x200;
}
else
{
/* modify the color of the tile - the pen modifier can be applied over existing sprite pixels, so we store it in the upper bits that we send to the mixer */
*pixel = (src_color &0xff) | ((gfx_pen - 8) << 12) | (high_priority << 8) | 0x200;
}
}
}
}
}
}
void gaelco_wrally_sprites_device::mix_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect, int priority)
{
for (int y = cliprect.min_y; y < cliprect.max_y; y++)
{
const uint16_t* spriteptr = &m_temp_bitmap_sprites.pix16(y);
uint16_t* dstptr = &bitmap.pix16(y);
for (int x = cliprect.min_x; x < cliprect.max_x; x++)
{
if (spriteptr[x] != 0)
{
// this is how we've packed the bits here
// ssss --ez PPPP pppp s = shadow multiplier e = shadow enabled, z = priority, P = palette select, p = pen
const int pridat = (spriteptr[x] & 0x100) >> 8;
if (pridat == priority)
{
const int shadow = (spriteptr[x] & 0x200) >> 9;
if (!shadow)
{
const uint16_t pendat = (spriteptr[x] & 0xff);
dstptr[x] = pendat + 0x200;
}
else
{
const uint16_t pendat = (spriteptr[x] & 0xff);
const int shadowlevel = (spriteptr[x] & 0xf000) >> 12;
if (pendat != 0)
{
dstptr[x] = (pendat + 0x200) + (shadowlevel * 0x400);
}
else
{
dstptr[x] = (dstptr[x]&0x3ff) + (shadowlevel * 0x400);
}
}
}
}
}
}
}
/***************************************************************************
Sprites Drawing
Offset: Bits: Value:
0 f--- ---- ---- ---- End Of Sprites
-edc ba9- ---- ----
---- ---8 7654 3210 Y (Signed)
1 Code
2 f--- ---- ---- ---- Flip Y
-e-- ---- ---- ---- Flip X
--dc ba98 7654 ----
---- ---- ---- 3210 Color (Bit 3 = Priority)
3 f--- ---- ---- ---- ? Is this ever used ?
-e-- ---- ---- ---- ? 1 = shadow sprite!
--dc ba9- ---- ----
---- ---8 7654 3210 X (Signed)
***************************************************************************/
blmbycar_sprites_device::blmbycar_sprites_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: gaelco_wrally_sprites_device(mconfig, BLMBYCAR_SPRITES, tag, owner, clock)
{
}
void blmbycar_sprites_device::get_sprites_info(uint16_t* spriteram, int& sx, int& sy, int& number, int& color, int& color_effect, int& attr, int& high_priority, int &end)
{
// bytes are swapped around and color attribute is moved
sx = spriteram[3] & 0x03ff;
sy = (spriteram[0] & 0x01ff);
sy = 0xf0 - ((sy & 0xff) - (sy & 0x100)); // check if this logic works for wrally
number = spriteram[1] & 0x3fff;
color = (spriteram[2] & 0x000f) >> 0; // note moved
color_effect = (spriteram[3] & 0x4000) >> 14;
attr = (spriteram[2] & 0xfe00) >> 9;
end = (spriteram[0] & 0x8000); // does wrally have this too?
high_priority = (~(color >> 3))&1;
}