1 // license:BSD-3-Clause
2 // copyright-holders:Zsolt Vasvari, Couriersud
3 /***************************************************************************
4 
5     video.c
6 
7     Functions to emulate the video hardware of the machine.
8 
9     This file is also used by scregg.c
10 
11 ***************************************************************************/
12 
13 #include "emu.h"
14 #include "includes/btime.h"
15 
16 /***************************************************************************
17 
18     Burger Time doesn't have a color PROM. It uses RAM to dynamically
19     create the palette.
20     The palette RAM is connected to the RGB output this way:
21 
22     bit 7 -- 15 kohm resistor  -- BLUE (inverted)
23           -- 33 kohm resistor  -- BLUE (inverted)
24           -- 15 kohm resistor  -- GREEN (inverted)
25           -- 33 kohm resistor  -- GREEN (inverted)
26           -- 47 kohm resistor  -- GREEN (inverted)
27           -- 15 kohm resistor  -- RED (inverted)
28           -- 33 kohm resistor  -- RED (inverted)
29     bit 0 -- 47 kohm resistor  -- RED (inverted)
30 
31 ***************************************************************************/
32 
btime_palette(palette_device & palette) const33 void btime_state::btime_palette(palette_device &palette) const
34 {
35 	// Burger Time doesn't have a color PROM, but Hamburge has.
36 	// This function is also used by Eggs.
37 	if (!m_prom_region)
38 		return;
39 
40 	uint8_t const *const color_prom = m_prom_region->base();
41 
42 	for (int i = 0; i < palette.entries(); i++)
43 	{
44 		// red component
45 		int bit0 = (color_prom[i] >> 0) & 0x01;
46 		int bit1 = (color_prom[i] >> 1) & 0x01;
47 		int bit2 = (color_prom[i] >> 2) & 0x01;
48 		int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
49 
50 		// green component
51 		bit0 = (color_prom[i] >> 3) & 0x01;
52 		bit1 = (color_prom[i] >> 4) & 0x01;
53 		bit2 = (color_prom[i] >> 5) & 0x01;
54 		int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
55 
56 		// blue component
57 		bit0 = 0;
58 		bit1 = (color_prom[i] >> 6) & 0x01;
59 		bit2 = (color_prom[i] >> 7) & 0x01;
60 		int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
61 
62 		palette.set_pen_color(i, rgb_t(r, g, b));
63 	}
64 }
65 
66 /***************************************************************************
67 
68     Convert the color PROMs into a more useable format.
69 
70     The PROM is connected to the RGB output this way:
71 
72     bit 7 -- 47 kohm resistor  -- RED
73           -- 33 kohm resistor  -- RED
74           -- 15 kohm resistor  -- RED
75           -- 47 kohm resistor  -- GREEN
76           -- 33 kohm resistor  -- GREEN
77           -- 15 kohm resistor  -- GREEN
78           -- 33 kohm resistor  -- BLUE
79     bit 0 -- 15 kohm resistor  -- BLUE
80 
81 ***************************************************************************/
82 
lnc_palette(palette_device & palette) const83 void btime_state::lnc_palette(palette_device &palette) const
84 {
85 	uint8_t const *const color_prom = memregion("proms")->base();
86 
87 	for (int i = 0; i < palette.entries(); i++)
88 	{
89 		// red component
90 		int bit0 = (color_prom[i] >> 7) & 0x01;
91 		int bit1 = (color_prom[i] >> 6) & 0x01;
92 		int bit2 = (color_prom[i] >> 5) & 0x01;
93 		int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
94 
95 		// green component
96 		bit0 = (color_prom[i] >> 4) & 0x01;
97 		bit1 = (color_prom[i] >> 3) & 0x01;
98 		bit2 = (color_prom[i] >> 2) & 0x01;
99 		int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
100 
101 		// blue component
102 		bit0 = 0;
103 		bit1 = (color_prom[i] >> 1) & 0x01;
104 		bit2 = (color_prom[i] >> 0) & 0x01;
105 		int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
106 
107 		palette.set_pen_color(i, rgb_t(r,g,b));
108 	}
109 }
110 
111 /***************************************************************************
112 
113 Start the video hardware emulation.
114 
115 ***************************************************************************/
116 
VIDEO_START_MEMBER(btime_state,disco)117 VIDEO_START_MEMBER(btime_state,disco)
118 {
119 	// graphics are in RAM
120 	m_gfxdecode->gfx(0)->set_source(m_deco_charram);
121 	m_gfxdecode->gfx(1)->set_source(m_deco_charram);
122 }
123 
VIDEO_START_MEMBER(btime_state,bnj)124 VIDEO_START_MEMBER(btime_state,bnj)
125 {
126 	/* the background area is twice as wide as the screen */
127 	int width = 256;
128 	int height = 256;
129 	m_background_bitmap = std::make_unique<bitmap_ind16>(2 * width, height);
130 
131 	save_item(NAME(*m_background_bitmap));
132 }
133 
lnc_videoram_w(offs_t offset,uint8_t data)134 void btime_state::lnc_videoram_w(offs_t offset, uint8_t data)
135 {
136 	m_videoram[offset] = data;
137 	m_colorram[offset] = *m_lnc_charbank;
138 }
139 
btime_mirrorvideoram_r(offs_t offset)140 uint8_t btime_state::btime_mirrorvideoram_r(offs_t offset)
141 {
142 	int x, y;
143 
144 	/* swap x and y coordinates */
145 	x = offset / 32;
146 	y = offset % 32;
147 	offset = 32 * y + x;
148 
149 	return m_videoram[offset];
150 }
151 
btime_mirrorcolorram_r(offs_t offset)152 uint8_t btime_state::btime_mirrorcolorram_r(offs_t offset)
153 {
154 	int x, y;
155 
156 	/* swap x and y coordinates */
157 	x = offset / 32;
158 	y = offset % 32;
159 	offset = 32 * y + x;
160 
161 	return m_colorram[offset];
162 }
163 
btime_mirrorvideoram_w(offs_t offset,uint8_t data)164 void btime_state::btime_mirrorvideoram_w(offs_t offset, uint8_t data)
165 {
166 	int x, y;
167 
168 	/* swap x and y coordinates */
169 	x = offset / 32;
170 	y = offset % 32;
171 	offset = 32 * y + x;
172 
173 	m_videoram[offset] = data;
174 }
175 
lnc_mirrorvideoram_w(offs_t offset,uint8_t data)176 void btime_state::lnc_mirrorvideoram_w(offs_t offset, uint8_t data)
177 {
178 	int x, y;
179 
180 	/* swap x and y coordinates */
181 	x = offset / 32;
182 	y = offset % 32;
183 	offset = 32 * y + x;
184 
185 	lnc_videoram_w(offset, data);
186 }
187 
btime_mirrorcolorram_w(offs_t offset,uint8_t data)188 void btime_state::btime_mirrorcolorram_w(offs_t offset, uint8_t data)
189 {
190 	int x, y;
191 
192 	/* swap x and y coordinates */
193 	x = offset / 32;
194 	y = offset % 32;
195 	offset = 32 * y + x;
196 
197 	m_colorram[offset] = data;
198 }
199 
deco_charram_w(offs_t offset,uint8_t data)200 void btime_state::deco_charram_w(offs_t offset, uint8_t data)
201 {
202 	if (m_deco_charram[offset] == data)
203 		return;
204 
205 	m_deco_charram[offset] = data;
206 
207 	offset &= 0x1fff;
208 
209 	/* dirty sprite */
210 	m_gfxdecode->gfx(1)->mark_dirty(offset >> 5);
211 
212 	/* diry char */
213 	m_gfxdecode->gfx(0)->mark_dirty(offset >> 3);
214 }
215 
bnj_background_w(offs_t offset,uint8_t data)216 void btime_state::bnj_background_w(offs_t offset, uint8_t data)
217 {
218 	m_bnj_backgroundram[offset] = data;
219 }
220 
bnj_scroll1_w(uint8_t data)221 void btime_state::bnj_scroll1_w(uint8_t data)
222 {
223 	m_bnj_scroll1 = data;
224 }
225 
bnj_scroll2_w(uint8_t data)226 void btime_state::bnj_scroll2_w(uint8_t data)
227 {
228 	m_bnj_scroll2 = data;
229 }
230 
btime_video_control_w(uint8_t data)231 void btime_state::btime_video_control_w(uint8_t data)
232 {
233 	// Btime video control
234 	//
235 	// Bit 0   = Flip screen
236 	// Bit 1-7 = Unknown
237 
238 	flip_screen_set(data & 0x01);
239 }
240 
bnj_video_control_w(uint8_t data)241 void btime_state::bnj_video_control_w(uint8_t data)
242 {
243 	/* Bnj/Lnc works a little differently than the btime/eggs (apparently). */
244 	/* According to the information at: */
245 	/* http://www.davesclassics.com/arcade/Switch_Settings/BumpNJump.sw */
246 	/* SW8 is used for cocktail video selection (as opposed to controls), */
247 	/* but bit 7 of the input port is used for vblank input. */
248 	/* My guess is that this switch open circuits some connection to */
249 	/* the monitor hardware. */
250 	/* For now we just check 0x40 in DSW1, and ignore the write if we */
251 	/* are in upright controls mode. */
252 
253 	if (ioport("DSW1")->read() & 0x40) /* cocktail mode */
254 		btime_video_control_w(data);
255 }
256 
zoar_video_control_w(uint8_t data)257 void btime_state::zoar_video_control_w(uint8_t data)
258 {
259 	// Zoar video control
260 	//
261 	// Bit 0-2 = Unknown (always 0). Marked as MCOL on schematics
262 	// Bit 3-4 = Palette
263 	// Bit 7   = Flip Screen
264 
265 	m_btime_palette = (data & 0x30) >> 3;
266 
267 	if (ioport("DSW1")->read() & 0x40) /* cocktail mode */
268 		flip_screen_set(data & 0x80);
269 }
270 
disco_video_control_w(uint8_t data)271 void btime_state::disco_video_control_w(uint8_t data)
272 {
273 	m_btime_palette = (data >> 2) & 0x03;
274 
275 	if (!(ioport("DSW1")->read() & 0x40)) /* cocktail mode */
276 		flip_screen_set(data & 0x01);
277 }
278 
279 
draw_chars(bitmap_ind16 & bitmap,const rectangle & cliprect,uint8_t transparency,uint8_t color,int priority)280 void btime_state::draw_chars( bitmap_ind16 &bitmap, const rectangle &cliprect, uint8_t transparency, uint8_t color, int priority )
281 {
282 	offs_t offs;
283 
284 	for (offs = 0; offs < m_videoram.bytes(); offs++)
285 	{
286 		uint8_t x = 31 - (offs / 32);
287 		uint8_t y = offs % 32;
288 
289 		uint16_t code = m_videoram[offs] + 256 * (m_colorram[offs] & 3);
290 
291 		/* check priority */
292 		if ((priority != -1) && (priority != ((code >> 7) & 0x01)))
293 			continue;
294 
295 		if (flip_screen())
296 		{
297 			x = 31 - x;
298 			y = 31 - y;
299 		}
300 
301 		m_gfxdecode->gfx(0)->transpen(bitmap,cliprect,
302 				code,
303 				color,
304 				flip_screen(),flip_screen(),
305 				8*x,8*y,
306 				transparency ? 0 : -1);
307 	}
308 }
309 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect,uint8_t color,uint8_t sprite_y_adjust,uint8_t sprite_y_adjust_flip_screen,uint8_t * sprite_ram,offs_t interleave)310 void btime_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect, uint8_t color,
311 							uint8_t sprite_y_adjust, uint8_t sprite_y_adjust_flip_screen,
312 							uint8_t *sprite_ram, offs_t interleave )
313 {
314 	int i;
315 	offs_t offs;
316 
317 	/* draw the sprites */
318 	for (i = 0, offs = 0; i < 8; i++, offs += 4 * interleave)
319 	{
320 		int x, y;
321 		uint8_t flipx, flipy;
322 
323 		if (!(sprite_ram[offs + 0] & 0x01)) continue;
324 
325 		x = 240 - sprite_ram[offs + 3 * interleave];
326 		y = 240 - sprite_ram[offs + 2 * interleave];
327 
328 		flipx = sprite_ram[offs + 0] & 0x04;
329 		flipy = sprite_ram[offs + 0] & 0x02;
330 
331 		if (flip_screen())
332 		{
333 			x = 240 - x;
334 			y = 240 - y + sprite_y_adjust_flip_screen;
335 
336 			flipx = !flipx;
337 			flipy = !flipy;
338 		}
339 
340 		y = y - sprite_y_adjust;
341 
342 		m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
343 				sprite_ram[offs + interleave],
344 				color,
345 				flipx,flipy,
346 				x, y,0);
347 
348 		y = y + (flip_screen() ? -256 : 256);
349 
350 		// Wrap around
351 		m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
352 				sprite_ram[offs + interleave],
353 				color,
354 				flipx,flipy,
355 				x,y,0);
356 	}
357 }
358 
359 
draw_background(bitmap_ind16 & bitmap,const rectangle & cliprect,uint8_t * tmap,uint8_t color)360 void btime_state::draw_background( bitmap_ind16 &bitmap, const rectangle &cliprect, uint8_t* tmap, uint8_t color )
361 {
362 	int i;
363 	const uint8_t *gfx = memregion("bg_map")->base();
364 	int scroll = -(m_bnj_scroll2 | ((m_bnj_scroll1 & 0x03) << 8));
365 
366 	// One extra iteration for wrap around
367 	for (i = 0; i < 5; i++, scroll += 256)
368 	{
369 		offs_t offs;
370 		offs_t tileoffset = tmap[i & 3] * 0x100;
371 
372 		// Skip if this tile is completely off the screen
373 		if (scroll > 256)
374 			break;
375 		if (scroll < -256)
376 			continue;
377 
378 		for (offs = 0; offs < 0x100; offs++)
379 		{
380 			int x = 240 - (16 * (offs / 16) + scroll) - 1;
381 			int y = 16 * (offs % 16);
382 
383 			if (flip_screen())
384 			{
385 				x = 240 - x;
386 				y = 240 - y;
387 			}
388 
389 			m_gfxdecode->gfx(2)->opaque(bitmap,cliprect,
390 					gfx[tileoffset + offs],
391 					color,
392 					flip_screen(),flip_screen(),
393 					x,y);
394 		}
395 	}
396 }
397 
398 
screen_update_btime(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)399 uint32_t btime_state::screen_update_btime(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
400 {
401 	if (m_bnj_scroll1 & 0x10)
402 	{
403 		int i, start;
404 
405 		// Generate tile map
406 		if (flip_screen())
407 			start = 0;
408 		else
409 			start = 1;
410 
411 		for (i = 0; i < 4; i++)
412 		{
413 			m_btime_tilemap[i] = start | (m_bnj_scroll1 & 0x04);
414 			start = (start + 1) & 0x03;
415 		}
416 
417 		draw_background(bitmap, cliprect, m_btime_tilemap, 0);
418 		draw_chars(bitmap, cliprect, true, 0, -1);
419 	}
420 	else
421 		draw_chars(bitmap, cliprect, false, 0, -1);
422 
423 	draw_sprites(bitmap, cliprect, 0, 1, 0, m_videoram, 0x20);
424 
425 	return 0;
426 }
427 
428 
screen_update_eggs(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)429 uint32_t btime_state::screen_update_eggs(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
430 {
431 	draw_chars(bitmap, cliprect, false, 0, -1);
432 	draw_sprites(bitmap, cliprect, 0, 0, 0, m_videoram, 0x20);
433 
434 	return 0;
435 }
436 
437 
screen_update_lnc(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)438 uint32_t btime_state::screen_update_lnc(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
439 {
440 	draw_chars(bitmap, cliprect, false, 0, -1);
441 	draw_sprites(bitmap, cliprect, 0, 1, 2, m_videoram, 0x20);
442 
443 	return 0;
444 }
445 
446 
screen_update_zoar(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)447 uint32_t btime_state::screen_update_zoar(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
448 {
449 	if (m_bnj_scroll1 & 0x04)
450 	{
451 		draw_background(bitmap, cliprect, m_zoar_scrollram, m_btime_palette);
452 		draw_chars(bitmap, cliprect, true, m_btime_palette + 1, -1);
453 	}
454 	else
455 		draw_chars(bitmap, cliprect, false, m_btime_palette + 1, -1);
456 
457 	/* The order is important for correct priorities */
458 	draw_sprites(bitmap, cliprect, m_btime_palette + 1, 1, 2, m_videoram + 0x1f, 0x20);
459 	draw_sprites(bitmap, cliprect, m_btime_palette + 1, 1, 2, m_videoram, 0x20);
460 
461 	return 0;
462 }
463 
464 
screen_update_bnj(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)465 uint32_t btime_state::screen_update_bnj(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
466 {
467 	if (m_bnj_scroll1)
468 	{
469 		int scroll, offs;
470 
471 		for (offs = m_bnj_backgroundram.bytes() - 1; offs >=0; offs--)
472 		{
473 			int sx, sy;
474 
475 			sx = 16 * ((offs < 0x100) ? ((offs % 0x80) / 8) : ((offs % 0x80) / 8) + 16);
476 			sy = 16 * (((offs % 0x100) < 0x80) ? offs % 8 : (offs % 8) + 8);
477 			sx = 496 - sx;
478 
479 			if (flip_screen())
480 			{
481 				sx = 496 - sx;
482 				sy = 240 - sy;
483 			}
484 
485 			m_gfxdecode->gfx(2)->opaque(*m_background_bitmap,m_background_bitmap->cliprect(),
486 					(m_bnj_backgroundram[offs] >> 4) + ((offs & 0x80) >> 3) + 32,
487 					0,
488 					flip_screen(), flip_screen(),
489 					sx, sy);
490 		}
491 
492 		/* copy the background bitmap to the screen */
493 		scroll = (m_bnj_scroll1 & 0x02) * 128 + 511 - m_bnj_scroll2;
494 		if (!flip_screen())
495 			scroll = 767 - scroll;
496 		copyscrollbitmap(bitmap, *m_background_bitmap, 1, &scroll, 0, nullptr, cliprect);
497 
498 		/* copy the low priority characters followed by the sprites
499 		   then the high priority characters */
500 		draw_chars(bitmap, cliprect, true, 0, 1);
501 		draw_sprites(bitmap, cliprect, 0, 0, 0, m_videoram, 0x20);
502 		draw_chars(bitmap, cliprect, true, 0, 0);
503 	}
504 	else
505 	{
506 		draw_chars(bitmap, cliprect, false, 0, -1);
507 		draw_sprites(bitmap, cliprect, 0, 0, 0, m_videoram, 0x20);
508 	}
509 
510 	return 0;
511 }
512 
513 
screen_update_cookrace(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)514 uint32_t btime_state::screen_update_cookrace(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
515 {
516 	int offs;
517 
518 	for (offs = m_bnj_backgroundram.bytes() - 1; offs >=0; offs--)
519 	{
520 		int sx, sy;
521 
522 		sx = 31 - (offs / 32);
523 		sy = offs % 32;
524 
525 		if (flip_screen())
526 		{
527 			sx = 31 - sx;
528 			sy = 31 - sy;
529 		}
530 
531 		m_gfxdecode->gfx(2)->opaque(bitmap,cliprect,
532 				m_bnj_backgroundram[offs],
533 				0,
534 				flip_screen(), flip_screen(),
535 				8*sx,8*sy);
536 	}
537 
538 	draw_chars(bitmap, cliprect, true, 0, -1);
539 	draw_sprites(bitmap, cliprect, 0, 1, 0, m_videoram, 0x20);
540 
541 	return 0;
542 }
543 
544 
screen_update_disco(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)545 uint32_t btime_state::screen_update_disco(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
546 {
547 	draw_chars(bitmap, cliprect, false, m_btime_palette, -1);
548 	draw_sprites(bitmap, cliprect, m_btime_palette, 0, 0, m_spriteram, 1);
549 
550 	return 0;
551 }
552