short whatsnew: fixed some gfx bugs in midas.c "livequiz"

long wn:
started converting neogeo video / sprite system to a device_reset
created base device + number of derived classes

NEOGEO_SPRITE_REGULAR is an reference implementation, drawing direct from 
NEOGEO_SPRITE_OPTIMZIED is a version with predecoded gfx (as we use now) this is the default used by the driver
NEOGEO_SPRITE_MIDAS is a version supporting the changes needed by the MIDAS games (mainly 8bpp instead of 4bpp)
This commit is contained in:
David Haywood 2014-05-15 15:46:21 +00:00
parent 36ad612f60
commit 1a9ed9ebe8
10 changed files with 1190 additions and 881 deletions

2
.gitattributes vendored
View File

@ -7266,6 +7266,8 @@ src/mame/video/nbmj8991.c svneol=native#text/plain
src/mame/video/nbmj9195.c svneol=native#text/plain
src/mame/video/nemesis.c svneol=native#text/plain
src/mame/video/neogeo.c svneol=native#text/plain
src/mame/video/neogeo_spr.c svneol=native#text/plain
src/mame/video/neogeo_spr.h svneol=native#text/plain
src/mame/video/news.c svneol=native#text/plain
src/mame/video/ninjakd2.c svneol=native#text/plain
src/mame/video/ninjaw.c svneol=native#text/plain

View File

