// license:BSD-3-Clause // copyright-holders:Luca Elia, David Haywood /* Kaneko View2 Tilemaps */ /* [ Scrolling Layers ] Each VIEW2 chip generates 2 layers. Up to 2 chips are used (4 layers) Layer Size: 512 x 512 Tiles: 16 x 16 x 4 Line scroll is supported by the chip: each layer has RAM for 512 horizontal scroll offsets (one per tilemap line) that are added to the global scroll values. See e.g. blazeon (2nd demo level), mgcrystl, sandscrp. *************************************************************************** Callbacks for the TileMap code [ Tiles Format ] Offset: 0000.w fedc b--- ---- ---- unused? ---- -a9- ---- ---- High Priority (vs Sprites) ---- ---8 ---- ---- High Priority (vs Tiles) ---- ---- 7654 32-- Color ---- ---- ---- --1- Flip X ---- ---- ---- ---0 Flip Y 0002.w Code *************************************************************************** *************************************************************************** Layers Registers Offset: Format: Value: 0000.w FG Scroll X 0002.w FG Scroll Y 0004.w BG Scroll X 0006.w BG Scroll Y 0008.w Layers Control fed- ---- ---- ---- ---c ---- ---- ---- BG Disable ---- b--- ---- ---- Line Scroll (Always 1 in berlwall & bakubrkr) ---- -a-- ---- ---- ? Always 1 in gtmr & bakubrkr ? ---- --9- ---- ---- BG Flip X ---- ---8 ---- ---- BG Flip Y ---- ---- 765- ---- ---- ---- ---4 ---- FG Disable ---- ---- ---- 3--- Line Scroll (Always 1 in berlwall & bakubrkr) ---- ---- ---- -2-- ? Always 1 in gtmr & bakubrkr ? ---- ---- ---- --1- FG Flip X ---- ---- ---- ---0 FG Flip Y 000a.w ? always 0x0002 ? There are more! *************************************************************************** [gtmr] car select screen scroll values: Flipscreen off: $6x0000: $72c0 ; $fbc0 ; 7340 ; 0 $72c0/$40 = $1cb = $200-$35 / $7340/$40 = $1cd = $1cb+2 $fbc0/$40 = -$11 Flipscreen on: $6x0000: $5d00 ; $3780 ; $5c80 ; $3bc0 $5d00/$40 = $174 = $200-$8c / $5c80/$40 = $172 = $174-2 $3780/$40 = $de / $3bc0/$40 = $ef */ #include "emu.h" #include "kaneko_tmap.h" void kaneko_view2_tilemap_device::vram_map(address_map &map) { map(0x0000, 0x0fff).rw(FUNC(kaneko_view2_tilemap_device::vram_1_r), FUNC(kaneko_view2_tilemap_device::vram_1_w)).share("vram_1"); map(0x1000, 0x1fff).rw(FUNC(kaneko_view2_tilemap_device::vram_0_r), FUNC(kaneko_view2_tilemap_device::vram_0_w)).share("vram_0"); map(0x2000, 0x2fff).rw(FUNC(kaneko_view2_tilemap_device::scroll_1_r), FUNC(kaneko_view2_tilemap_device::scroll_1_w)).share("scroll_1"); map(0x3000, 0x3fff).rw(FUNC(kaneko_view2_tilemap_device::scroll_0_r), FUNC(kaneko_view2_tilemap_device::scroll_0_w)).share("scroll_0"); } DEFINE_DEVICE_TYPE(KANEKO_TMAP, kaneko_view2_tilemap_device, "kaneko_view2", "Kaneko VIEW2 Tilemaps") kaneko_view2_tilemap_device::kaneko_view2_tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, KANEKO_TMAP, tag, owner, clock) , device_gfx_interface(mconfig, *this, nullptr) , m_vram(*this, "vram_%u", 0U) , m_vscroll(*this, "scroll_%u", 0U) , m_gfxrom(*this, DEVICE_SELF) , m_colbase(0) , m_dx(0) , m_dy(0) , m_xdim(0) , m_ydim(0) , m_invert_flip(0) , m_view2_cb(*this) , m_regs(nullptr) { } template TILE_GET_INFO_MEMBER(kaneko_view2_tilemap_device::get_tile_info) { const u16 attr = m_vram[Layer][2 * tile_index + 0]; u32 code = m_vram[Layer][2 * tile_index + 1]; if (!m_view2_cb.isnull()) m_view2_cb(Layer, &code); SET_TILE_INFO_MEMBER(0, code, (attr >> 2) & 0x3f, TILE_FLIPXY(attr & 3)); tileinfo.category = (attr >> 8) & 7; } void kaneko_view2_tilemap_device::device_start() { /* 16x16x4 tiles (made of four 8x8 tiles) */ gfx_layout layout = { 16,16, 0, 4, { STEP4(0,1) }, { 4, 0, 12, 8, 20, 16, 28, 24, 8*32+4, 8*32+0, 8*32+12, 8*32+8, 8*32+20, 8*32+16, 8*32+28, 8*32+24 }, { STEP8(0,32), STEP8(16*32,32) }, 16*16*4 }; layout.total = m_gfxrom->bytes() / ((16*16*4) / 8); m_view2_cb.resolve(); m_regs = make_unique_clear(0x20/2); set_gfx(0, std::make_unique(&palette(), layout, m_gfxrom->base(), 0, 0x40, m_colbase)); m_tmap[0] = &machine().tilemap().create( *this, tilemap_get_info_delegate(*this, FUNC(kaneko_view2_tilemap_device::get_tile_info<0>)), TILEMAP_SCAN_ROWS, 16,16, 0x20,0x20); m_tmap[1] = &machine().tilemap().create( *this, tilemap_get_info_delegate(*this, FUNC(kaneko_view2_tilemap_device::get_tile_info<1>)), TILEMAP_SCAN_ROWS, 16,16, 0x20,0x20); m_tmap[0]->set_transparent_pen(0); m_tmap[1]->set_transparent_pen(0); m_tmap[0]->set_scroll_rows(0x200); // Line Scroll m_tmap[1]->set_scroll_rows(0x200); m_tmap[0]->set_scrolldx(-m_dx, m_xdim + m_dx - 1 ); m_tmap[1]->set_scrolldx(-(m_dx+2), m_xdim + (m_dx + 2) - 1); m_tmap[0]->set_scrolldy(-m_dy, m_ydim + m_dy - 1); m_tmap[1]->set_scrolldy(-m_dy, m_ydim + m_dy - 1); save_pointer(NAME(m_regs), 0x20/2); } void kaneko_view2_tilemap_device::device_reset() { } void kaneko_view2_tilemap_device::vram_w(int _N_, offs_t offset, u16 data, u16 mem_mask) { COMBINE_DATA(&m_vram[_N_][offset]); m_tmap[_N_]->mark_tile_dirty(offset/2); } void kaneko_view2_tilemap_device::prepare(bitmap_ind16 &bitmap, const rectangle &cliprect) { prepare_common(bitmap, cliprect); } void kaneko_view2_tilemap_device::prepare(bitmap_rgb32 &bitmap, const rectangle &cliprect) { prepare_common(bitmap, cliprect); } template void kaneko_view2_tilemap_device::prepare_common(_BitmapClass &bitmap, const rectangle &cliprect) { const u16 layers_flip_0 = m_regs[4]; /* Enable layers */ m_tmap[0]->enable(~layers_flip_0 & 0x1000); m_tmap[1]->enable(~layers_flip_0 & 0x0010); /* Flip layers */ if (!m_invert_flip) { m_tmap[0]->set_flip(((layers_flip_0 & 0x0100) ? TILEMAP_FLIPY : 0) | ((layers_flip_0 & 0x0200) ? TILEMAP_FLIPX : 0)); m_tmap[1]->set_flip(((layers_flip_0 & 0x0100) ? TILEMAP_FLIPY : 0) | ((layers_flip_0 & 0x0200) ? TILEMAP_FLIPX : 0)); } else { m_tmap[0]->set_flip(((layers_flip_0 & 0x0100) ? 0 : TILEMAP_FLIPY) | ((layers_flip_0 & 0x0200) ? 0 : TILEMAP_FLIPX)); m_tmap[1]->set_flip(((layers_flip_0 & 0x0100) ? 0 : TILEMAP_FLIPY) | ((layers_flip_0 & 0x0200) ? 0 : TILEMAP_FLIPX)); } /* Scroll layers */ const u16 layer0_scrollx = m_regs[2]; const u16 layer0_scrolly = m_regs[3] >> 6; const u16 layer1_scrollx = m_regs[0]; const u16 layer1_scrolly = m_regs[1] >> 6; m_tmap[0]->set_scrolly(0, layer0_scrolly); m_tmap[1]->set_scrolly(0, layer1_scrolly); for (int i = 0; i < 0x200; i++) { u16 scroll = (layers_flip_0 & 0x0800) ? m_vscroll[0][i] : 0; m_tmap[0]->set_scrollx(i,(layer0_scrollx + scroll) >> 6 ); scroll = (layers_flip_0 & 0x0008) ? m_vscroll[1][i] : 0; m_tmap[1]->set_scrollx(i,(layer1_scrollx + scroll) >> 6 ); } } void kaneko_view2_tilemap_device::render_tilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri) { render_tilemap_common(screen, bitmap, cliprect, pri); } void kaneko_view2_tilemap_device::render_tilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int pri) { render_tilemap_common(screen, bitmap, cliprect, pri); } template void kaneko_view2_tilemap_device::render_tilemap_common(screen_device &screen, _BitmapClass &bitmap, const rectangle &cliprect, int pri) { m_tmap[0]->draw(screen, bitmap, cliprect, pri, pri, 0); m_tmap[1]->draw(screen, bitmap, cliprect, pri, pri, 0); } void kaneko_view2_tilemap_device::render_tilemap_alt(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri, int v2pri) { render_tilemap_alt_common(screen, bitmap, cliprect, pri, v2pri); } void kaneko_view2_tilemap_device::render_tilemap_alt(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int pri, int v2pri) { render_tilemap_alt_common(screen, bitmap, cliprect, pri, v2pri); } template void kaneko_view2_tilemap_device::render_tilemap_alt_common(screen_device &screen, _BitmapClass &bitmap, const rectangle &cliprect, int pri, int v2pri) { m_tmap[0]->draw(screen, bitmap, cliprect, pri, v2pri ? pri : 0, 0); m_tmap[1]->draw(screen, bitmap, cliprect, pri, v2pri ? pri : 0, 0); } void kaneko_view2_tilemap_device::vram_0_w(offs_t offset, u16 data, u16 mem_mask){ vram_w(0, offset, data, mem_mask); } void kaneko_view2_tilemap_device::vram_1_w(offs_t offset, u16 data, u16 mem_mask){ vram_w(1, offset, data, mem_mask); } u16 kaneko_view2_tilemap_device::vram_0_r(offs_t offset){ return m_vram[0][offset]; } u16 kaneko_view2_tilemap_device::vram_1_r(offs_t offset){ return m_vram[1][offset]; } void kaneko_view2_tilemap_device::scroll_0_w(offs_t offset, u16 data, u16 mem_mask){ COMBINE_DATA(&m_vscroll[0][offset]); } void kaneko_view2_tilemap_device::scroll_1_w(offs_t offset, u16 data, u16 mem_mask){ COMBINE_DATA(&m_vscroll[1][offset]); } u16 kaneko_view2_tilemap_device::scroll_0_r(offs_t offset){ return m_vscroll[0][offset]; } u16 kaneko_view2_tilemap_device::scroll_1_r(offs_t offset){ return m_vscroll[1][offset]; } u16 kaneko_view2_tilemap_device::regs_r(offs_t offset) { return m_regs[offset]; } void kaneko_view2_tilemap_device::regs_w(offs_t offset, u16 data, u16 mem_mask) { COMBINE_DATA(&m_regs[offset]); } void kaneko_view2_tilemap_device::mark_layer_dirty(u8 Layer) { m_tmap[Layer]->mark_all_dirty(); }