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