// license:BSD-3-Clause
// copyright-holders:Philip Bennett,Carlos A. Lozano, Rob Rosenbrock, Phil Stroffolino, Ernesto Corvi, David Haywood, R. Belmont
/***************************************************************************
Video Hardware for some Technos games:
Double Dragon, Double Dragon bootleg, Double Dragon II and China Gate
Two Tile layers.
Background layer is 512x512 , tiles are 16x16
Top layer is 256x256 , tiles are 8x8
Sprites are 16x16, 16x32, 32x16, or 32x32 (attribute bits set dimension)
BG Tile Layout
0 1
---- -xxx xxxx xxxx = Tile number
--xx x--- ---- ---- = Color
-x-- ---- ---- ---- = X Flip
x--- ---- ---- ---- = Y Flip
Top Tile layout.
0 1
---- xxxx xxxx xxxx = Tile number
xxxx ---- ---- ---- = Color (China Gate)
xxx- ---- ---- ---- = Color (Double Dragon)
Sprite layout.
0 1 2 3 4
---- ---- ---- ---- ---- xxxx xxxx xxxx ---- ---- = Sprite number
---- ---- ---- ---- xxxx ---- ---- ---- ---- ---- = Color
xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- = Y position
---- ---- ---- ---x ---- ---- ---- ---- ---- ---- = Y MSb position ???
---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx = X position
---- ---- ---- --x- ---- ---- ---- ---- ---- ---- = X position MSb
---- ---- ---- -x-- ---- ---- ---- ---- ---- ---- = Y Flip
---- ---- ---- x--- ---- ---- ---- ---- ---- ---- = X Flip
---- ---- --xx ---- ---- ---- ---- ---- ---- ---- = Sprite Dimension
---- ---- x--- ---- ---- ---- ---- ---- ---- ---- = Visible
***************************************************************************/
#include "emu.h"
#include "includes/ddragon.h"
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILEMAP_MAPPER_MEMBER(ddragon_state::background_scan)
{
/* logical (col,row) -> memory offset */
return (col & 0x0f) | ((row & 0x0f) << 4) | ((col & 0x10) << 4) | ((row & 0x10) << 5);
}
TILE_GET_INFO_MEMBER(ddragon_state::get_bg_tile_info)
{
tile_index <<= 1;
uint8_t attr = m_bgvideoram[tile_index];
SET_TILE_INFO_MEMBER(2,
m_bgvideoram[tile_index | 1] | ((attr & 0x07) << 8),
(attr >> 3) & 0x07,
TILE_FLIPYX((attr & 0xc0) >> 6));
}
TILE_GET_INFO_MEMBER(ddragon_state::get_fg_tile_info)
{
tile_index <<= 1;
uint8_t attr = m_fgvideoram[tile_index];
SET_TILE_INFO_MEMBER(0,
m_fgvideoram[tile_index | 1] | ((attr & 0x07) << 8),
attr >> 5,
0);
}
TILE_GET_INFO_MEMBER(ddragon_state::get_fg_16color_tile_info)
{
tile_index <<= 1;
uint8_t attr = m_fgvideoram[tile_index];
SET_TILE_INFO_MEMBER(0,
m_fgvideoram[tile_index | 1] | ((attr & 0x0f) << 8),
attr >> 4,
0);
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
VIDEO_START_MEMBER(ddragon_state,ddragon)
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(ddragon_state::get_bg_tile_info)), tilemap_mapper_delegate(*this, FUNC(ddragon_state::background_scan)), 16, 16, 32, 32);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(ddragon_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fg_tilemap->set_transparent_pen(0);
m_fg_tilemap->set_scrolldx(0, 0);
m_bg_tilemap->set_scrolldx(0, 0);
m_fg_tilemap->set_scrolldy(-8, -8);
m_bg_tilemap->set_scrolldy(-8, -8);
}
/***************************************************************************
Memory handlers
***************************************************************************/
WRITE8_MEMBER(ddragon_state::ddragon_bgvideoram_w)
{
m_bgvideoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset >> 1);
}
WRITE8_MEMBER(ddragon_state::ddragon_fgvideoram_w)
{
m_fgvideoram[offset] = data;
m_fg_tilemap->mark_tile_dirty(offset >> 1);
}
/***************************************************************************
Display refresh
***************************************************************************/
#define DRAW_SPRITE( order, sx, sy ) gfx->transpen(bitmap,\
cliprect, \
(which + order),color,flipx,flipy,sx,sy,0);
void ddragon_state::draw_sprites(bitmap_ind16 &bitmap,const rectangle &cliprect)
{
gfx_element *gfx = m_gfxdecode->gfx(1);
const uint8_t *src = m_spriteram;
const uint32_t bytes = m_spriteram.bytes();
for (uint32_t i = 0; i < bytes; i += 5)
{
int attr = src[i + 1];
if (attr & 0x80) /* visible */
{
int sx = 240 - src[i + 4] + ((attr & 2) << 7);
int sy = 232 - src[i + 0] + ((attr & 1) << 8);
int size = (attr & 0x30) >> 4;
int flipx = attr & 8;
int flipy = attr & 4;
int dx = -16, dy = -16;
int which;
int color;
if (m_technos_video_hw == 2) /* Double Dragon 2 */
{
color = src[i + 2] >> 5;
which = src[i + 3] | ((src[i + 2] & 0x1f) << 8);
}
else
{
if (m_technos_video_hw == 1) /* China Gate */
{
if ((sx < -7) && (sx > -16)) sx += 256; /* fix sprite clip */
if ((sy < -7) && (sy > -16)) sy += 256; /* fix sprite clip */
}
color = src[i + 2] >> 4;
which = src[i + 3] | ((src[i + 2] & 0x0f) << 8);
}
if (flip_screen())
{
sx = 240 - sx;
sy = 240 - 16 - sy;
flipx = !flipx;
flipy = !flipy;
dx = -dx;
dy = -dy;
}
which &= ~size;
switch (size)
{
case 0: /* normal */
DRAW_SPRITE(0, sx, sy);
break;
case 1: /* double y */
DRAW_SPRITE(0, sx, sy + dy);
DRAW_SPRITE(1, sx, sy);
break;
case 2: /* double x */
DRAW_SPRITE(0, sx + dx, sy);
DRAW_SPRITE(2, sx, sy);
break;
case 3:
DRAW_SPRITE(0, sx + dx, sy + dy);
DRAW_SPRITE(1, sx + dx, sy);
DRAW_SPRITE(2, sx, sy + dy);
DRAW_SPRITE(3, sx, sy);
break;
}
}
}
}
#undef DRAW_SPRITE
uint32_t ddragon_state::screen_update_ddragon(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int scrollx = (m_scrollx_hi << 8) | *m_scrollx_lo;
int scrolly = (m_scrolly_hi << 8) | *m_scrolly_lo;
m_bg_tilemap->set_scrollx(0, scrollx);
m_bg_tilemap->set_scrolly(0, scrolly);
m_bg_tilemap->draw(screen, bitmap, cliprect, 0,0);
draw_sprites(bitmap, cliprect);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}