1 /*
2 
3 	SEGA Zaxxon Hardware - Video
4 
5 	TODO:
6 
7 	- get rid of zaxxon_vid_type
8 	- draw backgrounds as tilemaps
9 	- convert skewing to use tilemap scrolling?
10 	- zaxxon fg tilemap color calculation
11 	- fix background size bug
12 	- clean up background functions
13 
14 */
15 
16 #include "driver.h"
17 #include "vidhrdw/generic.h"
18 
19 UINT8 *zaxxon_char_color_bank;
20 UINT8 *zaxxon_background_position;
21 UINT8 *zaxxon_background_color_bank;
22 UINT8 *zaxxon_background_enable;
23 static struct mame_bitmap *backgroundbitmap1,*backgroundbitmap2;
24 static const UINT8 *color_codes;
25 
26 int zaxxon_vid_type;	/* set by init_machine; 0 = zaxxon; 1 = congobongo */
27 
28 #define ZAXXON_VID	0
29 #define CONGO_VID	1
30 #define FUTSPY_VID	2
31 
32 static struct tilemap *fg_tilemap;
33 
34 /***************************************************************************
35 
36   Convert the color PROMs into a more useable format.
37 
38   Zaxxon has one 256x8 palette PROM and one 256x4 PROM which contains the
39   color codes to use for characters on a per row/column basis (groups of
40   of 4 characters in the same row).
41   Congo Bongo has similar hardware, but it has color RAM instead of the
42   lookup PROM.
43 
44   The palette PROM is connected to the RGB output this way:
45 
46   bit 7 -- 220 ohm resistor  -- BLUE
47         -- 470 ohm resistor  -- BLUE
48         -- 220 ohm resistor  -- GREEN
49         -- 470 ohm resistor  -- GREEN
50         -- 1  kohm resistor  -- GREEN
51         -- 220 ohm resistor  -- RED
52         -- 470 ohm resistor  -- RED
53   bit 0 -- 1  kohm resistor  -- RED
54 
55 ***************************************************************************/
PALETTE_INIT(zaxxon)56 PALETTE_INIT( zaxxon )
57 {
58 	int i;
59 	#define TOTAL_COLORS(gfxn) (Machine->gfx[gfxn]->total_colors * Machine->gfx[gfxn]->color_granularity)
60 	#define COLOR(gfxn,offs) (colortable[Machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
61 
62 	for (i = 0;i < Machine->drv->total_colors;i++)
63 	{
64 		int bit0,bit1,bit2,r,g,b;
65 
66 		/* red component */
67 		bit0 = (*color_prom >> 0) & 0x01;
68 		bit1 = (*color_prom >> 1) & 0x01;
69 		bit2 = (*color_prom >> 2) & 0x01;
70 		r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
71 		/* green component */
72 		bit0 = (*color_prom >> 3) & 0x01;
73 		bit1 = (*color_prom >> 4) & 0x01;
74 		bit2 = (*color_prom >> 5) & 0x01;
75 		g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
76 		/* blue component */
77 		bit0 = 0;
78 		bit1 = (*color_prom >> 6) & 0x01;
79 		bit2 = (*color_prom >> 7) & 0x01;
80 		b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
81 
82 		palette_set_color(i,r,g,b);
83 		color_prom++;
84 	}
85 
86 	/* color_prom now points to the beginning of the character color codes */
87 	color_codes = color_prom;	/* we'll need it later */
88 
89 	/* all gfx elements use the same palette */
90 	for (i = 0;i < TOTAL_COLORS(0);i++)
91 		COLOR(0,i) = i;
92 }
93 
WRITE_HANDLER(zaxxon_videoram_w)94 WRITE_HANDLER( zaxxon_videoram_w )
95 {
96 	if (videoram[offset] != data)
97 	{
98 		videoram[offset] = data;
99 		tilemap_mark_tile_dirty(fg_tilemap, offset);
100 	}
101 }
102 
WRITE_HANDLER(congo_colorram_w)103 WRITE_HANDLER( congo_colorram_w )
104 {
105 	if (colorram[offset] != data)
106 	{
107 		colorram[offset] = data;
108 		tilemap_mark_tile_dirty(fg_tilemap, offset);
109 	}
110 }
111 
copy_pixel(struct mame_bitmap * dst_bm,int dx,int dy,struct mame_bitmap * src_bm,int sx,int sy)112 static void copy_pixel(struct mame_bitmap *dst_bm, int dx, int dy,
113 					   struct mame_bitmap *src_bm, int sx, int sy)
114 {
115 	plot_pixel(dst_bm, dx, dy, read_pixel(src_bm, sx, sy));
116 }
117 
create_background(struct mame_bitmap * dst_bm,struct mame_bitmap * src_bm,int col)118 static void create_background( struct mame_bitmap *dst_bm, struct mame_bitmap *src_bm, int col )
119 {
120 	int offs;
121 	int sx,sy;
122 
123 	for (offs = 0;offs < 0x4000;offs++)
124 	{
125 		sy = 8 * (offs / 32);
126 		sx = 8 * (offs % 32);
127 
128 		if (!(Machine->orientation & ORIENTATION_SWAP_XY))
129 			/* leave screenful of black pixels at end */
130 			sy += 256;
131 
132 		drawgfx(src_bm,Machine->gfx[1],
133 				memory_region(REGION_GFX4)[offs] + 256 * (memory_region(REGION_GFX4)[0x4000 + offs] & 3),
134 				col + (memory_region(REGION_GFX4)[0x4000 + offs] >> 4),
135 				0,0,
136 				sx,sy,
137 				0,TRANSPARENCY_NONE,0);
138 	}
139 
140 	if (Machine->orientation & ORIENTATION_SWAP_XY)
141 	{
142 		/* the background is stored as a rectangle, but is drawn by the hardware skewed: */
143 		/* go right two pixels, then up one pixel. Doing the conversion at run time would */
144 		/* be extremely expensive, so we do it now. To save memory, we squash the image */
145 		/* horizontally (doing line shifts at run time is much less expensive than doing */
146 		/* column shifts) */
147 		for (offs = -510;offs < 4096;offs += 2)
148 		{
149 			sx = (2302-510/2) - offs/2;
150 
151 			for (sy = 0;sy < 512;sy += 2)
152 			{
153 				if (offs + sy >= 0 && offs + sy < 4096)
154 				{
155 					copy_pixel (dst_bm, sx, 511 -  sy   ,    src_bm, sy/2, 4095 - (offs+sy));
156 					copy_pixel (dst_bm, sx, 511 - (sy+1), src_bm, sy/2, 4095 - (offs+sy+1));
157 				}
158 			}
159 		}
160 	}
161 }
162 
zaxxon_create_background(void)163 static int zaxxon_create_background(void)
164 {
165 	struct mame_bitmap *prebitmap;
166 	int width, height;
167 
168 	/* for speed, backgrounds are arranged differently if axis is swapped */
169 	if (Machine->orientation & ORIENTATION_SWAP_XY)
170 		height = 512, width = 2303+32;
171 	else
172 		/* leave a screenful of black pixels at each end */
173 		height = 256+4096+256, width = 256;
174 
175 	/* large bitmap for the precalculated background */
176 	if ((backgroundbitmap1 = auto_bitmap_alloc(width,height)) == 0)
177 		return 1;
178 
179 	if (zaxxon_vid_type == ZAXXON_VID || zaxxon_vid_type == FUTSPY_VID)
180 	{
181 		if ((backgroundbitmap2 = auto_bitmap_alloc(width,height)) == 0)
182 			return 1;
183 	}
184 
185 	if (Machine->orientation & ORIENTATION_SWAP_XY)
186 	{
187 		/* create a temporary bitmap to prepare the background before converting it */
188 		if ((prebitmap = bitmap_alloc(256,4096)) == 0)
189 			return 1;
190 	}
191 	else
192 		prebitmap = backgroundbitmap1;
193 
194 	/* prepare the background */
195 	create_background(backgroundbitmap1, prebitmap, 0);
196 
197 	if (zaxxon_vid_type == ZAXXON_VID || zaxxon_vid_type == FUTSPY_VID)
198 	{
199 		if (!(Machine->orientation & ORIENTATION_SWAP_XY))
200 			prebitmap = backgroundbitmap2;
201 
202 		/* prepare a second background with different colors, used in the death sequence */
203 		create_background(backgroundbitmap2, prebitmap, 16);
204 	}
205 
206 	if (Machine->orientation & ORIENTATION_SWAP_XY)
207 		bitmap_free(prebitmap);
208 
209 	return 0;
210 }
211 
zaxxon_get_fg_tile_info(int tile_index)212 static void zaxxon_get_fg_tile_info(int tile_index)
213 {
214 	int sy = tile_index / 32;
215 	int sx = tile_index % 32;
216 	int code = videoram[tile_index];
217 	int color = (color_codes[sx + 32 * (sy / 4)] & 0x0f) + 16 * (*zaxxon_char_color_bank & 1);
218 	// not sure about the color code calculation - char_color_bank is used only in test mode
219 
220 	SET_TILE_INFO(0, code, color, 0)
221 }
222 
VIDEO_START(zaxxon)223 VIDEO_START( zaxxon )
224 {
225 	if ( zaxxon_create_background() )
226 		return 1;
227 
228 	fg_tilemap = tilemap_create(zaxxon_get_fg_tile_info, tilemap_scan_rows,
229 		TILEMAP_TRANSPARENT, 8, 8, 32, 32);
230 
231 	if ( !fg_tilemap )
232 		return 1;
233 
234 	tilemap_set_transparent_pen(fg_tilemap, 0);
235 
236 	return 0;
237 }
238 
zaxxon_draw_background(struct mame_bitmap * bitmap,const struct rectangle * cliprect)239 static void zaxxon_draw_background( struct mame_bitmap *bitmap, const struct rectangle *cliprect )
240 {
241 	/* copy the background */
242 	/* TODO: there's a bug here which shows only in test mode. The background doesn't */
243 	/* cover the whole screen, so the image is not fully overwritten and part of the */
244 	/* character color test screen remains on screen when it is replaced by the background */
245 	/* color test. */
246 	if (*zaxxon_background_enable)
247 	{
248 		int i,skew,scroll;
249 		struct rectangle clip;
250 
251 		if (Machine->orientation & ORIENTATION_SWAP_XY)
252 		{
253 			/* standard rotation - skew background horizontally */
254 			if (!flip_screen)
255 			{
256 				if (zaxxon_vid_type == CONGO_VID)
257 					scroll = 1023+63 - (zaxxon_background_position[0] + 256*zaxxon_background_position[1]);
258 				else
259 					scroll = 2048+63 - (zaxxon_background_position[0] + 256*(zaxxon_background_position[1]&7));
260 			}
261 			else
262 			{
263 				if (zaxxon_vid_type == CONGO_VID)
264 					scroll = 1024 + (zaxxon_background_position[0] + 256*zaxxon_background_position[1]) - 32;
265 				else
266 					scroll = (zaxxon_background_position[0] + 256*(zaxxon_background_position[1]&7)) - 32;
267 			}
268 
269 			skew = 128 - 512 + 2 * Machine->visible_area.min_x;
270 
271 			clip.min_y = Machine->visible_area.min_y;
272 			clip.max_y = Machine->visible_area.max_y;
273 
274 			for (i = Machine->visible_area.min_x;i <= Machine->visible_area.max_x;i++)
275 			{
276 				clip.min_x = i;
277 				clip.max_x = i;
278 
279 				if ((zaxxon_vid_type == ZAXXON_VID || zaxxon_vid_type == FUTSPY_VID)
280 					 && (*zaxxon_background_color_bank & 1))
281 					copybitmap(bitmap,backgroundbitmap2,flip_screen,flip_screen,-scroll,skew,&clip,TRANSPARENCY_NONE,0);
282 				else
283 					copybitmap(bitmap,backgroundbitmap1,flip_screen,flip_screen,-scroll,skew,&clip,TRANSPARENCY_NONE,0);
284 
285 				skew += 2;
286 			}
287 		}
288 		else
289 		{
290 			/* skew background up one pixel every 2 horizontal pixels */
291 			if (!flip_screen_y)
292 			{
293 				if (zaxxon_vid_type == CONGO_VID)
294 					scroll = 2050 + 2*(zaxxon_background_position[0] + 256*zaxxon_background_position[1])
295 							- backgroundbitmap1->height + 256;
296 				else
297 					scroll = 2*(zaxxon_background_position[0] + 256*(zaxxon_background_position[1]&7))
298 							- backgroundbitmap1->height + 256;
299 			}
300 			else
301 			{
302 				if (zaxxon_vid_type == CONGO_VID)
303 					scroll = -(2*(zaxxon_background_position[0] + 256*zaxxon_background_position[1])) - 2052;
304 				else
305 					scroll = -(2*(zaxxon_background_position[0] + 256*(zaxxon_background_position[1]&7))) - 2;
306 			}
307 
308 			skew = 72 - (255 - Machine->visible_area.max_y);
309 
310 			clip.min_x = Machine->visible_area.min_x;
311 			clip.max_x = Machine->visible_area.max_x;
312 
313 			for (i = Machine->visible_area.max_y;i >= Machine->visible_area.min_y;i-=2)
314 			{
315 				clip.min_y = i-1;
316 				clip.max_y = i;
317 
318 				if ((zaxxon_vid_type == ZAXXON_VID || zaxxon_vid_type == FUTSPY_VID)
319 					 && (*zaxxon_background_color_bank & 1))
320 					copybitmap(bitmap,backgroundbitmap2,flip_screen,flip_screen,skew,scroll,&clip,TRANSPARENCY_NONE,0);
321 				else
322 					copybitmap(bitmap,backgroundbitmap1,flip_screen,flip_screen,skew,scroll,&clip,TRANSPARENCY_NONE,0);
323 
324 				skew--;
325 			}
326 		}
327 	}
328 	else
329 	{
330 		fillbitmap(bitmap, get_black_pen(), cliprect);
331 	}
332 }
333 
zaxxon_draw_sprites(struct mame_bitmap * bitmap,const struct rectangle * cliprect)334 static void zaxxon_draw_sprites( struct mame_bitmap *bitmap, const struct rectangle *cliprect )
335 {
336 	int offs;
337 
338 	for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
339 	{
340 		if (spriteram[offs] != 0xff)
341 		{
342 			int code = spriteram[offs + 1] & 0x3f;
343 			int color = spriteram[offs + 2] & 0x3f;
344 			int flipx = spriteram[offs + 1] & 0x40;
345 			int flipy = spriteram[offs + 1] & 0x80;
346 			int sx = ((spriteram[offs + 3] + 16) & 0xff) - 32;
347 			int sy = 255 - spriteram[offs] - 16;
348 
349 			if (flip_screen)
350 			{
351 				flipx = !flipx;
352 				flipy = !flipy;
353 				sx = 223 - sx;
354 				sy = 224 - sy;
355 			}
356 
357 			drawgfx(bitmap, Machine->gfx[2], code, color, flipx, flipy,
358 				sx, sy, cliprect, TRANSPARENCY_PEN, 0);
359 		}
360 	}
361 }
362 
VIDEO_UPDATE(zaxxon)363 VIDEO_UPDATE( zaxxon )
364 {
365 	zaxxon_draw_background(bitmap, cliprect);
366 	zaxxon_draw_sprites(bitmap, cliprect);
367 	tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
368 }
369 
370 /* Razzmatazz */
371 
razmataz_get_fg_tile_info(int tile_index)372 static void razmataz_get_fg_tile_info(int tile_index)
373 {
374 	int code = videoram[tile_index];
375 	int color = (color_codes[code] & 0x0f) + 16 * (*zaxxon_char_color_bank & 0x01);
376 
377 	SET_TILE_INFO(0, code, color, 0)
378 }
379 
VIDEO_START(razmataz)380 VIDEO_START( razmataz )
381 {
382 	int offs;
383 
384 	/* large bitmap for the precalculated background */
385 	if ((backgroundbitmap1 = auto_bitmap_alloc(256,4096)) == 0)
386 		return 1;
387 
388 	if ((backgroundbitmap2 = auto_bitmap_alloc(256,4096)) == 0)
389 		return 1;
390 
391 	/* prepare the background */
392 	for (offs = 0;offs < 0x4000;offs++)
393 	{
394 		int sx,sy;
395 
396 		sy = 8 * (offs / 32);
397 		sx = 8 * (offs % 32);
398 
399 		drawgfx(backgroundbitmap1,Machine->gfx[1],
400 				memory_region(REGION_GFX4)[offs] + 256 * (memory_region(REGION_GFX4)[0x4000 + offs] & 3),
401 				memory_region(REGION_GFX4)[0x4000 + offs] >> 4,
402 				0,0,
403 				sx,sy,
404 				0,TRANSPARENCY_NONE,0);
405 
406 		drawgfx(backgroundbitmap2,Machine->gfx[1],
407 				memory_region(REGION_GFX4)[offs] + 256 * (memory_region(REGION_GFX4)[0x4000 + offs] & 3),
408 				16 + (memory_region(REGION_GFX4)[0x4000 + offs] >> 4),
409 				0,0,
410 				sx,sy,
411 				0,TRANSPARENCY_NONE,0);
412 	}
413 
414 	fg_tilemap = tilemap_create(razmataz_get_fg_tile_info, tilemap_scan_rows,
415 		TILEMAP_TRANSPARENT, 8, 8, 32, 32);
416 
417 	if ( !fg_tilemap )
418 		return 1;
419 
420 	tilemap_set_transparent_pen(fg_tilemap, 0);
421 
422 	return 0;
423 }
424 
razmataz_draw_background(struct mame_bitmap * bitmap,const struct rectangle * cliprect)425 static void razmataz_draw_background( struct mame_bitmap *bitmap, const struct rectangle *cliprect )
426 {
427 	if (*zaxxon_background_enable)
428 	{
429 		int scroll = 2 * (zaxxon_background_position[0] + 256 * (zaxxon_background_position[1] & 0x07));
430 
431 		if (*zaxxon_background_color_bank & 0x01)
432 			copyscrollbitmap(bitmap,backgroundbitmap2,0,0,1,&scroll,cliprect,TRANSPARENCY_NONE,0);
433 		else
434 			copyscrollbitmap(bitmap,backgroundbitmap1,0,0,1,&scroll,cliprect,TRANSPARENCY_NONE,0);
435 	}
436 	else
437 	{
438 		fillbitmap(bitmap, get_black_pen(), cliprect);
439 	}
440 }
441 
VIDEO_UPDATE(razmataz)442 VIDEO_UPDATE( razmataz )
443 {
444 	razmataz_draw_background(bitmap, cliprect);
445 	zaxxon_draw_sprites(bitmap, cliprect);
446 	tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
447 }
448 
449 /* Congo Bongo */
450 
congo_get_fg_tile_info(int tile_index)451 static void congo_get_fg_tile_info(int tile_index)
452 {
453 	int code = videoram[tile_index];
454 	int color = colorram[tile_index];
455 
456 	SET_TILE_INFO(0, code, color, 0)
457 }
458 
VIDEO_START(congo)459 VIDEO_START( congo )
460 {
461 	if ( zaxxon_create_background() )
462 		return 1;
463 
464 	fg_tilemap = tilemap_create(congo_get_fg_tile_info, tilemap_scan_rows,
465 		TILEMAP_TRANSPARENT, 8, 8, 32, 32);
466 
467 	if ( !fg_tilemap )
468 		return 1;
469 
470 	tilemap_set_transparent_pen(fg_tilemap, 0);
471 
472 	return 0;
473 }
474 
congo_draw_sprites(struct mame_bitmap * bitmap,const struct rectangle * cliprect)475 static void congo_draw_sprites( struct mame_bitmap *bitmap, const struct rectangle *cliprect )
476 {
477 	int offs;
478 	int i;
479 	static unsigned int sprpri[0x100]; /* this really should not be more
480 		                            * than 0x1e, but I did not want to check
481 		                            * for 0xff which is set when sprite is off
482 		                            * -V-
483 		                            */
484 
485 	/* Sprites actually start at 0xff * [0xc031], it seems to be static tho'*/
486 	/* The number of active sprites is stored at 0xc032 */
487 
488 	for (offs = 0x1e * 0x20; offs >= 0x00; offs -= 0x20)
489 		sprpri[spriteram[offs + 1]] = offs;
490 
491 	for (i = 0x1e; i >= 0; i--)
492 	{
493 		offs = sprpri[i];
494 
495 		if (spriteram[offs + 2] != 0xff)
496 		{
497 			int code = spriteram[offs + 2 + 1] & 0x7f;
498 			int color = spriteram[offs + 2 + 2];
499 			int flipx = spriteram[offs + 2 + 2] & 0x80;
500 			int flipy = spriteram[offs + 2 + 1] & 0x80;
501 			int sx = ((spriteram[offs + 2 + 3] + 16) & 0xff) - 31;
502 			int sy = 255 - spriteram[offs + 2] - 15;
503 
504 			if (flip_screen)
505 			{
506 				flipx = !flipx;
507 				flipy = !flipy;
508 				sx = 223 - sx;
509 				sy = 224 - sy;
510 			}
511 
512 			drawgfx(bitmap, Machine->gfx[2], code, color, flipx, flipy,
513 				sx, sy, cliprect, TRANSPARENCY_PEN, 0);
514 		}
515 	}
516 }
517 
VIDEO_UPDATE(congo)518 VIDEO_UPDATE( congo )
519 {
520 	zaxxon_draw_background(bitmap, cliprect);
521 	congo_draw_sprites(bitmap, cliprect);
522 	tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
523 }
524 
525 /* Future Spy */
526 
futspy_draw_sprites(struct mame_bitmap * bitmap,const struct rectangle * cliprect)527 static void futspy_draw_sprites( struct mame_bitmap *bitmap, const struct rectangle *cliprect )
528 {
529 	int offs;
530 
531 	for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
532 	{
533 		if (spriteram[offs] != 0xff)
534 		{
535 			int code = spriteram[offs + 1] & 0x7f;
536 			int color = spriteram[offs + 2] & 0x3f;
537 			int flipx = spriteram[offs + 1] & 0x80;
538 			int flipy = spriteram[offs + 1] & 0x80;
539 			int sx = ((spriteram[offs + 3] + 16) & 0xff) - 32;
540 			int sy = 255 - spriteram[offs] - 16;
541 
542 			if (flip_screen)
543 			{
544 				flipx = !flipx;
545 				flipy = !flipy;
546 				sx = 223 - sx;
547 				sy = 224 - sy;
548 			}
549 
550 			drawgfx(bitmap, Machine->gfx[2], code, color, flipx, flipy,
551 				sx, sy, cliprect, TRANSPARENCY_PEN, 0);
552 		}
553 	}
554 }
555 
VIDEO_UPDATE(futspy)556 VIDEO_UPDATE( futspy )
557 {
558 	zaxxon_draw_background(bitmap, cliprect);
559 	futspy_draw_sprites(bitmap, cliprect);
560 	tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
561 }
562