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