1 // license:BSD-3-Clause
2 // copyright-holders:Zsolt Vasvari
3 /***************************************************************************
4 
5   video.c
6 
7   Functions to emulate the video hardware of the machine.
8 
9   Convention: "sl" stands for "searchlight"
10 
11 ***************************************************************************/
12 
13 #include "emu.h"
14 #include "sound/ay8910.h"
15 #include "includes/dday.h"
16 
17 
18 /* Note: There seems to be no way to reset this timer via hardware.
19          The game uses a difference method to reset it to 99.
20 
21   Thanks Zwaxy for the timer info. */
22 
dday_countdown_timer_r()23 uint8_t dday_state::dday_countdown_timer_r()
24 {
25 	return ((m_timer_value / 10) << 4) | (m_timer_value % 10);
26 }
27 
TIMER_CALLBACK_MEMBER(dday_state::countdown_timer_callback)28 TIMER_CALLBACK_MEMBER(dday_state::countdown_timer_callback)
29 {
30 	m_timer_value--;
31 
32 	if (m_timer_value < 0)
33 		m_timer_value = 99;
34 }
35 
start_countdown_timer()36 void dday_state::start_countdown_timer()
37 {
38 	m_timer_value = 0;
39 
40 	m_countdown_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
41 }
42 
43 
44 /***************************************************************************
45 
46   Convert the color PROMs into a more useable format.
47 
48 ***************************************************************************/
49 
dday_palette(palette_device & palette) const50 void dday_state::dday_palette(palette_device &palette) const
51 {
52 	uint8_t const *const color_prom = memregion("proms")->base();
53 
54 	palette.set_shadow_factor(1.0 / 8);
55 
56 	// create a lookup table for the palette
57 	for (int i = 0; i < 0x100; i++)
58 	{
59 		int const r = pal4bit(color_prom[i + 0x000]);
60 		int const g = pal4bit(color_prom[i + 0x100]);
61 		int const b = pal4bit(color_prom[i + 0x200]);
62 
63 		palette.set_indirect_color(i, rgb_t(r, g, b));
64 	}
65 
66 	for (int i = 0; i < 0x100; i++)
67 		palette.set_pen_indirect(i, i);
68 
69 	// HACK!!! This table is handgenerated, but it matches the screenshot.  I have no clue how it really works
70 	palette.set_pen_indirect(0*8+0+0, 0x00);
71 	palette.set_pen_indirect(0*8+0+1, 0x01);
72 	palette.set_pen_indirect(0*8+0+2, 0x15);
73 	palette.set_pen_indirect(0*8+0+3, 0x02);
74 	palette.set_pen_indirect(0*8+4+0, 0x00);
75 	palette.set_pen_indirect(0*8+4+1, 0x01);
76 	palette.set_pen_indirect(0*8+4+2, 0x15);
77 	palette.set_pen_indirect(0*8+4+3, 0x02);
78 
79 	palette.set_pen_indirect(1*8+0+0, 0x04);
80 	palette.set_pen_indirect(1*8+0+1, 0x05);
81 	palette.set_pen_indirect(1*8+0+2, 0x03);
82 	palette.set_pen_indirect(1*8+0+3, 0x07);
83 	palette.set_pen_indirect(1*8+4+0, 0x04);
84 	palette.set_pen_indirect(1*8+4+1, 0x05);
85 	palette.set_pen_indirect(1*8+4+2, 0x03);
86 	palette.set_pen_indirect(1*8+4+3, 0x07);
87 
88 	palette.set_pen_indirect(2*8+0+0, 0x08);
89 	palette.set_pen_indirect(2*8+0+1, 0x15);
90 	palette.set_pen_indirect(2*8+0+2, 0x0a);
91 	palette.set_pen_indirect(2*8+0+3, 0x03);
92 	palette.set_pen_indirect(2*8+4+0, 0x08);
93 	palette.set_pen_indirect(2*8+4+1, 0x15);
94 	palette.set_pen_indirect(2*8+4+2, 0x0a);
95 	palette.set_pen_indirect(2*8+4+3, 0x03);
96 
97 	palette.set_pen_indirect(3*8+0+0, 0x08);
98 	palette.set_pen_indirect(3*8+0+1, 0x15);
99 	palette.set_pen_indirect(3*8+0+2, 0x0a);
100 	palette.set_pen_indirect(3*8+0+3, 0x03);
101 	palette.set_pen_indirect(3*8+4+0, 0x08);
102 	palette.set_pen_indirect(3*8+4+1, 0x15);
103 	palette.set_pen_indirect(3*8+4+2, 0x0a);
104 	palette.set_pen_indirect(3*8+4+3, 0x03);
105 
106 	palette.set_pen_indirect(4*8+0+0, 0x10);
107 	palette.set_pen_indirect(4*8+0+1, 0x11);
108 	palette.set_pen_indirect(4*8+0+2, 0x12);
109 	palette.set_pen_indirect(4*8+0+3, 0x07);
110 	palette.set_pen_indirect(4*8+4+0, 0x10);
111 	palette.set_pen_indirect(4*8+4+1, 0x11);
112 	palette.set_pen_indirect(4*8+4+2, 0x12);
113 	palette.set_pen_indirect(4*8+4+3, 0x07);
114 
115 	palette.set_pen_indirect(5*8+0+0, 0x1d);
116 	palette.set_pen_indirect(5*8+0+1, 0x15);
117 	palette.set_pen_indirect(5*8+0+2, 0x16);
118 	palette.set_pen_indirect(5*8+0+3, 0x1b);
119 	palette.set_pen_indirect(5*8+4+0, 0x1d);
120 	palette.set_pen_indirect(5*8+4+1, 0x15);
121 	palette.set_pen_indirect(5*8+4+2, 0x16);
122 	palette.set_pen_indirect(5*8+4+3, 0x1b);
123 
124 	palette.set_pen_indirect(6*8+0+0, 0x1d);
125 	palette.set_pen_indirect(6*8+0+1, 0x15);
126 	palette.set_pen_indirect(6*8+0+2, 0x1a);
127 	palette.set_pen_indirect(6*8+0+3, 0x1b);
128 	palette.set_pen_indirect(6*8+4+0, 0x1d);
129 	palette.set_pen_indirect(6*8+4+1, 0x15);
130 	palette.set_pen_indirect(6*8+4+2, 0x1a);
131 	palette.set_pen_indirect(6*8+4+3, 0x1b);
132 
133 	palette.set_pen_indirect(7*8+0+0, 0x1d);
134 	palette.set_pen_indirect(7*8+0+1, 0x02);
135 	palette.set_pen_indirect(7*8+0+2, 0x04);
136 	palette.set_pen_indirect(7*8+0+3, 0x1b);
137 	palette.set_pen_indirect(7*8+4+0, 0x1d);
138 	palette.set_pen_indirect(7*8+4+1, 0x02);
139 	palette.set_pen_indirect(7*8+4+2, 0x04);
140 	palette.set_pen_indirect(7*8+4+3, 0x1b);
141 }
142 
143 
144 /***************************************************************************
145 
146   Callbacks for the TileMap code
147 
148 ***************************************************************************/
149 
TILE_GET_INFO_MEMBER(dday_state::get_bg_tile_info)150 TILE_GET_INFO_MEMBER(dday_state::get_bg_tile_info)
151 {
152 	int code;
153 
154 	code = m_bgvideoram[tile_index];
155 	tileinfo.set(0, code, code >> 5, 0);
156 }
157 
TILE_GET_INFO_MEMBER(dday_state::get_fg_tile_info)158 TILE_GET_INFO_MEMBER(dday_state::get_fg_tile_info)
159 {
160 	int code, flipx;
161 
162 	flipx = m_colorram[tile_index & 0x03e0] & 0x01;
163 	code = m_fgvideoram[flipx ? tile_index ^ 0x1f : tile_index];
164 	tileinfo.set(2, code, code >> 5, flipx ? TILE_FLIPX : 0);
165 }
166 
TILE_GET_INFO_MEMBER(dday_state::get_text_tile_info)167 TILE_GET_INFO_MEMBER(dday_state::get_text_tile_info)
168 {
169 	int code;
170 
171 	code = m_textvideoram[tile_index];
172 	tileinfo.set(1, code, code >> 5, 0);
173 }
174 
TILE_GET_INFO_MEMBER(dday_state::get_sl_tile_info)175 TILE_GET_INFO_MEMBER(dday_state::get_sl_tile_info)
176 {
177 	int code, sl_flipx, flipx;
178 	uint8_t* sl_map;
179 
180 	sl_map = &memregion("user1")->base()[(m_sl_image & 0x07) * 0x0200];
181 
182 	flipx = (tile_index >> 4) & 0x01;
183 	sl_flipx = (m_sl_image >> 3) & 0x01;
184 
185 	/* bit 4 is really a flip indicator.  Need to shift bits 5-9 to the right by 1 */
186 	tile_index = ((tile_index & 0x03e0) >> 1) | (tile_index & 0x0f);
187 
188 	code = sl_map[flipx ? tile_index ^ 0x0f : tile_index];
189 
190 	if ((sl_flipx != flipx) && (code & 0x80))
191 		/* no mirroring, draw dark spot */
192 		code = 1;
193 
194 	tileinfo.set(3, code & 0x3f, 0, flipx ? TILE_FLIPX : 0);
195 }
196 
197 
198 /***************************************************************************
199 
200   Start the video hardware emulation.
201 
202 ***************************************************************************/
203 
video_start()204 void dday_state::video_start()
205 {
206 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dday_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
207 	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dday_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
208 	m_text_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dday_state::get_text_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
209 	m_sl_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dday_state::get_sl_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
210 
211 	m_screen->register_screen_bitmap(m_main_bitmap);
212 
213 	m_bg_tilemap->set_transmask(0, 0x00f0, 0xff0f); /* pens 0-3 have priority over the foreground layer */
214 	m_fg_tilemap->set_transparent_pen(0);
215 	m_text_tilemap->set_transparent_pen(0);
216 
217 	m_countdown_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dday_state::countdown_timer_callback), this));
218 
219 	start_countdown_timer();
220 }
221 
dday_bgvideoram_w(offs_t offset,uint8_t data)222 void dday_state::dday_bgvideoram_w(offs_t offset, uint8_t data)
223 {
224 	m_bgvideoram[offset] = data;
225 	m_bg_tilemap->mark_tile_dirty(offset);
226 }
227 
dday_fgvideoram_w(offs_t offset,uint8_t data)228 void dday_state::dday_fgvideoram_w(offs_t offset, uint8_t data)
229 {
230 	m_fgvideoram[offset] = data;
231 	m_fg_tilemap->mark_tile_dirty(offset);
232 	m_fg_tilemap->mark_tile_dirty(offset ^ 0x1f);  /* for flipx case */
233 }
234 
dday_textvideoram_w(offs_t offset,uint8_t data)235 void dday_state::dday_textvideoram_w(offs_t offset, uint8_t data)
236 {
237 	m_textvideoram[offset] = data;
238 	m_text_tilemap->mark_tile_dirty(offset);
239 }
240 
dday_colorram_w(offs_t offset,uint8_t data)241 void dday_state::dday_colorram_w(offs_t offset, uint8_t data)
242 {
243 	offset &= 0x03e0;
244 
245 	m_colorram[offset & 0x3e0] = data;
246 
247 	for (int i = 0; i < 0x20; i++)
248 		m_fg_tilemap->mark_tile_dirty(offset + i);
249 }
250 
dday_colorram_r(offs_t offset)251 uint8_t dday_state::dday_colorram_r(offs_t offset)
252 {
253 	return m_colorram[offset & 0x03e0];
254 }
255 
256 
dday_sl_control_w(uint8_t data)257 void dday_state::dday_sl_control_w(uint8_t data)
258 {
259 	if (m_sl_image != data)
260 	{
261 		m_sl_image = data;
262 		m_sl_tilemap->mark_all_dirty();
263 	}
264 }
265 
266 
dday_control_w(uint8_t data)267 void dday_state::dday_control_w(uint8_t data)
268 {
269 	//if (data & 0xac)  logerror("Control = %02X\n", data & 0xac);
270 
271 	/* bit 0 is coin counter 1 */
272 	machine().bookkeeping().coin_counter_w(0, data & 0x01);
273 
274 	/* bit 1 is coin counter 2 */
275 	machine().bookkeeping().coin_counter_w(1, data & 0x02);
276 
277 	/* bit 4 is sound enable */
278 	if (!(data & 0x10) && (m_control & 0x10))
279 		m_ay1->reset();
280 
281 	machine().sound().system_enable(data & 0x10);
282 
283 	/* bit 6 is search light enable */
284 	m_sl_enable = data & 0x40;
285 
286 	m_control = data;
287 }
288 
289 /***************************************************************************
290 
291   Display refresh
292 
293 ***************************************************************************/
294 
screen_update_dday(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)295 uint32_t dday_state::screen_update_dday(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
296 {
297 	m_bg_tilemap->draw(screen, m_main_bitmap, cliprect, TILEMAP_DRAW_LAYER1, 0);
298 	m_fg_tilemap->draw(screen, m_main_bitmap, cliprect, 0, 0);
299 	m_bg_tilemap->draw(screen, m_main_bitmap, cliprect, TILEMAP_DRAW_LAYER0, 0);
300 	m_text_tilemap->draw(screen, m_main_bitmap, cliprect, 0, 0);
301 
302 	if (m_sl_enable)
303 	{
304 		/* apply shadow */
305 		bitmap_ind16 &sl_bitmap = m_sl_tilemap->pixmap();
306 
307 		for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
308 			for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
309 			{
310 				uint16_t src_pixel = m_main_bitmap.pix(y, x);
311 
312 				if (sl_bitmap.pix(y, x) == 0xff)
313 					src_pixel += m_palette->entries();
314 
315 				bitmap.pix(y, x) = src_pixel;
316 			}
317 	}
318 	else
319 		copybitmap(bitmap, m_main_bitmap, 0, 0, 0, 0, cliprect);
320 
321 	return 0;
322 }
323