1 /*##########################################################################
2
3 atarimo.c
4
5 Common motion object management functions for Atari raster games.
6
7 ##########################################################################*/
8
9 #include "driver.h"
10 #include "atarimo.h"
11 #include "tilemap.h"
12
13
14 /*##########################################################################
15 TYPES & STRUCTURES
16 ##########################################################################*/
17
18 /* internal structure containing a word index, shift and mask */
19 struct atarimo_mask
20 {
21 int word; /* word index */
22 int shift; /* shift amount */
23 int mask; /* final mask */
24 };
25
26 /* internal structure containing the state of the motion objects */
27 struct atarimo_data
28 {
29 int gfxchanged; /* true if the gfx info has changed */
30 struct GfxElement gfxelement[MAX_GFX_ELEMENTS]; /* local copy of graphics elements */
31 int gfxgranularity[MAX_GFX_ELEMENTS];
32
33 struct mame_bitmap *bitmap; /* temporary bitmap to render to */
34
35 int linked; /* are the entries linked? */
36 int split; /* are entries split or together? */
37 int reverse; /* render in reverse order? */
38 int swapxy; /* render in swapped X/Y order? */
39 UINT8 nextneighbor; /* does the neighbor bit affect the next object? */
40 int slipshift; /* log2(pixels_per_SLIP) */
41 int slipoffset; /* pixel offset for SLIP */
42
43 int entrycount; /* number of entries per bank */
44 int entrybits; /* number of bits needed to represent entrycount */
45 int bankcount; /* number of banks */
46
47 int tilewidth; /* width of non-rotated tile */
48 int tileheight; /* height of non-rotated tile */
49 int tilexshift; /* bits to shift X coordinate when drawing */
50 int tileyshift; /* bits to shift Y coordinate when drawing */
51 int bitmapwidth; /* width of the full playfield bitmap */
52 int bitmapheight; /* height of the full playfield bitmap */
53 int bitmapxmask; /* x coordinate mask for the playfield bitmap */
54 int bitmapymask; /* y coordinate mask for the playfield bitmap */
55
56 int spriterammask; /* combined mask when accessing sprite RAM with raw addresses */
57 int spriteramsize; /* total size of sprite RAM, in entries */
58 int sliprammask; /* combined mask when accessing SLIP RAM with raw addresses */
59 int slipramsize; /* total size of SLIP RAM, in entries */
60
61 int palettebase; /* base palette entry */
62 int maxcolors; /* maximum number of colors */
63 int transpen; /* transparent pen index */
64
65 int bank; /* current bank number */
66 int xscroll; /* current x scroll offset */
67 int yscroll; /* current y scroll offset */
68
69 int maxperline; /* maximum number of entries/line */
70
71 struct atarimo_mask linkmask; /* mask for the link */
72 struct atarimo_mask gfxmask; /* mask for the graphics bank */
73 struct atarimo_mask codemask; /* mask for the code index */
74 struct atarimo_mask codehighmask; /* mask for the upper code index */
75 struct atarimo_mask colormask; /* mask for the color */
76 struct atarimo_mask xposmask; /* mask for the X position */
77 struct atarimo_mask yposmask; /* mask for the Y position */
78 struct atarimo_mask widthmask; /* mask for the width, in tiles*/
79 struct atarimo_mask heightmask; /* mask for the height, in tiles */
80 struct atarimo_mask hflipmask; /* mask for the horizontal flip */
81 struct atarimo_mask vflipmask; /* mask for the vertical flip */
82 struct atarimo_mask prioritymask; /* mask for the priority */
83 struct atarimo_mask neighbormask; /* mask for the neighbor */
84 struct atarimo_mask absolutemask; /* mask for absolute coordinates */
85
86 struct atarimo_mask specialmask; /* mask for the special value */
87 int specialvalue; /* resulting value to indicate "special" */
88 atarimo_special_cb specialcb; /* callback routine for special entries */
89 int codehighshift; /* shift count for the upper code */
90
91 struct atarimo_entry *spriteram; /* pointer to sprite RAM */
92 data16_t ** slipram; /* pointer to the SLIP RAM pointer */
93 UINT16 * codelookup; /* lookup table for codes */
94 UINT8 * colorlookup; /* lookup table for colors */
95 UINT8 * gfxlookup; /* lookup table for graphics */
96
97 struct atarimo_entry *activelist[ATARIMO_MAXPERBANK]; /* pointers to active motion objects */
98 struct atarimo_entry **activelast; /* pointer to the last pointer in the active list */
99 int last_link; /* previous starting point */
100
101 UINT8 * dirtygrid; /* grid of dirty rects for blending */
102 int dirtywidth; /* width of dirty grid */
103 int dirtyheight; /* height of dirty grid */
104
105 struct rectangle rectlist[ATARIMO_MAXPERBANK]; /* list of bounding rectangles */
106 int rectcount;
107
108 int last_xpos; /* (during processing) the previous X position */
109 int next_xpos; /* (during processing) the next X position */
110 };
111
112
113
114 /*##########################################################################
115 MACROS
116 ##########################################################################*/
117
118 /* verification macro for void functions */
119 #define VERIFY(cond, msg) if (!(cond)) { log_cb(RETRO_LOG_DEBUG, LOGPRE msg); return; }
120
121 /* verification macro for non-void functions */
122 #define VERIFYRETFREE(cond, msg, ret) if (!(cond)) { log_cb(RETRO_LOG_DEBUG, LOGPRE msg); return (ret); }
123
124
125 /* data extraction */
126 #define EXTRACT_DATA(_input, _mask) (((_input)->data[(_mask).word] >> (_mask).shift) & (_mask).mask)
127
128
129
130 /*##########################################################################
131 GLOBAL VARIABLES
132 ##########################################################################*/
133
134 data16_t *atarimo_0_spriteram;
135 data16_t *atarimo_0_slipram;
136
137 data16_t *atarimo_1_spriteram;
138 data16_t *atarimo_1_slipram;
139
140
141
142 /*##########################################################################
143 STATIC VARIABLES
144 ##########################################################################*/
145
146 static struct atarimo_data atarimo[ATARIMO_MAX];
147
148
149
150 /*##########################################################################
151 STATIC FUNCTION DECLARATIONS
152 ##########################################################################*/
153
154 static int mo_render_object(struct atarimo_data *mo, const struct atarimo_entry *entry, const struct rectangle *cliprect);
155
156
157
158 /*##########################################################################
159 static INLINE FUNCTIONS
160 ##########################################################################*/
161
162 /*---------------------------------------------------------------
163 compute_log: Computes the number of bits necessary to
164 hold a given value. The input must be an even power of
165 two.
166 ---------------------------------------------------------------*/
167
compute_log(int value)168 static INLINE int compute_log(int value)
169 {
170 int log = 0;
171
172 if (value == 0)
173 return -1;
174 while (!(value & 1))
175 log++, value >>= 1;
176 if (value != 1)
177 return -1;
178 return log;
179 }
180
181
182 /*---------------------------------------------------------------
183 round_to_powerof2: Rounds a number up to the nearest
184 power of 2. Even powers of 2 are rounded up to the
185 next greatest power (e.g., 4 returns 8).
186 ---------------------------------------------------------------*/
187
round_to_powerof2(int value)188 static INLINE int round_to_powerof2(int value)
189 {
190 int log = 0;
191
192 if (value == 0)
193 return 1;
194 while ((value >>= 1) != 0)
195 log++;
196 return 1 << (log + 1);
197 }
198
199
200 /*---------------------------------------------------------------
201 convert_mask: Converts a 4-word mask into a word index,
202 shift, and adjusted mask. Returns 0 if invalid.
203 ---------------------------------------------------------------*/
204
convert_mask(const struct atarimo_entry * input,struct atarimo_mask * result)205 static INLINE int convert_mask(const struct atarimo_entry *input, struct atarimo_mask *result)
206 {
207 int i, temp;
208
209 /* determine the word and make sure it's only 1 */
210 result->word = -1;
211 for (i = 0; i < 4; i++)
212 if (input->data[i])
213 {
214 if (result->word == -1)
215 result->word = i;
216 else
217 return 0;
218 }
219
220 /* if all-zero, it's valid */
221 if (result->word == -1)
222 {
223 result->word = result->shift = result->mask = 0;
224 return 1;
225 }
226
227 /* determine the shift and final mask */
228 result->shift = 0;
229 temp = input->data[result->word];
230 while (!(temp & 1))
231 {
232 result->shift++;
233 temp >>= 1;
234 }
235 result->mask = temp;
236 return 1;
237 }
238
239
240 /*---------------------------------------------------------------
241 init_gfxelement: Make a copy of the main gfxelement that
242 gives us full control over colors.
243 ---------------------------------------------------------------*/
244
init_gfxelement(struct atarimo_data * mo,int idx)245 static INLINE void init_gfxelement(struct atarimo_data *mo, int idx)
246 {
247 mo->gfxelement[idx] = *Machine->gfx[idx];
248 mo->gfxgranularity[idx] = mo->gfxelement[idx].color_granularity;
249 mo->gfxelement[idx].color_granularity = 1;
250 mo->gfxelement[idx].colortable = Machine->remapped_colortable;
251 mo->gfxelement[idx].total_colors = 65536;
252 }
253
254
255
256 /*##########################################################################
257 GLOBAL FUNCTIONS
258 ##########################################################################*/
259
force_update(int scanline)260 static void force_update(int scanline)
261 {
262 if (scanline > 0)
263 force_partial_update(scanline - 1);
264
265 scanline += 64;
266 if (scanline >= Machine->visible_area.max_y)
267 scanline = 0;
268 timer_set(cpu_getscanlinetime(scanline), scanline, force_update);
269 }
270
271 /*---------------------------------------------------------------
272 atarimo_init: Configures the motion objects using the input
273 description. Allocates all memory necessary and generates
274 the attribute lookup table.
275 ---------------------------------------------------------------*/
276
atarimo_init(int map,const struct atarimo_desc * desc)277 int atarimo_init(int map, const struct atarimo_desc *desc)
278 {
279 struct GfxElement *gfx = Machine->gfx[desc->gfxindex];
280 struct atarimo_data *mo = &atarimo[map];
281 int i;
282
283 VERIFYRETFREE(map >= 0 && map < ATARIMO_MAX, "atarimo_init: map out of range", 0)
284
285 /* determine the masks first */
286 convert_mask(&desc->linkmask, &mo->linkmask);
287 convert_mask(&desc->gfxmask, &mo->gfxmask);
288 convert_mask(&desc->codemask, &mo->codemask);
289 convert_mask(&desc->codehighmask, &mo->codehighmask);
290 convert_mask(&desc->colormask, &mo->colormask);
291 convert_mask(&desc->xposmask, &mo->xposmask);
292 convert_mask(&desc->yposmask, &mo->yposmask);
293 convert_mask(&desc->widthmask, &mo->widthmask);
294 convert_mask(&desc->heightmask, &mo->heightmask);
295 convert_mask(&desc->hflipmask, &mo->hflipmask);
296 convert_mask(&desc->vflipmask, &mo->vflipmask);
297 convert_mask(&desc->prioritymask, &mo->prioritymask);
298 convert_mask(&desc->neighbormask, &mo->neighbormask);
299 convert_mask(&desc->absolutemask, &mo->absolutemask);
300
301 /* copy in the basic data */
302 mo->gfxchanged = 0;
303
304 mo->linked = desc->linked;
305 mo->split = desc->split;
306 mo->reverse = desc->reverse;
307 mo->swapxy = desc->swapxy;
308 mo->nextneighbor = desc->nextneighbor;
309 mo->slipshift = desc->slipheight ? compute_log(desc->slipheight) : 0;
310 mo->slipoffset = desc->slipoffset;
311
312 mo->entrycount = round_to_powerof2(mo->linkmask.mask);
313 mo->entrybits = compute_log(mo->entrycount);
314 mo->bankcount = desc->banks;
315
316 mo->tilewidth = gfx->width;
317 mo->tileheight = gfx->height;
318 mo->tilexshift = compute_log(mo->tilewidth);
319 mo->tileyshift = compute_log(mo->tileheight);
320 mo->bitmapwidth = round_to_powerof2(mo->xposmask.mask);
321 mo->bitmapheight = round_to_powerof2(mo->yposmask.mask);
322 mo->bitmapxmask = mo->bitmapwidth - 1;
323 mo->bitmapymask = mo->bitmapheight - 1;
324
325 mo->spriteramsize = mo->bankcount * mo->entrycount;
326 mo->spriterammask = mo->spriteramsize - 1;
327 mo->slipramsize = mo->bitmapheight >> mo->slipshift;
328 mo->sliprammask = mo->slipramsize - 1;
329
330 mo->palettebase = desc->palettebase;
331 mo->maxcolors = desc->maxcolors / gfx->color_granularity;
332 mo->transpen = desc->transpen;
333
334 mo->bank = 0;
335 mo->xscroll = 0;
336 mo->yscroll = 0;
337
338 mo->maxperline = desc->maxlinks ? desc->maxlinks : 0x400;
339
340 convert_mask(&desc->specialmask, &mo->specialmask);
341 mo->specialvalue = desc->specialvalue;
342 mo->specialcb = desc->specialcb;
343 mo->codehighshift = compute_log(round_to_powerof2(mo->codemask.mask));
344
345 mo->slipram = (map == 0) ? &atarimo_0_slipram : &atarimo_1_slipram;
346
347 mo->last_link = -1;
348
349 /* allocate the temp bitmap */
350 mo->bitmap = auto_bitmap_alloc(Machine->drv->screen_width, Machine->drv->screen_height);
351 VERIFYRETFREE(mo->bitmap, "atarimo_init: out of memory for temporary bitmap", 0)
352 fillbitmap(mo->bitmap, desc->transpen, NULL);
353
354 /* allocate the spriteram */
355 mo->spriteram = auto_malloc(sizeof(mo->spriteram[0]) * mo->spriteramsize);
356 VERIFYRETFREE(mo->spriteram, "atarimo_init: out of memory for spriteram", 0)
357
358 /* clear it to zero */
359 memset(mo->spriteram, 0, sizeof(mo->spriteram[0]) * mo->spriteramsize);
360
361 /* allocate the code lookup */
362 mo->codelookup = auto_malloc(sizeof(mo->codelookup[0]) * round_to_powerof2(mo->codemask.mask));
363 VERIFYRETFREE(mo->codelookup, "atarimo_init: out of memory for code lookup", 0)
364
365 /* initialize it 1:1 */
366 for (i = 0; i < round_to_powerof2(mo->codemask.mask); i++)
367 mo->codelookup[i] = i;
368
369 /* allocate the color lookup */
370 mo->colorlookup = auto_malloc(sizeof(mo->colorlookup[0]) * round_to_powerof2(mo->colormask.mask));
371 VERIFYRETFREE(mo->colorlookup, "atarimo_init: out of memory for color lookup", 0)
372
373 /* initialize it 1:1 */
374 for (i = 0; i < round_to_powerof2(mo->colormask.mask); i++)
375 mo->colorlookup[i] = i;
376
377 /* allocate dirty grid */
378 mo->dirtywidth = (Machine->drv->screen_width >> mo->tilexshift) + 2;
379 mo->dirtyheight = (Machine->drv->screen_height >> mo->tileyshift) + 2;
380 mo->dirtygrid = auto_malloc(mo->dirtywidth * mo->dirtyheight);
381 VERIFYRETFREE(mo->dirtygrid, "atarimo_init: out of memory for dirty grid", 0)
382
383 /* allocate the gfx lookup */
384 mo->gfxlookup = auto_malloc(sizeof(mo->gfxlookup[0]) * round_to_powerof2(mo->gfxmask.mask));
385 VERIFYRETFREE(mo->gfxlookup, "atarimo_init: out of memory for gfx lookup", 0)
386
387 /* initialize it with the gfxindex we were passed in */
388 for (i = 0; i < round_to_powerof2(mo->gfxmask.mask); i++)
389 mo->gfxlookup[i] = desc->gfxindex;
390
391 /* initialize the gfx elements so we have full control over colors */
392 init_gfxelement(mo, desc->gfxindex);
393
394 /* start a timer to update a few times during refresh */
395 timer_set(cpu_getscanlinetime(0), 0, force_update);
396
397 log_cb(RETRO_LOG_DEBUG, LOGPRE "atarimo_init:\n");
398 log_cb(RETRO_LOG_DEBUG, LOGPRE " width=%d (shift=%d), height=%d (shift=%d)\n", mo->tilewidth, mo->tilexshift, mo->tileheight, mo->tileyshift);
399 log_cb(RETRO_LOG_DEBUG, LOGPRE " spriteram mask=%X, size=%d\n", mo->spriterammask, mo->spriteramsize);
400 log_cb(RETRO_LOG_DEBUG, LOGPRE " slipram mask=%X, size=%d\n", mo->sliprammask, mo->slipramsize);
401 log_cb(RETRO_LOG_DEBUG, LOGPRE " bitmap size=%dx%d\n", mo->bitmapwidth, mo->bitmapheight);
402
403 return 1;
404 }
405
406
407 /*---------------------------------------------------------------
408 atarimo_get_code_lookup: Returns a pointer to the code
409 lookup table.
410 ---------------------------------------------------------------*/
411
atarimo_get_code_lookup(int map,int * size)412 UINT16 *atarimo_get_code_lookup(int map, int *size)
413 {
414 struct atarimo_data *mo = &atarimo[map];
415
416 if (size)
417 *size = round_to_powerof2(mo->codemask.mask);
418 return mo->codelookup;
419 }
420
421
422 /*---------------------------------------------------------------
423 atarimo_get_color_lookup: Returns a pointer to the color
424 lookup table.
425 ---------------------------------------------------------------*/
426
atarimo_get_color_lookup(int map,int * size)427 UINT8 *atarimo_get_color_lookup(int map, int *size)
428 {
429 struct atarimo_data *mo = &atarimo[map];
430
431 if (size)
432 *size = round_to_powerof2(mo->colormask.mask);
433 return mo->colorlookup;
434 }
435
436
437 /*---------------------------------------------------------------
438 atarimo_get_gfx_lookup: Returns a pointer to the graphics
439 lookup table.
440 ---------------------------------------------------------------*/
441
atarimo_get_gfx_lookup(int map,int * size)442 UINT8 *atarimo_get_gfx_lookup(int map, int *size)
443 {
444 struct atarimo_data *mo = &atarimo[map];
445
446 mo->gfxchanged = 1;
447 if (size)
448 *size = round_to_powerof2(mo->gfxmask.mask);
449 return mo->gfxlookup;
450 }
451
452
453 /*---------------------------------------------------------------
454 update_active_list: Update the list of active objects.
455 ---------------------------------------------------------------*/
456
update_active_list(struct atarimo_data * mo,int link)457 static void update_active_list(struct atarimo_data *mo, int link)
458 {
459 struct atarimo_entry *bankbase = &mo->spriteram[mo->bank << mo->entrybits];
460 UINT8 movisit[ATARIMO_MAXPERBANK];
461 struct atarimo_entry **current;
462 int i;
463
464 /* reset the visit map */
465 memset(movisit, 0, mo->entrycount);
466
467 /* remember the last link */
468 mo->last_link = link;
469
470 /* visit all the motion objects and copy their data into the display list */
471 for (i = 0, current = mo->activelist; i < mo->maxperline && !movisit[link]; i++)
472 {
473 struct atarimo_entry *modata = &bankbase[link];
474
475 /* copy the current entry into the list */
476 *current++ = modata;
477
478 /* link to the next object */
479 movisit[link] = 1;
480 if (mo->linked)
481 link = EXTRACT_DATA(modata, mo->linkmask);
482 else
483 link = (link + 1) & mo->linkmask.mask;
484 }
485
486 /* note the last entry */
487 mo->activelast = current;
488 }
489
490
491 /*---------------------------------------------------------------
492 get_dirty_base: Return the dirty grid pointer for a given
493 X and Y position.
494 ---------------------------------------------------------------*/
495
get_dirty_base(struct atarimo_data * mo,int x,int y)496 static INLINE UINT8 *get_dirty_base(struct atarimo_data *mo, int x, int y)
497 {
498 UINT8 *result = mo->dirtygrid;
499 result += ((y >> mo->tileyshift) + 1) * mo->dirtywidth;
500 result += (x >> mo->tilexshift) + 1;
501 return result;
502 }
503
504
505 /*---------------------------------------------------------------
506 erase_dirty_grid: Erases the dirty grid within a given
507 cliprect.
508 ---------------------------------------------------------------*/
509
erase_dirty_grid(struct atarimo_data * mo,const struct rectangle * cliprect)510 static void erase_dirty_grid(struct atarimo_data *mo, const struct rectangle *cliprect)
511 {
512 int sx = cliprect->min_x >> mo->tilexshift;
513 int ex = cliprect->max_x >> mo->tilexshift;
514 int sy = cliprect->min_y >> mo->tileyshift;
515 int ey = cliprect->max_y >> mo->tileyshift;
516 int y;
517
518 /* loop over all grid rows that intersect our cliprect */
519 for (y = sy; y <= ey; y++)
520 {
521 /* get the base pointer and memset the row */
522 UINT8 *dirtybase = get_dirty_base(mo, cliprect->min_x, y << mo->tileyshift);
523 memset(dirtybase, 0, ex - sx + 1);
524 }
525 }
526
527
528 /*---------------------------------------------------------------
529 convert_dirty_grid_to_rects: Converts a dirty grid into a
530 series of cliprects.
531 ---------------------------------------------------------------*/
532
convert_dirty_grid_to_rects(struct atarimo_data * mo,const struct rectangle * cliprect,struct atarimo_rect_list * rectlist)533 static void convert_dirty_grid_to_rects(struct atarimo_data *mo, const struct rectangle *cliprect, struct atarimo_rect_list *rectlist)
534 {
535 int sx = cliprect->min_x >> mo->tilexshift;
536 int ex = cliprect->max_x >> mo->tilexshift;
537 int sy = cliprect->min_y >> mo->tileyshift;
538 int ey = cliprect->max_y >> mo->tileyshift;
539 int tilewidth = 1 << mo->tilexshift;
540 int tileheight = 1 << mo->tileyshift;
541 struct rectangle *rect;
542 int x, y;
543
544 /* initialize the rect list */
545 rectlist->numrects = 0;
546 rectlist->rect = mo->rectlist;
547 rect = &mo->rectlist[-1];
548
549 /* loop over all grid rows that intersect our cliprect */
550 for (y = sy; y <= ey; y++)
551 {
552 UINT8 *dirtybase = get_dirty_base(mo, cliprect->min_x, y << mo->tileyshift);
553 int can_add_to_existing = 0;
554
555 /* loop over all grid columns that intersect our cliprect */
556 for (x = sx; x <= ex; x++)
557 {
558 /* if this tile is dirty, add that to our rectlist */
559 if (*dirtybase++)
560 {
561 /* if we can't add to an existing rect, create a new one */
562 if (!can_add_to_existing)
563 {
564 /* advance pointers */
565 rectlist->numrects++;
566 rect++;
567
568 /* make a rect describing this grid square */
569 rect->min_x = x << mo->tilexshift;
570 rect->max_x = rect->min_x + tilewidth - 1;
571 rect->min_y = y << mo->tileyshift;
572 rect->max_y = rect->min_y + tileheight - 1;
573
574 /* neighboring grid squares can add to this one */
575 can_add_to_existing = 1;
576 }
577
578 /* if we can add to the previous rect, just expand its width */
579 else
580 rect->max_x += tilewidth;
581 }
582
583 /* once we hit a non-dirty square, we can no longer add on */
584 else
585 can_add_to_existing = 0;
586 }
587 }
588 }
589
590
591 /*---------------------------------------------------------------
592 atarimo_render: Render the motion objects to the
593 destination bitmap.
594 ---------------------------------------------------------------*/
595
atarimo_render(int map,const struct rectangle * cliprect,struct atarimo_rect_list * rectlist)596 struct mame_bitmap *atarimo_render(int map, const struct rectangle *cliprect, struct atarimo_rect_list *rectlist)
597 {
598 struct atarimo_data *mo = &atarimo[map];
599 int startband, stopband, band, i;
600 struct rectangle *rect;
601
602 /* if the graphics info has changed, recompute */
603 if (mo->gfxchanged)
604 {
605 mo->gfxchanged = 0;
606 for (i = 0; i < round_to_powerof2(mo->gfxmask.mask); i++)
607 init_gfxelement(mo, mo->gfxlookup[i]);
608 }
609
610 /* compute start/stop bands */
611 startband = ((cliprect->min_y + mo->yscroll - mo->slipoffset) & mo->bitmapymask) >> mo->slipshift;
612 stopband = ((cliprect->max_y + mo->yscroll - mo->slipoffset) & mo->bitmapymask) >> mo->slipshift;
613 if (startband > stopband)
614 startband -= mo->bitmapheight >> mo->slipshift;
615 if (!mo->slipshift)
616 stopband = startband;
617
618 /* erase the dirty grid */
619 erase_dirty_grid(mo, cliprect);
620
621 /* loop over SLIP bands */
622 for (band = startband; band <= stopband; band++)
623 {
624 struct atarimo_entry **first, **current, **last;
625 struct rectangle bandclip;
626 int link, step;
627
628 /* if we don't use SLIPs, just recapture from 0 */
629 if (!mo->slipshift)
630 {
631 link = 0;
632 bandclip = *cliprect;
633 }
634
635 /* otherwise, grab the SLIP and compute the bandrect */
636 else
637 {
638 int slipentry = band & mo->sliprammask;
639 link = ((*mo->slipram)[slipentry] >> mo->linkmask.shift) & mo->linkmask.mask;
640
641 /* start with the cliprect */
642 bandclip = *cliprect;
643
644 /* compute minimum Y and wrap around if necessary */
645 bandclip.min_y = ((band << mo->slipshift) - mo->yscroll + mo->slipoffset) & mo->bitmapymask;
646 if (bandclip.min_y > Machine->visible_area.max_y)
647 bandclip.min_y -= mo->bitmapheight;
648
649 /* maximum Y is based on the minimum */
650 bandclip.max_y = bandclip.min_y + (1 << mo->slipshift) - 1;
651
652 /* keep within the cliprect */
653 sect_rect(&bandclip, cliprect);
654 }
655
656 /* if this matches the last link, we don't need to re-process the list */
657 if (link != mo->last_link)
658 update_active_list(mo, link);
659
660 /* set the start and end points */
661 if (mo->reverse)
662 {
663 first = mo->activelast - 1;
664 last = mo->activelist - 1;
665 step = -1;
666 }
667 else
668 {
669 first = mo->activelist;
670 last = mo->activelast;
671 step = 1;
672 }
673
674 /* initialize the parameters */
675 mo->next_xpos = 123456;
676
677 /* render the mos */
678 for (current = first; current != last; current += step)
679 mo_render_object(mo, *current, &bandclip);
680 }
681
682 /* convert the dirty grid to a rectlist */
683 convert_dirty_grid_to_rects(mo, cliprect, rectlist);
684
685 /* clip the rectlist */
686 for (i = 0, rect = rectlist->rect; i < rectlist->numrects; i++, rect++)
687 sect_rect(rect, cliprect);
688
689 /* return the bitmap */
690 return mo->bitmap;
691 }
692
693
694 /*---------------------------------------------------------------
695 mo_render_object: Internal processing callback that
696 renders to the backing bitmap and then copies the result
697 to the destination.
698 ---------------------------------------------------------------*/
699
mo_render_object(struct atarimo_data * mo,const struct atarimo_entry * entry,const struct rectangle * cliprect)700 static int mo_render_object(struct atarimo_data *mo, const struct atarimo_entry *entry, const struct rectangle *cliprect)
701 {
702 int gfxindex = mo->gfxlookup[EXTRACT_DATA(entry, mo->gfxmask)];
703 const struct GfxElement *gfx = &mo->gfxelement[gfxindex];
704 struct mame_bitmap *bitmap = mo->bitmap;
705 int x, y, sx, sy;
706
707 /* extract data from the various words */
708 int code = mo->codelookup[EXTRACT_DATA(entry, mo->codemask)] | (EXTRACT_DATA(entry, mo->codehighmask) << mo->codehighshift);
709 int color = mo->colorlookup[EXTRACT_DATA(entry, mo->colormask)];
710 int xpos = EXTRACT_DATA(entry, mo->xposmask);
711 int ypos = -EXTRACT_DATA(entry, mo->yposmask);
712 int hflip = EXTRACT_DATA(entry, mo->hflipmask);
713 int vflip = EXTRACT_DATA(entry, mo->vflipmask);
714 int width = EXTRACT_DATA(entry, mo->widthmask) + 1;
715 int height = EXTRACT_DATA(entry, mo->heightmask) + 1;
716 int priority = EXTRACT_DATA(entry, mo->prioritymask);
717 int xadv, yadv, rendered = 0;
718 UINT8 *dirtybase;
719
720 #ifdef TEMPDEBUG
721 int temp = EXTRACT_DATA(entry, mo->codemask);
722 if ((temp & 0xff00) == 0xc800)
723 {
724 static UINT8 hits[256];
725 if (!hits[temp & 0xff])
726 {
727 fprintf(stderr, "code = %04X\n", temp);
728 hits[temp & 0xff] = 1;
729 }
730 }
731 #endif
732
733 /* compute the effective color, merging in priority */
734 color = (color * mo->gfxgranularity[gfxindex]) | (priority << ATARIMO_PRIORITY_SHIFT);
735 color += mo->palettebase;
736
737 /* add in the scroll positions if we're not in absolute coordinates */
738 if (!EXTRACT_DATA(entry, mo->absolutemask))
739 {
740 xpos -= mo->xscroll;
741 ypos -= mo->yscroll;
742 }
743
744 /* adjust for height */
745 ypos -= height << mo->tileyshift;
746
747 /* handle previous hold bits */
748 if (mo->next_xpos != 123456)
749 xpos = mo->next_xpos;
750 mo->next_xpos = 123456;
751
752 /* check for the hold bit */
753 if (EXTRACT_DATA(entry, mo->neighbormask))
754 {
755 if (!mo->nextneighbor)
756 xpos = mo->last_xpos + mo->tilewidth;
757 else
758 mo->next_xpos = xpos + mo->tilewidth;
759 }
760 mo->last_xpos = xpos;
761
762 /* adjust the final coordinates */
763 xpos &= mo->bitmapxmask;
764 ypos &= mo->bitmapymask;
765 if (xpos > Machine->visible_area.max_x) xpos -= mo->bitmapwidth;
766 if (ypos > Machine->visible_area.max_y) ypos -= mo->bitmapheight;
767
768 /* is this one special? */
769 if (mo->specialmask.mask != 0 && EXTRACT_DATA(entry, mo->specialmask) == mo->specialvalue)
770 {
771 if (mo->specialcb)
772 return (*mo->specialcb)(bitmap, cliprect, code, color, xpos, ypos, NULL);
773 return 0;
774 }
775
776 /* adjust for h flip */
777 xadv = mo->tilewidth;
778 if (hflip)
779 {
780 xpos += (width - 1) << mo->tilexshift;
781 xadv = -xadv;
782 }
783
784 /* adjust for v flip */
785 yadv = mo->tileheight;
786 if (vflip)
787 {
788 ypos += (height - 1) << mo->tileyshift;
789 yadv = -yadv;
790 }
791
792 /* standard order is: loop over Y first, then X */
793 if (!mo->swapxy)
794 {
795 /* loop over the height */
796 for (y = 0, sy = ypos; y < height; y++, sy += yadv)
797 {
798 /* clip the Y coordinate */
799 if (sy <= cliprect->min_y - mo->tileheight)
800 {
801 code += width;
802 continue;
803 }
804 else if (sy > cliprect->max_y)
805 break;
806
807 /* loop over the width */
808 for (x = 0, sx = xpos; x < width; x++, sx += xadv, code++)
809 {
810 /* clip the X coordinate */
811 if (sx <= -cliprect->min_x - mo->tilewidth || sx > cliprect->max_x)
812 continue;
813
814 /* draw the sprite */
815 drawgfx(bitmap, gfx, code, color, hflip, vflip, sx, sy, cliprect, TRANSPARENCY_PEN_RAW, mo->transpen);
816 rendered = 1;
817
818 /* mark the grid dirty */
819 dirtybase = get_dirty_base(mo, sx, sy);
820 dirtybase[0] = 1;
821 dirtybase[1] = 1;
822 dirtybase[mo->dirtywidth] = 1;
823 dirtybase[mo->dirtywidth + 1] = 1;
824 }
825 }
826 }
827
828 /* alternative order is swapped */
829 else
830 {
831 /* loop over the width */
832 for (x = 0, sx = xpos; x < width; x++, sx += xadv)
833 {
834 /* clip the X coordinate */
835 if (sx <= cliprect->min_x - mo->tilewidth)
836 {
837 code += height;
838 continue;
839 }
840 else if (sx > cliprect->max_x)
841 break;
842
843 /* loop over the height */
844 dirtybase = get_dirty_base(mo, sx, ypos);
845 for (y = 0, sy = ypos; y < height; y++, sy += yadv, code++)
846 {
847 /* clip the X coordinate */
848 if (sy <= -cliprect->min_y - mo->tileheight || sy > cliprect->max_y)
849 continue;
850
851 /* draw the sprite */
852 drawgfx(bitmap, gfx, code, color, hflip, vflip, sx, sy, cliprect, TRANSPARENCY_PEN_RAW, mo->transpen);
853 rendered = 1;
854
855 /* mark the grid dirty */
856 dirtybase = get_dirty_base(mo, sx, sy);
857 dirtybase[0] = 1;
858 dirtybase[1] = 1;
859 dirtybase[mo->dirtywidth] = 1;
860 dirtybase[mo->dirtywidth + 1] = 1;
861 }
862 }
863 }
864
865 return rendered;
866 }
867
868
869 /*---------------------------------------------------------------
870 atarimo_set_bank: Set the banking value for
871 the motion objects.
872 ---------------------------------------------------------------*/
873
atarimo_set_bank(int map,int bank)874 void atarimo_set_bank(int map, int bank)
875 {
876 struct atarimo_data *mo = &atarimo[map];
877 if (mo->bank != bank)
878 {
879 mo->bank = bank;
880 mo->last_link = -1;
881 }
882 }
883
884
885 /*---------------------------------------------------------------
886 atarimo_set_palettebase: Set the palette base for
887 the motion objects.
888 ---------------------------------------------------------------*/
889
atarimo_set_palettebase(int map,int base)890 void atarimo_set_palettebase(int map, int base)
891 {
892 struct atarimo_data *mo = &atarimo[map];
893 int i;
894
895 mo->palettebase = base;
896 for (i = 0; i < MAX_GFX_ELEMENTS; i++)
897 mo->gfxelement[i].colortable = &Machine->remapped_colortable[base];
898 }
899
900
901 /*---------------------------------------------------------------
902 atarimo_set_xscroll: Set the horizontal scroll value for
903 the motion objects.
904 ---------------------------------------------------------------*/
905
atarimo_set_xscroll(int map,int xscroll)906 void atarimo_set_xscroll(int map, int xscroll)
907 {
908 struct atarimo_data *mo = &atarimo[map];
909 mo->xscroll = xscroll;
910 }
911
912
913 /*---------------------------------------------------------------
914 atarimo_set_yscroll: Set the vertical scroll value for
915 the motion objects.
916 ---------------------------------------------------------------*/
917
atarimo_set_yscroll(int map,int yscroll)918 void atarimo_set_yscroll(int map, int yscroll)
919 {
920 struct atarimo_data *mo = &atarimo[map];
921 mo->yscroll = yscroll;
922 }
923
924
925 /*---------------------------------------------------------------
926 atarimo_get_bank: Returns the banking value
927 for the motion objects.
928 ---------------------------------------------------------------*/
929
atarimo_get_bank(int map)930 int atarimo_get_bank(int map)
931 {
932 return atarimo[map].bank;
933 }
934
935
936 /*---------------------------------------------------------------
937 atarimo_get_palettebase: Returns the palette base
938 for the motion objects.
939 ---------------------------------------------------------------*/
940
atarimo_get_palettebase(int map)941 int atarimo_get_palettebase(int map)
942 {
943 return atarimo[map].palettebase;
944 }
945
946
947 /*---------------------------------------------------------------
948 atarimo_get_xscroll: Returns the horizontal scroll value
949 for the motion objects.
950 ---------------------------------------------------------------*/
951
atarimo_get_xscroll(int map)952 int atarimo_get_xscroll(int map)
953 {
954 return atarimo[map].xscroll;
955 }
956
957
958 /*---------------------------------------------------------------
959 atarimo_get_yscroll: Returns the vertical scroll value for
960 the motion objects.
961 ---------------------------------------------------------------*/
962
atarimo_get_yscroll(int map)963 int atarimo_get_yscroll(int map)
964 {
965 return atarimo[map].yscroll;
966 }
967
968
969 /*---------------------------------------------------------------
970 atarimo_0_spriteram_w: Write handler for the spriteram.
971 ---------------------------------------------------------------*/
972
WRITE16_HANDLER(atarimo_0_spriteram_w)973 WRITE16_HANDLER( atarimo_0_spriteram_w )
974 {
975 int entry, idx, bank;
976
977 COMBINE_DATA(&atarimo_0_spriteram[offset]);
978 if (atarimo[0].split)
979 {
980 entry = offset & atarimo[0].linkmask.mask;
981 idx = (offset >> atarimo[0].entrybits) & 3;
982 }
983 else
984 {
985 entry = (offset >> 2) & atarimo[0].linkmask.mask;
986 idx = offset & 3;
987 }
988 bank = offset >> (2 + atarimo[0].entrybits);
989 COMBINE_DATA(&atarimo[0].spriteram[(bank << atarimo[0].entrybits) + entry].data[idx]);
990 atarimo[0].last_link = -1;
991 }
992
993
994 /*---------------------------------------------------------------
995 atarimo_1_spriteram_w: Write handler for the spriteram.
996 ---------------------------------------------------------------*/
997
WRITE16_HANDLER(atarimo_1_spriteram_w)998 WRITE16_HANDLER( atarimo_1_spriteram_w )
999 {
1000 int entry, idx, bank;
1001
1002 COMBINE_DATA(&atarimo_1_spriteram[offset]);
1003 if (atarimo[1].split)
1004 {
1005 entry = offset & atarimo[1].linkmask.mask;
1006 idx = (offset >> atarimo[1].entrybits) & 3;
1007 }
1008 else
1009 {
1010 entry = (offset >> 2) & atarimo[1].linkmask.mask;
1011 idx = offset & 3;
1012 }
1013 bank = offset >> (2 + atarimo[1].entrybits);
1014 COMBINE_DATA(&atarimo[1].spriteram[(bank << atarimo[1].entrybits) + entry].data[idx]);
1015 atarimo[1].last_link = -1;
1016 }
1017
1018
1019 /*---------------------------------------------------------------
1020 atarimo_0_spriteram_expanded_w: Write handler for the
1021 expanded form of spriteram.
1022 ---------------------------------------------------------------*/
1023
WRITE16_HANDLER(atarimo_0_spriteram_expanded_w)1024 WRITE16_HANDLER( atarimo_0_spriteram_expanded_w )
1025 {
1026 int entry, idx, bank;
1027
1028 COMBINE_DATA(&atarimo_0_spriteram[offset]);
1029 if (!(offset & 1))
1030 {
1031 offset >>= 1;
1032 if (atarimo[0].split)
1033 {
1034 entry = offset & atarimo[0].linkmask.mask;
1035 idx = (offset >> atarimo[0].entrybits) & 3;
1036 }
1037 else
1038 {
1039 entry = (offset >> 2) & atarimo[0].linkmask.mask;
1040 idx = offset & 3;
1041 }
1042 bank = offset >> (2 + atarimo[0].entrybits);
1043 COMBINE_DATA(&atarimo[0].spriteram[(bank << atarimo[0].entrybits) + entry].data[idx]);
1044 atarimo[0].last_link = -1;
1045 }
1046 }
1047
1048
1049 /*---------------------------------------------------------------
1050 atarimo_0_slipram_w: Write handler for the slipram.
1051 ---------------------------------------------------------------*/
1052
WRITE16_HANDLER(atarimo_0_slipram_w)1053 WRITE16_HANDLER( atarimo_0_slipram_w )
1054 {
1055 COMBINE_DATA(&atarimo_0_slipram[offset]);
1056 }
1057
1058
1059 /*---------------------------------------------------------------
1060 atarimo_1_slipram_w: Write handler for the slipram.
1061 ---------------------------------------------------------------*/
1062
WRITE16_HANDLER(atarimo_1_slipram_w)1063 WRITE16_HANDLER( atarimo_1_slipram_w )
1064 {
1065 COMBINE_DATA(&atarimo_1_slipram[offset]);
1066 }
1067