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