@ -7,7 +7,6 @@
a reengineered Neo-Geo, with a few differences: no Z80, better sound chip, serial eeprom and 256 color tiles.
Plus a PIC12C508A microcontroller, probably for the protection checks (I've patched them out for now).
This driver should be merged with neogeo.c
Hardware description:
http://web.archive.org/web/20041018094226/http://www.andamiro.com/kor/business/hard_05.html
@ -55,22 +54,22 @@
#include "sound/ymz280b.h"
#include "machine/eepromser.h"
#include "machine/ticket.h"
#include "includes/neogeo.h"
class midas_state : public driver_device
{
public:
midas_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag),
m_gfxregs(*this, "gfxregs"),
m_maincpu(*this, "maincpu"),
m_eeprom(*this, "eeprom"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette") { }
m_palette(*this, "palette"),
m_sprgen(*this, "spritegen"),
m_screen(*this, "screen"),
m_zoomram(*this, "zoomtable")
{ }
UINT16 *m_gfxram;
required_shared_ptr<UINT16> m_gfxregs;
tilemap_t *m_tmap;
DECLARE_READ16_MEMBER(ret_ffff);
DECLARE_WRITE16_MEMBER(midas_gfxregs_w);
DECLARE_WRITE16_MEMBER(livequiz_coin_w);
@ -79,16 +78,25 @@ public:
DECLARE_WRITE16_MEMBER(hammer_motor_w);
DECLARE_WRITE16_MEMBER(hammer_led_w);
DECLARE_WRITE16_MEMBER(midas_eeprom_w);
DECLARE_WRITE16_MEMBER(midas_zoomtable_w);
DECLARE_DRIVER_INIT(livequiz);
TILE_GET_INFO_MEMBER(get_tile_info);
virtual void video_start();
UINT32 screen_update_midas(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
virtual void machine_start();
virtual void machine_reset();
UINT32 screen_update_midas(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(livequiz_irqhandler);
required_device<cpu_device> m_maincpu;
required_device<eeprom_serial_93cxx_device> m_eeprom;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_device<neosprite_midas_device> m_sprgen;
required_device<screen_device> m_screen;
required_shared_ptr<UINT16> m_zoomram;
void screen_eof_midas(screen_device &screen, bool state);
};
@ -96,122 +104,18 @@ public:
TILE_GET_INFO_MEMBER(midas_state::get_tile_info)
{
UINT16 code = m_gfxram[ tile_index + 0x7000 ];
SET_TILE_INFO_MEMBER(1, code & 0xfff, (code >> 12) & 0xf, TILE_FLIPXY( 0 ));
}
void midas_state::video_start()
{
m_gfxram = auto_alloc_array(machine(), UINT16, 0x20000/2);
m_tmap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(midas_state::get_tile_info),this), TILEMAP_SCAN_COLS,8,8,0x80,0x20);
m_tmap->set_transparent_pen(0);
}
void midas_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
UINT32 midas_state::screen_update_midas(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
UINT16 *s = m_gfxram + 0x8000;
UINT16 *codes = m_gfxram;
// fill with background color first
bitmap.fill(0x0, cliprect);
int sx_old = 0, sy_old = 0, ynum_old = 0, xzoom_old = 0;
int xdim, ydim, xscale, yscale;
int i,y;
m_sprgen->draw_sprites(bitmap, cliprect.min_y);
for (i = 0; i < 0x180; i++,s++,codes+=0x40)
{
int zoom = s[0x000];
int sy = s[0x200];
int sx = s[0x400];
int xzoom = ((zoom >> 8) & 0x0f) + 1;
int yzoom = ((zoom >> 0) & 0x7f) + 1;
int ynum;
if (sy & 0x40)
{
ynum = ynum_old;
sx = sx_old + xzoom_old;
sy = sy_old;
if (sx >= 0x1f0)
sx -= 0x200;
}
else
{
ynum = sy & 0x3f;
sx = (sx >> 7);
sy = 0x200 - (sy >> 7);
if (sx >= 0x1f0)
sx -= 0x200;
if (ynum > 0x20)
ynum = 0x20;
}
ynum_old = ynum;
sx_old = sx;
sy_old = sy;
xzoom_old = xzoom;
// Use fixed point values (16.16), for accuracy
sx <<= 16;
sy <<= 16;
xdim = ( xzoom << 16 ) * 16 / 16;
ydim = ( yzoom << 16 ) * 16 / 0x80;
xscale = xdim / 16;
yscale = ydim / 16;
// Let's approximate to the nearest greater integer value
// to avoid holes in between tiles
if (xscale & 0xffff) xscale += (1<<16) / 16;
if (yscale & 0xffff) yscale += (1<<16) / 16;
// Draw the tiles
for (y = 0; y < ynum; y++)
{
UINT16 code = codes[y*2];
UINT16 attr = codes[y*2+1];
m_gfxdecode->gfx(0)->zoom_transpen(bitmap,cliprect,
code,
attr >> 8,
attr & 1, attr & 2,
sx / 0x10000, ((sy + y * ydim) / 0x10000)&0x1ff,
xscale, yscale, 0 );
}
}
}
UINT32 midas_state::screen_update_midas(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int layers_ctrl = -1;
#ifdef MAME_DEBUG
if ( machine().input().code_pressed(KEYCODE_Z) )
{
int msk = 0;
if (machine().input().code_pressed(KEYCODE_Q)) msk |= 1 << 0; // for m_tmap
if (machine().input().code_pressed(KEYCODE_A)) msk |= 1 << 1; // for sprites
if (msk != 0) layers_ctrl &= msk;
}
#endif
bitmap.fill(4095, cliprect);
if (layers_ctrl & 2) draw_sprites(bitmap,cliprect);
if (layers_ctrl & 1) m_tmap->draw(screen, bitmap, cliprect, 0, 0);
m_sprgen->draw_fixed_layer(bitmap, cliprect.min_y);
return 0;
}
@ -238,23 +142,34 @@ READ16_MEMBER(midas_state::ret_ffff)
WRITE16_MEMBER(midas_state::midas_gfxregs_w)
{
COMBINE_DATA( m_gfxregs + offset );
switch( offset )
/* accessing the LSB only is not mapped */
if (mem_mask != 0x00ff)
{
case 1:
/* accessing the MSB only stores same data in MSB and LSB */
if (mem_mask == 0xff00)
data = (data & 0xff00) | (data >> 8);
switch (offset)
{
UINT16 addr = m_gfxregs[0];
m_gfxram[addr] = data;
m_gfxregs[0] += m_gfxregs[2];
if ( addr >= 0x7000 && addr <= 0x7fff ) m_tmap->mark_tile_dirty(addr - 0x7000);
break;
case 0x00: m_sprgen->set_videoram_offset(data); break;
case 0x01: m_sprgen->set_videoram_data(data); break;
case 0x02: m_sprgen->set_videoram_modulo(data); break;
}
}
}
WRITE16_MEMBER(midas_state::midas_zoomtable_w)
{
COMBINE_DATA(&m_zoomram[offset]);
UINT8 *rgn = memregion("zoomy")->base();
if (ACCESSING_BITS_0_7)
{
rgn[offset+0x00000] = data & 0xff;
rgn[offset+0x10000] = data & 0xff;
}
}
/***************************************************************************************
Live Quiz Show
***************************************************************************************/
@ -297,7 +212,7 @@ static ADDRESS_MAP_START( livequiz_map, AS_PROGRAM, 16, midas_state )
AM_RANGE(0xba0000, 0xba0001) AM_READ_PORT("START3")
AM_RANGE(0xbc0000, 0xbc0001) AM_READ_PORT("PLAYER3")
AM_RANGE(0xd00000, 0xd1ffff) AM_RAM // zoom table?
AM_RANGE(0xd00000, 0xd1ffff) AM_RAM_WRITE(midas_zoomtable_w) AM_SHARE("zoomtable") // zoom table?
AM_RANGE(0xe00000, 0xe3ffff) AM_RAM
ADDRESS_MAP_END
@ -361,7 +276,7 @@ static ADDRESS_MAP_START( hammer_map, AS_PROGRAM, 16, midas_state )
AM_RANGE(0x9a0000, 0x9a0001) AM_WRITE(midas_eeprom_w )
AM_RANGE(0x9c0000, 0x9c0005) AM_WRITE(midas_gfxregs_w ) AM_SHARE("gfxregs")
AM_RANGE(0x9c0000, 0x9c0005) AM_WRITE(midas_gfxregs_w )
AM_RANGE(0xa00000, 0xa3ffff) AM_RAM_DEVWRITE("palette", palette_device, write) AM_SHARE("palette")
AM_RANGE(0xa40000, 0xa7ffff) AM_RAM
@ -380,7 +295,7 @@ static ADDRESS_MAP_START( hammer_map, AS_PROGRAM, 16, midas_state )
AM_RANGE(0xbc0004, 0xbc0005) AM_READ(hammer_sensor_r )
AM_RANGE(0xd00000, 0xd1ffff) AM_RAM // zoom table?
AM_RANGE(0xd00000, 0xd1ffff) AM_RAM_WRITE(midas_zoomtable_w) AM_SHARE("zoomtable") // zoom table?
AM_RANGE(0xe00000, 0xe3ffff) AM_RAM
ADDRESS_MAP_END
@ -389,17 +304,14 @@ ADDRESS_MAP_END
static const gfx_layout layout16x16x8 =
{
16,16,
RGN_FRAC(1,4),
RGN_FRAC(1,1),
8,
{
RGN_FRAC(3,4)+8,RGN_FRAC(3,4)+0,
RGN_FRAC(2,4)+8,RGN_FRAC(2,4)+0,
RGN_FRAC(1,4)+8,RGN_FRAC(1,4)+0,
RGN_FRAC(0,4)+8,RGN_FRAC(0,4)+0
56,48,40,32,24,16,8,0
},
{ STEP8(8*16*2+7,-1), STEP8(7,-1) },
{ STEP16(0,8*2) },
16*16*2
{ 0,1,2,3,4,5,6,7, 16*64+0, 6*64+1, 6*64+2, 6*64+3, 6*64+4, 6*64+5, 6*64+6, 6*64+7, },
{ 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64, 8*64, 9*64, 10*64, 11*64, 12*64, 13*64, 14*64, 15*64 },
16*128
};
static const gfx_layout layout8x8x8_2 =
@ -692,12 +604,35 @@ static INPUT_PORTS_START( hammer )
INPUT_PORTS_END
void midas_state::machine_start()
{
m_sprgen->set_pens((pen_t*)m_palette->pens());
m_sprgen->set_screen(m_screen);
m_sprgen->set_sprite_region(memregion("sprites"));
m_sprgen->set_fixed_regions(memregion("tiles"), memregion("tiles"));
}
void midas_state::machine_reset()
{
}
WRITE_LINE_MEMBER(midas_state::livequiz_irqhandler)
{
logerror("YMZ280 is generating an interrupt. State=%08x\n",state);
}
void midas_state::screen_eof_midas(screen_device &screen, bool state)
{
m_sprgen->buffer_vram();
}
static MACHINE_CONFIG_START( livequiz, midas_state )
/* basic machine hardware */
@ -709,12 +644,11 @@ static MACHINE_CONFIG_START( livequiz, midas_state )
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(60)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
MCFG_SCREEN_SIZE(320, 256)
MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 16, 256-16-1)
MCFG_SCREEN_RAW_PARAMS(NEOGEO_PIXEL_CLOCK, NEOGEO_HTOTAL, NEOGEO_HBEND, NEOGEO_HBSTART, NEOGEO_VTOTAL, NEOGEO_VBEND, NEOGEO_VBSTART)
MCFG_SCREEN_UPDATE_DRIVER(midas_state, screen_update_midas)
MCFG_SCREEN_PALETTE("palette")
MCFG_SCREEN_VBLANK_DRIVER(midas_state, screen_eof_midas)
MCFG_DEVICE_ADD("spritegen", NEOGEO_SPRITE_MIDAS, 0)
MCFG_GFXDECODE_ADD("gfxdecode", "palette", midas)
MCFG_PALETTE_ADD("palette", 0x10000)
@ -743,12 +677,11 @@ static MACHINE_CONFIG_START( hammer, midas_state )
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(60)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
MCFG_SCREEN_SIZE(320, 256)
MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 16, 256-16-1)
MCFG_SCREEN_RAW_PARAMS(NEOGEO_PIXEL_CLOCK, NEOGEO_HTOTAL, NEOGEO_HBEND, NEOGEO_HBSTART, NEOGEO_VTOTAL, NEOGEO_VBEND, NEOGEO_VBSTART)
MCFG_SCREEN_UPDATE_DRIVER(midas_state, screen_update_midas)
MCFG_SCREEN_PALETTE("palette")
MCFG_SCREEN_VBLANK_DRIVER(midas_state, screen_eof_midas)
MCFG_DEVICE_ADD("spritegen", NEOGEO_SPRITE_MIDAS, 0)
MCFG_GFXDECODE_ADD("gfxdecode", "palette", midas)
MCFG_PALETTE_ADD("palette", 0x10000)
@ -861,16 +794,19 @@ ROM_START( livequiz )
ROM_LOAD( "sub_pic12c508a.u4", 0x000000, 0x000400, CRC(e52ebdc4) SHA1(0f3af66b5ea184e49188e74a873699324a3930f1) )
ROM_REGION( 0x800000, "sprites", 0 )
ROM_LOAD( "flash.u15", 0x000000, 0x200000, CRC(d6eb56f1) SHA1(52d67bb25dd968c79eccb05159a578516b27e557) )
ROM_LOAD( "flash.u19", 0x200000, 0x200000, CRC(daa81532) SHA1(9e66bb4639b92c3d76b7918535f55883f22f24b2) )
ROM_LOAD( "flash.u16", 0x400000, 0x200000, CRC(4c9fd873) SHA1(6e185304ce29771265d3c48b0ef0e840d8bed02d) )
ROM_LOAD( "flash.u20", 0x600000, 0x200000, CRC(b540a8c7) SHA1(25b9b30c7d5ff1e410ea30580017e45590542561) )
ROM_LOAD32_BYTE( "flash.u15", 0x000000, 0x200000, CRC(d6eb56f1) SHA1(52d67bb25dd968c79eccb05159a578516b27e557) )
ROM_LOAD32_BYTE( "flash.u19", 0x000001, 0x200000, CRC(daa81532) SHA1(9e66bb4639b92c3d76b7918535f55883f22f24b2) )
ROM_LOAD32_BYTE( "flash.u16", 0x000002, 0x200000, CRC(4c9fd873) SHA1(6e185304ce29771265d3c48b0ef0e840d8bed02d) )
ROM_LOAD32_BYTE( "flash.u20", 0x000003, 0x200000, CRC(b540a8c7) SHA1(25b9b30c7d5ff1e410ea30580017e45590542561) )
ROM_REGION( 0x080000, "tiles", 0 )
ROM_LOAD( "27c4096.u23", 0x000000, 0x080000, CRC(25121de8) SHA1(edf24d87551639b871baf3243b452a4e2ba84107) )
ROM_REGION( 0x200000, "ymz", 0 )
ROM_LOAD( "flash.u5", 0x000000, 0x200000, CRC(dc062792) SHA1(ec415c918c47ce9d181f014cde317af5717600e4) )
ROM_REGION( 0x20000, "zoomy", ROMREGION_ERASE00 )
/* uploaded */
ROM_END
DRIVER_INIT_MEMBER(midas_state,livequiz)
@ -944,17 +880,17 @@ ROM_START( hammer )
ROM_LOAD16_WORD_SWAP( "p.u22", 0x000000, 0x200000, CRC(687f1596) SHA1(3dc5fb0af1e8c4f3a42ce4aad39635b1111831d8) )
ROM_REGION( 0x1000000, "sprites", 0 )
ROM_LOAD( "a0l.u44", 0x000000, 0x200000, CRC(b9cafd81) SHA1(24698970d1aea0907e2963c872ce61077f44c3af) )
ROM_LOAD( "a0h.u46", 0x200000, 0x200000, CRC(f60f188b) SHA1(486f26c473b46efb402662b2f374e361cd7b4284) )
ROM_LOAD32_BYTE( "a0l.u44", 0x000000, 0x200000, CRC(b9cafd81) SHA1(24698970d1aea0907e2963c872ce61077f44c3af) )
ROM_LOAD32_BYTE( "a0h.u46", 0x800000, 0x200000, CRC(f60f188b) SHA1(486f26c473b46efb402662b2f374e361cd7b4284) )
ROM_LOAD( "a1l.u48", 0x400000, 0x200000, CRC(82129cf9) SHA1(6d68e943854bc9e8ea555bf03107dc9e836ca4d9) )
ROM_LOAD( "a1h.u50", 0x600000, 0x200000, CRC(76897c90) SHA1(aded60d3db834598cd54ad9140eee7be4129cb27) )
ROM_LOAD32_BYTE( "a1l.u48", 0x000001, 0x200000, CRC(82129cf9) SHA1(6d68e943854bc9e8ea555bf03107dc9e836ca4d9) )
ROM_LOAD32_BYTE( "a1h.u50", 0x800001, 0x200000, CRC(76897c90) SHA1(aded60d3db834598cd54ad9140eee7be4129cb27) )
ROM_LOAD( "a2l.u45", 0x800000, 0x200000, CRC(d8086ee5) SHA1(9d5f2b3a0f903a69cfd1108ddf5ea61b571c3fe3) )
ROM_LOAD( "a2h.u47", 0xa00000, 0x200000, CRC(a64aa2df) SHA1(7e4eb049cd6a5971a455488a484f225763921614) )
ROM_LOAD32_BYTE( "a2l.u45", 0x000002, 0x200000, CRC(d8086ee5) SHA1(9d5f2b3a0f903a69cfd1108ddf5ea61b571c3fe3) )
ROM_LOAD32_BYTE( "a2h.u47", 0x800002, 0x200000, CRC(a64aa2df) SHA1(7e4eb049cd6a5971a455488a484f225763921614) )
ROM_LOAD( "a3l.u49", 0xc00000, 0x200000, CRC(4e83cf00) SHA1(e66a0b4eae0f46bf36126be3795cfac3ad3d4282) )
ROM_LOAD( "a3h.u51", 0xe00000, 0x200000, CRC(834de39f) SHA1(6e9867180ca20e64f60bad5cad82674ce8f45b7b) )
ROM_LOAD32_BYTE( "a3l.u49", 0x000003, 0x200000, CRC(4e83cf00) SHA1(e66a0b4eae0f46bf36126be3795cfac3ad3d4282) )
ROM_LOAD32_BYTE( "a3h.u51", 0x800003, 0x200000, CRC(834de39f) SHA1(6e9867180ca20e64f60bad5cad82674ce8f45b7b) )
ROM_REGION( 0x080000, "tiles", ROMREGION_ERASE )
// Use the tiles rom from livequiz (not present in this set) to show some debug text
@ -963,7 +899,10 @@ ROM_START( hammer )
ROM_REGION( 0x400000, "ymz", 0 )
ROM_LOAD( "s0.u25", 0x000000, 0x200000, CRC(c049a3e0) SHA1(0c7016c3128c170a84ad3f92fad1165775210e3d) )
ROM_LOAD( "s1.u26", 0x200000, 0x200000, CRC(9cc4b3ec) SHA1(b91a8747074a1032eb7f70a015d394fe8e896d7e) )
ROM_REGION( 0x20000, "zoomy", ROMREGION_ERASE00 )
/* uploaded */
ROM_END
GAME( 1999, livequiz, 0, livequiz, livequiz, midas_state, livequiz, ROT0, "Andamiro", "Live Quiz Show", GAME_IMPERFECT_GRAPHICS )
GAME( 1999, livequiz, 0, livequiz, livequiz, midas_state, livequiz, ROT0, "Andamiro", "Live Quiz Show", 0 )
GAME( 2000, hammer, 0, hammer, hammer, driver_device, 0, ROT0, "Andamiro", "Hammer", 0 )

View File

