1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria, Lee Taylor
3 /***************************************************************************
4 
5  cosmic.cpp
6 
7  emulation of video hardware of cosmic machines of 1979-1980(ish)
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 #include "includes/cosmic.h"
13 
14 
cosmic_color_register_w(offs_t offset,uint8_t data)15 void cosmic_state::cosmic_color_register_w(offs_t offset, uint8_t data)
16 {
17 	m_color_registers[offset] = data ? 1 : 0;
18 }
19 
20 
panic_map_color(uint8_t x,uint8_t y)21 pen_t cosmic_state::panic_map_color( uint8_t x, uint8_t y )
22 {
23 	offs_t offs = (m_color_registers[0] << 9) | (m_color_registers[2] << 10) | ((x >> 4) << 5) | (y >> 3);
24 	pen_t pen = memregion("user1")->base()[offs];
25 
26 	if (m_color_registers[1])
27 		pen >>= 4;
28 
29 	return pen & 0x0f;
30 }
31 
cosmica_map_color(uint8_t x,uint8_t y)32 pen_t cosmic_state::cosmica_map_color( uint8_t x, uint8_t y )
33 {
34 	offs_t offs = (m_color_registers[0] << 9) | ((x >> 4) << 5) | (y >> 3);
35 	pen_t pen = memregion("user1")->base()[offs];
36 
37 	if (m_color_registers[1]) // 0 according to the schematics, but that breaks alien formation colors
38 		pen >>= 4;
39 
40 	return pen & 0x07;
41 }
42 
cosmicg_map_color(uint8_t x,uint8_t y)43 pen_t cosmic_state::cosmicg_map_color( uint8_t x, uint8_t y )
44 {
45 	offs_t offs = (m_color_registers[0] << 8) | (m_color_registers[1] << 9) | ((y >> 4) << 4) | (x >> 4);
46 	pen_t pen = memregion("user1")->base()[offs];
47 
48 	/* the upper 4 bits are for cocktail mode support */
49 	return pen & 0x0f;
50 }
51 
magspot_map_color(uint8_t x,uint8_t y)52 pen_t cosmic_state::magspot_map_color( uint8_t x, uint8_t y )
53 {
54 	offs_t offs = (m_color_registers[0] << 9) | ((x >> 3) << 4) | (y >> 4);
55 	pen_t pen = memregion("user1")->base()[offs];
56 
57 	if (m_color_registers[1])
58 		pen >>= 4;
59 
60 	return pen & m_magspot_pen_mask;
61 }
62 
63 
64 
65 /*
66  * Panic Color table setup
67  *
68  * Bit 0 = RED, Bit 1 = GREEN, Bit 2 = BLUE
69  *
70  * First 8 colors are normal intensities
71  *
72  * But, bit 3 can be used to pull Blue via a 2k resistor to 5v
73  * (1k to ground) so second version of table has blue set to 2/3
74  */
75 
panic_palette(palette_device & palette)76 void cosmic_state::panic_palette(palette_device &palette)
77 {
78 	uint8_t const *const color_prom = memregion("proms")->base();
79 
80 	// create a lookup table for the palette
81 	for (int i = 0; i < 0x10; i++)
82 	{
83 		int const r = pal1bit(i >> 0);
84 		int const g = pal1bit(i >> 1);
85 		int const b = ((i & 0x0c) == 0x08) ? 0xaa : pal1bit(i >> 2);
86 
87 		palette.set_indirect_color(i, rgb_t(r, g, b));
88 	}
89 
90 	// background uses colors 0x00-0x0f
91 	for (int i = 0; i < 0x0f; i++)
92 		palette.set_pen_indirect(i, i);
93 
94 	// sprites use colors 0x00-0x07
95 	for (int i = 0; i < 0x20; i++)
96 		palette.set_pen_indirect(i + 0x10, color_prom[i] & 0x07);
97 
98 	m_map_color = &cosmic_state::panic_map_color;
99 }
100 
101 
102 /*
103  * Cosmic Alien Color table setup
104  *
105  * 8 colors, 16 sprite color codes
106  *
107  * Bit 0 = RED, Bit 1 = GREEN, Bit 2 = BLUE
108  *
109  */
110 
cosmica_palette(palette_device & palette)111 void cosmic_state::cosmica_palette(palette_device &palette)
112 {
113 	uint8_t const *const color_prom = memregion("proms")->base();
114 
115 	// create a lookup table for the palette
116 	for (int i = 0; i < 0x08; i++)
117 		palette.set_indirect_color(i, rgb_t(pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2)));
118 
119 	// background and sprites use colors 0x00-0x07
120 	for (int i = 0; i < 0x08; i++)
121 		palette.set_pen_indirect(i, i);
122 
123 	for (int i = 0; i < 0x20; i++)
124 	{
125 		palette.set_pen_indirect(i + 0x08, (color_prom[i] >> 0) & 0x07);
126 		palette.set_pen_indirect(i + 0x28, (color_prom[i] >> 4) & 0x07);
127 	}
128 
129 	m_map_color = &cosmic_state::cosmica_map_color;
130 }
131 
132 
133 /*
134  * Cosmic guerilla table setup
135  *
136  * Use AA for normal, FF for Full Red
137  * Bit 0 = R, bit 1 = G, bit 2 = B, bit 4 = High Red
138  *
139  * It's possible that the background is dark gray and not black, as the
140  * resistor chain would never drop to zero, Anybody know ?
141  */
cosmicg_palette(palette_device & palette)142 void cosmic_state::cosmicg_palette(palette_device &palette)
143 {
144 	for (int i = 0; i < palette.entries(); i++)
145 	{
146 		int const r = (i > 8) ? 0xff : 0xaa * BIT(i, 0);
147 		int const g = 0xaa * BIT(i, 1);
148 		int const b = 0xaa * BIT(i, 2);
149 
150 		palette.set_pen_color(i, rgb_t(r, g, b));
151 	}
152 
153 	m_map_color = &cosmic_state::cosmicg_map_color;
154 }
155 
156 
magspot_palette(palette_device & palette)157 void cosmic_state::magspot_palette(palette_device &palette)
158 {
159 	uint8_t const *const color_prom = memregion("proms")->base();
160 
161 	// create a lookup table for the palette
162 	for (int i = 0; i < 0x10; i++)
163 	{
164 		int const r = ((i & 0x09) == 0x08) ? 0xaa : pal1bit(i >> 0);
165 		int const g = pal1bit(i >> 1);
166 		int const b = pal1bit(i >> 2);
167 
168 		palette.set_indirect_color(i, rgb_t(r, g, b));
169 	}
170 
171 	// background uses colors 0x00-0x0f
172 	for (int i = 0; i < 0x0f; i++)
173 		palette.set_pen_indirect(i, i);
174 
175 	// sprites use colors 0x00-0x0f
176 	for (int i = 0; i < 0x20; i++)
177 		palette.set_pen_indirect(i + 0x10, color_prom[i] & 0x0f);
178 
179 	m_map_color = &cosmic_state::magspot_map_color;
180 	m_magspot_pen_mask = 0x0f;
181 }
182 
183 
nomnlnd_palette(palette_device & palette)184 void cosmic_state::nomnlnd_palette(palette_device &palette)
185 {
186 	uint8_t const *const color_prom = memregion("proms")->base();
187 
188 	// create a lookup table for the palette
189 	for (int i = 0; i < 0x10; i++)
190 	{
191 		rgb_t const color = rgb_t(pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2));
192 		palette.set_indirect_color(i, color);
193 	}
194 
195 	// background uses colors 0x00-0x07
196 	for (int i = 0; i < 0x07; i++)
197 		palette.set_pen_indirect(i, i);
198 
199 	// sprites use colors 0x00-0x07 */
200 	for (int i = 0; i < 0x20; i++)
201 		palette.set_pen_indirect(i + 0x10, color_prom[i] & 0x07);
202 
203 	m_map_color = &cosmic_state::magspot_map_color;
204 	m_magspot_pen_mask = 0x07;
205 }
206 
207 
cosmic_background_enable_w(uint8_t data)208 void cosmic_state::cosmic_background_enable_w(uint8_t data)
209 {
210 	m_background_enable = data;
211 }
212 
213 
draw_bitmap(bitmap_ind16 & bitmap,const rectangle & cliprect)214 void cosmic_state::draw_bitmap( bitmap_ind16 &bitmap, const rectangle &cliprect )
215 {
216 	for (offs_t offs = 0; offs < m_videoram.bytes(); offs++)
217 	{
218 		uint8_t data = m_videoram[offs];
219 
220 		uint8_t x = offs << 3;
221 		uint8_t const y = offs >> 5;
222 
223 		pen_t pen = (this->*m_map_color)(x, y);
224 
225 		for (int i = 0; i < 8; i++)
226 		{
227 			if (data & 0x80)
228 			{
229 				if (flip_screen())
230 					bitmap.pix(255-y, 255-x) = pen;
231 				else
232 					bitmap.pix(y, x) = pen;
233 			}
234 
235 			x++;
236 			data <<= 1;
237 		}
238 	}
239 }
240 
241 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect,int color_mask,int extra_sprites)242 void cosmic_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect, int color_mask, int extra_sprites )
243 {
244 	int offs;
245 
246 	for (offs = m_spriteram.bytes() - 4;offs >= 0;offs -= 4)
247 	{
248 		if (m_spriteram[offs] != 0)
249 		{
250 			int code, color;
251 
252 			code  = ~m_spriteram[offs] & 0x3f;
253 			color = ~m_spriteram[offs + 3] & color_mask;
254 
255 			if (extra_sprites)
256 				code |= (m_spriteram[offs + 3] & 0x08) << 3;
257 
258 			if (m_spriteram[offs] & 0x80)
259 				/* 16x16 sprite */
260 				m_gfxdecode->gfx(0)->transpen(bitmap,cliprect,
261 						code, color,
262 						0, ~m_spriteram[offs] & 0x40,
263 						256-m_spriteram[offs + 2],m_spriteram[offs + 1],0);
264 			else
265 				/* 32x32 sprite */
266 				m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
267 						code >> 2, color,
268 						0, ~m_spriteram[offs] & 0x40,
269 						256-m_spriteram[offs + 2],m_spriteram[offs + 1],0);
270 		}
271 	}
272 }
273 
274 
cosmica_draw_starfield(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)275 void cosmic_state::cosmica_draw_starfield( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect )
276 {
277 	uint8_t y = 0;
278 	uint8_t map = 0;
279 	uint8_t *PROM = memregion("user2")->base();
280 
281 	while (1)
282 	{
283 		int va  =  y       & 0x01;
284 		int vb  = (y >> 1) & 0x01;
285 
286 		uint8_t x = 0;
287 
288 		while (1)
289 		{
290 			uint8_t x1;
291 			int hc, hb_;
292 
293 			if (flip_screen())
294 				x1 = x - screen.frame_number();
295 			else
296 				x1 = x + screen.frame_number();
297 
298 			hc  = (x1 >> 2) & 0x01;
299 			hb_ = (x  >> 5) & 0x01;  /* not a bug, this one is the real x */
300 
301 			if ((x1 & 0x1f) == 0)
302 				// flip-flop at IC11 is clocked
303 				map = PROM[(x1 >> 5) | (y >> 1 << 3)];
304 
305 			if (((!(hc & va)) & (vb ^ hb_)) &&          /* right network */
306 				(((x1 ^ map) & (hc | 0x1e)) == 0x1e))   /* left network */
307 			{
308 				/* RGB order is reversed -- bit 7=R, 6=G, 5=B */
309 				int col = (map >> 7) | ((map >> 5) & 0x02) | ((map >> 3) & 0x04);
310 
311 				bitmap.pix(y, x) = col;
312 			}
313 
314 			x++;
315 			if (x == 0)  break;
316 		}
317 
318 		y++;
319 		if (y == 0)  break;
320 	}
321 }
322 
323 
devzone_draw_grid(bitmap_ind16 & bitmap,const rectangle & cliprect)324 void cosmic_state::devzone_draw_grid( bitmap_ind16 &bitmap, const rectangle &cliprect )
325 {
326 	uint8_t const *const horz_PROM = memregion("user2")->base();
327 	uint8_t const *const vert_PROM = memregion("user3")->base();
328 	offs_t horz_addr = 0;
329 
330 	uint8_t count = 0;
331 	uint8_t horz_data = 0;
332 	uint8_t vert_data;
333 
334 	for (int y = 32; y < 224; y++)
335 	{
336 		uint8_t x = 0;
337 
338 		while (1)
339 		{
340 			/* for the vertical lines, each bit indicates
341 			   if there should be a line at the x position */
342 			vert_data = vert_PROM[x >> 3];
343 
344 			/* the horizontal (perspective) lines are RLE encoded.
345 			   When the screen is flipped, the address should be
346 			   decrementing.  But since it's just a mirrored image,
347 			   this is easier. */
348 			if (count == 0)
349 				count = horz_PROM[horz_addr++];
350 
351 			count++;
352 
353 			if (count == 0)
354 				horz_data = horz_PROM[horz_addr++];
355 
356 			for (int x1 = 0; x1 < 8; x1++)
357 			{
358 				if (!(vert_data & horz_data & 0x80))    /* NAND gate */
359 				{
360 					/* blue */
361 					if (flip_screen())
362 						bitmap.pix(255-y, 255-x) = 4;
363 					else
364 						bitmap.pix(y, x) = 4;
365 				}
366 
367 				horz_data = (horz_data << 1) | 0x01;
368 				vert_data = (vert_data << 1) | 0x01;
369 
370 				x++;
371 			}
372 
373 			if (x == 0)  break;
374 		}
375 	}
376 }
377 
378 
nomnlnd_draw_background(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)379 void cosmic_state::nomnlnd_draw_background( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect )
380 {
381 	uint8_t y = 0;
382 	uint8_t water = screen.frame_number();
383 	uint8_t *PROM = memregion("user2")->base();
384 
385 	/* all positioning is via logic gates:
386 
387 	   tree is displayed where
388 	   __          __
389 	   HD' ^ HC' ^ HB'
390 
391 	   and
392 	    __          __              __
393 	   (VB' ^ VC' ^ VD')  X  (VB' ^ VC' ^ VD')
394 
395 	   water is displayed where
396 	         __         __
397 	   HD' ^ HC' ^ HB ^ HA'
398 
399 	   and vertically the same equation as the trees,
400 	   but the final result is inverted.
401 
402 
403 	   The colors are coded in logic gates:
404 
405 	   trees:
406 	                            P1 P2  BGR
407 	     R = Plane1 ^ Plane2     0  0  000
408 	     G = Plane2              0  1  010
409 	     B = Plane1 ^ ~Plane2    1  0  100
410 	                             1  1  011
411 	   water:
412 	                            P1 P2  BGR or
413 	     R = Plane1 ^ Plane2     0  0  100 000
414 	     G = Plane2 v Plane2     0  1  110 010
415 	     B = ~Plane1 or          1  0  010 010
416 	         0 based oh HD       1  1  011 011
417 
418 	     Not sure about B, the logic seems convulated for such
419 	     a simple result.
420 	*/
421 
422 	while (1)
423 	{
424 		int vb_ = (y >> 5) & 0x01;
425 		int vc_ = (y >> 6) & 0x01;
426 		int vd_ =  y >> 7;
427 
428 		uint8_t x = 0;
429 
430 		while (1)
431 		{
432 			int color = 0;
433 
434 			int hd  = (x >> 3) & 0x01;
435 			int ha_ = (x >> 4) & 0x01;
436 			int hb_ = (x >> 5) & 0x01;
437 			int hc_ = (x >> 6) & 0x01;
438 			int hd_ =  x >> 7;
439 
440 			if (((!vb_) & vc_ & (!vd_)) ^ (vb_ & (!vc_) & vd_))
441 			{
442 				/* tree */
443 				if (!hd_ && hc_ && !hb_)
444 				{
445 					offs_t offs = ((x >> 3) & 0x03) | ((y & 0x1f) << 2) |
446 									(flip_screen() ? 0x80 : 0);
447 
448 					uint8_t plane1 = PROM[offs         ] << (x & 0x07);
449 					uint8_t plane2 = PROM[offs | 0x0400] << (x & 0x07);
450 
451 					plane1 >>= 7;
452 					plane2 >>= 7;
453 
454 					color = (plane1 & plane2)       |   // R
455 							(plane2         )  << 1 |   // G
456 							(plane1 & ~plane2) << 2;    // B
457 				}
458 			}
459 			else
460 			{
461 				/* water */
462 				if (hd_ && !hc_ && hb_ && !ha_)
463 				{
464 					offs_t offs = hd | (water << 1) | 0x0200;
465 
466 					uint8_t plane1 = PROM[offs         ] << (x & 0x07);
467 					uint8_t plane2 = PROM[offs | 0x0400] << (x & 0x07);
468 
469 					plane1 >>= 7;
470 					plane2 >>= 7;
471 
472 					color = ( plane1 & plane2)      |   // R
473 							( plane1 | plane2) << 1 |   // G
474 							((!plane1) & hd)     << 2;  // B - see above
475 				}
476 			}
477 
478 			if (color != 0)
479 			{
480 				if (flip_screen())
481 					bitmap.pix(255-y, 255-x) = color;
482 				else
483 					bitmap.pix(y, x) = color;
484 			}
485 
486 			x++;
487 			if (x == 0)  break;
488 		}
489 
490 
491 		// this is obviously wrong
492 //      if (vb_)
493 			water++;
494 
495 		y++;
496 		if (y == 0)  break;
497 	}
498 }
499 
500 
screen_update_cosmicg(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)501 uint32_t cosmic_state::screen_update_cosmicg(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
502 {
503 	bitmap.fill(0, cliprect);
504 	draw_bitmap(bitmap, cliprect);
505 	return 0;
506 }
507 
508 
screen_update_panic(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)509 uint32_t cosmic_state::screen_update_panic(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
510 {
511 	bitmap.fill(0, cliprect);
512 	draw_bitmap(bitmap, cliprect);
513 	draw_sprites(bitmap, cliprect, 0x07, 1);
514 	return 0;
515 }
516 
517 
screen_update_cosmica(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)518 uint32_t cosmic_state::screen_update_cosmica(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
519 {
520 	bitmap.fill(0, cliprect);
521 	cosmica_draw_starfield(screen, bitmap, cliprect);
522 	draw_bitmap(bitmap, cliprect);
523 	draw_sprites(bitmap, cliprect, 0x0f, 0);
524 	return 0;
525 }
526 
527 
screen_update_magspot(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)528 uint32_t cosmic_state::screen_update_magspot(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
529 {
530 	bitmap.fill(0, cliprect);
531 	draw_bitmap(bitmap, cliprect);
532 	draw_sprites(bitmap, cliprect, 0x07, 0);
533 	return 0;
534 }
535 
536 
screen_update_devzone(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)537 uint32_t cosmic_state::screen_update_devzone(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
538 {
539 	bitmap.fill(0, cliprect);
540 
541 	if (m_background_enable)
542 		devzone_draw_grid(bitmap, cliprect);
543 
544 	draw_bitmap(bitmap, cliprect);
545 	draw_sprites(bitmap, cliprect, 0x07, 0);
546 	return 0;
547 }
548 
549 
screen_update_nomnlnd(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)550 uint32_t cosmic_state::screen_update_nomnlnd(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
551 {
552 	/* according to the video summation logic on pg4, the trees and river
553 	   have the highest priority */
554 
555 	bitmap.fill(0, cliprect);
556 	draw_bitmap(bitmap, cliprect);
557 	draw_sprites(bitmap, cliprect, 0x07, 0);
558 
559 	if (m_background_enable)
560 		nomnlnd_draw_background(screen, bitmap, cliprect);
561 
562 	return 0;
563 }
564