Rewritten Imagetek i4100 / i4220 / i4300 video display processor family, hooked it up to metro.cpp [Angelo Salese]

This commit is contained in:
angelosa 2017-11-21 07:04:52 +01:00
parent c268543e40
commit 56828c2446
6 changed files with 1609 additions and 1665 deletions

View File

@ -1021,3 +1021,15 @@ if (VIDEOS["BT459"]~=null) then
MAME_DIR .. "src/devices/video/bt459.h",
}
end
--------------------------------------------------
--
--@src/devices/video/imagetek_i4100.h,VIDEOS["I4100"] = true
--------------------------------------------------
if (VIDEOS["I4100"]~=null) then
files {
MAME_DIR .. "src/devices/video/imagetek_i4100.cpp",
MAME_DIR .. "src/devices/video/imagetek_i4100.h",
}
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,229 @@
// license:BSD-3-Clause
// copyright-holders:Luca Elia,David Haywood,Angelo Salese
/***************************************************************************
Imagetek I4100 / I4220 / I4300 device files
***************************************************************************/
#ifndef MAME_VIDEO_I4100_H
#define MAME_VIDEO_I4100_H
#pragma once
#include "screen.h"
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_I4100_ADD(tag) \
MCFG_DEVICE_ADD((tag), I4100, (0))
#define MCFG_I4220_ADD(tag) \
MCFG_DEVICE_ADD((tag), I4220, (0))
#define MCFG_I4300_ADD(tag) \
MCFG_DEVICE_ADD((tag), I4300, (0))
#define MCFG_I4100_GFXDECODE(gfxtag) \
imagetek_i4100_device::static_set_gfxdecode_tag(*device, ("^" gfxtag));
#define MCFG_I4100_BLITTER_END_CALLBACK(_devcb) \
devcb = &imagetek_i4100_device::static_set_blitter_irq_callback(*device, DEVCB_##_devcb);
#define MCFG_I4100_TILEMAP_XOFFSETS(_a, _b, _c) \
imagetek_i4100_device::static_set_tmap_xoffsets(*device, _a, _b, _c);
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> i4100_device
class imagetek_i4100_device : public device_t,
public device_video_interface
{
public:
// construction/destruction
imagetek_i4100_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_ADDRESS_MAP(map, 16);
static void static_set_gfxdecode_tag(device_t &device, const char *tag);
static void static_set_tmap_xoffsets(device_t &device, int x1, int x2, int x3);
template <class Object> static devcb_base &static_set_blitter_irq_callback(device_t &device, Object &&cb) { return downcast<imagetek_i4100_device &>(device).m_blit_irq_cb.set_callback(std::forward<Object>(cb)); }
// I/O operations
DECLARE_READ16_MEMBER( vram_0_r );
DECLARE_READ16_MEMBER( vram_1_r );
DECLARE_READ16_MEMBER( vram_2_r );
DECLARE_WRITE16_MEMBER( vram_0_w );
DECLARE_WRITE16_MEMBER( vram_1_w );
DECLARE_WRITE16_MEMBER( vram_2_w );
DECLARE_READ16_MEMBER( rmw_vram_0_r );
DECLARE_READ16_MEMBER( rmw_vram_1_r );
DECLARE_READ16_MEMBER( rmw_vram_2_r );
DECLARE_WRITE16_MEMBER( rmw_vram_0_w );
DECLARE_WRITE16_MEMBER( rmw_vram_1_w );
DECLARE_WRITE16_MEMBER( rmw_vram_2_w );
DECLARE_READ16_MEMBER( scratchram_r );
DECLARE_WRITE16_MEMBER( scratchram_w );
DECLARE_READ16_MEMBER( spriteram_r );
DECLARE_WRITE16_MEMBER( spriteram_w );
DECLARE_READ16_MEMBER( tiletable_r );
DECLARE_WRITE16_MEMBER( tiletable_w );
DECLARE_READ16_MEMBER( sprite_count_r );
DECLARE_WRITE16_MEMBER( sprite_count_w );
DECLARE_READ16_MEMBER( sprite_priority_r );
DECLARE_WRITE16_MEMBER( sprite_priority_w );
DECLARE_READ16_MEMBER( sprite_xoffset_r );
DECLARE_WRITE16_MEMBER( sprite_xoffset_w );
DECLARE_READ16_MEMBER( sprite_yoffset_r );
DECLARE_WRITE16_MEMBER( sprite_yoffset_w );
DECLARE_READ16_MEMBER( sprite_color_code_r );
DECLARE_WRITE16_MEMBER( sprite_color_code_w );
DECLARE_READ16_MEMBER( layer_priority_r );
DECLARE_WRITE16_MEMBER( layer_priority_w );
DECLARE_READ16_MEMBER( background_color_r );
DECLARE_WRITE16_MEMBER( background_color_w );
DECLARE_READ16_MEMBER( screen_xoffset_r );
DECLARE_WRITE16_MEMBER( screen_xoffset_w );
DECLARE_READ16_MEMBER( screen_yoffset_r );
DECLARE_WRITE16_MEMBER( screen_yoffset_w );
DECLARE_READ16_MEMBER( window_r );
DECLARE_WRITE16_MEMBER( window_w );
DECLARE_READ16_MEMBER( scroll_r );
DECLARE_WRITE16_MEMBER( scroll_w );
DECLARE_READ16_MEMBER( gfxrom_r );
DECLARE_WRITE16_MEMBER( crtc_vert_w );
DECLARE_WRITE16_MEMBER( crtc_horz_w );
DECLARE_WRITE16_MEMBER( crtc_unlock_w );
DECLARE_WRITE16_MEMBER( blitter_w );
DECLARE_WRITE16_MEMBER( screen_ctrl_w );
DECLARE_WRITE16_MEMBER( rombank_w );
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
protected:
imagetek_i4100_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool has_ext_tiles);
// device-level overrides
//virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
required_shared_ptr<uint16_t> m_vram_0;
required_shared_ptr<uint16_t> m_vram_1;
required_shared_ptr<uint16_t> m_vram_2;
required_shared_ptr<uint16_t> m_scratchram;
required_shared_ptr<uint16_t> m_blitter_regs;
required_shared_ptr<uint16_t> m_spriteram;
required_shared_ptr<uint16_t> m_tiletable;
required_shared_ptr<uint16_t> m_window;
required_shared_ptr<uint16_t> m_scroll;
required_device<palette_device> m_palette;
required_device<gfxdecode_device> m_gfxdecode;
required_region_ptr<uint8_t> m_gfxrom;
std::unique_ptr<uint8_t[]> m_expanded_gfx1;
devcb_write_line m_blit_irq_cb;
uint16_t m_rombank;
size_t m_gfxrom_size;
bool m_crtc_unlock;
uint16_t m_sprite_count;
uint16_t m_sprite_priority;
uint16_t m_sprite_xoffset,m_sprite_yoffset;
uint16_t m_sprite_color_code;
uint8_t m_layer_priority[3];
uint16_t m_background_color;
uint16_t m_screen_xoffset,m_screen_yoffset;
bool m_layer_tile_select[3];
bool m_screen_blank;
bool m_screen_flip;
const bool m_support_8bpp, m_support_16x16;
int m_tilemap_scrolldx[3];
void blt_write( address_space &space, const int tmap, const offs_t offs, const uint16_t data, const uint16_t mask );
enum
{
TIMER_BLIT_END = 1
};
emu_timer *m_blit_done_timer;
void draw_layers( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri );
inline uint8_t get_tile_pix( uint16_t code, uint8_t x, uint8_t y, bool big, uint16_t *pix );
void draw_tilemap( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, uint32_t flags, uint32_t pcode,
int sx, int sy, int wx, int wy, bool big, uint16_t *tilemapram, int layer );
void draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect );
void expand_gfx1();
// A 2048 x 2048 virtual tilemap
static constexpr uint32_t BIG_NX = (0x100);
static constexpr uint32_t BIG_NY = (0x100);
// A smaller 512 x 256 window defines the actual tilemap
static constexpr uint32_t WIN_NX = (0x40);
static constexpr uint32_t WIN_NY = (0x20);
bool m_inited_hack;
};
class imagetek_i4220_device : public imagetek_i4100_device
{
public:
// construction/destruction
imagetek_i4220_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_ADDRESS_MAP(v2_map, 16);
// needed by Blazing Tornado / Grand Striker 2 for mixing with PSAC
// (it's unknown how the chip enables external sync)
uint16_t get_background_pen() { return m_background_color; };
protected:
};
class imagetek_i4300_device : public imagetek_i4100_device
{
public:
// construction/destruction
imagetek_i4300_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_ADDRESS_MAP(v3_map, 16);
protected:
};
// device type definition
DECLARE_DEVICE_TYPE(I4100, imagetek_i4100_device)
DECLARE_DEVICE_TYPE(I4220, imagetek_i4220_device)
DECLARE_DEVICE_TYPE(I4300, imagetek_i4300_device)
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
#endif // MAME_VIDEO_I4100_H

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
#include "sound/ym2151.h"
#include "sound/es8712.h"
#include "video/k053936.h"
#include "video/imagetek_i4100.h"
#include "machine/eepromser.h"
#include "machine/gen_latch.h"
#include "screen.h"
@ -20,8 +21,7 @@ public:
enum
{
TIMER_KARATOUR_IRQ,
TIMER_MOUJA_IRQ,
TIMER_METRO_BLIT_DONE
TIMER_MOUJA_IRQ
};
metro_state(const machine_config &mconfig, device_type type, const char *tag)
@ -31,27 +31,17 @@ public:
m_oki(*this, "oki"),
m_ymsnd(*this, "ymsnd"),
m_essnd(*this, "essnd"),
m_vdp(*this, "vdp"),
m_vdp2(*this, "vdp2"),
m_vdp3(*this, "vdp3"),
m_k053936(*this, "k053936") ,
m_eeprom(*this, "eeprom"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_soundlatch(*this, "soundlatch"),
m_vram_0(*this, "vram_0"),
m_vram_1(*this, "vram_1"),
m_vram_2(*this, "vram_2"),
m_spriteram(*this, "spriteram"),
m_spriteregs(*this, "spriteregs"),
m_tiletable(*this, "tiletable"),
m_blitter_regs(*this, "blitter_regs"),
m_scroll(*this, "scroll"),
m_window(*this, "window"),
m_irq_enable(*this, "irq_enable"),
m_irq_levels(*this, "irq_levels"),
m_irq_vectors(*this, "irq_vectors"),
m_rombank(*this, "rombank"),
m_videoregs(*this, "videoregs"),
m_screenctrl(*this, "screenctrl"),
m_input_sel(*this, "input_sel"),
m_k053936_ram(*this, "k053936_ram")
{ }
@ -70,25 +60,13 @@ public:
DECLARE_WRITE8_MEMBER(daitorid_portb_w);
DECLARE_WRITE16_MEMBER(metro_coin_lockout_1word_w);
DECLARE_WRITE16_MEMBER(metro_coin_lockout_4words_w);
DECLARE_READ16_MEMBER(metro_bankedrom_r);
DECLARE_WRITE16_MEMBER(metro_blitter_w);
DECLARE_READ16_MEMBER(balcube_dsw_r);
DECLARE_READ16_MEMBER(karatour_vram_0_r);
DECLARE_READ16_MEMBER(karatour_vram_1_r);
DECLARE_READ16_MEMBER(karatour_vram_2_r);
DECLARE_WRITE16_MEMBER(karatour_vram_0_w);
DECLARE_WRITE16_MEMBER(karatour_vram_1_w);
DECLARE_WRITE16_MEMBER(karatour_vram_2_w);
DECLARE_READ16_MEMBER(gakusai_input_r);
DECLARE_WRITE16_MEMBER(blzntrnd_sound_w);
DECLARE_WRITE8_MEMBER(blzntrnd_sh_bankswitch_w);
DECLARE_WRITE16_MEMBER(puzzlet_irq_enable_w);
DECLARE_WRITE16_MEMBER(puzzlet_portb_w);
DECLARE_WRITE16_MEMBER(metro_k053936_w);
DECLARE_WRITE16_MEMBER(metro_vram_0_w);
DECLARE_WRITE16_MEMBER(metro_vram_1_w);
DECLARE_WRITE16_MEMBER(metro_vram_2_w);
DECLARE_WRITE16_MEMBER(metro_window_w);
DECLARE_CUSTOM_INPUT_MEMBER(custom_soundstatus_r);
DECLARE_WRITE8_MEMBER(gakusai_oki_bank_hi_w);
DECLARE_WRITE8_MEMBER(gakusai_oki_bank_lo_w);
@ -98,8 +76,7 @@ public:
DECLARE_WRITE8_MEMBER(dokyusp_eeprom_bit_w);
DECLARE_WRITE8_MEMBER(dokyusp_eeprom_reset_w);
DECLARE_WRITE8_MEMBER(mouja_sound_rombank_w);
DECLARE_READ16_MEMBER(gakusai_spriteregs_r);
DECLARE_WRITE16_MEMBER(gakusai_spriteregs_w);
DECLARE_WRITE_LINE_MEMBER(vdp_blit_end_w);
// vmetal
DECLARE_WRITE8_MEMBER(vmetal_control_w);
@ -120,19 +97,13 @@ public:
TILE_GET_INFO_MEMBER(metro_k053936_get_tile_info);
TILE_GET_INFO_MEMBER(metro_k053936_gstrik2_get_tile_info);
TILEMAP_MAPPER_MEMBER(tilemap_scan_gstrik2);
DECLARE_VIDEO_START(metro_i4100);
DECLARE_VIDEO_START(metro_i4220);
DECLARE_VIDEO_START(metro_i4220_dx_tmap);
DECLARE_VIDEO_START(metro_i4220_dx_sprite);
DECLARE_VIDEO_START(metro_i4300);
DECLARE_VIDEO_START(blzntrnd);
DECLARE_VIDEO_START(gstrik2);
uint32_t screen_update_metro(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
uint32_t screen_update_psac_vdp2_mix(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER(metro_vblank_interrupt);
INTERRUPT_GEN_MEMBER(metro_periodic_interrupt);
INTERRUPT_GEN_MEMBER(karatour_interrupt);
INTERRUPT_GEN_MEMBER(puzzlet_interrupt);
TIMER_CALLBACK_MEMBER(metro_blit_done);
IRQ_CALLBACK_MEMBER(metro_irq_callback);
DECLARE_READ_LINE_MEMBER(metro_rxd_r);
@ -147,47 +118,25 @@ private:
optional_device<okim6295_device> m_oki;
optional_device<device_t> m_ymsnd; // TODO set correct type
optional_device<es8712_device> m_essnd;
optional_device<imagetek_i4100_device> m_vdp;
optional_device<imagetek_i4220_device> m_vdp2;
optional_device<imagetek_i4300_device> m_vdp3;
optional_device<k053936_device> m_k053936;
optional_device<eeprom_serial_93cxx_device> m_eeprom;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
optional_device<generic_latch_8_device> m_soundlatch;
/* memory pointers */
optional_shared_ptr<uint16_t> m_vram_0;
optional_shared_ptr<uint16_t> m_vram_1;
optional_shared_ptr<uint16_t> m_vram_2;
required_shared_ptr<uint16_t> m_spriteram;
required_shared_ptr<uint16_t> m_spriteregs;
optional_shared_ptr<uint16_t> m_tiletable;
optional_shared_ptr<uint16_t> m_blitter_regs;
optional_shared_ptr<uint16_t> m_scroll;
optional_shared_ptr<uint16_t> m_window;
optional_shared_ptr<uint16_t> m_irq_enable;
optional_shared_ptr<uint16_t> m_irq_levels;
optional_shared_ptr<uint16_t> m_irq_vectors;
optional_shared_ptr<uint16_t> m_rombank;
required_shared_ptr<uint16_t> m_videoregs;
optional_shared_ptr<uint16_t> m_screenctrl;
optional_shared_ptr<uint16_t> m_input_sel;
optional_shared_ptr<uint16_t> m_k053936_ram;
int m_flip_screen;
/* video-related */
tilemap_t *m_k053936_tilemap;
int m_tilemap_scrolldx[3];
int m_support_8bpp;
int m_support_16x16;
int m_has_zoom;
int m_sprite_xoffs;
int m_sprite_yoffs;
int m_sprite_xoffs_dx;
emu_timer *m_blit_done_timer;
std::unique_ptr<uint8_t[]> m_expanded_gfx1;
/* irq_related */
int m_vblank_bit;
@ -209,16 +158,9 @@ private:
int m_gakusai_oki_bank_hi;
void update_irq_state();
inline uint8_t get_tile_pix( uint16_t code, uint8_t x, uint8_t y, int big, uint16_t *pix );
inline void metro_vram_w( offs_t offset, uint16_t data, uint16_t mem_mask, int layer, uint16_t *vram );
void metro_draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect );
void draw_layers( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri, int layers_ctrl );
inline int blt_read( const uint8_t *ROM, const int offs );
void metro_common();
void draw_tilemap( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, uint32_t flags, uint32_t pcode,
int sx, int sy, int wx, int wy, int big, uint16_t *tilemapram, int layer );
void expand_gfx1();
void blt_write( address_space &space, const int tmap, const offs_t offs, const uint16_t data, const uint16_t mask );
void gakusai_oki_bank_set();
// blazing tornado
bitmap_ind16 m_vdp_bitmap;
};

View File

@ -2,54 +2,8 @@
// copyright-holders:Luca Elia, David Haywood
/***************************************************************************
-= Metro Games =-
driver by Luca Elia (l.elia@tin.it)
Note: if MAME_DEBUG is defined, pressing Z with:
Q Shows Layer 0
W Shows Layer 1
E Shows Layer 2
A Shows Sprites
Keys can be used together!
[ 3 Scrolling Layers ]
There is memory for a huge layer, but the actual tilemap
is a smaller window (of fixed size) carved from anywhere
inside that layer.
Tile Size: 8 x 8 x 4
(later games can switch to 8 x 8 x 8, 16 x 16 x 4/8 at run time)
Big Layer Size: 2048 x 2048 (8x8 tiles) or 4096 x 4096 (16x16 tiles)
Tilemap Window Size: 512 x 256 (8x8 tiles) or 1024 x 512 (16x16 tiles)
The tile codes in memory do not map directly to tiles. They
are indexes into a table (with 0x200 entries) that defines
a virtual set of tiles for the 3 layers. Each entry in that
table adds 16 tiles to the set of available tiles, and decides
their color code.
Tile code with their msbit set are different as they mean:
draw a tile filled with a single color (0-fff)
[ 512 Zooming Sprites ]
The sprites are NOT tile based: the "tile" size can vary from
8 to 64 (independently for width and height) with an 8 pixel
granularity. The "tile" address is a multiple of 8x8 pixels.
Each sprite can be shrinked to ~1/4 or enlarged to ~32x following
an exponential curve of sizes (with one zoom value for both width
and height)
(legacy metro.cpp, currently contains Blazing Tornado overrides,
to be moved into its own driver file!)
***************************************************************************/
@ -95,647 +49,30 @@ TILEMAP_MAPPER_MEMBER(metro_state::tilemap_scan_gstrik2)
return val;
}
/***************************************************************************
Tilemaps: Tiles Set & Window
Each entry in the Tiles Set RAM uses 2 words to specify a starting
tile code and a color code. This adds 16 consecutive tiles with
that color code to the set of available tiles.
Offset: Bits: Value:
0.w fedc ---- ---- ----
---- ba98 7654 ---- Color Code*
---- ---- ---- 3210 Code High Bits
2.w Code Low Bits
* 00-ff, but on later chips supporting it, xf means 256 color tile and palette x
***************************************************************************/
/***************************************************************************
Tilemaps: Rendering
***************************************************************************/
// A 2048 x 2048 virtual tilemap
#define BIG_NX (0x100)
#define BIG_NY (0x100)
// A smaller 512 x 256 window defines the actual tilemap
#define WIN_NX (0x40)
#define WIN_NY (0x20)
/* This looks up a single pixel in a tile, given the tile code.
The Metro hardware has an indirection table, which is used here.
Returns if to draw the pixel or not, pixel colour is placed in pix */
inline uint8_t metro_state::get_tile_pix( uint16_t code, uint8_t x, uint8_t y, int big, uint16_t *pix )
{
int table_index;
uint32_t tile;
// Use code as an index into the tiles set table
table_index = ((code & 0x1ff0) >> 4) * 2;
tile = (m_tiletable[table_index + 0] << 16) + m_tiletable[table_index + 1];
if (code & 0x8000) // Special: draw a tile of a single color (i.e. not from the gfx ROMs)
{
*pix = code & 0x0fff;
if ((*pix & 0xf) != 0xf)
return 1;
else
return 0;
}
else if (((tile & 0x00f00000) == 0x00f00000) && (m_support_8bpp)) /* draw tile as 8bpp (e.g. balcube bg) */
{
gfx_element *gfx1 = m_gfxdecode->gfx(big?3:1);
uint32_t tile2 = big ? ((tile & 0xfffff) + 8*(code & 0xf)) :
((tile & 0xfffff) + 2*(code & 0xf));
const uint8_t* data;
uint8_t flipxy = (code & 0x6000) >> 13;
if (tile2 < gfx1->elements())
data = gfx1->get_data(tile2);
else
{
*pix = 0;
return 0;
}
switch (flipxy)
{
default:
case 0x0: *pix = data[(y * (big?16:8)) + x]; break;
case 0x1: *pix = data[(((big?15:7)-y) * (big?16:8)) + x]; break;
case 0x2: *pix = data[(y * (big?16:8)) + ((big?15:7)-x)]; break;
case 0x3: *pix = data[(((big?15:7)-y) * (big?16:8)) + ((big?15:7)-x)]; break;
}
*pix |= ((tile & 0x0f000000) >> 24) * 0x100;
if ((*pix & 0xff) != 0xff)
return 1;
else
return 0;
}
else
{
gfx_element *gfx1 = m_gfxdecode->gfx(big?2:0);
uint32_t tile2 = big ? ((tile & 0xfffff) + 4*(code & 0xf)) :
((tile & 0xfffff) + (code & 0xf));
const uint8_t* data;
uint8_t flipxy = (code & 0x6000) >> 13;
if (tile2 < gfx1->elements())
data = gfx1->get_data(tile2);
else
{
*pix = 0;
return 0;
}
switch (flipxy)
{
default:
case 0x0: *pix = data[(y * (big?16:8)) + x]; break;
case 0x1: *pix = data[(((big?15:7)-y) * (big?16:8)) + x]; break;
case 0x2: *pix = data[(y * (big?16:8)) + ((big?15:7)-x)]; break;
case 0x3: *pix = data[(((big?15:7)-y) * (big?16:8)) + ((big?15:7)-x)]; break;
}
*pix |= (((tile & 0x0ff00000) >> 20)) * 0x10;
if ((*pix & 0xf) != 0xf)
return 1;
else
return 0;
}
}
inline void metro_state::metro_vram_w( offs_t offset, uint16_t data, uint16_t mem_mask, int layer, uint16_t *vram )
{
COMBINE_DATA(&vram[offset]);
}
WRITE16_MEMBER(metro_state::metro_vram_0_w){ metro_vram_w(offset, data, mem_mask, 0, m_vram_0); }
WRITE16_MEMBER(metro_state::metro_vram_1_w){ metro_vram_w(offset, data, mem_mask, 1, m_vram_1); }
WRITE16_MEMBER(metro_state::metro_vram_2_w){ metro_vram_w(offset, data, mem_mask, 2, m_vram_2); }
WRITE16_MEMBER(metro_state::metro_window_w)
{
COMBINE_DATA(&m_window[offset]);
}
/***************************************************************************
Video Init Routines
***************************************************************************/
/*
Sprites are not tile based, so we decode their graphics at runtime.
*/
void metro_state::expand_gfx1()
{
uint8_t *base_gfx = memregion("gfx1")->base();
uint32_t length = memregion("gfx1")->bytes() * 2;
m_expanded_gfx1 = std::make_unique<uint8_t[]>(length);
for (int i = 0; i < length; i += 2)
{
uint8_t src = base_gfx[i / 2];
m_expanded_gfx1[i + 0] = src & 0xf;
m_expanded_gfx1[i + 1] = src >> 4;
}
}
VIDEO_START_MEMBER(metro_state,metro_i4100)
{
expand_gfx1();
m_support_8bpp = 0;
m_support_16x16 = 0;
m_has_zoom = 0;
m_tilemap_scrolldx[0] = 0;
m_tilemap_scrolldx[1] = 0;
m_tilemap_scrolldx[2] = 0;
m_sprite_xoffs_dx = 0;
}
VIDEO_START_MEMBER(metro_state,metro_i4220)
{
VIDEO_START_CALL_MEMBER(metro_i4100);
m_support_8bpp = 1; // balcube
m_support_16x16 = 1; // vmetal
}
VIDEO_START_MEMBER(metro_state,metro_i4220_dx_tmap)
{
VIDEO_START_CALL_MEMBER(metro_i4220);
m_tilemap_scrolldx[0] = -2;
m_tilemap_scrolldx[1] = -2;
m_tilemap_scrolldx[2] = -2;
}
VIDEO_START_MEMBER(metro_state,metro_i4220_dx_sprite)
{
VIDEO_START_CALL_MEMBER(metro_i4220);
m_tilemap_scrolldx[0] = -16;
m_tilemap_scrolldx[1] = -16;
m_tilemap_scrolldx[2] = -16;
m_sprite_xoffs_dx = 0;
}
VIDEO_START_MEMBER(metro_state,metro_i4300)
{
VIDEO_START_CALL_MEMBER(metro_i4220);
// any additional feature?
}
VIDEO_START_MEMBER(metro_state,blzntrnd)
{
VIDEO_START_CALL_MEMBER(metro_i4220);
m_has_zoom = 1;
m_k053936_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(metro_state::metro_k053936_get_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 256, 512);
m_tilemap_scrolldx[0] = 0;
m_tilemap_scrolldx[1] = 0;
m_tilemap_scrolldx[2] = 0;
m_sprite_xoffs_dx = 0;
m_screen->register_screen_bitmap(m_vdp_bitmap);
}
VIDEO_START_MEMBER(metro_state,gstrik2)
{
VIDEO_START_CALL_MEMBER(metro_i4220);
m_has_zoom = 1;
m_k053936_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(metro_state::metro_k053936_gstrik2_get_tile_info),this), tilemap_mapper_delegate(FUNC(metro_state::tilemap_scan_gstrik2),this), 16, 16, 128, 256);
m_tilemap_scrolldx[0] = 0;
m_tilemap_scrolldx[1] = -8;
m_tilemap_scrolldx[2] = 0;
m_sprite_xoffs_dx = 0;
}
/***************************************************************************
Video Registers
Offset: Bits: Value:
0.w Number Of Sprites To Draw
2.w f--- ---- ---- ---- Disable Sprites Layer Priority
-edc ---- ---- ----
---- ba-- ---- ---- Sprites Masked Layer
---- --98 ---- ---- Sprites Priority
---- ---- 765- ----
---- ---- ---4 3210 Sprites Masked Number
4.w Sprites Y Offset
6.w Sprites X Offset
8.w Sprites Color Codes Start
-
10.w fedc ba98 76-- ----
---- ---- --54 ---- Layer 2 Priority (3 backmost, 0 frontmost)
---- ---- ---- 32-- Layer 1 Priority
---- ---- ---- --10 Layer 0 Priority
12.w Backround Color
***************************************************************************/
/***************************************************************************
Sprite Registers
Offset: Bits: Value:
0.w Sprite Y center point
2.w Sprite X center point
***************************************************************************/
/***************************************************************************
Sprites Drawing
Offset: Bits: Value:
0.w fedc b--- ---- ---- Priority (0 = Max)
---- -a98 7654 3210 X
2.w fedc ba-- ---- ---- Zoom (Both X & Y)
---- --98 7654 3210 Y
4.w f--- ---- ---- ---- Flip X
-e-- ---- ---- ---- Flip Y
--dc b--- ---- ---- Size X *
---- -a98 ---- ---- Size Y *
---- ---- 7654 ---- Color
---- ---- ---- 3210 Code High Bits **
6.w Code Low Bits **
* 8 pixel increments
** 8x8 pixel increments
***************************************************************************/
void metro_state::metro_draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect )
{
uint8_t *base_gfx4 = m_expanded_gfx1.get();
uint8_t *base_gfx8 = memregion("gfx1")->base();
uint32_t gfx_size = memregion("gfx1")->bytes();
int max_x = (m_spriteregs[1]+1)*2;
int max_y = (m_spriteregs[0]+1)*2;
int max_sprites = m_spriteram.bytes() / 8;
int sprites = m_videoregs[0x00/2] % max_sprites;
int color_start = (m_videoregs[0x08/2] & 0x0f) << 4;
int i, j, pri;
static const int primask[4] = { 0x0000, 0xff00, 0xff00 | 0xf0f0, 0xff00 | 0xf0f0 | 0xcccc };
uint16_t *src;
int inc;
if (sprites == 0)
return;
for (i = 0; i < 0x20; i++)
{
if (!(m_videoregs[0x02/2] & 0x8000))
{
src = m_spriteram + (sprites - 1) * (8 / 2);
inc = -(8 / 2);
} else {
src = m_spriteram;
inc = (8 / 2);
}
for (j = 0; j < sprites; j++)
{
int x, y, attr, code, color, flipx, flipy, zoom, curr_pri, width, height;
// Exponential zoom table extracted from daitoride
static const int zoomtable[0x40] =
{ 0xAAC,0x800,0x668,0x554,0x494,0x400,0x390,0x334,
0x2E8,0x2AC,0x278,0x248,0x224,0x200,0x1E0,0x1C8,
0x1B0,0x198,0x188,0x174,0x164,0x154,0x148,0x13C,
0x130,0x124,0x11C,0x110,0x108,0x100,0x0F8,0x0F0,
0x0EC,0x0E4,0x0DC,0x0D8,0x0D4,0x0CC,0x0C8,0x0C4,
0x0C0,0x0BC,0x0B8,0x0B4,0x0B0,0x0AC,0x0A8,0x0A4,
0x0A0,0x09C,0x098,0x094,0x090,0x08C,0x088,0x080,
0x078,0x070,0x068,0x060,0x058,0x050,0x048,0x040 };
x = src[0];
curr_pri = (x & 0xf800) >> 11;
if ((curr_pri == 0x1f) || (curr_pri != i))
{
src += inc;
continue;
}
pri = (m_videoregs[0x02/2] & 0x0300) >> 8;
if (!(m_videoregs[0x02/2] & 0x8000))
{
if (curr_pri > (m_videoregs[0x02/2] & 0x1f))
pri = (m_videoregs[0x02/2] & 0x0c00) >> 10;
}
y = src[1];
attr = src[2];
code = src[3];
flipx = attr & 0x8000;
flipy = attr & 0x4000;
color = (attr & 0xf0) >> 4;
zoom = zoomtable[(y & 0xfc00) >> 10] << (16 - 8);
x = (x & 0x07ff) - m_sprite_xoffs;
y = (y & 0x03ff) - m_sprite_yoffs;
width = (((attr >> 11) & 0x7) + 1) * 8;
height = (((attr >> 8) & 0x7) + 1) * 8;
uint32_t gfxstart = (8 * 8 * 4 / 8) * (((attr & 0x000f) << 16) + code);
if (m_flip_screen)
{
flipx = !flipx; x = max_x - x - width;
flipy = !flipy; y = max_y - y - height;
}
if (m_support_8bpp && color == 0xf) /* 8bpp */
{
/* Bounds checking */
if ((gfxstart + width * height - 1) >= gfx_size)
continue;
gfx_element gfx(m_palette, base_gfx8 + gfxstart, width, height, width, m_palette->entries(), 0, 256);
gfx.prio_zoom_transpen(bitmap,cliprect,
0,
color_start >> 4,
flipx, flipy,
x, y,
zoom, zoom,
screen.priority(),primask[pri], 255);
}
else
{
/* Bounds checking */
if ((gfxstart + width / 2 * height - 1) >= gfx_size)
continue;
gfx_element gfx(m_palette, base_gfx4 + 2 * gfxstart, width, height, width, m_palette->entries(),0, 16);
gfx.prio_zoom_transpen(bitmap,cliprect,
0,
color + color_start,
flipx, flipy,
x, y,
zoom, zoom,
screen.priority(),primask[pri], 15);
}
#if 0
{ /* Display priority + zoom on each sprite */
char buf[80];
sprintf(buf, "%02X %02X", ((src[0] & 0xf800) >> 11) ^ 0x1f, ((src[1] & 0xfc00) >> 10));
ui_draw_text(buf, x, y);
}
#endif
src += inc;
}
}
}
/***************************************************************************
Screen Drawing
***************************************************************************/
// Copy a 'window' from the large 2048x2048 (or 4096x4096 for 16x16 tiles) tilemap
void metro_state::draw_tilemap( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, uint32_t flags, uint32_t pcode,
int sx, int sy, int wx, int wy, int big, uint16_t *tilemapram, int layer )
{
int y;
bitmap_ind8 &priority_bitmap = m_screen->priority();
int width = big ? 4096 : 2048;
int height = big ? 4096 : 2048;
int scrwidth = bitmap.width();
int scrheight = bitmap.height();
int windowwidth = width >> 2;
int windowheight = height >> 3;
sx += m_tilemap_scrolldx[layer] * (m_flip_screen ? 1 : -1);
for (y = 0; y < scrheight; y++)
{
int scrolly = (sy+y-wy)&(windowheight-1);
int x;
uint16_t *dst;
uint8_t *priority_baseaddr;
int srcline = (wy+scrolly)&(height-1);
int srctilerow = srcline >> (big ? 4 : 3);
if (!m_flip_screen)
{
dst = &bitmap.pix16(y);
priority_baseaddr = &priority_bitmap.pix8(y);
for (x = 0; x < scrwidth; x++)
{
int scrollx = (sx+x-wx)&(windowwidth-1);
int srccol = (wx+scrollx)&(width-1);
int srctilecol = srccol >> (big ? 4 : 3);
int tileoffs = srctilecol + srctilerow * BIG_NX;
uint16_t dat = 0;
uint16_t tile = tilemapram[tileoffs];
uint8_t draw = get_tile_pix(tile, big ? (srccol&0xf) : (srccol&0x7), big ? (srcline&0xf) : (srcline&0x7), big, &dat);
if (draw)
{
dst[x] = dat;
priority_baseaddr[x] = (priority_baseaddr[x] & (pcode >> 8)) | pcode;
}
}
}
else // flipped case
{
dst = &bitmap.pix16(scrheight-y-1);
priority_baseaddr = &priority_bitmap.pix8(scrheight-y-1);
for (x = 0; x < scrwidth; x++)
{
int scrollx = (sx+x-wx)&(windowwidth-1);
int srccol = (wx+scrollx)&(width-1);
int srctilecol = srccol >> (big ? 4 : 3);
int tileoffs = srctilecol + srctilerow * BIG_NX;
uint16_t dat = 0;
uint16_t tile = tilemapram[tileoffs];
uint8_t draw = get_tile_pix(tile, big ? (srccol&0xf) : (srccol&0x7), big ? (srcline&0xf) : (srcline&0x7), big, &dat);
if (draw)
{
dst[scrwidth-x-1] = dat;
priority_baseaddr[scrwidth-x-1] = (priority_baseaddr[scrwidth-x-1] & (pcode >> 8)) | pcode;
}
}
}
}
}
// Draw all the layers that match the given priority
void metro_state::draw_layers( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri, int layers_ctrl )
{
uint16_t layers_pri = m_videoregs[0x10 / 2];
int layer;
// Draw all the layers with priority == pri
for (layer = 2; layer >= 0; layer--)
{
if (pri == ((layers_pri >> (layer * 2)) & 3))
{
// Scroll and Window values
uint16_t sy = m_scroll[layer * 2 + 0]; uint16_t sx = m_scroll[layer * 2 + 1];
uint16_t wy = m_window[layer * 2 + 0]; uint16_t wx = m_window[layer * 2 + 1];
if (BIT(layers_ctrl, layer)) // for debug
{
uint16_t *tilemapram = nullptr;
switch (layer)
{
case 0: tilemapram = m_vram_0; break;
case 1: tilemapram = m_vram_1; break;
case 2: tilemapram = m_vram_2; break;
}
int big = m_support_16x16 && (*m_screenctrl & (0x0020 << layer));
draw_tilemap(screen, bitmap, cliprect, 0, 1 << (3 - pri), sx, sy, wx, wy, big, tilemapram, layer);
}
}
}
}
uint32_t metro_state::screen_update_metro(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int pri, layers_ctrl = -1;
uint16_t screenctrl = *m_screenctrl;
m_sprite_xoffs = m_videoregs[0x06 / 2] - (m_spriteregs[1]+1) + m_sprite_xoffs_dx;
m_sprite_yoffs = m_videoregs[0x04 / 2] - (m_spriteregs[0]+1);
screen.priority().fill(0, cliprect);
// The background color is selected by a register
bitmap.fill(m_videoregs[0x12/2] & 0x0fff, cliprect);
/* Screen Control Register:
f--- ---- ---- ---- ?
-edc b--- ---- ----
---- -a98 ---- ---- ? Leds (see gakusai attract)
---- ---- 765- ---- 16x16 Tiles (Layer 2-1-0)
---- ---- ---4 32--
---- ---- ---- --1- Blank Screen
---- ---- ---- ---0 Flip Screen */
if (screenctrl & 2)
return 0;
m_flip_screen = screenctrl & 1;
#ifdef MAME_DEBUG
if (machine().input().code_pressed(KEYCODE_Z))
{
int msk = 0;
if (machine().input().code_pressed(KEYCODE_Q)) msk |= 1;
if (machine().input().code_pressed(KEYCODE_W)) msk |= 2;
if (machine().input().code_pressed(KEYCODE_E)) msk |= 4;
if (machine().input().code_pressed(KEYCODE_A)) msk |= 8;
if (msk != 0)
{
bitmap.fill(m_palette->black_pen(), cliprect);
layers_ctrl &= msk;
}
popmessage( "lyr: %x-%x-%x spr: %04x clr: %04x scr: %04x",
(m_videoregs[0x10/2] & 0x30) >> 4, (m_videoregs[0x10/2] & 0xc) >> 2, m_videoregs[0x10/2] & 3,
m_videoregs[0x02/2], m_videoregs[0x12/2],
*m_screenctrl);
m_screen->register_screen_bitmap(m_vdp_bitmap);
}
#endif
if (m_has_zoom)
{
/* TODO: bit 5 of reg 7 is off when ROZ is supposed to be disabled
* (Blazing Tornado title screen/character select/ending and Grand Striker 2 title/how to play transition)
*/
uint32_t metro_state::screen_update_psac_vdp2_mix(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
/* TODO: bit 5 of reg 7 is off when ROZ is supposed to be disabled
* (Blazing Tornado title screen/character select/ending and Grand Striker 2 title/how to play transition)
*/
m_k053936->zoom_draw(screen, bitmap, cliprect, m_k053936_tilemap, 0, 0, 1);
}
bitmap.fill(m_vdp2->get_background_pen(), cliprect);
m_k053936->zoom_draw(screen, bitmap, cliprect, m_k053936_tilemap, 0, 0, 1);
m_vdp2->screen_update(screen, m_vdp_bitmap, cliprect);
copybitmap_trans(bitmap, m_vdp_bitmap, 0, 0, 0, 0, cliprect, m_vdp2->get_background_pen());
for (pri = 3; pri >= 0; pri--)
draw_layers(screen, bitmap, cliprect, pri, layers_ctrl);
if (layers_ctrl & 0x08)
metro_draw_sprites(screen, bitmap, cliprect);
return 0;
}