@ -457,9 +457,7 @@
*
*************************************/
// On scanline 224, /VBLANK goes low 56 mclks (14 pixels) from the rising edge of /HSYNC.
// Two mclks after /VBLANK goes low, the hardware sets a pending IRQ1 flip-flop.
#define NEOGEO_VBLANK_IRQ_HTIM (attotime::from_ticks(56+2, NEOGEO_MASTER_CLOCK))
// The display counter is automatically reloaded with the load register contents on scanline 224,
// 1146 mclks from the rising edge of /HSYNC.
@ -999,7 +997,7 @@ WRITE8_MEMBER(neogeo_state::system_control_w)
case 0x05:
if (m_type == NEOGEO_MVS)
{
neogeo_set_fixed_layer_source(bit);
m_sprgen->neogeo_set_fixed_layer_source(bit);
m_bank_audio_main->set_entry(bit);
}
break;
@ -1088,7 +1086,7 @@ void neogeo_state::set_output_data( UINT8 data )
DRIVER_INIT_MEMBER(neogeo_state,neogeo)
{
m_fixed_layer_bank_type = 0;
m_sprgen->m_fixed_layer_bank_type = 0;
}
@ -1143,6 +1141,12 @@ void neogeo_state::machine_start()
save_item(NAME(m_led2_value));
machine().save().register_postload(save_prepost_delegate(FUNC(neogeo_state::neogeo_postload), this));
m_sprgen->set_screen(m_screen);
m_sprgen->set_sprite_region(m_region_sprites);
m_sprgen->set_fixed_regions(m_region_fixed, m_region_fixedbios);
}
@ -1787,6 +1791,8 @@ MACHINE_CONFIG_START( neogeo_base, neogeo_state )
MCFG_SCREEN_RAW_PARAMS(NEOGEO_PIXEL_CLOCK, NEOGEO_HTOTAL, NEOGEO_HBEND, NEOGEO_HBSTART, NEOGEO_VTOTAL, NEOGEO_VBEND, NEOGEO_VBSTART)
MCFG_SCREEN_UPDATE_DRIVER(neogeo_state, screen_update_neogeo)
MCFG_DEVICE_ADD("spritegen", NEOGEO_SPRITE_OPTIMZIED, 0)
/* audio hardware */
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
@ -10208,7 +10214,7 @@ DRIVER_INIT_MEMBER(neogeo_state,fatfury2)
DRIVER_INIT_MEMBER(neogeo_state,zupapa)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0xbd);
}
@ -10229,7 +10235,7 @@ DRIVER_INIT_MEMBER(neogeo_state,kof99)
{
DRIVER_INIT_CALL(neogeo);
kof99_decrypt_68k();
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0x00);
kof99_install_protection();
}
@ -10237,7 +10243,7 @@ DRIVER_INIT_MEMBER(neogeo_state,kof99)
DRIVER_INIT_MEMBER(neogeo_state,kof99k)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0x00);
}
@ -10245,7 +10251,7 @@ DRIVER_INIT_MEMBER(neogeo_state,garou)
{
DRIVER_INIT_CALL(neogeo);
garou_decrypt_68k();
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0x06);
garou_install_protection();
}
@ -10254,7 +10260,7 @@ DRIVER_INIT_MEMBER(neogeo_state,garouh)
{
DRIVER_INIT_CALL(neogeo);
garouh_decrypt_68k();
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0x06);
garouh_install_protection();
}
@ -10270,7 +10276,7 @@ DRIVER_INIT_MEMBER(neogeo_state,mslug3)
{
DRIVER_INIT_CALL(neogeo);
mslug3_decrypt_68k();
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0xad);
mslug3_install_protection();
}
@ -10278,7 +10284,7 @@ DRIVER_INIT_MEMBER(neogeo_state,mslug3)
DRIVER_INIT_MEMBER(neogeo_state,mslug3h)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0xad);
}
@ -10293,7 +10299,7 @@ DRIVER_INIT_MEMBER(neogeo_state,kof2000)
{
DRIVER_INIT_CALL(neogeo);
kof2000_decrypt_68k();
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x00);
kof2000_install_protection();
@ -10302,7 +10308,7 @@ DRIVER_INIT_MEMBER(neogeo_state,kof2000)
DRIVER_INIT_MEMBER(neogeo_state,kof2000n)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x00);
}
@ -10310,7 +10316,7 @@ DRIVER_INIT_MEMBER(neogeo_state,kof2000n)
DRIVER_INIT_MEMBER(neogeo_state,kof2001)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof2000_neogeo_gfx_decrypt(0x1e);
neogeo_cmc50_m1_decrypt();
}
@ -10339,7 +10345,7 @@ DRIVER_INIT_MEMBER(neogeo_state,ct2k3sa)
DRIVER_INIT_MEMBER(neogeo_state,mslug4)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1; /* USA violent content screen is wrong -- not a bug, confirmed on real hardware! */
m_sprgen->m_fixed_layer_bank_type = 1; /* USA violent content screen is wrong -- not a bug, confirmed on real hardware! */
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x31);
neo_pcm2_snk_1999(8);
@ -10356,42 +10362,42 @@ DRIVER_INIT_MEMBER(neogeo_state,ms4plus)
DRIVER_INIT_MEMBER(neogeo_state,ganryu)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0x07);
}
DRIVER_INIT_MEMBER(neogeo_state,s1945p)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0x05);
}
DRIVER_INIT_MEMBER(neogeo_state,preisle2)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0x9f);
}
DRIVER_INIT_MEMBER(neogeo_state,bangbead)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0xf8);
}
DRIVER_INIT_MEMBER(neogeo_state,nitd)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0xff);
}
DRIVER_INIT_MEMBER(neogeo_state,sengoku3)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
kof99_neogeo_gfx_decrypt(0xfe);
}
@ -10399,7 +10405,7 @@ DRIVER_INIT_MEMBER(neogeo_state,rotd)
{
DRIVER_INIT_CALL(neogeo);
neo_pcm2_snk_1999(16);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x3f);
}
@ -10483,7 +10489,7 @@ DRIVER_INIT_MEMBER(neogeo_state,matrim)
DRIVER_INIT_CALL(neogeo);
matrim_decrypt_68k();
neo_pcm2_swap(1);
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x6a);
}
@ -10492,7 +10498,7 @@ DRIVER_INIT_MEMBER(neogeo_state,matrimbl)
{
DRIVER_INIT_CALL(neogeo);
matrim_decrypt_68k();
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
matrimbl_decrypt();
neogeo_sfix_decrypt(); /* required for text layer */
}
@ -10501,7 +10507,7 @@ DRIVER_INIT_MEMBER(neogeo_state,pnyaa)
{
DRIVER_INIT_CALL(neogeo);
neo_pcm2_snk_1999(4);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x2e);
}
@ -10511,7 +10517,7 @@ DRIVER_INIT_MEMBER(neogeo_state,mslug5)
DRIVER_INIT_CALL(neogeo);
mslug5_decrypt_68k();
neo_pcm2_swap(2);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x19);
install_pvc_protection();
@ -10537,7 +10543,7 @@ DRIVER_INIT_MEMBER(neogeo_state,ms5pcb)
svcpcb_gfx_decrypt();
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x19);
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
svcpcb_s1data_decrypt();
neo_pcm2_swap(2);
install_pvc_protection();
@ -10550,7 +10556,7 @@ DRIVER_INIT_MEMBER(neogeo_state,ms5plus)
cmc50_neogeo_gfx_decrypt(0x19);
neo_pcm2_swap(2);
neogeo_bootleg_sx_decrypt(1);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
neogeo_cmc50_m1_decrypt();
install_ms5plus_protection();
}
@ -10565,7 +10571,7 @@ DRIVER_INIT_MEMBER(neogeo_state,svcpcb)
kof2000_neogeo_gfx_decrypt(0x57);
svcpcb_s1data_decrypt();
neo_pcm2_swap(3);
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
install_pvc_protection();
install_banked_bios();
}
@ -10575,7 +10581,7 @@ DRIVER_INIT_MEMBER(neogeo_state,svc)
DRIVER_INIT_CALL(neogeo);
svc_px_decrypt();
neo_pcm2_swap(3);
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x57);
install_pvc_protection();
@ -10621,7 +10627,7 @@ DRIVER_INIT_MEMBER(neogeo_state,samsho5)
DRIVER_INIT_CALL(neogeo);
samsho5_decrypt_68k();
neo_pcm2_swap(4);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x0f);
}
@ -10658,7 +10664,7 @@ DRIVER_INIT_MEMBER(neogeo_state,kf2k3pcb)
kof2000_neogeo_gfx_decrypt(0x9d);
kf2k3pcb_decrypt_s1data();
neo_pcm2_swap(5);
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
install_pvc_protection();
m_maincpu->space(AS_PROGRAM).install_rom(0xc00000, 0xc7ffff, 0, 0x080000, memregion("mainbios")->base()); // 512k bios
}
@ -10668,7 +10674,7 @@ DRIVER_INIT_MEMBER(neogeo_state,kof2003)
DRIVER_INIT_CALL(neogeo);
kof2003_decrypt_68k();
neo_pcm2_swap(5);
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x9d);
install_pvc_protection();
@ -10679,7 +10685,7 @@ DRIVER_INIT_MEMBER(neogeo_state,kof2003h)
DRIVER_INIT_CALL(neogeo);
kof2003h_decrypt_68k();
neo_pcm2_swap(5);
m_fixed_layer_bank_type = 2;
m_sprgen->m_fixed_layer_bank_type = 2;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x9d);
install_pvc_protection();
@ -10719,7 +10725,7 @@ DRIVER_INIT_MEMBER(neogeo_state,samsh5sp)
DRIVER_INIT_CALL(neogeo);
samsh5sp_decrypt_68k();
neo_pcm2_swap(6);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0x0d);
}
@ -10727,7 +10733,7 @@ DRIVER_INIT_MEMBER(neogeo_state,samsh5sp)
DRIVER_INIT_MEMBER(neogeo_state,jockeygp)
{
DRIVER_INIT_CALL(neogeo);
m_fixed_layer_bank_type = 1;
m_sprgen->m_fixed_layer_bank_type = 1;
neogeo_cmc50_m1_decrypt();
kof2000_neogeo_gfx_decrypt(0xac);

View File

@ -6,19 +6,11 @@
#include "machine/upd1990a.h"
#include "machine/ng_memcard.h"
#include "video/neogeo_spr.h"
#define NEOGEO_MASTER_CLOCK (24000000)
#define NEOGEO_MAIN_CPU_CLOCK (NEOGEO_MASTER_CLOCK / 2)
#define NEOGEO_AUDIO_CPU_CLOCK (NEOGEO_MASTER_CLOCK / 6)
#define NEOGEO_YM2610_CLOCK (NEOGEO_MASTER_CLOCK / 3)
#define NEOGEO_PIXEL_CLOCK (NEOGEO_MASTER_CLOCK / 4)
#define NEOGEO_HTOTAL (0x180)
#define NEOGEO_HBEND (0x01e) /* this should really be 29.5 */
#define NEOGEO_HBSTART (0x15e) /* this should really be 349.5 */
#define NEOGEO_VTOTAL (0x108)
#define NEOGEO_VBEND (0x010)
#define NEOGEO_VBSTART (0x0f0)
#define NEOGEO_VSSTART (0x100)
// On scanline 224, /VBLANK goes low 56 mclks (14 pixels) from the rising edge of /HSYNC.
// Two mclks after /VBLANK goes low, the hardware sets a pending IRQ1 flip-flop.
#define NEOGEO_VBLANK_IRQ_HTIM (attotime::from_ticks(56+2, NEOGEO_MASTER_CLOCK))
class neogeo_state : public driver_device
@ -39,7 +31,8 @@ public:
m_save_ram(*this, "saveram"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_memcard(*this, "memcard")
m_memcard(*this, "memcard"),
m_sprgen(*this, "spritegen")
{ }
DECLARE_WRITE8_MEMBER(io_control_w);
@ -130,8 +123,7 @@ public:
TIMER_CALLBACK_MEMBER(display_position_interrupt_callback);
TIMER_CALLBACK_MEMBER(display_position_vblank_callback);
TIMER_CALLBACK_MEMBER(vblank_interrupt_callback);
TIMER_CALLBACK_MEMBER(auto_animation_timer_callback);
TIMER_CALLBACK_MEMBER(sprite_line_timer_callback);
DECLARE_DEVICE_IMAGE_LOAD_MEMBER(neo_cartridge);
// MVS-specific
@ -158,31 +150,17 @@ protected:
void neogeo_set_display_counter_msb(UINT16 data);
void neogeo_set_display_counter_lsb(UINT16 data);
void set_video_control( UINT16 data );
void optimize_sprite_data();
void draw_fixed_layer( bitmap_rgb32 &bitmap, int scanline );
void set_videoram_offset( UINT16 data );
UINT16 get_videoram_data( );
void set_videoram_data( UINT16 data);
void set_videoram_modulo( UINT16 data);
UINT16 get_videoram_modulo( );
void compute_rgb_weights( );
void regenerate_pens();
pen_t get_pen( UINT16 data );
void neogeo_set_palette_bank( UINT8 data );
void neogeo_set_screen_dark( UINT8 data );
void set_auto_animation_speed( UINT8 data);
void set_auto_animation_disabled( UINT8 data);
UINT8 neogeo_get_auto_animation_counter( );
void create_auto_animation_timer( );
void start_auto_animation_timer( );
void neogeo_set_fixed_layer_source( UINT8 data );
inline int rows_to_height(int rows);
inline int sprite_on_scanline(int scanline, int y, int rows);
void draw_sprites( bitmap_rgb32 &bitmap, int scanline );
void parse_sprites( int scanline );
void create_sprite_line_timer( );
void start_sprite_line_timer( );
UINT16 get_video_control( );
void audio_cpu_check_nmi();
void select_controller( UINT8 data );
void set_save_ram_unlock( UINT8 data );
@ -359,8 +337,6 @@ protected:
emu_timer *m_display_position_interrupt_timer;
emu_timer *m_display_position_vblank_timer;
emu_timer *m_vblank_interrupt_timer;
emu_timer *m_auto_animation_timer;
emu_timer *m_sprite_line_timer;
UINT32 m_display_counter;
UINT8 m_vblank_interrupt_pending;
UINT8 m_display_position_interrupt_pending;
@ -369,23 +345,8 @@ protected:
UINT8 m_vblank_level;
UINT8 m_raster_level;
UINT16 *m_videoram;
UINT16 m_vram_offset;
UINT16 m_vram_read_buffer;
UINT16 m_vram_modulo;
const UINT8 *m_region_zoomy;
dynamic_array<UINT8> m_sprite_gfx;
UINT32 m_sprite_gfx_address_mask;
UINT8 m_auto_animation_speed;
UINT8 m_auto_animation_disabled;
UINT8 m_auto_animation_counter;
UINT8 m_auto_animation_frame_counter;
UINT8 m_fixed_layer_source;
UINT8 m_fixed_layer_bank_type;
required_device<neosprite_optimized_device> m_sprgen;
UINT16 get_video_control( );
// color/palette related
// TODO: disentangle from the rest of the video emulation
@ -416,6 +377,8 @@ protected:
const UINT8 *address_0_7_xor;
UINT16 m_cartridge_ram[0x1000];
};

View File

@ -1524,6 +1524,7 @@ $(MAMEOBJ)/nasco.a: \
$(MAMEOBJ)/neogeo.a: \
$(DRIVERS)/neogeo.o $(VIDEO)/neogeo.o \
$(VIDEO)/neogeo_spr.o \
$(MACHINE)/neoboot.o \
$(MACHINE)/neocrypt.o \
$(MACHINE)/neoprot.o \

View File

@ -10,48 +10,6 @@
#define NUM_PENS (0x1000)
#define VERBOSE (0)
/*************************************
*
* Video RAM access
*
*************************************/
void neogeo_state::set_videoram_offset( UINT16 data )
{
m_vram_offset = (data & 0x8000 ? data & 0x87ff : data);
/* the read happens right away */
m_vram_read_buffer = m_videoram[m_vram_offset];
}
UINT16 neogeo_state::get_videoram_data( )
{
return m_vram_read_buffer;
}
void neogeo_state::set_videoram_data( UINT16 data)
{
m_videoram[m_vram_offset] = data;
/* auto increment/decrement the current offset - A15 is NOT affected */
set_videoram_offset((m_vram_offset & 0x8000) | ((m_vram_offset + m_vram_modulo) & 0x7fff));
}
void neogeo_state::set_videoram_modulo( UINT16 data)
{
m_vram_modulo = data;
}
UINT16 neogeo_state::get_videoram_modulo( )
{
return m_vram_modulo;
}
@ -185,519 +143,63 @@ WRITE16_MEMBER(neogeo_state::neogeo_paletteram_w)
/*************************************
*
* Auto animation
* Video system start
*
*************************************/
void neogeo_state::set_auto_animation_speed( UINT8 data)
void neogeo_state::video_start()
{
m_auto_animation_speed = data;
}
/* allocate memory not directly mapped */
m_palettes[0] = auto_alloc_array(machine(), UINT16, NUM_PENS);
m_palettes[1] = auto_alloc_array(machine(), UINT16, NUM_PENS);
m_pens = auto_alloc_array(machine(), pen_t, NUM_PENS);
compute_rgb_weights();
void neogeo_state::set_auto_animation_disabled( UINT8 data)
{
m_auto_animation_disabled = data;
}
memset(m_palettes[0], 0x00, NUM_PENS * sizeof(UINT16));
memset(m_palettes[1], 0x00, NUM_PENS * sizeof(UINT16));
memset(m_pens, 0x00, NUM_PENS * sizeof(pen_t));
save_pointer(NAME(m_palettes[0]), NUM_PENS);
save_pointer(NAME(m_palettes[1]), NUM_PENS);
save_item(NAME(m_screen_dark));
save_item(NAME(m_palette_bank));
machine().save().register_postload(save_prepost_delegate(FUNC(neogeo_state::regenerate_pens), this));
UINT8 neogeo_state::neogeo_get_auto_animation_counter( )
{
return m_auto_animation_counter;
}
TIMER_CALLBACK_MEMBER(neogeo_state::auto_animation_timer_callback)
{
if (m_auto_animation_frame_counter == 0)
{
m_auto_animation_frame_counter = m_auto_animation_speed;
m_auto_animation_counter += 1;
}
else
m_auto_animation_frame_counter = m_auto_animation_frame_counter - 1;
m_auto_animation_timer->adjust(m_screen->time_until_pos(NEOGEO_VSSTART));
}
void neogeo_state::create_auto_animation_timer( )
{
m_auto_animation_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(neogeo_state::auto_animation_timer_callback),this));
}
void neogeo_state::start_auto_animation_timer( )
{
m_auto_animation_timer->adjust(m_screen->time_until_pos(NEOGEO_VSSTART));
m_sprgen->set_pens(m_pens);
}
/*************************************
*
* Fixed layer
* Video system reset
*
*************************************/
void neogeo_state::neogeo_set_fixed_layer_source( UINT8 data )
void neogeo_state::video_reset()
{
m_fixed_layer_source = data;
}
void neogeo_state::draw_fixed_layer( bitmap_rgb32 &bitmap, int scanline )
{
int x;
UINT8* gfx_base = m_fixed_layer_source ? m_region_fixed->base() : m_region_fixedbios->base();
UINT32 addr_mask = ( m_fixed_layer_source ? m_region_fixed->bytes() : m_region_fixedbios->bytes() ) - 1;
UINT16 *video_data = &m_videoram[0x7000 | (scanline >> 3)];
UINT32 *pixel_addr = &bitmap.pix32(scanline, NEOGEO_HBEND);
int garouoffsets[32];
int banked = m_fixed_layer_source && (addr_mask > 0x1ffff);
/* thanks to Mr K for the garou & kof2000 banking info */
/* Build line banking table for Garou & MS3 before starting render */
if (banked && m_fixed_layer_bank_type == 1)
{
int garoubank = 0;
int k = 0;
int y = 0;
while (y < 32)
{
if (m_videoram[0x7500 + k] == 0x0200 && (m_videoram[0x7580 + k] & 0xff00) == 0xff00)
{
garoubank = m_videoram[0x7580 + k] & 3;
garouoffsets[y++] = garoubank;
}
garouoffsets[y++] = garoubank;
k += 2;
}
}
for (x = 0; x < 40; x++)
{
UINT16 code_and_palette = *video_data;
UINT16 code = code_and_palette & 0x0fff;
if (banked)
{
int y = scanline >> 3;
switch (m_fixed_layer_bank_type)
{
case 1:
/* Garou, MSlug 3 */
code += 0x1000 * (garouoffsets[(y - 2) & 31] ^ 3);
break;
case 2:
code += 0x1000 * (((m_videoram[0x7500 + ((y - 1) & 31) + 32 * (x / 6)] >> (5 - (x % 6)) * 2) & 3) ^ 3);
break;
}
}
{
UINT8 data;
int i;
UINT8 *gfx = &gfx_base[((code << 5) | (scanline & 0x07)) & addr_mask];
pen_t *char_pens = &m_pens[code_and_palette >> 12 << 4];
for (i = 0; i < 4; i++)
{
static const UINT32 pix_offsets[] = { 0x10, 0x18, 0x00, 0x08 };
data = gfx[pix_offsets[i]];
if (data & 0x0f)
*pixel_addr = char_pens[data & 0x0f];
pixel_addr++;
if (data & 0xf0)
*pixel_addr = char_pens[(data & 0xf0) >> 4];
pixel_addr++;
}
}
video_data = video_data + 0x20;
}
}
/*************************************
*
* Sprite hardware
* Video update
*
*************************************/
#define MAX_SPRITES_PER_SCREEN (381)
#define MAX_SPRITES_PER_LINE (96)
/* horizontal zoom table - verified on real hardware */
static const int zoom_x_tables[][16] =
UINT32 neogeo_state::screen_update_neogeo(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
{ 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 },
{ 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0 },
{ 0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 },
{ 0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0 },
{ 0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0 },
{ 0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0 },
{ 0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 },
{ 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 },
{ 1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0 },
{ 1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0 },
{ 1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1 },
{ 1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1 },
{ 1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1 },
{ 1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1 },
{ 1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1 },
{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }
};
// fill with background color first
bitmap.fill(m_pens[0x0fff], cliprect);
m_sprgen->draw_sprites(bitmap, cliprect.min_y);
inline int neogeo_state::rows_to_height(int rows)
{
if ((rows == 0) || (rows > 0x20))
rows = 0x20;
m_sprgen->draw_fixed_layer(bitmap, cliprect.min_y);
return rows * 0x10;
}
inline int neogeo_state::sprite_on_scanline(int scanline, int y, int rows)
{
/* check if the current scanline falls inside this sprite,
two possible scenerios, wrap around or not */
int max_y = (y + rows_to_height(rows) - 1) & 0x1ff;
return (((max_y >= y) && (scanline >= y) && (scanline <= max_y)) ||
((max_y < y) && ((scanline >= y) || (scanline <= max_y))));
}
void neogeo_state::draw_sprites( bitmap_rgb32 &bitmap, int scanline )
{
int sprite_index;
int max_sprite_index;
int y = 0;
int x = 0;
int rows = 0;
int zoom_y = 0;
int zoom_x = 0;
UINT16 *sprite_list;
/* select the active list */
if (scanline & 0x01)
sprite_list = &m_videoram[0x8680];
else
sprite_list = &m_videoram[0x8600];
/* optimization -- find last non-zero entry and only draw that many +1
sprite. This is not 100% correct as the hardware will keep drawing
the #0 sprite over and over, but we need the speed */
for (max_sprite_index = (MAX_SPRITES_PER_LINE - 1); max_sprite_index >= 0; max_sprite_index--)
{
if (sprite_list[max_sprite_index] != 0)
break;
}
/* add the +1 now, just in case the 0 at the end is real sprite */
if (max_sprite_index != (MAX_SPRITES_PER_LINE - 1))
max_sprite_index = max_sprite_index + 1;
for (sprite_index = 0; sprite_index <= max_sprite_index; sprite_index++)
{
UINT16 sprite_number = sprite_list[sprite_index] & 0x01ff;
UINT16 y_control = m_videoram[0x8200 | sprite_number];
UINT16 zoom_control = m_videoram[0x8000 | sprite_number];
/* if chained, go to next X coordinate and get new X zoom */
if (y_control & 0x40)
{
x = (x + zoom_x + 1) & 0x01ff;
zoom_x = (zoom_control >> 8) & 0x0f;
}
/* new block */
else
{
y = 0x200 - (y_control >> 7);
x = m_videoram[0x8400 | sprite_number] >> 7;
zoom_y = zoom_control & 0xff;
zoom_x = (zoom_control >> 8) & 0x0f;
rows = y_control & 0x3f;
}
/* skip if falls completely outside the screen */
if ((x >= 0x140) && (x <= 0x1f0))
continue;
/* double check the Y coordinate, in case somebody modified the sprite coordinate
since we buffered it */
if (sprite_on_scanline(scanline, y, rows))
{
int sprite_y;
int tile;
UINT8 sprite_y_and_tile;
offs_t attr_and_code_offs;
UINT16 attr;
UINT32 code;
const int *zoom_x_table;
UINT8 *gfx;
pen_t *line_pens;
int x_inc;
int sprite_line = (scanline - y) & 0x1ff;
int zoom_line = sprite_line & 0xff;
int invert = sprite_line & 0x100;
if (invert)
zoom_line ^= 0xff;
if (rows > 0x20)
{
zoom_line = zoom_line % ((zoom_y + 1) << 1);
if (zoom_line > zoom_y)
{
zoom_line = ((zoom_y + 1) << 1) - 1 - zoom_line;
invert = !invert;
}
}
sprite_y_and_tile = m_region_zoomy[(zoom_y << 8) | zoom_line];
sprite_y = sprite_y_and_tile & 0x0f;
tile = sprite_y_and_tile >> 4;
if (invert)
{
sprite_y ^= 0x0f;
tile ^= 0x1f;
}
attr_and_code_offs = (sprite_number << 6) | (tile << 1);
attr = m_videoram[attr_and_code_offs + 1];
code = ((attr << 12) & 0x70000) | m_videoram[attr_and_code_offs];
/* substitute auto animation bits */
if (!m_auto_animation_disabled)
{
if (attr & 0x0008)
code = (code & ~0x07) | (m_auto_animation_counter & 0x07);
else if (attr & 0x0004)
code = (code & ~0x03) | (m_auto_animation_counter & 0x03);
}
/* vertical flip? */
if (attr & 0x0002)
sprite_y ^= 0x0f;
zoom_x_table = zoom_x_tables[zoom_x];
/* compute offset in gfx ROM and mask it to the number of bits available */
gfx = &m_sprite_gfx[((code << 8) | (sprite_y << 4)) & m_sprite_gfx_address_mask];
line_pens = &m_pens[attr >> 8 << 4];
/* horizontal flip? */
if (attr & 0x0001)
{
gfx = gfx + 0x0f;
x_inc = -1;
}
else
x_inc = 1;
/* draw the line - no wrap-around */
if (x <= 0x01f0)
{
int i;
UINT32 *pixel_addr = &bitmap.pix32(scanline, x + NEOGEO_HBEND);
for (i = 0; i < 0x10; i++)
{
if (*zoom_x_table)
{
if (*gfx)
*pixel_addr = line_pens[*gfx];
pixel_addr++;
}
zoom_x_table++;
gfx += x_inc;
}
}
/* wrap-around */
else
{
int i;
int x_save = x;
UINT32 *pixel_addr = &bitmap.pix32(scanline, NEOGEO_HBEND);
for (i = 0; i < 0x10; i++)
{
if (*zoom_x_table)
{
if (x >= 0x200)
{
if (*gfx)
*pixel_addr = line_pens[*gfx];
pixel_addr++;
}
x++;
}
zoom_x_table++;
gfx += x_inc;
}
x = x_save;
}
}
}
}
void neogeo_state::parse_sprites( int scanline )
{
UINT16 sprite_number;
int y = 0;
int rows = 0;
UINT16 *sprite_list;
int active_sprite_count = 0;
/* select the active list */
if (scanline & 0x01)
sprite_list = &m_videoram[0x8680];
else
sprite_list = &m_videoram[0x8600];
/* scan all sprites */
for (sprite_number = 0; sprite_number < MAX_SPRITES_PER_SCREEN; sprite_number++)
{
UINT16 y_control = m_videoram[0x8200 | sprite_number];
/* if not chained, get Y position and height, otherwise use previous values */
if (~y_control & 0x40)
{
y = 0x200 - (y_control >> 7);
rows = y_control & 0x3f;
}
/* skip sprites with 0 rows */
if (rows == 0)
continue;
if (!sprite_on_scanline(scanline, y, rows))
continue;
/* sprite is on this scanline, add it to active list */
*sprite_list = sprite_number;
sprite_list++;
/* increment sprite count, and if we reached the max, bail out */
active_sprite_count++;
if (active_sprite_count == MAX_SPRITES_PER_LINE)
break;
}
/* fill the rest of the sprite list with 0, including one extra entry */
memset(sprite_list, 0, sizeof(sprite_list[0]) * (MAX_SPRITES_PER_LINE - active_sprite_count + 1));
}
TIMER_CALLBACK_MEMBER(neogeo_state::sprite_line_timer_callback)
{
int scanline = param;
/* we are at the beginning of a scanline -
we need to draw the previous scanline and parse the sprites on the current one */
if (scanline != 0)
m_screen->update_partial(scanline - 1);
parse_sprites(scanline);
/* let's come back at the beginning of the next line */
scanline = (scanline + 1) % NEOGEO_VTOTAL;
m_sprite_line_timer->adjust(m_screen->time_until_pos(scanline), scanline);
}
void neogeo_state::create_sprite_line_timer( )
{
m_sprite_line_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(neogeo_state::sprite_line_timer_callback),this));
}
void neogeo_state::start_sprite_line_timer( )
{
m_sprite_line_timer->adjust(m_screen->time_until_pos(0));
}
void neogeo_state::optimize_sprite_data()
{
/* convert the sprite graphics data into a format that
allows faster blitting */
UINT8 *src;
UINT8 *dest;
UINT32 mask;
UINT32 len;
UINT32 bit;
/* get mask based on the length rounded up to the nearest
power of 2 */
mask = 0xffffffff;
len = m_region_sprites->bytes();
for (bit = 0x80000000; bit != 0; bit >>= 1)
{
if ((len * 2 - 1) & bit)
break;
mask >>= 1;
}
m_sprite_gfx.resize(mask + 1);
m_sprite_gfx_address_mask = mask;
src = m_region_sprites->base();
dest = m_sprite_gfx;
for (unsigned i = 0; i < len; i += 0x80, src += 0x80)
{
for (unsigned y = 0; y < 0x10; y++)
{
for (unsigned x = 0; x < 8; x++)
{
*(dest++) = (((src[0x43 | (y << 2)] >> x) & 0x01) << 3) |
(((src[0x41 | (y << 2)] >> x) & 0x01) << 2) |
(((src[0x42 | (y << 2)] >> x) & 0x01) << 1) |
(((src[0x40 | (y << 2)] >> x) & 0x01) << 0);
}
for (unsigned x = 0; x < 8; x++)
{
*(dest++) = (((src[0x03 | (y << 2)] >> x) & 0x01) << 3) |
(((src[0x01 | (y << 2)] >> x) & 0x01) << 2) |
(((src[0x02 | (y << 2)] >> x) & 0x01) << 1) |
(((src[0x00 | (y << 2)] >> x) & 0x01) << 0);
}
}
}
return 0;
}
@ -740,7 +242,7 @@ UINT16 neogeo_state::get_video_control( )
if (v_counter >= 0x200)
v_counter = v_counter - NEOGEO_VTOTAL;
ret = (v_counter << 7) | (neogeo_get_auto_animation_counter() & 0x0007);
ret = (v_counter << 7) | (m_sprgen->neogeo_get_auto_animation_counter() & 0x0007);
if (VERBOSE) logerror("%s: video_control read (%04x)\n", machine().describe_context(), ret);
@ -752,8 +254,8 @@ void neogeo_state::set_video_control( UINT16 data )
{
if (VERBOSE) logerror("%s: video control write %04x\n", machine().describe_context(), data);
set_auto_animation_speed(data >> 8);
set_auto_animation_disabled(data & 0x0008);
m_sprgen->set_auto_animation_speed(data >> 8);
m_sprgen->set_auto_animation_disabled(data & 0x0008);
neogeo_set_display_position_interrupt_control(data & 0x00f0);
}
@ -772,8 +274,8 @@ READ16_MEMBER(neogeo_state::neogeo_video_register_r)
{
default:
case 0x00:
case 0x01: ret = get_videoram_data(); break;
case 0x02: ret = get_videoram_modulo(); break;
case 0x01: ret = m_sprgen->get_videoram_data(); break;
case 0x02: ret = m_sprgen->get_videoram_modulo(); break;
case 0x03: ret = get_video_control(); break;
}
}
@ -793,9 +295,9 @@ WRITE16_MEMBER(neogeo_state::neogeo_video_register_w)
switch (offset)
{
case 0x00: set_videoram_offset(data); break;
case 0x01: set_videoram_data(data); break;
case 0x02: set_videoram_modulo(data); break;
case 0x00: m_sprgen->set_videoram_offset(data); break;
case 0x01: m_sprgen->set_videoram_data(data); break;
case 0x02: m_sprgen->set_videoram_modulo(data); break;
case 0x03: set_video_control(data); break;
case 0x04: neogeo_set_display_counter_msb(data); break;
case 0x05: neogeo_set_display_counter_lsb(data); break;
@ -806,93 +308,3 @@ WRITE16_MEMBER(neogeo_state::neogeo_video_register_w)
}
/*************************************
*
* Video system start
*
*************************************/
void neogeo_state::video_start()
{
/* allocate memory not directly mapped */
m_palettes[0] = auto_alloc_array(machine(), UINT16, NUM_PENS);
m_palettes[1] = auto_alloc_array(machine(), UINT16, NUM_PENS);
m_pens = auto_alloc_array(machine(), pen_t, NUM_PENS);
m_videoram = auto_alloc_array(machine(), UINT16, 0x8000 + 0x800);
/* clear allocated memory */
memset(m_palettes[0], 0x00, NUM_PENS * sizeof(UINT16));
memset(m_palettes[1], 0x00, NUM_PENS * sizeof(UINT16));
memset(m_pens, 0x00, NUM_PENS * sizeof(pen_t));
memset(m_videoram, 0x00, (0x8000 + 0x800) * sizeof(UINT16));
compute_rgb_weights();
create_sprite_line_timer();
create_auto_animation_timer();
m_sprite_gfx_address_mask = 0;
optimize_sprite_data();
/* initialize values that are not modified on a reset */
m_vram_offset = 0;
m_vram_read_buffer = 0;
m_vram_modulo = 0;
m_auto_animation_speed = 0;
m_auto_animation_disabled = 0;
m_auto_animation_counter = 0;
m_auto_animation_frame_counter = 0;
/* register for state saving */
save_pointer(NAME(m_palettes[0]), NUM_PENS);
save_pointer(NAME(m_palettes[1]), NUM_PENS);
save_pointer(NAME(m_videoram), 0x8000 + 0x800);
save_item(NAME(m_vram_offset));
save_item(NAME(m_vram_read_buffer));
save_item(NAME(m_vram_modulo));
save_item(NAME(m_fixed_layer_source));
save_item(NAME(m_screen_dark));
save_item(NAME(m_palette_bank));
save_item(NAME(m_auto_animation_speed));
save_item(NAME(m_auto_animation_disabled));
save_item(NAME(m_auto_animation_counter));
save_item(NAME(m_auto_animation_frame_counter));
machine().save().register_postload(save_prepost_delegate(FUNC(neogeo_state::regenerate_pens), this));
m_region_zoomy = memregion("zoomy")->base();
}
/*************************************
*
* Video system reset
*
*************************************/
void neogeo_state::video_reset()
{
start_sprite_line_timer();
start_auto_animation_timer();
}
/*************************************
*
* Video update
*
*************************************/
UINT32 neogeo_state::screen_update_neogeo(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
// fill with background color first
bitmap.fill(m_pens[0x0fff], cliprect);
draw_sprites(bitmap, cliprect.min_y);
draw_fixed_layer(bitmap, cliprect.min_y);
return 0;
}

