1 // license:BSD-3-Clause
2 // copyright-holders:Lee Taylor
3 // thanks-to:John Clegg,Tomasz Slanina
4 /***************************************************************************
5 
6   video.c
7 
8   Traverse USA
9 
10 L Taylor
11 J Clegg
12 
13   Functions to emulate the video hardware of the machine.
14 
15 ***************************************************************************/
16 
17 #include "emu.h"
18 #include "includes/travrusa.h"
19 
20 /***************************************************************************
21 
22   Convert the color PROMs into a more useable format.
23 
24   Traverse USA has one 256x8 character palette PROM (some versions have two
25   256x4), one 32x8 sprite palette PROM, and one 256x4 sprite color lookup
26   table PROM.
27 
28   I don't know for sure how the palette PROMs are connected to the RGB
29   output, but it's probably something like this; note that RED and BLUE
30   are swapped wrt the usual configuration.
31 
32   bit 7 -- 220 ohm resistor  -- RED
33         -- 470 ohm resistor  -- RED
34         -- 220 ohm resistor  -- GREEN
35         -- 470 ohm resistor  -- GREEN
36         -- 1  kohm resistor  -- GREEN
37         -- 220 ohm resistor  -- BLUE
38         -- 470 ohm resistor  -- BLUE
39   bit 0 -- 1  kohm resistor  -- BLUE
40 
41 ***************************************************************************/
42 
travrusa_palette(palette_device & palette) const43 void travrusa_state::travrusa_palette(palette_device &palette) const
44 {
45 	const uint8_t *color_prom = memregion("proms")->base();
46 
47 	// create a lookup table for the palette
48 	for (int i = 0; i < 0x80; i++)
49 	{
50 		int bit0, bit1, bit2;
51 
52 		// red component
53 		bit0 = 0;
54 		bit1 = BIT(color_prom[i], 6);
55 		bit2 = BIT(color_prom[i], 7);
56 		int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
57 
58 		// green component
59 		bit0 = BIT(color_prom[i], 3);
60 		bit1 = BIT(color_prom[i], 4);
61 		bit2 = BIT(color_prom[i], 5);
62 		int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
63 
64 		// blue component
65 		bit0 = BIT(color_prom[i], 0);
66 		bit1 = BIT(color_prom[i], 1);
67 		bit2 = BIT(color_prom[i], 2);
68 		int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
69 
70 		palette.set_indirect_color(i, rgb_t(r, g, b));
71 	}
72 
73 	for (int i = 0x80; i < 0x90; i++)
74 	{
75 		int bit0, bit1, bit2;
76 
77 		// red component
78 		bit0 = 0;
79 		bit1 = BIT(color_prom[(i - 0x80) + 0x200], 6);
80 		bit2 = BIT(color_prom[(i - 0x80) + 0x200], 7);
81 		int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
82 
83 		// green component
84 		bit0 = BIT(color_prom[(i - 0x80) + 0x200], 3);
85 		bit1 = BIT(color_prom[(i - 0x80) + 0x200], 4);
86 		bit2 = BIT(color_prom[(i - 0x80) + 0x200], 5);
87 		int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
88 
89 		// blue component
90 		bit0 = BIT(color_prom[(i - 0x80) + 0x200], 0);
91 		bit1 = BIT(color_prom[(i - 0x80) + 0x200], 1);
92 		bit2 = BIT(color_prom[(i - 0x80) + 0x200], 2);
93 		int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
94 
95 		palette.set_indirect_color(i, rgb_t(r, g, b));
96 	}
97 
98 	// color_prom now points to the beginning of the lookup table
99 	color_prom += 0x220;
100 
101 	// characters
102 	for (int i = 0; i < 0x80; i++)
103 		palette.set_pen_indirect(i, i);
104 
105 	// sprites
106 	for (int i = 0x80; i < 0x100; i++)
107 	{
108 		uint8_t const ctabentry = (color_prom[i - 0x80] & 0x0f) | 0x80;
109 		palette.set_pen_indirect(i, ctabentry);
110 	}
111 }
112 
shtrider_palette(palette_device & palette) const113 void travrusa_state::shtrider_palette(palette_device &palette) const
114 {
115 	const uint8_t *color_prom = memregion("proms")->base();
116 
117 	// create a lookup table for the palette
118 	for (int i = 0; i < 0x80; i++)
119 	{
120 		int bit0, bit1, bit2;
121 
122 		// red component
123 		bit0 = 0;
124 		bit1 = BIT(color_prom[i + 0x000], 2);
125 		bit2 = BIT(color_prom[i + 0x000], 3);
126 		int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
127 
128 		// green component
129 		bit0 = BIT(color_prom[i + 0x100], 3);
130 		bit1 = BIT(color_prom[i + 0x000], 0);
131 		bit2 = BIT(color_prom[i + 0x000], 1);
132 		int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
133 
134 		// blue component
135 		bit0 = BIT(color_prom[i + 0x100], 0);
136 		bit1 = BIT(color_prom[i + 0x100], 1);
137 		bit2 = BIT(color_prom[i + 0x100], 2);
138 		int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
139 
140 		palette.set_indirect_color(i, rgb_t(r, g, b));
141 	}
142 
143 	for (int i = 0x80; i < 0x90; i++)
144 	{
145 		int bit0, bit1, bit2;
146 
147 		// red component
148 		bit0 = 0;
149 		bit1 = BIT(color_prom[(i - 0x80) + 0x200], 6);
150 		bit2 = BIT(color_prom[(i - 0x80) + 0x200], 7);
151 		int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
152 
153 		// green component
154 		bit0 = BIT(color_prom[(i - 0x80) + 0x200], 3);
155 		bit1 = BIT(color_prom[(i - 0x80) + 0x200], 4);
156 		bit2 = BIT(color_prom[(i - 0x80) + 0x200], 5);
157 		int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
158 
159 		// blue component
160 		bit0 = BIT(color_prom[(i - 0x80) + 0x200], 0);
161 		bit1 = BIT(color_prom[(i - 0x80) + 0x200], 1);
162 		bit2 = BIT(color_prom[(i - 0x80) + 0x200], 2);
163 		int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
164 
165 		palette.set_indirect_color(i, rgb_t(r, g, b));
166 	}
167 
168 	// color_prom now points to the beginning of the lookup table
169 	color_prom += 0x220;
170 
171 	// characters
172 	for (int i = 0; i < 0x80; i++)
173 		palette.set_pen_indirect(i, i);
174 
175 	// sprites
176 	for (int i = 0x80; i < 0x100; i++)
177 	{
178 		uint8_t const ctabentry = (color_prom[i - 0x80] & 0x0f) | 0x80;
179 		palette.set_pen_indirect(i, ctabentry);
180 	}
181 }
182 
183 
184 
185 /***************************************************************************
186 
187   Callbacks for the TileMap code
188 
189 ***************************************************************************/
190 
TILE_GET_INFO_MEMBER(travrusa_state::get_tile_info)191 TILE_GET_INFO_MEMBER(travrusa_state::get_tile_info)
192 {
193 	uint8_t attr = m_videoram[2 * tile_index + 1];
194 	int flags = TILE_FLIPXY((attr & 0x30) >> 4);
195 
196 	tileinfo.group = ((attr & 0x0f) == 0x0f) ? 1 : 0;   /* tunnels */
197 
198 	tileinfo.set(0,
199 			m_videoram[2 * tile_index] + ((attr & 0xc0) << 2),
200 			attr & 0x0f,
201 			flags);
202 }
203 
204 
205 
206 /***************************************************************************
207 
208   Start the video hardware emulation.
209 
210 ***************************************************************************/
211 
video_start()212 void travrusa_state::video_start()
213 {
214 	save_item(NAME(m_scrollx));
215 
216 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(travrusa_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
217 
218 	m_bg_tilemap->set_transmask(0, 0xff, 0x00); /* split type 0 is totally transparent in front half */
219 	m_bg_tilemap->set_transmask(1, 0x3f, 0xc0); /* split type 1 has pens 6 and 7 opaque - tunnels */
220 
221 	m_bg_tilemap->set_scroll_rows(4);
222 }
223 
224 
225 
226 /***************************************************************************
227 
228   Memory handlers
229 
230 ***************************************************************************/
231 
travrusa_videoram_w(offs_t offset,uint8_t data)232 void travrusa_state::travrusa_videoram_w(offs_t offset, uint8_t data)
233 {
234 	m_videoram[offset] = data;
235 	m_bg_tilemap->mark_tile_dirty(offset / 2);
236 }
237 
238 
set_scroll()239 void travrusa_state::set_scroll(  )
240 {
241 	int i;
242 
243 	for (i = 0; i <= 2; i++)
244 		m_bg_tilemap->set_scrollx(i, m_scrollx[0] + 256 * m_scrollx[1]);
245 
246 	m_bg_tilemap->set_scrollx(3, 0);
247 }
248 
travrusa_scroll_x_low_w(uint8_t data)249 void travrusa_state::travrusa_scroll_x_low_w(uint8_t data)
250 {
251 	m_scrollx[0] = data;
252 	set_scroll();
253 }
254 
travrusa_scroll_x_high_w(uint8_t data)255 void travrusa_state::travrusa_scroll_x_high_w(uint8_t data)
256 {
257 	m_scrollx[1] = data;
258 	set_scroll();
259 }
260 
261 
travrusa_flipscreen_w(uint8_t data)262 void travrusa_state::travrusa_flipscreen_w(uint8_t data)
263 {
264 	/* screen flip is handled both by software and hardware */
265 	data ^= ~ioport("DSW2")->read() & 1;
266 
267 	flip_screen_set(data & 1);
268 
269 	machine().bookkeeping().coin_counter_w(0, data & 0x02);
270 	machine().bookkeeping().coin_counter_w(1, data & 0x20);
271 }
272 
273 
274 
275 /***************************************************************************
276 
277   Display refresh
278 
279 ***************************************************************************/
280 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect)281 void travrusa_state::draw_sprites(bitmap_ind16 &bitmap,const rectangle &cliprect)
282 {
283 	int offs;
284 	const rectangle spritevisiblearea(1*8, 31*8-1, 0*8, 24*8-1);
285 	const rectangle spritevisibleareaflip(1*8, 31*8-1, 8*8, 32*8-1);
286 	rectangle clip = cliprect;
287 	if (flip_screen())
288 		clip &= spritevisibleareaflip;
289 	else
290 		clip &= spritevisiblearea;
291 
292 
293 	for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
294 	{
295 		int sx = ((m_spriteram[offs + 3] + 8) & 0xff) - 8;
296 		int sy = 240 - m_spriteram[offs];
297 		int code = m_spriteram[offs + 2];
298 		int attr = m_spriteram[offs + 1];
299 		int flipx = attr & 0x40;
300 		int flipy = attr & 0x80;
301 
302 		if (flip_screen())
303 		{
304 			sx = 240 - sx;
305 			sy = 240 - sy;
306 			flipx = !flipx;
307 			flipy = !flipy;
308 		}
309 
310 		m_gfxdecode->gfx(1)->transpen(bitmap,clip,
311 				code,
312 				attr & 0x0f,
313 				flipx, flipy,
314 				sx, sy, 0);
315 	}
316 }
317 
318 
screen_update_travrusa(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)319 uint32_t travrusa_state::screen_update_travrusa(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
320 {
321 	m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER1, 0);
322 	draw_sprites(bitmap,cliprect);
323 	m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER0, 0);
324 	return 0;
325 }
326