1 // license:BSD-3-Clause
2 // copyright-holders:Phil Stroffolino, Aaron Giles, Alex W. Jackson
3 /**************************************************************************************************************/
4 /*
5     Land Line Buffer
6     Land Generator
7         0xf,0x7,0xe,0x6,0xd,0x5,0xc,0x4,
8         0xb,0x3,0xa,0x2,0x9,0x1,0x8,0x0
9 
10 */
11 
12 /* Preliminary!  The road circuitry is identical for all the driving games.
13  *
14  * There are several chunks of RAM
15  *
16  *  Road Tilemap:
17  *      0x00000..0x0ffff    64x512 tilemap
18  *
19  *  Road Tiles:
20  *      0x10000..0x1f9ff    16x16x2bpp tiles
21  *
22  *
23  *  Line Attributes:
24  *
25  *      0x1fa00..0x1fbdf    xxx- ---- ---- ----     priority
26  *                          ---- xxxx xxxx xxxx     xscroll
27  *
28  *      0x1fbfe             horizontal adjust?
29  *                          0x0017
30  *                          0x0018 (Final Lap3)
31  *
32  *      0x1fc00..0x1fddf    selects line in source bitmap
33  *      0x1fdfe             yscroll
34  *
35  *      0x1fe00..0x1ffdf    ---- --xx xxxx xxxx     zoomx
36  *      0x1fffd             always 0xffff 0xffff?
37  */
38 
39 #include "emu.h"
40 #include "video/c45.h"
41 
42 
43 //****************************************************************************
44 //  CONSTANTS
45 //****************************************************************************
46 
47 // device type definition
48 DEFINE_DEVICE_TYPE(NAMCO_C45_ROAD, namco_c45_road_device, "namco_c45_road", "Namco C45 Road")
49 
50 
51 const gfx_layout namco_c45_road_device::tilelayout =
52 {
53 	ROAD_TILE_SIZE, ROAD_TILE_SIZE,
54 	RGN_FRAC(1,1),
55 	2,
56 	{ 0, 8 },
57 	{ STEP8(0, 1), STEP8(16, 1) },
58 	{ STEP16(0, 32) },
59 	0x200 // offset to next tile
60 };
61 
62 
63 GFXDECODE_MEMBER( namco_c45_road_device::gfxinfo )
64 	GFXDECODE_DEVICE_RAM( "tileram", 0, tilelayout, 0xf00, 64 )
65 GFXDECODE_END
66 
67 
map(address_map & map)68 void namco_c45_road_device::map(address_map &map)
69 {
70 	map(0x00000, 0x0ffff).ram().w(FUNC(namco_c45_road_device::tilemap_w)).share("tmapram");
71 	map(0x10000, 0x1f9ff).ram().w(FUNC(namco_c45_road_device::tileram_w)).share("tileram");
72 	map(0x1fa00, 0x1ffff).ram().share("lineram");
73 }
74 
75 
76 //-------------------------------------------------
77 //  namco_c45_road_device -- constructor
78 //-------------------------------------------------
79 
namco_c45_road_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)80 namco_c45_road_device::namco_c45_road_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
81 	device_t(mconfig, NAMCO_C45_ROAD, tag, owner, clock),
82 	device_gfx_interface(mconfig, *this, gfxinfo),
83 	device_memory_interface(mconfig, *this),
84 	m_space_config("c45", ENDIANNESS_BIG, 16, 17, 0, address_map_constructor(FUNC(namco_c45_road_device::map), this)),
85 	m_tmapram(*this, "tmapram"),
86 	m_tileram(*this, "tileram"),
87 	m_lineram(*this, "lineram"),
88 	m_clut(*this, "clut"),
89 	m_transparent_color(~0)
90 {
91 }
92 
93 
94 
95 // We need these trampolines for now because uplift_submaps()
96 // can't deal with address maps that contain RAM.
97 // We need to explicitly use device_memory_interface::space()
98 // because read/write handlers have a parameter called 'space'
99 
100 //-------------------------------------------------
101 //  read -- CPU read from our address space
102 //-------------------------------------------------
103 
read(offs_t offset)104 uint16_t namco_c45_road_device::read(offs_t offset)
105 {
106 	return device_memory_interface::space().read_word(offset*2);
107 }
108 
109 
110 //-------------------------------------------------
111 //  write -- CPU write to our address space
112 //-------------------------------------------------
113 
write(offs_t offset,uint16_t data,uint16_t mem_mask)114 void namco_c45_road_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
115 {
116 	device_memory_interface::space().write_word(offset*2, data, mem_mask);
117 }
118 
119 
120 //-------------------------------------------------
121 //  tilemap_w -- write to tilemap RAM
122 //-------------------------------------------------
123 
tilemap_w(offs_t offset,uint16_t data,uint16_t mem_mask)124 void namco_c45_road_device::tilemap_w(offs_t offset, uint16_t data, uint16_t mem_mask)
125 {
126 	COMBINE_DATA(&m_tmapram[offset]);
127 	m_tilemap->mark_tile_dirty(offset);
128 }
129 
130 
131 //-------------------------------------------------
132 //  tileram_w -- write to tile RAM
133 //-------------------------------------------------
134 
tileram_w(offs_t offset,uint16_t data,uint16_t mem_mask)135 void namco_c45_road_device::tileram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
136 {
137 	COMBINE_DATA(&m_tileram[offset]);
138 	gfx(0)->mark_dirty(offset / WORDS_PER_ROAD_TILE);
139 }
140 
141 
142 //-------------------------------------------------
143 //  draw -- render to the target bitmap
144 //-------------------------------------------------
145 
draw(bitmap_ind16 & bitmap,const rectangle & cliprect,int pri)146 void namco_c45_road_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect, int pri)
147 {
148 	bitmap_ind16 &source_bitmap = m_tilemap->pixmap();
149 	unsigned yscroll = m_lineram[0x3fe/2];
150 
151 	// loop over scanlines
152 	for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
153 	{
154 		// skip if we are not the right priority
155 		int screenx = m_lineram[y + 15];
156 		if (pri != ((screenx & 0xf000) >> 12))
157 			continue;
158 
159 		// skip if we don't have a valid zoom factor
160 		unsigned zoomx = m_lineram[0x400/2 + y + 15] & 0x3ff;
161 		if (zoomx == 0)
162 			continue;
163 
164 		// skip if we don't have a valid source increment
165 		unsigned sourcey = m_lineram[0x200/2 + y + 15] + yscroll;
166 		const uint16_t *source_gfx = &source_bitmap.pix(sourcey & (ROAD_TILEMAP_HEIGHT - 1));
167 		unsigned dsourcex = (ROAD_TILEMAP_WIDTH << 16) / zoomx;
168 		if (dsourcex == 0)
169 			continue;
170 
171 		// mask off priority bits and sign-extend
172 		screenx &= 0x0fff;
173 		if (screenx & 0x0800)
174 			screenx |= ~0x7ff;
175 
176 		// adjust the horizontal placement
177 		screenx -= 64; // needs adjustment to left
178 
179 		int numpixels = (44 * ROAD_TILE_SIZE << 16) / dsourcex;
180 		unsigned sourcex = 0;
181 
182 		// crop left
183 		int clip_pixels = cliprect.min_x - screenx;
184 		if (clip_pixels > 0)
185 		{
186 			numpixels -= clip_pixels;
187 			sourcex += dsourcex*clip_pixels;
188 			screenx = cliprect.min_x;
189 		}
190 
191 		// crop right
192 		clip_pixels = (screenx + numpixels) - (cliprect.max_x + 1);
193 		if (clip_pixels > 0)
194 			numpixels -= clip_pixels;
195 
196 		// TBA: work out palette mapping for Final Lap, Suzuka
197 
198 		// BUT: support transparent color for Thunder Ceptor
199 		uint16_t *dest = &bitmap.pix(y);
200 		if (m_transparent_color != ~0)
201 		{
202 			while (numpixels-- > 0)
203 			{
204 				int pen = source_gfx[sourcex >> 16];
205 				if (palette().pen_indirect(pen) != m_transparent_color)
206 				{
207 					if (m_clut != nullptr)
208 						pen = (pen & ~0xff) | m_clut[pen & 0xff];
209 					dest[screenx] = pen;
210 				}
211 				screenx++;
212 				sourcex += dsourcex;
213 			}
214 		}
215 		else
216 		{
217 			while (numpixels-- > 0)
218 			{
219 				int pen = source_gfx[sourcex >> 16];
220 				if (m_clut != nullptr)
221 					pen = (pen & ~0xff) | m_clut[pen & 0xff];
222 				dest[screenx++] = pen;
223 				sourcex += dsourcex;
224 			}
225 		}
226 	}
227 }
228 
229 
230 //-------------------------------------------------
231 //  device_start -- device startup
232 //-------------------------------------------------
233 
device_start()234 void namco_c45_road_device::device_start()
235 {
236 	// create a tilemap for the road
237 	m_tilemap = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(namco_c45_road_device::get_road_info)),
238 			TILEMAP_SCAN_ROWS, ROAD_TILE_SIZE, ROAD_TILE_SIZE, ROAD_COLS, ROAD_ROWS);
239 }
240 
241 
242 //-------------------------------------------------
243 //  memory_space_config - return a description of
244 //  any address spaces owned by this device
245 //-------------------------------------------------
246 
memory_space_config() const247 device_memory_interface::space_config_vector namco_c45_road_device::memory_space_config() const
248 {
249 	return space_config_vector {
250 		std::make_pair(0, &m_space_config)
251 	};
252 }
253 
254 
255 //-------------------------------------------------
256 //  get_road_info -- tilemap callback
257 //-------------------------------------------------
258 
TILE_GET_INFO_MEMBER(namco_c45_road_device::get_road_info)259 TILE_GET_INFO_MEMBER( namco_c45_road_device::get_road_info )
260 {
261 	// ------xx xxxxxxxx tile number
262 	// xxxxxx-- -------- palette select
263 	uint16_t data = m_tmapram[tile_index];
264 	int tile = data & 0x3ff;
265 	int color = data >> 10;
266 	tileinfo.set(0, tile, color, 0);
267 }
268