/***************************************************************************
Lock-On video hardware
***************************************************************************/
#include "emu.h"
#include "includes/lockon.h"
#include "cpu/nec/nec.h"
#include "video/resnet.h"
#define CURSOR_XPOS 168
#define CURSOR_YPOS 239
#define FRAMEBUFFER_MAX_X 431
#define FRAMEBUFFER_MAX_Y (UINT32)((FRAMEBUFFER_CLOCK / (float)(FRAMEBUFFER_MAX_X-1)) / ((float)PIXEL_CLOCK/(HTOTAL*VTOTAL)))
/*************************************
*
* HD46505S-2 CRT Controller
*
*************************************/
READ16_HANDLER( lockon_crtc_r )
{
return 0xffff;
}
WRITE16_HANDLER( lockon_crtc_w )
{
#if 0
data &= 0xff;
if (offset == 0)
{
switch (data)
{
case 0x00: mame_printf_debug("Horizontal Total "); break;
case 0x01: mame_printf_debug("Horizontal displayed "); break;
case 0x02: mame_printf_debug("Horizontal sync position "); break;
case 0x03: mame_printf_debug("Horizontal sync width "); break;
case 0x04: mame_printf_debug("Vertical total "); break;
case 0x05: mame_printf_debug("Vertical total adjust "); break;
case 0x06: mame_printf_debug("Vertical displayed "); break;
case 0x07: mame_printf_debug("Vertical sync position "); break;
case 0x08: mame_printf_debug("Interlace mode "); break;
case 0x09: mame_printf_debug("Max. scan line address "); break;
case 0x0a: mame_printf_debug("Cursror start "); break;
case 0x0b: mame_printf_debug("Cursor end "); break;
case 0x0c: mame_printf_debug("Start address (h) "); break;
case 0x0d: mame_printf_debug("Start address (l) "); break;
case 0x0e: mame_printf_debug("Cursor (h) "); break;
case 0x0f: mame_printf_debug("Cursor (l) "); break;
case 0x10: mame_printf_debug("Light pen (h)) "); break;
case 0x11: mame_printf_debug("Light pen (l) "); break;
}
}
else if (offset == 1)
{
mame_printf_debug("0x%.2x, (%d)\n",data, data);
}
#endif
}
static TIMER_CALLBACK( cursor_callback )
{
lockon_state *state = machine.driver_data<lockon_state>();
if (state->m_main_inten)
device_set_input_line_and_vector(state->m_maincpu, 0, HOLD_LINE, 0xff);
state->m_cursor_timer->adjust(machine.primary_screen->time_until_pos(CURSOR_YPOS, CURSOR_XPOS));
}
/*************************************
*
* Palette decoding
*
*************************************/
static const res_net_info lockon_net_info =
{
RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT,
{
{RES_NET_AMP_NONE, 560, 0, 5, {4700, 2200, 1000, 470, 220}},
{RES_NET_AMP_NONE, 560, 0, 5, {4700, 2200, 1000, 470, 220}},
{RES_NET_AMP_NONE, 560, 0, 5, {4700, 2200, 1000, 470, 220}}
}
};
static const res_net_info lockon_pd_net_info =
{
RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT,
{
{RES_NET_AMP_NONE, 560, 580, 5, {4700, 2200, 1000, 470, 220}},
{RES_NET_AMP_NONE, 560, 580, 5, {4700, 2200, 1000, 470, 220}},
{RES_NET_AMP_NONE, 560, 580, 5, {4700, 2200, 1000, 470, 220}}
}
};
PALETTE_INIT( lockon )
{
int i;
for (i = 0; i < 1024; ++i)
{
UINT8 r, g, b;
UINT8 p1 = color_prom[i];
UINT8 p2 = color_prom[i + 0x400];
if (p2 & 0x80)
{
r = compute_res_net((p2 >> 2) & 0x1f, 0, &lockon_net_info);
g = compute_res_net(((p1 >> 5) & 0x7) | (p2 & 3) << 3, 1, &lockon_net_info);
b = compute_res_net((p1 & 0x1f), 2, &lockon_net_info);
}
else
{
r = compute_res_net((p2 >> 2) & 0x1f, 0, &lockon_pd_net_info);
g = compute_res_net(((p1 >> 5) & 0x7) | (p2 & 3) << 3, 1, &lockon_pd_net_info);
b = compute_res_net((p1 & 0x1f), 2, &lockon_pd_net_info);
}
palette_set_color(machine, i, MAKE_RGB(r, g, b));
}
}
/*************************************
*
* Character tilemap handling
*
*************************************/
WRITE16_HANDLER( lockon_char_w )
{
lockon_state *state = space->machine().driver_data<lockon_state>();
state->m_char_ram[offset] = data;
tilemap_mark_tile_dirty(state->m_tilemap, offset);
}
static TILE_GET_INFO( get_lockon_tile_info )
{
lockon_state *state = machine.driver_data<lockon_state>();
UINT32 tileno = state->m_char_ram[tile_index] & 0x03ff;
UINT32 col = (state->m_char_ram[tile_index] >> 10) & 0x3f;
col = (col & 0x1f) + (col & 0x20 ? 64 : 0);
SET_TILE_INFO(0, tileno, col, 0);
}
/*******************************************************************************************
Scene tilemap hardware
*******************************************************************************************/
WRITE16_HANDLER( lockon_scene_h_scr_w )
{
lockon_state *state = space->machine().driver_data<lockon_state>();
state->m_scroll_h = data & 0x1ff;
}
WRITE16_HANDLER( lockon_scene_v_scr_w )
{
lockon_state *state = space->machine().driver_data<lockon_state>();
state->m_scroll_v = data & 0x81ff;
}
static void scene_draw( running_machine &machine )
{
lockon_state *state = machine.driver_data<lockon_state>();
UINT32 y;
/* 3bpp characters */
const UINT8 *const gfx1 = machine.region("gfx2")->base();
const UINT8 *const gfx2 = gfx1 + 0x10000;
const UINT8 *const gfx3 = gfx1 + 0x20000;
const UINT8 *const clut = gfx1 + 0x30000;
for (y = 0; y < FRAMEBUFFER_MAX_Y; ++y)
{
UINT32 x;
UINT32 d0 = 0, d1 = 0, d2 = 0;
UINT32 colour = 0;
UINT32 y_offs;
UINT32 x_offs;
UINT32 y_gran;
UINT16 *bmpaddr;
UINT32 ram_mask = 0x7ff;
y_offs = (y + state->m_scroll_v) & 0x1ff;
/* Clamp - stops tilemap wrapping when screen is rotated */
if (BIT(state->m_scroll_v, 15) && y_offs & 0x100)
ram_mask = 0x7;
x_offs = (state->m_scroll_h - 8) & 0x1ff;
y_gran = y_offs & 7;
if (x_offs & 7)
{
UINT32 tileidx;
UINT16 addr = ((y_offs & ~7) << 3) + ((x_offs >> 3) & 0x3f);
UINT16 ram_val = state->m_scene_ram[addr & ram_mask];
colour = (clut[ram_val & 0x7fff] & 0x3f) << 3;
tileidx = ((ram_val & 0x0fff) << 3) + y_gran;
d0 = *(gfx1 + tileidx);
d1 = *(gfx2 + tileidx);
d2 = *(gfx3 + tileidx);
}
bmpaddr = BITMAP_ADDR16(state->m_back_buffer, y, 0);
for (x = 0; x < FRAMEBUFFER_MAX_X; ++x)
{
UINT32 x_gran = (x_offs & 7) ^ 7;
UINT32 col;
if (!(x_offs & 7))
{
UINT32 tileidx;
UINT16 addr = ((y_offs & ~7) << 3) + ((x_offs >> 3) & 0x3f);
UINT16 ram_val = state->m_scene_ram[addr & ram_mask];
colour = (clut[ram_val & 0x7fff] & 0x3f) << 3;
tileidx = ((ram_val & 0x0fff) << 3) + y_gran;
d0 = *(gfx1 + tileidx);
d1 = *(gfx2 + tileidx);
d2 = *(gfx3 + tileidx);
}
col = colour
| (((d2 >> x_gran) & 1) << 2)
| (((d1 >> x_gran) & 1) << 1)
| ( (d0 >> x_gran) & 1);
*bmpaddr++ = 0xa00 + col;
x_offs = (x_offs + 1) & 0x1ff;
}
}
}
/*******************************************************************************************
Ground Hardware
Each framebuffer line corresponds to a three word entry in ground RAM,
starting from offset 3:
FEDCBA9876543210
0 |.............xxx| Tile line (A0-A2 GFX ROMs)
|...........xx...| Tile index (A6-A5 GFX ROMs)
|........xxx.....| ROM lut address (A6-A4)
|.xxxxxxx........| ROM lut address (A13-A7)
|x...............| /Line enable
1 |........xxxxxxxx| TZ2213 value
|xxxxxxxx........| X offset
2 |........xxxxxxxx| TZ2213 DX
|.......x........| Carry
|x...............| End of list marker
An 8-bit ground control register controls the following:
76543210
|......xx| LUT ROM A15-A14
|....xx..| LUT ROM select
|..xx....| CLUT ROM A13-A12
|.x......| GFX ROM A15, CLUT ROM A14
|x.......| GFX ROM bank select (always 0 - only 1 bank is present)
*******************************************************************************************/
WRITE16_HANDLER( lockon_ground_ctrl_w )
{
lockon_state *state = space->machine().driver_data<lockon_state>();
state->m_ground_ctrl = data & 0xff;
}
static TIMER_CALLBACK( bufend_callback )
{
lockon_state *state = machine.driver_data<lockon_state>();
device_set_input_line_and_vector(state->m_ground, 0, HOLD_LINE, 0xff);
device_set_input_line(state->m_object, NEC_INPUT_LINE_POLL, ASSERT_LINE);
}
/* Get data for a each 8x8x3 ground tile */
#define GET_GROUND_DATA() \
{ \
UINT32 gfx_a4_3 = (ls163 & 0xc) << 1; \
UINT32 lut_addr = lut_address + ((ls163 >> 4) & 0xf); \
UINT32 gfx_a14_7 = lut_rom[lut_addr] << 7; \
clut_addr = (lut_rom[lut_addr] << 4) | clut_a14_12 | clut_a4_3 | (ls163 & 0xc) >> 2; \
gfx_addr = gfx_a15 | gfx_a14_7 | gfx_a6_5 | gfx_a4_3 | gfx_a2_0; \
pal = (clut_rom[clut_addr] << 3); \
rom_data1 = gfx_rom[gfx_addr]; \
rom_data2 = gfx_rom[gfx_addr + 0x10000]; \
rom_data3 = gfx_rom[gfx_addr + 0x20000]; \
}
static void ground_draw( running_machine &machine )
{
lockon_state *state = machine.driver_data<lockon_state>();
/* ROM pointers */
const UINT8 *const gfx_rom = machine.region("gfx4")->base();
const UINT8 *const lut_rom = gfx_rom + 0x30000 + ((state->m_ground_ctrl >> 2) & 0x3 ? 0x10000 : 0);
const UINT8 *const clut_rom = gfx_rom + 0x50000;
UINT32 lut_a15_14 = (state->m_ground_ctrl & 0x3) << 14;
UINT32 clut_a14_12 = (state->m_ground_ctrl & 0x70) << 8;
UINT32 gfx_a15 = (state->m_ground_ctrl & 0x40) << 9;
UINT32 offs = 3;
UINT32 y;
/* TODO: Clean up and emulate CS of GFX ROMs? */
for (y = 0; y < FRAMEBUFFER_MAX_Y; ++y)
{
UINT16 *bmpaddr = BITMAP_ADDR16(state->m_back_buffer, y, 0);
UINT8 ls163;
UINT32 clut_addr;
UINT32 gfx_addr;
UINT8 rom_data1 = 0;
UINT8 rom_data2 = 0;
UINT8 rom_data3 = 0;
UINT32 pal = 0;
UINT32 x;
/* Draw this line? */
if (!(state->m_ground_ram[offs] & 0x8000))
{
UINT32 gfx_a2_0 = state->m_ground_ram[offs] & 0x0007;
UINT32 gfx_a6_5 = (state->m_ground_ram[offs] & 0x0018) << 2;
UINT32 clut_a4_3 = (state->m_ground_ram[offs] & 0x0018) >> 1;
UINT8 tz2213_x = state->m_ground_ram[offs + 1] & 0xff;
UINT8 tz2213_dx = state->m_ground_ram[offs + 2] & 0xff;
UINT32 lut_address = lut_a15_14 + ((state->m_ground_ram[offs] & 0x7fe0) >> 1);
UINT32 cy = state->m_ground_ram[offs + 2] & 0x0100;
UINT32 color;
UINT32 gpbal2_0_prev;
ls163 = state->m_ground_ram[offs + 1] >> 8;
gpbal2_0_prev = ((ls163 & 3) << 1) | BIT(tz2213_x, 7);
if (gpbal2_0_prev)
GET_GROUND_DATA();
for (x = 0; x < FRAMEBUFFER_MAX_X; x++)
{
UINT32 tz2213_cy;
UINT32 gpbal2_0 = ((ls163 & 3) << 1) | BIT(tz2213_x, 7);
/* Stepped into a new tile? */
if (gpbal2_0 < gpbal2_0_prev)
GET_GROUND_DATA();
gpbal2_0_prev = gpbal2_0;
color = pal;
color += (rom_data1 >> gpbal2_0) & 0x1;
color += ((rom_data2 >> gpbal2_0) & 0x1) << 1;
color += ((rom_data3 >> gpbal2_0) & 0x1) << 2;
*bmpaddr++ = 0x800 + color;
/* Update the counters */
tz2213_cy = (UINT8)tz2213_dx > (UINT8)~(tz2213_x);
tz2213_x = (tz2213_x + tz2213_dx);
/* Carry? */
if (tz2213_cy || cy)
++ls163;
}
}
offs += 3;
/* End of list marker */
if (state->m_ground_ram[offs + 2] & 0x8000)
{
state->m_bufend_timer->adjust(attotime::from_hz(FRAMEBUFFER_CLOCK) * (FRAMEBUFFER_MAX_X * y));
}
}
}
/*******************************************************************************************
Object hardware
Customs (4 each, 1 per bitplane)
TZA118 - Scaling
TZ4203 - Objects with integrated line buffer.
FEDCBA9876543210
0 |......xxxxxxxxxx| Y position
|....xx..........| Object Y size
|..xx............| Object X size
|.x..............| Y flip
|x...............| X flip
1 |........xxxxxxxx| X/Y scale
|.xxxxxxx........| Colour
|x...............| End of list marker
2 |xxxxxxxxxxxxxxxx| Chunk ROM address
3 |.....xxxxxxxxxxx| X position
*******************************************************************************************/
/*
There's logic to prevent shadow pixels from being drawn against the scene tilemap,
so that shadows don't appear against the sky.
*/
#define DRAW_OBJ_PIXEL(COLOR) \
do { \
if (px < FRAMEBUFFER_MAX_X) \
if (COLOR != 0xf) \
{ \
UINT8 clr = state->m_obj_pal_ram[(pal << 4) + COLOR]; \
UINT16 *pix = (line + px); \
if (!(clr == 0xff && ((*pix & 0xe00) == 0xa00))) \
*pix = 0x400 + clr; \
} \
px = (px + 1) & 0x7ff; \
} while(0)
static void objects_draw( running_machine &machine )
{
UINT32 offs;
lockon_state *state = machine.driver_data<lockon_state>();
const UINT8 *const romlut = machine.region("user1")->base();
const UINT16 *const chklut = (UINT16*)machine.region("user2")->base();
const UINT8 *const gfxrom = machine.region("gfx5")->base();
const UINT8 *const sproms = machine.region("proms")->base() + 0x800;
for (offs = 0; offs < state->m_objectram_size; offs += 4)
{
UINT32 y;
UINT32 xpos;
UINT32 ypos;
UINT32 xsize;
UINT32 ysize;
UINT32 xflip;
UINT32 yflip;
UINT32 scale;
UINT32 pal;
UINT32 lines;
UINT32 opsta;
UINT32 opsta15_8;
/* Retrieve the object attributes */
ypos = state->m_object_ram[offs] & 0x03ff;
xpos = state->m_object_ram[offs + 3] & 0x07ff;
ysize = (state->m_object_ram[offs] >> 10) & 0x3;
xsize = (state->m_object_ram[offs] >> 12) & 0x3;
yflip = BIT(state->m_object_ram[offs], 14);
xflip = BIT(state->m_object_ram[offs], 15);
scale = state->m_object_ram[offs + 1] & 0xff;
pal = (state->m_object_ram[offs + 1] >> 8) & 0x7f;
opsta = state->m_object_ram[offs + 2];
if (state->m_iden)
{
state->m_obj_pal_ram[(pal << 4) + state->m_obj_pal_addr] = state->m_obj_pal_latch;
break;
}
/* How many lines will this sprite occupy? The PAL @ IC154 knows... */
lines = scale >> (3 - ysize);
opsta15_8 = opsta & 0xff00;
/* Account for line buffering */
ypos -=1;
for (y = 0; y < FRAMEBUFFER_MAX_Y; y++)
{
UINT32 cy = (y + ypos) & 0x3ff;
UINT32 optab;
UINT32 lutaddr;
UINT32 tile;
UINT8 cnt;
UINT32 yidx;
UINT16 *line = BITMAP_ADDR16(state->m_back_buffer, y, 0);
UINT32 px = xpos;
/* Outside the limits? */
if (cy & 0x300)
continue;
if ((cy & 0xff) >= lines)
break;
lutaddr = (scale & 0x80 ? 0x8000 : 0) | ((scale & 0x7f) << 8) | (cy & 0xff);
optab = romlut[lutaddr] & 0x7f;
if (yflip)
optab ^= 7;
yidx = (optab & 7);
/* Now calculate the lower 7-bits of the LUT ROM address. PAL @ IC157 does this */
cnt = (optab >> 3) * (1 << xsize);
if (xflip)
cnt ^= 7 >> (3 - xsize);
if (yflip)
cnt ^= (0xf >> (3 - ysize)) * (1 << xsize);
cnt = (cnt + (opsta & 0xff));
/* Draw! */
for (tile = 0; tile < (1 << xsize); ++tile)
{
UINT16 sc;
UINT16 scl;
UINT32 x;
UINT32 tileaddr;
UINT16 td0, td1, td2, td3;
UINT32 j;
UINT32 bank;
scl = scale & 0x7f;
tileaddr = (chklut[opsta15_8 + cnt] & 0x7fff);
bank = ((tileaddr >> 12) & 3) * 0x40000;
tileaddr = bank + ((tileaddr & ~0xf000) << 3);
if (xflip)
--cnt;
else
++cnt;
/* Draw two 8x8 tiles */
for (j = 0; j < 2; ++j)
{
/* Get tile data */
UINT32 tileadd = tileaddr + (0x20000 * (j ^ xflip));
/* Retrieve scale values from PROMs */
sc = sproms[(scl << 4) + (tile * 2) + j];
/* Data from ROMs is inverted */
td3 = gfxrom[tileadd + yidx] ^ 0xff;
td2 = gfxrom[tileadd + 0x8000 + yidx] ^ 0xff;
td1 = gfxrom[tileadd + 0x10000 + yidx] ^ 0xff;
td0 = gfxrom[tileadd + 0x18000 + yidx] ^ 0xff;
if (scale & 0x80)
{
for (x = 0; x < 8; ++x)
{
UINT8 col;
UINT8 pix = x;
if (!xflip)
pix ^= 0x7;
col = BIT(td0, pix)
| (BIT(td1, pix) << 1)
| (BIT(td2, pix) << 2)
| (BIT(td3, pix) << 3);
DRAW_OBJ_PIXEL(col);
if (BIT(sc, x))
DRAW_OBJ_PIXEL(col);
}
}
else
{
for (x = 0; x < 8; ++x)
{
UINT8 col;
UINT8 pix = x;
if (BIT(sc, x))
{
if (!xflip)
pix ^= 0x7;
col = BIT(td0, pix)
| (BIT(td1, pix) << 1)
| (BIT(td2, pix) << 2)
| (BIT(td3, pix) << 3);
DRAW_OBJ_PIXEL(col);
}
}
}
}
}
}
/* Check for the end of list marker */
if (state->m_object_ram[offs + 1] & 0x8000)
return;
}
}
/* The mechanism used by the object CPU to update the object ASICs palette RAM */
WRITE16_HANDLER( lockon_tza112_w )
{
lockon_state *state = space->machine().driver_data<lockon_state>();
if (state->m_iden)
{
state->m_obj_pal_latch = data & 0xff;
state->m_obj_pal_addr = offset & 0xf;
objects_draw(space->machine());
}
}
READ16_HANDLER( lockon_obj_4000_r )
{
lockon_state *state = space->machine().driver_data<lockon_state>();
device_set_input_line(state->m_object, NEC_INPUT_LINE_POLL, CLEAR_LINE);
return 0xffff;
}
WRITE16_HANDLER( lockon_obj_4000_w )
{
lockon_state *state = space->machine().driver_data<lockon_state>();
state->m_iden = data & 1;
}
/*******************************************************************************************
Frame buffer rotation hardware
FEDCBA9876543210
0 |........xxxxxxxx| X start address
|.......x........| Direction
1 |........xxxxxxxx| TZ2213 IC65 value
|.......x........| TZ2213 IC65 /enable
2 |........xxxxxxxx| TZ2213 IC65 delta
3 |........xxxxxxxx| TZ2213 IC106 delta
|.......x........| TZ2213 IC106 enable
4 |.......xxxxxxxxx| Y start address
5 |........xxxxxxxx| TZ2213 IC66 value
6 |........xxxxxxxx| TZ2213 IC66 delta
|.......x........| TZ2213 IC65 /enable
7 |........xxxxxxxx| TZ2213 IC107 delta
|.......x........| TZ2213 /enable
|......x.........| Direction
*******************************************************************************************/
WRITE16_HANDLER( lockon_fb_clut_w )
{
rgb_t color;
color = palette_get_color(space->machine(), 0x300 + (data & 0xff));
palette_set_color(space->machine(), 0x400 + offset, color);
}
/* Rotation control register */
WRITE16_HANDLER( lockon_rotate_w )
{
lockon_state *state = space->machine().driver_data<lockon_state>();
switch (offset & 7)
{
case 0: state->m_xsal = data & 0x1ff; break;
case 1: state->m_x0ll = data & 0xff; break;
case 2: state->m_dx0ll = data & 0x1ff; break;
case 3: state->m_dxll = data & 0x1ff; break;
case 4: state->m_ysal = data & 0x1ff; break;
case 5: state->m_y0ll = data & 0xff; break;
case 6: state->m_dy0ll = data & 0x1ff; break;
case 7: state->m_dyll = data & 0x3ff; break;
}
}
#define INCREMENT(ACC, CNT) \
do { \
carry = (UINT8)d##ACC > (UINT8)~ACC; \
ACC += d##ACC; \
if (carry) ++CNT; \
} while(0)
#define DECREMENT(ACC, CNT) \
do { \
carry = (UINT8)d##ACC > (UINT8)ACC; \
ACC -= d##ACC; \
if (carry) --CNT; \
} while(0)
static void rotate_draw( running_machine &machine, bitmap_t *bitmap, const rectangle *cliprect )
{
lockon_state *state = machine.driver_data<lockon_state>();
UINT32 y;
/* Counters */
UINT32 cxy = state->m_xsal & 0xff;
UINT32 cyy = state->m_ysal & 0x1ff;
/* Accumulator values and deltas */
UINT8 axy = state->m_x0ll & 0xff;
UINT8 daxy = state->m_dx0ll & 0xff;
UINT8 ayy = state->m_y0ll & 0xff;
UINT8 dayy = state->m_dy0ll & 0xff;
UINT8 dayx = state->m_dyll & 0xff;
UINT8 daxx = state->m_dxll & 0xff;
UINT32 xy_up = BIT(state->m_xsal, 8);
UINT32 yx_up = BIT(state->m_dyll, 9);
UINT32 axx_en = !BIT(state->m_dxll, 8);
UINT32 ayx_en = !BIT(state->m_dyll, 8);
UINT32 axy_en = !BIT(state->m_dx0ll, 8);
UINT32 ayy_en = !BIT(state->m_dy0ll, 8);
for (y = 0; y <= cliprect->max_y; ++y)
{
UINT32 carry;
UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
UINT32 x;
UINT32 cx = cxy;
UINT32 cy = cyy;
UINT8 axx = axy;
UINT8 ayx = ayy;
for (x = 0; x <= cliprect->max_x; ++x)
{
cx &= 0x1ff;
cy &= 0x1ff;
*dst++ = *BITMAP_ADDR16(state->m_front_buffer, cy, cx);
if (axx_en)
INCREMENT(axx, cx);
else
++cx;
if (ayx_en)
{
if (yx_up)
INCREMENT(ayx, cy);
else
DECREMENT(ayx, cy);
}
else
{
if (yx_up)
++cy;
else
--cy;
}
}
if (axy_en)
{
if (xy_up)
INCREMENT(axy, cxy);
else
DECREMENT(axy, cxy);
}
else
{
if (xy_up)
++cxy;
else
--cxy;
}
if (ayy_en)
INCREMENT(ayy, cyy);
else
++cyy;
cxy &= 0xff;
cyy &= 0x1ff;
}
}
/*******************************************************************************************
HUD Drawing Hardware
A sprite layer that uses 8x8x1bpp tiles to form bigger sprites
0 |.......xxxxxxxxx| Y Position
|xxxxxxx.........| Code
1 |.......xxxxxxxxx| X Position
|....xxx.........| Colour
|.xxx............| Sprite width (0=8, 1=16, 2=24, 3=32 pixels, etc.)
|x...............| End of list marker
*******************************************************************************************/
static void hud_draw( running_machine &machine, bitmap_t *bitmap, const rectangle *cliprect )
{
lockon_state *state = machine.driver_data<lockon_state>();
UINT8 *tile_rom = machine.region("gfx3")->base();
UINT32 offs;
for (offs = 0x0; offs <= state->m_hudram_size; offs += 2)
{
UINT32 y;
UINT32 y_pos;
UINT32 x_pos;
UINT32 y_size;
UINT32 x_size;
UINT32 layout;
UINT16 colour;
UINT32 code;
UINT32 rom_a12_7;
/* End of sprite list marker */
if (state->m_hud_ram[offs + 1] & 0x8000)
break;
y_pos = state->m_hud_ram[offs] & 0x1ff;
x_pos = state->m_hud_ram[offs + 1] & 0x1ff;
x_size = (state->m_hud_ram[offs + 1] >> 12) & 7;
code = (state->m_hud_ram[offs] >> 9) & 0x7f;
colour = 0x200 + ((state->m_hud_ram[offs + 1] >> 9) & 7);
layout = (code >> 5) & 3;
rom_a12_7 = (code & 0xfe) << 6;
/* Account for line buffering */
y_pos -= 1;
if (layout == 3)
y_size = 32;
else if (layout == 2)
y_size = 16;
else
y_size = 8;
for (y = cliprect->min_y; y <= cliprect->max_y; ++y)
{
UINT32 xt;
UINT32 cy;
cy = y_pos + y;
if (cy < 0x200)
continue;
if ((cy & 0xff) == y_size)
break;
for (xt = 0; xt <= x_size; ++xt)
{
UINT32 rom_a6_3;
UINT32 px;
UINT8 gfx_strip;
if (layout == 3)
rom_a6_3 = (BIT(cy, 4) << 3) | (BIT(cy, 3) << 2) | (BIT(xt, 1) << 1) | BIT(xt, 0);
else if (layout == 2)
rom_a6_3 = ((BIT(code, 0) << 3) | (BIT(xt, 1) << 2) | (BIT(cy, 3) << 1) | (BIT(xt, 0)));
else
rom_a6_3 = (BIT(code, 0) << 3) | (xt & 7);
rom_a6_3 <<= 3;
/* Get tile data */
gfx_strip = tile_rom[rom_a12_7 | rom_a6_3 | (cy & 7)];
if (gfx_strip == 0)
continue;
/* Draw */
for (px = 0; px < 8; ++px)
{
UINT32 x = x_pos + (xt << 3) + px;
if (x <= cliprect->max_x)
{
UINT16 *dst = BITMAP_ADDR16(bitmap, y, x);
if (BIT(gfx_strip, px ^ 7) && *dst > 255)
*dst = colour;
}
}
}
}
}
}
/*************************************
*
* Driver video handlers
*
*************************************/
VIDEO_START( lockon )
{
lockon_state *state = machine.driver_data<lockon_state>();
state->m_tilemap = tilemap_create(machine, get_lockon_tile_info, tilemap_scan_rows, 8, 8, 64, 32);
tilemap_set_transparent_pen(state->m_tilemap, 0);
/* Allocate the two frame buffers for rotation */
state->m_back_buffer = auto_bitmap_alloc(machine, 512, 512, BITMAP_FORMAT_INDEXED16);
state->m_front_buffer = auto_bitmap_alloc(machine, 512, 512, BITMAP_FORMAT_INDEXED16);
/* 2kB of object ASIC palette RAM */
state->m_obj_pal_ram = auto_alloc_array(machine, UINT8, 2048);
/* Timer for ground display list callback */
state->m_bufend_timer = machine.scheduler().timer_alloc(FUNC(bufend_callback));
/* Timer for the CRTC cursor pulse */
state->m_cursor_timer = machine.scheduler().timer_alloc(FUNC(cursor_callback));
state->m_cursor_timer->adjust(machine.primary_screen->time_until_pos(CURSOR_YPOS, CURSOR_XPOS));
state->save_item(NAME(*state->m_back_buffer));
state->save_item(NAME(*state->m_front_buffer));
state->save_pointer(NAME(state->m_obj_pal_ram), 2048);
}
SCREEN_UPDATE( lockon )
{
lockon_state *state = screen->machine().driver_data<lockon_state>();
/* If screen output is disabled, fill with black */
if (!BIT(state->m_ctrl_reg, 7))
{
bitmap_fill(bitmap, cliprect, get_black_pen(screen->machine()));
return 0;
}
/* Scan out the frame buffer in rotated order */
rotate_draw(screen->machine(), bitmap, cliprect);
/* Draw the character tilemap */
tilemap_draw(bitmap, cliprect, state->m_tilemap, 0, 0);
/* Draw the HUD */
hud_draw(screen->machine(), bitmap, cliprect);
return 0;
}
SCREEN_EOF( lockon )
{
lockon_state *state = machine.driver_data<lockon_state>();
/* Swap the frame buffers */
bitmap_t *tmp = state->m_front_buffer;
state->m_front_buffer = state->m_back_buffer;
state->m_back_buffer = tmp;
/* Draw the frame buffer layers */
scene_draw(machine);
ground_draw(machine);
objects_draw(machine);
}