1 // license:BSD-3-Clause
2 // copyright-holders:Paul Leaman, Couriersud
3 /***************************************************************************
4 
5   video.c
6 
7   Functions to emulate the video hardware of the machine.
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 #include "includes/1942.h"
13 
14 /***************************************************************************
15 
16   Convert the color PROMs into a more useable format.
17 
18   1942 has three 256x4 palette PROMs (one per gun) and three 256x4 lookup
19   table PROMs (one for characters, one for sprites, one for background tiles).
20   The palette PROMs are connected to the RGB output this way:
21 
22   bit 3 -- 220 ohm resistor  -- RED/GREEN/BLUE
23         -- 470 ohm resistor  -- RED/GREEN/BLUE
24         -- 1  kohm resistor  -- RED/GREEN/BLUE
25   bit 0 -- 2.2kohm resistor  -- RED/GREEN/BLUE
26 
27 ***************************************************************************/
28 
create_palette(palette_device & palette) const29 void _1942_state::create_palette(palette_device &palette) const
30 {
31 	const uint8_t *color_prom = memregion("palproms")->base();
32 
33 	for (int i = 0; i < 256; i++)
34 	{
35 		// red component
36 		int bit0 = BIT(color_prom[i + 0 * 256], 0);
37 		int bit1 = BIT(color_prom[i + 0 * 256], 1);
38 		int bit2 = BIT(color_prom[i + 0 * 256], 2);
39 		int bit3 = BIT(color_prom[i + 0 * 256], 3);
40 		int const r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
41 		// green component
42 		bit0 = BIT(color_prom[i + 1 * 256], 0);
43 		bit1 = BIT(color_prom[i + 1 * 256], 1);
44 		bit2 = BIT(color_prom[i + 1 * 256], 2);
45 		bit3 = BIT(color_prom[i + 1 * 256], 3);
46 		int const g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
47 		// blue component
48 		bit0 = BIT(color_prom[i + 2 * 256], 0);
49 		bit1 = BIT(color_prom[i + 2 * 256], 1);
50 		bit2 = BIT(color_prom[i + 2 * 256], 2);
51 		bit3 = BIT(color_prom[i + 2 * 256], 3);
52 		int const b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
53 
54 		palette.set_indirect_color(i, rgb_t(r, g, b));
55 	}
56 }
57 
_1942_palette(palette_device & palette) const58 void _1942_state::_1942_palette(palette_device &palette) const
59 {
60 	create_palette(palette);
61 
62 	/* characters use palette entries 128-143 */
63 	int colorbase = 0;
64 	const uint8_t *charlut_prom = memregion("charprom")->base();
65 	for (int i = 0; i < 64 * 4; i++)
66 		palette.set_pen_indirect(colorbase + i, 0x80 | charlut_prom[i]);
67 
68 	// background tiles use palette entries 0-63 in four banks
69 	colorbase += 64 * 4;
70 	const uint8_t *tilelut_prom = memregion("tileprom")->base();
71 	for (int i = 0; i < 32 * 8; i++)
72 	{
73 		palette.set_pen_indirect(colorbase + 0 * 32 * 8 + i, 0x00 | tilelut_prom[i]);
74 		palette.set_pen_indirect(colorbase + 1 * 32 * 8 + i, 0x10 | tilelut_prom[i]);
75 		palette.set_pen_indirect(colorbase + 2 * 32 * 8 + i, 0x20 | tilelut_prom[i]);
76 		palette.set_pen_indirect(colorbase + 3 * 32 * 8 + i, 0x30 | tilelut_prom[i]);
77 	}
78 
79 	// sprites use palette entries 64-79
80 	colorbase += 4 * 32 * 8;
81 	const uint8_t *sprlut_prom = memregion("sprprom")->base();
82 	for (int i = 0; i < 16 * 16; i++)
83 		palette.set_pen_indirect(colorbase + i, 0x40 | sprlut_prom[i]);
84 }
85 
_1942p_palette(palette_device & palette) const86 void _1942p_state::_1942p_palette(palette_device &palette) const
87 {
88 	for (int i = 0; i < 0x400; i++)
89 		palette.set_pen_indirect(i, i);
90 
91 	uint8_t const *const color_prom = memregion("proms")->base();
92 	for (int i = 0; i < 0x100; i++)
93 		palette.set_pen_indirect(i + 0x400, color_prom[i] | 0x240);
94 }
95 
96 
97 
98 /***************************************************************************
99 
100   Callbacks for the TileMap code
101 
102 ***************************************************************************/
103 
TILE_GET_INFO_MEMBER(_1942_state::get_fg_tile_info)104 TILE_GET_INFO_MEMBER(_1942_state::get_fg_tile_info)
105 {
106 	int code = m_fg_videoram[tile_index];
107 	int color = m_fg_videoram[tile_index + 0x400];
108 	tileinfo.set(0,
109 			code + ((color & 0x80) << 1),
110 			color & 0x3f,
111 			0);
112 }
113 
TILE_GET_INFO_MEMBER(_1942_state::get_bg_tile_info)114 TILE_GET_INFO_MEMBER(_1942_state::get_bg_tile_info)
115 {
116 	tile_index = (tile_index & 0x0f) | ((tile_index & 0x01f0) << 1);
117 
118 	int code = m_bg_videoram[tile_index];
119 	int color = m_bg_videoram[tile_index + 0x10];
120 	tileinfo.set(1,
121 			code + ((color & 0x80) << 1),
122 			(color & 0x1f) + (0x20 * m_palette_bank),
123 			TILE_FLIPYX((color & 0x60) >> 5));
124 }
125 
126 
127 /***************************************************************************
128 
129   Start the video hardware emulation.
130 
131 ***************************************************************************/
video_start()132 void _1942_state::video_start()
133 {
134 	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(_1942_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
135 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(_1942_state::get_bg_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 32, 16);
136 
137 	m_fg_tilemap->set_transparent_pen(0);
138 }
139 
video_start()140 void _1942p_state::video_start()
141 {
142 	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(_1942_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
143 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(_1942_state::get_bg_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 32, 16);
144 
145 	m_fg_tilemap->set_transparent_pen(3);
146 }
147 
148 
149 /***************************************************************************
150 
151   Memory handlers
152 
153 ***************************************************************************/
154 
_1942_fgvideoram_w(offs_t offset,uint8_t data)155 void _1942_state::_1942_fgvideoram_w(offs_t offset, uint8_t data)
156 {
157 	m_fg_videoram[offset] = data;
158 	m_fg_tilemap->mark_tile_dirty(offset & 0x3ff);
159 }
160 
_1942_bgvideoram_w(offs_t offset,uint8_t data)161 void _1942_state::_1942_bgvideoram_w(offs_t offset, uint8_t data)
162 {
163 	m_bg_videoram[offset] = data;
164 	m_bg_tilemap->mark_tile_dirty((offset & 0x0f) | ((offset >> 1) & 0x01f0));
165 }
166 
167 
_1942_palette_bank_w(uint8_t data)168 void _1942_state::_1942_palette_bank_w(uint8_t data)
169 {
170 	if (m_palette_bank != data)
171 	{
172 		m_palette_bank = data & 3;
173 		m_bg_tilemap->mark_all_dirty();
174 	}
175 }
176 
_1942_scroll_w(offs_t offset,uint8_t data)177 void _1942_state::_1942_scroll_w(offs_t offset, uint8_t data)
178 {
179 	m_scroll[offset] = data;
180 	m_bg_tilemap->set_scrollx(0, m_scroll[0] | (m_scroll[1] << 8));
181 }
182 
183 
_1942_c804_w(uint8_t data)184 void _1942_state::_1942_c804_w(uint8_t data)
185 {
186 	/* bit 7: flip screen
187 	   bit 4: cpu B reset
188 	   bit 0: coin counter */
189 
190 	machine().bookkeeping().coin_counter_w(0,data & 0x01);
191 
192 	m_audiocpu->set_input_line(INPUT_LINE_RESET, (data & 0x10) ? ASSERT_LINE : CLEAR_LINE);
193 
194 	flip_screen_set(data & 0x80);
195 }
196 
197 
198 /***************************************************************************
199 
200   Display refresh
201 
202 ***************************************************************************/
203 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect)204 void _1942_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
205 {
206 	// Sprites 0 to 15 are drawn on all scanlines.
207 	// Sprites 16 to 23 are drawn on scanlines 16 to 127.
208 	// Sprites 24 to 31 are drawn on scanlines 128 to 239.
209 	//
210 	// The reason for this is ostensibly so that the back half of the sprite list can
211 	// be used to selectively mask sprites along the midpoint of the screen.
212 	//
213 	// Moreover, the H counter runs from 128 to 511 for a total of 384 horizontal
214 	// clocks per scanline. With an effective 6MHz pixel clock, this produces a
215 	// horizontal scan rate of exactly 15.625kHz, a standard scan rate for games
216 	// of this era.
217 	//
218 	// Sprites are drawn by MAME in reverse order, as the actual hardware only
219 	// permits a transparent pixel to be overwritten by an opaque pixel, and does
220 	// not support opaque-opaque overwriting - i.e., the first sprite to draw wins
221 	// control over its horizontal range. If MAME drew in forward order, it would
222 	// instead produce a last-sprite-wins behavior.
223 
224 	for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
225 	{
226 		const rectangle cliprecty(cliprect.min_x, cliprect.max_x, y, y);
227 		uint8_t objdata[4];
228 		uint8_t v = flip_screen() ? ~(y - 1) : y - 1;
229 		for (int h = 496; h >= 128; h -= 16)
230 		{
231 			const bool objcnt4 = BIT(h, 8) != BIT(~h, 7);
232 			const bool objcnt3 = (BIT(v, 7) && objcnt4) != BIT(~h, 7);
233 			uint8_t obj_idx = (h >> 4) & 7;
234 			obj_idx |= objcnt3 ? 0x08 : 0x00;
235 			obj_idx |= objcnt4 ? 0x10 : 0x00;
236 			obj_idx <<= 2;
237 			for (int i = 0; i < 4; i++)
238 				objdata[i] = m_spriteram[obj_idx | i];
239 
240 			int code = (objdata[0] & 0x7f) + ((objdata[1] & 0x20) << 2) + ((objdata[0] & 0x80) << 1);
241 			int col = objdata[1] & 0x0f;
242 			int sx = objdata[3] - 0x10 * (objdata[1] & 0x10);
243 			int sy = objdata[2];
244 			int dir = 1;
245 
246 			uint8_t valpha = (uint8_t)sy;
247 			uint8_t v2c = (uint8_t)(~v) + (flip_screen() ? 0x01 : 0xff);
248 			uint8_t lvbeta = v2c + valpha;
249 			uint8_t vbeta = ~lvbeta;
250 			bool vleq = vbeta <= ((~valpha) & 0xff);
251 			bool vinlen = true;
252 			uint8_t vlen = objdata[1] >> 6;
253 			switch (vlen & 3)
254 			{
255 			case 0:
256 				vinlen = BIT(lvbeta, 7) && BIT(lvbeta, 6) && BIT(lvbeta, 5) && BIT(lvbeta, 4);
257 				break;
258 			case 1:
259 				vinlen = BIT(lvbeta, 7) && BIT(lvbeta, 6) && BIT(lvbeta, 5);
260 				break;
261 			case 2:
262 				vinlen = BIT(lvbeta, 7) && BIT(lvbeta, 6);
263 				break;
264 			case 3:
265 				vinlen = true;
266 				break;
267 			}
268 			bool vinzone = !(vleq && vinlen);
269 
270 			if (flip_screen())
271 			{
272 				sx = 240 - sx;
273 				sy = 240 - sy;
274 				dir = -1;
275 			}
276 
277 			/* handle double / quadruple height */
278 			int i = (objdata[1] & 0xc0) >> 6;
279 			if (i == 2)
280 				i = 3;
281 
282 			if (!vinzone)
283 			{
284 				do
285 				{
286 					m_gfxdecode->gfx(2)->transpen(bitmap, cliprecty, code + i, col, flip_screen(), flip_screen(), sx, sy + 16 * i * dir, 15);
287 				} while (i-- > 0);
288 			}
289 		}
290 	}
291 }
292 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)293 uint32_t _1942_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
294 {
295 	m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
296 	draw_sprites(bitmap, cliprect);
297 	m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
298 	return 0;
299 }
300 
301 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect)302 void _1942p_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
303 {
304 	for (int offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
305 	{
306 		int code = (m_spriteram[offs] & 0x7f) + 4 * (m_spriteram[offs + 3] & 0x20)
307 					+ 2 * (m_spriteram[offs] & 0x80);
308 		int col = m_spriteram[offs + 3] & 0x0f;
309 
310 		int sx = m_spriteram[offs + 2] - 0x10 * (m_spriteram[offs + 3] & 0x10);
311 		int sy = m_spriteram[offs + 1];
312 
313 		int dir;
314 		if (flip_screen())
315 		{
316 			sx = 240 - sx;
317 			dir = -1;
318 		}
319 		else
320 		{
321 			sy = 240 - sy;
322 			dir = 1;
323 		}
324 
325 		/* handle double / quadruple height */
326 		int i = (m_spriteram[offs + 3] & 0xc0) >> 6;
327 		if (i == 2)
328 			i = 3;
329 
330 		i = 0;
331 
332 		do
333 		{
334 			m_gfxdecode->gfx(2)->transpen(bitmap, cliprect, code + i, col, flip_screen(), flip_screen(), sx, sy + 16 * i * dir, 15);
335 
336 			i--;
337 		} while (i >= 0);
338 	}
339 
340 }
341