838
src/mame/video/neogeo_spr.c Normal file
View File

@ -0,0 +1,838 @@
/* NeoGeo sprites (and fixed text layer) */
#include "emu.h"
#include "neogeo_spr.h"
// pure virtual functions
//const device_type NEOGEO_SPRITE_BASE = &device_creator<neosprite_base_device>;
/*
neosprite_base_device::neosprite_base_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, NEOGEO_SPRITE_BASE, "Neogeo Sprites", tag, owner, clock, "neospritebase", __FILE__),
m_bppshift(4)
{
}
*/
neosprite_base_device::neosprite_base_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock, device_type type)
: device_t(mconfig, type, "Neogeo Sprites", tag, owner, clock, "neosprite", __FILE__),
m_bppshift(4)
{
}
void neosprite_base_device::device_start()
{
m_videoram = auto_alloc_array(machine(), UINT16, 0x8000 + 0x800);
m_videoram_drawsource = m_videoram;
/* clear allocated memory */
memset(m_videoram, 0x00, (0x8000 + 0x800) * sizeof(UINT16));
create_sprite_line_timer();
create_auto_animation_timer();
/* initialize values that are not modified on a reset */
m_vram_offset = 0;
m_vram_read_buffer = 0;
m_vram_modulo = 0;
m_auto_animation_speed = 0;
m_auto_animation_disabled = 0;
m_auto_animation_counter = 0;
m_auto_animation_frame_counter = 0;
/* register for state saving */
save_pointer(NAME(m_videoram), 0x8000 + 0x800);
save_item(NAME(m_vram_offset));
save_item(NAME(m_vram_read_buffer));
save_item(NAME(m_vram_modulo));
save_item(NAME(m_fixed_layer_source));
save_item(NAME(m_auto_animation_speed));
save_item(NAME(m_auto_animation_disabled));
save_item(NAME(m_auto_animation_counter));
save_item(NAME(m_auto_animation_frame_counter));
m_region_zoomy = memregion(":zoomy")->base();
}
void neosprite_base_device::device_reset()
{
//m_sprite_gfx_address_mask = 0;
optimize_sprite_data();
start_sprite_line_timer();
start_auto_animation_timer();
}
/*************************************
*
* Video RAM access
*
*************************************/
void neosprite_base_device::set_videoram_offset( UINT16 data )
{
m_vram_offset = (data & 0x8000 ? data & 0x87ff : data);
/* the read happens right away */
m_vram_read_buffer = m_videoram[m_vram_offset];
}
UINT16 neosprite_base_device::get_videoram_data( )
{
return m_vram_read_buffer;
}
void neosprite_base_device::set_videoram_data( UINT16 data)
{
m_videoram[m_vram_offset] = data;
/* auto increment/decrement the current offset - A15 is NOT affected */
set_videoram_offset((m_vram_offset & 0x8000) | ((m_vram_offset + m_vram_modulo) & 0x7fff));
}
void neosprite_base_device::set_videoram_modulo( UINT16 data)
{
m_vram_modulo = data;
}
UINT16 neosprite_base_device::get_videoram_modulo( )
{
return m_vram_modulo;
}
/*************************************
*
* Auto animation
*
*************************************/
void neosprite_base_device::set_auto_animation_speed( UINT8 data)
{
m_auto_animation_speed = data;
}
void neosprite_base_device::set_auto_animation_disabled( UINT8 data)
{
m_auto_animation_disabled = data;
}
UINT8 neosprite_base_device::neogeo_get_auto_animation_counter( )
{
return m_auto_animation_counter;
}
TIMER_CALLBACK_MEMBER(neosprite_base_device::auto_animation_timer_callback)
{
if (m_auto_animation_frame_counter == 0)
{
m_auto_animation_frame_counter = m_auto_animation_speed;
m_auto_animation_counter += 1;
}
else
m_auto_animation_frame_counter = m_auto_animation_frame_counter - 1;
m_auto_animation_timer->adjust(m_screen->time_until_pos(NEOGEO_VSSTART));
}
void neosprite_base_device::create_auto_animation_timer( )
{
m_auto_animation_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(neosprite_base_device::auto_animation_timer_callback),this));
}
void neosprite_base_device::start_auto_animation_timer( )
{
m_auto_animation_timer->adjust(m_screen->time_until_pos(NEOGEO_VSSTART));
}
/*************************************
*
* Fixed layer
*
*************************************/
void neosprite_base_device::neogeo_set_fixed_layer_source( UINT8 data )
{
m_fixed_layer_source = data;
}
void neosprite_base_device::draw_fixed_layer( bitmap_rgb32 &bitmap, int scanline )
{
int x;
UINT8* gfx_base = m_fixed_layer_source ? m_region_fixed->base() : m_region_fixedbios->base();
UINT32 addr_mask = ( m_fixed_layer_source ? m_region_fixed->bytes() : m_region_fixedbios->bytes() ) - 1;
UINT16 *video_data = &m_videoram_drawsource[0x7000 | (scanline >> 3)];
UINT32 *pixel_addr = &bitmap.pix32(scanline, NEOGEO_HBEND);
int garouoffsets[32];
int banked = m_fixed_layer_source && (addr_mask > 0x1ffff);
/* thanks to Mr K for the garou & kof2000 banking info */
/* Build line banking table for Garou & MS3 before starting render */
if (banked && m_fixed_layer_bank_type == 1)
{
int garoubank = 0;
int k = 0;
int y = 0;
while (y < 32)
{
if (m_videoram_drawsource[0x7500 + k] == 0x0200 && (m_videoram_drawsource[0x7580 + k] & 0xff00) == 0xff00)
{
garoubank = m_videoram_drawsource[0x7580 + k] & 3;
garouoffsets[y++] = garoubank;
}
garouoffsets[y++] = garoubank;
k += 2;
}
}
for (x = 0; x < 40; x++)
{
UINT16 code_and_palette = *video_data;
UINT16 code = code_and_palette & 0x0fff;
if (banked)
{
int y = scanline >> 3;
switch (m_fixed_layer_bank_type)
{
case 1:
/* Garou, MSlug 3 */
code += 0x1000 * (garouoffsets[(y - 2) & 31] ^ 3);
break;
case 2:
code += 0x1000 * (((m_videoram_drawsource[0x7500 + ((y - 1) & 31) + 32 * (x / 6)] >> (5 - (x % 6)) * 2) & 3) ^ 3);
break;
}
}
{
int i;
int gfx_offset = ((code << 5) | (scanline & 0x07)) & addr_mask;
pen_t *char_pens;
char_pens = &m_pens[code_and_palette >> 12 << m_bppshift];
static const UINT32 pix_offsets[] = { 0x10, 0x18, 0x00, 0x08 };
for (i = 0; i < 4; i++)
{
draw_fixed_layer_2pixels(pixel_addr, gfx_offset + pix_offsets[i], gfx_base, char_pens);
}
}
video_data = video_data + 0x20;
}
}
inline void neosprite_base_device::draw_fixed_layer_2pixels(UINT32*&pixel_addr, int offset, UINT8* gfx_base, pen_t* char_pens)
{
UINT8 data = gfx_base[offset];
if (data & 0x0f)
*pixel_addr = char_pens[data & 0x0f];
pixel_addr++;
if (data & 0xf0)
*pixel_addr = char_pens[(data & 0xf0) >> 4];
pixel_addr++;
}
/*************************************
*
* Sprite hardware
*
*************************************/
#define MAX_SPRITES_PER_SCREEN (381)
#define MAX_SPRITES_PER_LINE (96)
/* horizontal zoom table - verified on real hardware */
static const int zoom_x_tables[][16] =
{
{ 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 },
{ 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0 },
{ 0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 },
{ 0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0 },
{ 0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0 },
{ 0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0 },
{ 0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 },
{ 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 },
{ 1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0 },
{ 1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0 },
{ 1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1 },
{ 1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1 },
{ 1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1 },
{ 1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1 },
{ 1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1 },
{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }
};
inline int neosprite_base_device::rows_to_height(int rows)
{
if ((rows == 0) || (rows > 0x20))
rows = 0x20;
return rows * 0x10;
}
inline int neosprite_base_device::sprite_on_scanline(int scanline, int y, int rows)
{
/* check if the current scanline falls inside this sprite,
two possible scenerios, wrap around or not */
int max_y = (y + rows_to_height(rows) - 1) & 0x1ff;
return (((max_y >= y) && (scanline >= y) && (scanline <= max_y)) ||
((max_y < y) && ((scanline >= y) || (scanline <= max_y))));
}
void neosprite_base_device::draw_sprites( bitmap_rgb32 &bitmap, int scanline )
{
int sprite_index;
int max_sprite_index;
int y = 0;
int x = 0;
int rows = 0;
int zoom_y = 0;
int zoom_x = 0;
UINT16 *sprite_list;
/* select the active list */
if (scanline & 0x01)
sprite_list = &m_videoram_drawsource[0x8680];
else
sprite_list = &m_videoram_drawsource[0x8600];
/* optimization -- find last non-zero entry and only draw that many +1
sprite. This is not 100% correct as the hardware will keep drawing
the #0 sprite over and over, but we need the speed */
for (max_sprite_index = (MAX_SPRITES_PER_LINE - 1); max_sprite_index >= 0; max_sprite_index--)
{
if (sprite_list[max_sprite_index] != 0)
break;
}
/* add the +1 now, just in case the 0 at the end is real sprite */
if (max_sprite_index != (MAX_SPRITES_PER_LINE - 1))
max_sprite_index = max_sprite_index + 1;
for (sprite_index = 0; sprite_index <= max_sprite_index; sprite_index++)
{
UINT16 sprite_number = sprite_list[sprite_index] & 0x01ff;
UINT16 y_control = m_videoram_drawsource[0x8200 | sprite_number];
UINT16 zoom_control = m_videoram_drawsource[0x8000 | sprite_number];
/* if chained, go to next X coordinate and get new X zoom */
if (y_control & 0x40)
{
x = (x + zoom_x + 1) & 0x01ff;
zoom_x = (zoom_control >> 8) & 0x0f;
}
/* new block */
else
{
y = 0x200 - (y_control >> 7);
x = m_videoram_drawsource[0x8400 | sprite_number] >> 7;
zoom_y = (zoom_control & 0xff);
zoom_x = (zoom_control >> 8) & 0x0f;
rows = y_control & 0x3f;
}
/* skip if falls completely outside the screen */
if ((x >= 0x140) && (x <= 0x1f0))
continue;
/* double check the Y coordinate, in case somebody modified the sprite coordinate
since we buffered it */
if (sprite_on_scanline(scanline, y, rows))
{
int sprite_y;
int tile;
UINT8 sprite_y_and_tile;
offs_t attr_and_code_offs;
UINT16 attr;
UINT32 code;
const int *zoom_x_table;
pen_t *line_pens;
int x_inc;
int sprite_line = (scanline - y) & 0x1ff;
int zoom_line = sprite_line & 0xff;
int invert = sprite_line & 0x100;
if (invert)
zoom_line ^= 0xff;
if (rows > 0x20)
{
zoom_line = zoom_line % ((zoom_y + 1) << 1);
if (zoom_line > zoom_y)
{
zoom_line = ((zoom_y + 1) << 1) - 1 - zoom_line;
invert = !invert;
}
}
sprite_y_and_tile = m_region_zoomy[(zoom_y << 8) | zoom_line];
sprite_y = sprite_y_and_tile & 0x0f;
tile = sprite_y_and_tile >> 4;
if (invert)
{
sprite_y ^= 0x0f;
tile ^= 0x1f;
}
attr_and_code_offs = (sprite_number << 6) | (tile << 1);
attr = m_videoram_drawsource[attr_and_code_offs + 1];
code = ((attr << 12) & 0x70000) | m_videoram_drawsource[attr_and_code_offs];
/* substitute auto animation bits */
if (!m_auto_animation_disabled)
{
if (attr & 0x0008)
code = (code & ~0x07) | (m_auto_animation_counter & 0x07);
else if (attr & 0x0004)
code = (code & ~0x03) | (m_auto_animation_counter & 0x03);
}
/* vertical flip? */
if (attr & 0x0002)
sprite_y ^= 0x0f;
zoom_x_table = zoom_x_tables[zoom_x];
/* compute offset in gfx ROM and mask it to the number of bits available */
int gfx_base = ((code << 8) | (sprite_y << 4)) & m_sprite_gfx_address_mask;
line_pens = &m_pens[attr >> 8 << m_bppshift];
/* horizontal flip? */
if (attr & 0x0001)
{
gfx_base = gfx_base + 0x0f;
x_inc = -1;
}
else
x_inc = 1;
/* draw the line - no wrap-around */
if (x <= 0x01f0)
{
int i;
UINT32 *pixel_addr = &bitmap.pix32(scanline, x + NEOGEO_HBEND);
for (i = 0; i < 0x10; i++)
{
if (*zoom_x_table)
{
draw_pixel(gfx_base, pixel_addr, line_pens);
pixel_addr++;
}
zoom_x_table++;
gfx_base += x_inc;
}
}
/* wrap-around */
else
{
int i;
int x_save = x;
UINT32 *pixel_addr = &bitmap.pix32(scanline, NEOGEO_HBEND);
for (i = 0; i < 0x10; i++)
{
if (*zoom_x_table)
{
if (x >= 0x200)
{
draw_pixel(gfx_base, pixel_addr, line_pens);
pixel_addr++;
}
x++;
}
zoom_x_table++;
gfx_base += x_inc;
}
x = x_save;
}
}
}
}
void neosprite_base_device::parse_sprites( int scanline )
{
UINT16 sprite_number;
int y = 0;
int rows = 0;
UINT16 *sprite_list;
int active_sprite_count = 0;
/* select the active list */
if (scanline & 0x01)
sprite_list = &m_videoram_drawsource[0x8680];
else
sprite_list = &m_videoram_drawsource[0x8600];
/* scan all sprites */
for (sprite_number = 0; sprite_number < MAX_SPRITES_PER_SCREEN; sprite_number++)
{
UINT16 y_control = m_videoram_drawsource[0x8200 | sprite_number];
/* if not chained, get Y position and height, otherwise use previous values */
if (~y_control & 0x40)
{
y = 0x200 - (y_control >> 7);
rows = y_control & 0x3f;
}
/* skip sprites with 0 rows */
if (rows == 0)
continue;
if (!sprite_on_scanline(scanline, y, rows))
continue;
/* sprite is on this scanline, add it to active list */
*sprite_list = sprite_number;
sprite_list++;
/* increment sprite count, and if we reached the max, bail out */
active_sprite_count++;
if (active_sprite_count == MAX_SPRITES_PER_LINE)
break;
}
/* fill the rest of the sprite list with 0, including one extra entry */
memset(sprite_list, 0, sizeof(sprite_list[0]) * (MAX_SPRITES_PER_LINE - active_sprite_count + 1));
}
TIMER_CALLBACK_MEMBER(neosprite_base_device::sprite_line_timer_callback)
{
int scanline = param;
/* we are at the beginning of a scanline -
we need to draw the previous scanline and parse the sprites on the current one */
if (scanline != 0)
m_screen->update_partial(scanline - 1);
parse_sprites(scanline);
/* let's come back at the beginning of the next line */
scanline = (scanline + 1) % NEOGEO_VTOTAL;
m_sprite_line_timer->adjust(m_screen->time_until_pos(scanline), scanline);
}
void neosprite_base_device::create_sprite_line_timer( )
{
m_sprite_line_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(neosprite_base_device::sprite_line_timer_callback),this));
}
void neosprite_base_device::start_sprite_line_timer( )
{
m_sprite_line_timer->adjust(m_screen->time_until_pos(0));
}
UINT32 neosprite_base_device::get_region_mask(memory_region* rgn)
{
/* convert the sprite graphics data into a format that
allows faster blitting */
UINT32 mask;
UINT32 len;
UINT32 bit;
/* get mask based on the length rounded up to the nearest
power of 2 */
mask = 0xffffffff;
len = rgn->bytes();
for (bit = 0x80000000; bit != 0; bit >>= 1)
{
if ((len * 2 - 1) & bit)
break;
mask >>= 1;
}
return mask;
}
void neosprite_base_device::optimize_sprite_data()
{
// this does nothing in this implementation, it's used by neosprite_optimized_device
// m_sprite_gfx_address_mask gets set when the GFX region is assigned
return;
}
// these are for passing in pointers from the main system
void neosprite_base_device::set_sprite_region(memory_region* region_sprites)
{
m_region_sprites = region_sprites;
}
void neosprite_base_device::set_fixed_regions(memory_region* fix_cart, memory_region* fix_bios)
{
m_region_fixed = fix_cart;
m_region_fixedbios = fix_bios;
}
void neosprite_base_device::set_screen(screen_device* screen)
{
m_screen = screen;
}
void neosprite_base_device::set_pens(pen_t* pens)
{
m_pens = pens;
}
/*********************************************************************************************************************************/
/* Regular NeoGeo sprite handling - drawing directly from ROM (or RAM on NeoCD) */
/* */
/* note, we don't currently use this implementation, reference only */
/* if we do it will be important to ensure that all sprite regions are ^2 sizes - the optimized routine automatically allocates */
/* ^2 sized regions when pre-decoding, but obviously we don't here, so if we want to be safe we'll have to adjust the actual */
/* regions (alternatively I could add an additional size check in the draw routine, but that would be slower) */
/*********************************************************************************************************************************/
const device_type NEOGEO_SPRITE_REGULAR = &device_creator<neosprite_regular_device>;
neosprite_regular_device::neosprite_regular_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: neosprite_base_device(mconfig, tag, owner, clock, NEOGEO_SPRITE_REGULAR)
{
}
void neosprite_regular_device::set_sprite_region(memory_region* region_sprites)
{
m_region_sprites = region_sprites;
UINT32 mask = get_region_mask(m_region_sprites);
UINT32 proper_size = (mask + 1) >>1;
printf("lengths %08x %08x m_region_sprites", m_region_sprites->bytes(), proper_size);
if (m_region_sprites->bytes() != proper_size)
{
fatalerror("please use power of 2 region sizes with neosprite_base_device to ensure masking works correctly");
}
m_sprite_gfx_address_mask = mask;
}
inline void neosprite_regular_device::draw_pixel(int romaddr, UINT32* dst, pen_t *line_pens)
{
const UINT8* src = m_region_sprites->base() + (((romaddr &~0xff)>>1) | (((romaddr&0x8)^0x8)<<3) | ((romaddr & 0xf0) >> 2));
const int x = romaddr & 0x7;
const UINT8 gfx = (((src[0x3] >> x) & 0x01) << 3) |
(((src[0x1] >> x) & 0x01) << 2) |
(((src[0x2] >> x) & 0x01) << 1) |
(((src[0x0] >> x) & 0x01) << 0);
if (gfx)
*dst = line_pens[gfx];
}
/*********************************************************************************************************************************/
/* Regular NeoGeo sprite handling with pre-decode optimization */
/* */
/* this is closer to the old MAME implementation where the 4bpp graphics have been expanded to an easier to draw 8bpp format */
/* for additional speed */
/*********************************************************************************************************************************/
const device_type NEOGEO_SPRITE_OPTIMZIED = &device_creator<neosprite_optimized_device>;
neosprite_optimized_device::neosprite_optimized_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: neosprite_base_device(mconfig, tag, owner, clock, NEOGEO_SPRITE_OPTIMZIED)
{
}
void neosprite_optimized_device::optimize_sprite_data()
{
/* convert the sprite graphics data into a format that
allows faster blitting */
UINT8 *src;
UINT8 *dest;
UINT32 mask = get_region_mask(m_region_sprites);
m_sprite_gfx.resize(mask + 1);
m_sprite_gfx_address_mask = mask;
src = m_region_sprites->base();
dest = m_sprite_gfx;
for (unsigned i = 0; i < m_region_sprites->bytes(); i += 0x80, src += 0x80)
{
for (unsigned y = 0; y < 0x10; y++)
{
for (unsigned x = 0; x < 8; x++)
{
*(dest++) = (((src[0x43 | (y << 2)] >> x) & 0x01) << 3) |
(((src[0x41 | (y << 2)] >> x) & 0x01) << 2) |
(((src[0x42 | (y << 2)] >> x) & 0x01) << 1) |
(((src[0x40 | (y << 2)] >> x) & 0x01) << 0);
}
for (unsigned x = 0; x < 8; x++)
{
*(dest++) = (((src[0x03 | (y << 2)] >> x) & 0x01) << 3) |
(((src[0x01 | (y << 2)] >> x) & 0x01) << 2) |
(((src[0x02 | (y << 2)] >> x) & 0x01) << 1) |
(((src[0x00 | (y << 2)] >> x) & 0x01) << 0);
}
}
}
}
inline void neosprite_optimized_device::draw_pixel(int romaddr, UINT32* dst, pen_t *line_pens)
{
const UINT8 gfx = m_sprite_gfx[romaddr];
if (gfx)
*dst = line_pens[gfx];
}
/*********************************************************************************************************************************/
/* MIDAS specific sprite handling */
/* */
/* this is used by the midas.c hardware which is a reengineered NeoGeo, it has 8bbp tiles instead of 4bpp tiles */
/* and uploads the zoom table. The additional videoram buffering is a guess because 'hammer' is very glitchy without it */
/*********************************************************************************************************************************/
const device_type NEOGEO_SPRITE_MIDAS = &device_creator<neosprite_midas_device>;
neosprite_midas_device::neosprite_midas_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: neosprite_base_device(mconfig, tag, owner, clock, NEOGEO_SPRITE_MIDAS)
{
m_bppshift = 8;
}
inline void neosprite_midas_device::draw_pixel(int romaddr, UINT32* dst, pen_t *line_pens)
{
const UINT8* src = m_region_sprites->base() + (((romaddr &~0xff)) | (((romaddr&0x8)^0x8)<<4) | ((romaddr & 0xf0) >> 1));
const int x = romaddr & 0x7;
const UINT8 gfx =
(((src[0x7] >> x) & 0x01) << 7) |
(((src[0x3] >> x) & 0x01) << 6) |
(((src[0x6] >> x) & 0x01) << 5) |
(((src[0x2] >> x) & 0x01) << 4) |
(((src[0x5] >> x) & 0x01) << 3) |
(((src[0x1] >> x) & 0x01) << 2) |
(((src[0x4] >> x) & 0x01) << 1) |
(((src[0x0] >> x) & 0x01) << 0);
if (gfx)
*dst = line_pens[gfx];
}
void neosprite_midas_device::device_start()
{
neosprite_base_device::device_start();
m_videoram_buffer = auto_alloc_array(machine(), UINT16, 0x8000 + 0x800);
m_videoram_drawsource = m_videoram_buffer;
memset(m_videoram_buffer, 0x00, (0x8000 + 0x800) * sizeof(UINT16));
}
void neosprite_midas_device::buffer_vram()
{
memcpy(m_videoram_buffer, m_videoram, (0x8000 + 0x800) * sizeof(UINT16));
}
inline void neosprite_midas_device::draw_fixed_layer_2pixels(UINT32*&pixel_addr, int offset, UINT8* gfx_base, pen_t* char_pens)
{
UINT8 data;
data = ((gfx_base[(offset * 2)+0] & 0x0f)<<0) | ((gfx_base[(offset * 2)+1] & 0x0f)<<4);
if (data)
*pixel_addr = char_pens[data];
pixel_addr++;
data = ((gfx_base[(offset * 2)+0] & 0xf0)>>4) | ((gfx_base[(offset * 2)+1] & 0xf0)<<0);
if (data)
*pixel_addr = char_pens[data];
pixel_addr++;
}
void neosprite_midas_device::set_sprite_region(memory_region* region_sprites)
{
m_region_sprites = region_sprites;
UINT32 mask = get_region_mask(m_region_sprites);
m_sprite_gfx_address_mask = mask;
}

