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