// license:BSD-3-Clause // copyright-holders:Phil Stroffolino, Aaron Giles, Alex W. Jackson /**************************************************************************************************************/ /* Land Line Buffer Land Generator 0xf,0x7,0xe,0x6,0xd,0x5,0xc,0x4, 0xb,0x3,0xa,0x2,0x9,0x1,0x8,0x0 */ /* Preliminary! The road circuitry is identical for all the driving games. * * There are several chunks of RAM * * Road Tilemap: * 0x00000..0x0ffff 64x512 tilemap * * Road Tiles: * 0x10000..0x1f9ff 16x16x2bpp tiles * * * Line Attributes: * * 0x1fa00..0x1fbdf xxx- ---- ---- ---- priority * ---- xxxx xxxx xxxx xscroll * * 0x1fbfe horizontal adjust? * 0x0017 * 0x0018 (Final Lap3) * * 0x1fc00..0x1fddf selects line in source bitmap * 0x1fdfe yscroll * * 0x1fe00..0x1ffdf ---- --xx xxxx xxxx zoomx * 0x1fffd always 0xffff 0xffff? */ #include "emu.h" #include "video/c45.h" //**************************************************************************** // CONSTANTS //**************************************************************************** // device type definition DEFINE_DEVICE_TYPE(NAMCO_C45_ROAD, namco_c45_road_device, "namco_c45_road", "Namco C45 Road") const gfx_layout namco_c45_road_device::tilelayout = { ROAD_TILE_SIZE, ROAD_TILE_SIZE, RGN_FRAC(1,1), 2, { 0, 8 }, { STEP8(0, 1), STEP8(16, 1) }, { STEP16(0, 32) }, 0x200 // offset to next tile }; GFXDECODE_MEMBER( namco_c45_road_device::gfxinfo ) GFXDECODE_DEVICE_RAM( "tileram", 0, tilelayout, 0xf00, 64 ) GFXDECODE_END void namco_c45_road_device::map(address_map &map) { map(0x00000, 0x0ffff).ram().w(this, FUNC(namco_c45_road_device::tilemap_w)).share("tmapram"); map(0x10000, 0x1f9ff).ram().w(this, FUNC(namco_c45_road_device::tileram_w)).share("tileram"); map(0x1fa00, 0x1ffff).ram().share("lineram"); } //------------------------------------------------- // namco_c45_road_device -- constructor //------------------------------------------------- namco_c45_road_device::namco_c45_road_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, NAMCO_C45_ROAD, tag, owner, clock), device_gfx_interface(mconfig, *this, gfxinfo), device_memory_interface(mconfig, *this), m_space_config("c45", ENDIANNESS_BIG, 16, 17, 0, address_map_constructor(FUNC(namco_c45_road_device::map), this)), m_tmapram(*this, "tmapram"), m_tileram(*this, "tileram"), m_lineram(*this, "lineram"), m_transparent_color(~0) { } // We need these trampolines for now because uplift_submaps() // can't deal with address maps that contain RAM. // We need to explicitly use device_memory_interface::space() // because read/write handlers have a parameter called 'space' //------------------------------------------------- // read -- CPU read from our address space //------------------------------------------------- READ16_MEMBER( namco_c45_road_device::read ) { return device_memory_interface::space().read_word(offset*2); } //------------------------------------------------- // write -- CPU write to our address space //------------------------------------------------- WRITE16_MEMBER( namco_c45_road_device::write ) { device_memory_interface::space().write_word(offset*2, data, mem_mask); } //------------------------------------------------- // tilemap_w -- write to tilemap RAM //------------------------------------------------- WRITE16_MEMBER( namco_c45_road_device::tilemap_w ) { COMBINE_DATA(&m_tmapram[offset]); m_tilemap->mark_tile_dirty(offset); } //------------------------------------------------- // tileram_w -- write to tile RAM //------------------------------------------------- WRITE16_MEMBER( namco_c45_road_device::tileram_w ) { COMBINE_DATA(&m_tileram[offset]); gfx(0)->mark_dirty(offset / WORDS_PER_ROAD_TILE); } //------------------------------------------------- // draw -- render to the target bitmap //------------------------------------------------- void namco_c45_road_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect, int pri) { bitmap_ind16 &source_bitmap = m_tilemap->pixmap(); unsigned yscroll = m_lineram[0x3fe/2]; // loop over scanlines for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { // skip if we are not the right priority int screenx = m_lineram[y + 15]; if (pri != ((screenx & 0xf000) >> 12)) continue; // skip if we don't have a valid zoom factor unsigned zoomx = m_lineram[0x400/2 + y + 15] & 0x3ff; if (zoomx == 0) continue; // skip if we don't have a valid source increment unsigned sourcey = m_lineram[0x200/2 + y + 15] + yscroll; const uint16_t *source_gfx = &source_bitmap.pix(sourcey & (ROAD_TILEMAP_HEIGHT - 1)); unsigned dsourcex = (ROAD_TILEMAP_WIDTH << 16) / zoomx; if (dsourcex == 0) continue; // mask off priority bits and sign-extend screenx &= 0x0fff; if (screenx & 0x0800) screenx |= ~0x7ff; // adjust the horizontal placement screenx -= 64; // needs adjustment to left int numpixels = (44 * ROAD_TILE_SIZE << 16) / dsourcex; unsigned sourcex = 0; // crop left int clip_pixels = cliprect.min_x - screenx; if (clip_pixels > 0) { numpixels -= clip_pixels; sourcex += dsourcex*clip_pixels; screenx = cliprect.min_x; } // crop right clip_pixels = (screenx + numpixels) - (cliprect.max_x + 1); if (clip_pixels > 0) numpixels -= clip_pixels; // TBA: work out palette mapping for Final Lap, Suzuka // BUT: support transparent color for Thunder Ceptor uint16_t *dest = &bitmap.pix(y); if (m_transparent_color != ~0) { while (numpixels-- > 0) { int pen = source_gfx[sourcex >> 16]; if (palette().pen_indirect(pen) != m_transparent_color) { if (m_clut != nullptr) pen = (pen & ~0xff) | m_clut[pen & 0xff]; dest[screenx] = pen; } screenx++; sourcex += dsourcex; } } else { while (numpixels-- > 0) { int pen = source_gfx[sourcex >> 16]; if (m_clut != nullptr) pen = (pen & ~0xff) | m_clut[pen & 0xff]; dest[screenx++] = pen; sourcex += dsourcex; } } } } //------------------------------------------------- // device_start -- device startup //------------------------------------------------- void namco_c45_road_device::device_start() { if (memregion("clut") != nullptr) m_clut = memregion("clut")->base(); // create a tilemap for the road m_tilemap = &machine().tilemap().create(*this, tilemap_get_info_delegate(FUNC(namco_c45_road_device::get_road_info), this), TILEMAP_SCAN_ROWS, ROAD_TILE_SIZE, ROAD_TILE_SIZE, ROAD_COLS, ROAD_ROWS); } //------------------------------------------------- // memory_space_config - return a description of // any address spaces owned by this device //------------------------------------------------- device_memory_interface::space_config_vector namco_c45_road_device::memory_space_config() const { return space_config_vector { std::make_pair(0, &m_space_config) }; } //------------------------------------------------- // get_road_info -- tilemap callback //------------------------------------------------- TILE_GET_INFO_MEMBER( namco_c45_road_device::get_road_info ) { // ------xx xxxxxxxx tile number // xxxxxx-- -------- palette select uint16_t data = m_tmapram[tile_index]; int tile = data & 0x3ff; int color = data >> 10; SET_TILE_INFO_MEMBER(0, tile, color, 0); }