143
src/mame/video/neogeo_spr.h Normal file
View File

@ -0,0 +1,143 @@
#define VERBOSE (0)
// todo, move these back, currently the sprite code needs some of the values tho
#define NEOGEO_MASTER_CLOCK (24000000)
#define NEOGEO_MAIN_CPU_CLOCK (NEOGEO_MASTER_CLOCK / 2)
#define NEOGEO_AUDIO_CPU_CLOCK (NEOGEO_MASTER_CLOCK / 6)
#define NEOGEO_YM2610_CLOCK (NEOGEO_MASTER_CLOCK / 3)
#define NEOGEO_PIXEL_CLOCK (NEOGEO_MASTER_CLOCK / 4)
#define NEOGEO_HTOTAL (0x180)
#define NEOGEO_HBEND (0x01e) /* this should really be 29.5 */
#define NEOGEO_HBSTART (0x15e) /* this should really be 349.5 */
#define NEOGEO_VTOTAL (0x108)
#define NEOGEO_VBEND (0x010)
#define NEOGEO_VBSTART (0x0f0)
#define NEOGEO_VSSTART (0x100)
// todo, sort out what needs to be public and make the rest private/protected
class neosprite_base_device : public device_t
{
public:
neosprite_base_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock, device_type type);
// neosprite_base_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual void optimize_sprite_data();
virtual void draw_fixed_layer_2pixels(UINT32*&pixel_addr, int offset, UINT8* gfx_base, pen_t* char_pens);
void draw_fixed_layer( bitmap_rgb32 &bitmap, int scanline );
void set_videoram_offset( UINT16 data );
UINT16 get_videoram_data( );
void set_videoram_data( UINT16 data);
void set_videoram_modulo( UINT16 data);
UINT16 get_videoram_modulo( );
void set_auto_animation_speed( UINT8 data);
void set_auto_animation_disabled( UINT8 data);
UINT8 neogeo_get_auto_animation_counter( );
void create_auto_animation_timer( );
void start_auto_animation_timer( );
void neogeo_set_fixed_layer_source( UINT8 data );
inline int rows_to_height(int rows);
inline int sprite_on_scanline(int scanline, int y, int rows);
virtual void draw_pixel(int romaddr, UINT32* dst, pen_t *line_pens) = 0;
void draw_sprites( bitmap_rgb32 &bitmap, int scanline );
void parse_sprites( int scanline );
void create_sprite_line_timer( );
void start_sprite_line_timer( );
virtual void set_sprite_region(memory_region* region_sprites);
void set_fixed_regions(memory_region* fix_cart, memory_region* fix_bios);
void set_screen(screen_device* screen);
void set_pens(pen_t* pens);
UINT16 *m_videoram;
UINT16 *m_videoram_drawsource;
UINT16 m_vram_offset;
UINT16 m_vram_read_buffer;
UINT16 m_vram_modulo;
const UINT8 *m_region_zoomy;
UINT32 m_sprite_gfx_address_mask;
UINT8 m_auto_animation_speed;
UINT8 m_auto_animation_disabled;
UINT8 m_auto_animation_counter;
UINT8 m_auto_animation_frame_counter;
UINT8 m_fixed_layer_source;
UINT8 m_fixed_layer_bank_type;
emu_timer *m_auto_animation_timer;
emu_timer *m_sprite_line_timer;
TIMER_CALLBACK_MEMBER(auto_animation_timer_callback);
TIMER_CALLBACK_MEMBER(sprite_line_timer_callback);
int m_bppshift; // 4 for 4bpp gfx (NeoGeo) 8 for 8bpp gfx (Midas)
protected:
virtual void device_start();
virtual void device_reset();
UINT32 get_region_mask(memory_region* rgn);
memory_region* m_region_sprites;
memory_region* m_region_fixed;
memory_region* m_region_fixedbios;
screen_device* m_screen;
pen_t *m_pens;
private:
};
//extern const device_type NEOGEO_SPRITE_BASE;
class neosprite_regular_device : public neosprite_base_device
{
public:
neosprite_regular_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual void draw_pixel(int romaddr, UINT32* dst, pen_t *line_pens);
virtual void set_sprite_region(memory_region* region_sprites);
};
extern const device_type NEOGEO_SPRITE_REGULAR;
class neosprite_optimized_device : public neosprite_base_device
{
public:
neosprite_optimized_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual void optimize_sprite_data();
virtual void draw_pixel(int romaddr, UINT32* dst, pen_t *line_pens);
dynamic_array<UINT8> m_sprite_gfx;
};
extern const device_type NEOGEO_SPRITE_OPTIMZIED;
class neosprite_midas_device : public neosprite_base_device
{
public:
neosprite_midas_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual void draw_pixel(int romaddr, UINT32* dst, pen_t *line_pens);
UINT16* m_videoram_buffer;
void buffer_vram();
virtual void draw_fixed_layer_2pixels(UINT32*&pixel_addr, int offset, UINT8* gfx_base, pen_t* char_pens);
virtual void set_sprite_region(memory_region* region_sprites);
protected:
virtual void device_start();
};
extern const device_type NEOGEO_SPRITE_MIDAS;

