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