1 // license:BSD-3-Clause
2 // copyright-holders:Paul Leaman
3 /***************************************************************************
4 
5 1943 Video Hardware
6 
7 This board handles tile/tile and tile/sprite priority with a PROM. Its
8 working is hardcoded in the driver.
9 
10 The PROM have address inputs wired as follows:
11 
12 A0 bg (SCR) opaque
13 A1 bit 2 of sprite (OBJ) attribute (guess)
14 A2 bit 3 of sprite (OBJ) attribute (guess)
15 A3 sprite (OBJ) opaque
16 A4 fg (CHAR) opaque
17 A5 wired to mass
18 A6 wired to mass
19 A7 wired to mass
20 
21 2 bits of the output selects the active layer, it can be:
22 (output & 0x03)
23 0 bg2 (SCR2)
24 1 bg (SCR)
25 2 sprite (OBJ)
26 3 fg (CHAR)
27 
28 other 2 bits (output & 0x0c) unknown
29 
30 ***************************************************************************/
31 
32 #include "emu.h"
33 #include "includes/1943.h"
34 
35 /***************************************************************************
36 
37   Convert the color PROMs into a more useable format.
38 
39   1943 has three 256x4 palette PROMs (one per gun) and a lot ;-) of 256x4
40   lookup table PROMs.
41   The palette PROMs are connected to the RGB output this way:
42 
43   bit 3 -- 220 ohm resistor  -- RED/GREEN/BLUE
44         -- 470 ohm resistor  -- RED/GREEN/BLUE
45         -- 1  kohm resistor  -- RED/GREEN/BLUE
46   bit 0 -- 2.2kohm resistor  -- RED/GREEN/BLUE
47 
48 ***************************************************************************/
49 
_1943_palette(palette_device & palette) const50 void _1943_state::_1943_palette(palette_device &palette) const
51 {
52 	const u8 *color_prom = m_proms;
53 	for (int i = 0; i < 0x100; i++)
54 	{
55 		int bit0, bit1, bit2, bit3;
56 
57 		// red component
58 		bit0 = (color_prom[i + 0x000] >> 0) & 0x01;
59 		bit1 = (color_prom[i + 0x000] >> 1) & 0x01;
60 		bit2 = (color_prom[i + 0x000] >> 2) & 0x01;
61 		bit3 = (color_prom[i + 0x000] >> 3) & 0x01;
62 		const int r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
63 
64 		// green component
65 		bit0 = (color_prom[i + 0x100] >> 0) & 0x01;
66 		bit1 = (color_prom[i + 0x100] >> 1) & 0x01;
67 		bit2 = (color_prom[i + 0x100] >> 2) & 0x01;
68 		bit3 = (color_prom[i + 0x100] >> 3) & 0x01;
69 		const int g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
70 
71 		// blue component
72 		bit0 = (color_prom[i + 0x200] >> 0) & 0x01;
73 		bit1 = (color_prom[i + 0x200] >> 1) & 0x01;
74 		bit2 = (color_prom[i + 0x200] >> 2) & 0x01;
75 		bit3 = (color_prom[i + 0x200] >> 3) & 0x01;
76 		const int b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
77 
78 		palette.set_indirect_color(i, rgb_t(r, g, b));
79 	}
80 
81 	// color_prom now points to the beginning of the lookup table
82 	color_prom += 0x300;
83 
84 	// characters use colors 0x40-0x4f
85 	for (int i = 0x00; i < 0x80; i++)
86 	{
87 		const u8 ctabentry = (color_prom[i] & 0x0f) | 0x40;
88 		palette.set_pen_indirect(i, ctabentry);
89 	}
90 
91 	// foreground tiles use colors 0x00-0x3f
92 	for (int i = 0x80; i < 0x180; i++)
93 	{
94 		const u8 ctabentry =
95 				((color_prom[0x200 + (i - 0x080)] & 0x03) << 4) |
96 				((color_prom[0x100 + (i - 0x080)] & 0x0f) << 0);
97 		palette.set_pen_indirect(i, ctabentry);
98 	}
99 
100 	// background tiles also use colors 0x00-0x3f
101 	for (int i = 0x180; i < 0x280; i++)
102 	{
103 		const u8 ctabentry =
104 				((color_prom[0x400 + (i - 0x180)] & 0x03) << 4) |
105 				((color_prom[0x300 + (i - 0x180)] & 0x0f) << 0);
106 		palette.set_pen_indirect(i, ctabentry);
107 	}
108 
109 	/* sprites use colors 0x80-0xff
110 	   bit 3 of BMPROM.07 selects priority over the background,
111 	   but we handle it differently for speed reasons */
112 	for (int i = 0x280; i < 0x380; i++)
113 	{
114 		const u8 ctabentry =
115 				((color_prom[0x600 + (i - 0x280)] & 0x07) << 4) |
116 				((color_prom[0x500 + (i - 0x280)] & 0x0f) << 0) |
117 				0x80;
118 		palette.set_pen_indirect(i, ctabentry);
119 	}
120 }
121 
videoram_w(offs_t offset,u8 data)122 void _1943_state::videoram_w(offs_t offset, u8 data)
123 {
124 	m_videoram[offset] = data;
125 	m_fg_tilemap->mark_tile_dirty(offset);
126 }
127 
colorram_w(offs_t offset,u8 data)128 void _1943_state::colorram_w(offs_t offset, u8 data)
129 {
130 	m_colorram[offset] = data;
131 	m_fg_tilemap->mark_tile_dirty(offset);
132 }
133 
c804_w(u8 data)134 void _1943_state::c804_w(u8 data)
135 {
136 	/* bits 0 and 1 are coin counters */
137 	machine().bookkeeping().coin_counter_w(0, data & 0x01);
138 	machine().bookkeeping().coin_counter_w(1, data & 0x02);
139 
140 	/* bits 2, 3 and 4 select the ROM bank */
141 	m_mainbank->set_entry((data & 0x1c) >> 2);
142 
143 	/* bit 5 resets the sound CPU - we ignore it */
144 
145 	/* bit 6 flips screen */
146 	flip_screen_set(data & 0x40);
147 
148 	/* bit 7 enables characters */
149 	m_char_on = data & 0x80;
150 }
151 
d806_w(u8 data)152 void _1943_state::d806_w(u8 data)
153 {
154 	/* bit 4 enables bg 1 */
155 	m_bg1_on = data & 0x10;
156 
157 	/* bit 5 enables bg 2 */
158 	m_bg2_on = data & 0x20;
159 
160 	/* bit 6 enables sprites */
161 	m_obj_on = data & 0x40;
162 }
163 
TILE_GET_INFO_MEMBER(_1943_state::get_bg2_tile_info)164 TILE_GET_INFO_MEMBER(_1943_state::get_bg2_tile_info)
165 {
166 	const int offs = 0x8000 + (tile_index * 2);
167 	const u8 attr = m_tilerom[offs + 1];
168 	const u32 code = m_tilerom[offs];
169 	const u32 color = (attr & 0x3c) >> 2;
170 	const int flags = TILE_FLIPYX((attr & 0xc0) >> 6);
171 
172 	tileinfo.set(2, code, color, flags);
173 }
174 
TILE_GET_INFO_MEMBER(_1943_state::get_bg_tile_info)175 TILE_GET_INFO_MEMBER(_1943_state::get_bg_tile_info)
176 {
177 	const int offs = tile_index * 2;
178 	const u8 attr = m_tilerom[offs + 1];
179 	const u32 code = m_tilerom[offs] + ((attr & 0x01) << 8);
180 	const u32 color = (attr & 0x3c) >> 2;
181 	const int flags = TILE_FLIPYX((attr & 0xc0) >> 6);
182 
183 	tileinfo.group = color;
184 	tileinfo.set(1, code, color, flags);
185 }
186 
TILE_GET_INFO_MEMBER(_1943_state::get_fg_tile_info)187 TILE_GET_INFO_MEMBER(_1943_state::get_fg_tile_info)
188 {
189 	const u8 attr = m_colorram[tile_index];
190 	const u32 code = m_videoram[tile_index] + ((attr & 0xe0) << 3);
191 	const u32 color = attr & 0x1f;
192 
193 	tileinfo.set(0, code, color, 0);
194 }
195 
video_start()196 void _1943_state::video_start()
197 {
198 	m_bg2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(_1943_state::get_bg2_tile_info)), TILEMAP_SCAN_COLS, 32, 32, 2048, 8);
199 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(_1943_state::get_bg_tile_info)), TILEMAP_SCAN_COLS, 32, 32, 2048, 8);
200 	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(_1943_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
201 
202 	m_bg_tilemap->configure_groups(*m_gfxdecode->gfx(1), 0x0f);
203 	m_fg_tilemap->set_transparent_pen(0);
204 
205 	save_item(NAME(m_char_on));
206 	save_item(NAME(m_obj_on));
207 	save_item(NAME(m_bg1_on));
208 	save_item(NAME(m_bg2_on));
209 }
210 
_1943_drawgfx(bitmap_ind16 & dest_bmp,const rectangle & clip,gfx_element * gfx,u32 code,u32 color,bool flipx,bool flipy,int offsx,int offsy,u8 transparent_color)211 void _1943_state::_1943_drawgfx(bitmap_ind16 &dest_bmp,const rectangle &clip,gfx_element *gfx,
212 							u32 code,u32 color,bool flipx,bool flipy,int offsx,int offsy,
213 							u8 transparent_color)
214 {
215 	bitmap_ind8 &priority_bitmap = m_screen->priority();
216 	/* Start drawing */
217 	const u16 pal = gfx->colorbase() + gfx->granularity() * (color % gfx->colors());
218 	const u8 *source_base = gfx->get_data(code % gfx->elements());
219 
220 	const int xinc = flipx ? -1 : 1;
221 	const int yinc = flipy ? -1 : 1;
222 
223 	int x_index_base = flipx ? gfx->width() - 1 : 0;
224 	int y_index = flipy ? gfx->height() - 1 : 0;
225 
226 	// start coordinates
227 	int sx = offsx;
228 	int sy = offsy;
229 
230 	// end coordinates
231 	int ex = sx + gfx->width();
232 	int ey = sy + gfx->height();
233 
234 	if (sx < clip.min_x)
235 	{ // clip left
236 		const int pixels = clip.min_x - sx;
237 		sx += pixels;
238 		x_index_base += xinc * pixels;
239 	}
240 	if (sy < clip.min_y)
241 	{ // clip top
242 		const int pixels = clip.min_y - sy;
243 		sy += pixels;
244 		y_index += yinc * pixels;
245 	}
246 	// NS 980211 - fixed incorrect clipping
247 	if (ex > clip.max_x + 1)
248 	{ // clip right
249 		ex = clip.max_x + 1;
250 	}
251 	if (ey > clip.max_y + 1)
252 	{ // clip bottom
253 		ey = clip.max_y + 1;
254 	}
255 
256 	if (ex > sx)
257 	{ // skip if inner loop doesn't draw anything
258 		for (int y = sy; y < ey; y++)
259 		{
260 			u8 const *const source = source_base + y_index * gfx->rowbytes();
261 			u16 *const dest = &dest_bmp.pix(y);
262 			u8 *const pri = &priority_bitmap.pix(y);
263 			int x_index = x_index_base;
264 			for (int x = sx; x < ex; x++)
265 			{
266 				if (!(pri[x] & 0x80))
267 				{
268 					u8 const c = source[x_index];
269 					if (c != transparent_color)
270 					{
271 						// the priority is actually selected by bit 3 of BMPROM.07
272 						if (((pri[x] & 2) == 0) || ((m_proms[0x900 + c + (color << 4)] & 0x08) == 0))
273 							dest[x] = pal + c;
274 
275 						pri[x] = 0xff; // mark it 'already drawn'
276 					}
277 				}
278 				x_index += xinc;
279 			}
280 			y_index += yinc;
281 		}
282 	}
283 }
284 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect)285 void _1943_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
286 {
287 	for (int offs = 0; offs <= m_spriteram.bytes(); offs += 32)
288 	{
289 		const u8 attr = m_spriteram[offs + 1];
290 		const u32 code = m_spriteram[offs] + ((attr & 0xe0) << 3);
291 		const u32 color = attr & 0x0f;
292 		int sx = m_spriteram[offs + 3] - ((attr & 0x10) << 4);
293 		int sy = m_spriteram[offs + 2];
294 
295 		if (flip_screen())
296 		{
297 			sx = 240 - sx;
298 			sy = 240 - sy;
299 		}
300 
301 		_1943_drawgfx(bitmap,cliprect, m_gfxdecode->gfx(3), code, color, flip_screen(), flip_screen(), sx, sy, 0);
302 	}
303 }
304 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)305 u32 _1943_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
306 {
307 	m_bg2_tilemap->set_scrollx(0, m_bgscrollx[0] + 256 * m_bgscrollx[1]);
308 	m_bg_tilemap->set_scrollx(0, m_scrollx[0] + 256 * m_scrollx[1]);
309 	m_bg_tilemap->set_scrolly(0, m_scrolly[0]);
310 
311 	screen.priority().fill(0, cliprect);
312 
313 	if (m_bg2_on)
314 		m_bg2_tilemap->draw(screen, bitmap, cliprect, 0, 1);
315 	else
316 		bitmap.fill(m_palette->black_pen(), cliprect);
317 
318 	if (m_bg1_on)
319 		m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 2);
320 
321 	if (m_obj_on)
322 		draw_sprites(bitmap, cliprect);
323 
324 	if (m_char_on)
325 		m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
326 
327 	return 0;
328 }
329