View File

@ -375,7 +375,7 @@ WRITE16_MEMBER(ng_aes_state::neocd_control_w)
case 0x0140:
// bprintf(PRINT_NORMAL, _T(" - NGCD OBJ BUSREQ -> 0 (PC: 0x%06X)\n"), SekGetPC(-1));
m_has_sprite_bus = true;
optimize_sprite_data();
m_sprgen->optimize_sprite_data();
break;
case 0x0142:
// bprintf(PRINT_NORMAL, _T(" - NGCD PCM BUSREQ -> 0 (PC: 0x%06X)\n"), SekGetPC(-1));
@ -1015,6 +1015,10 @@ void ng_aes_state::common_machine_start()
save_item(NAME(m_main_cpu_bank_address));
machine().save().register_postload(save_prepost_delegate(FUNC(ng_aes_state::neogeo_postload), this));
m_sprgen->set_screen(m_screen);
m_sprgen->set_sprite_region(m_region_sprites);
m_sprgen->set_fixed_regions(m_region_fixed, m_region_fixedbios);
}
MACHINE_START_MEMBER(ng_aes_state,neogeo)
@ -1077,7 +1081,7 @@ MACHINE_RESET_MEMBER(ng_aes_state,neogeo)
m_recurse = false;
/* AES has no SFIX ROM and always uses the cartridge's */
neogeo_set_fixed_layer_source(1);
m_sprgen->neogeo_set_fixed_layer_source(1);
NeoSpriteRAM = memregion("sprites")->base();
YM2610ADPCMAROM = memregion("ymsnd")->base();
@ -1453,9 +1457,9 @@ UINT32 ng_aes_state::screen_update_neocd(screen_device &screen, bitmap_rgb32 &bi
// fill with background color first
bitmap.fill(m_pens[0x0fff], cliprect);
if (m_has_sprite_bus) draw_sprites(bitmap, cliprect.min_y);
if (m_has_sprite_bus) m_sprgen->draw_sprites(bitmap, cliprect.min_y);
if (m_has_text_bus) draw_fixed_layer(bitmap, cliprect.min_y);
if (m_has_text_bus) m_sprgen->draw_fixed_layer(bitmap, cliprect.min_y);
return 0;
}

View File

@ -1771,6 +1771,7 @@ $(MESSOBJ)/snk.a: \
$(MAME_MACHINE)/neocrypt.o \
$(MAME_MACHINE)/neoprot.o \
$(MAME_MACHINE)/neoboot.o \
$(MAME_VIDEO)/neogeo_spr.o \
$(MAME_DRIVERS)/neogeo.o \
$(MESS_DRIVERS)/ngp.o \
$(MESS_VIDEO)/k1ge.o \