1 /* tilemap.c
2 
3 In Progress
4 -	visibility walk (temporarily broken)
5 -	nowrap
6 
7 To Do:
8 -	virtualization for huge tilemaps
9 -	precompute spans per row (to speed up the low level code)
10 -	support for unusual tile sizes (8x12, 8x10)
11 -	screenwise scrolling
12 -	internal profiling
13 
14 	Usage Notes:
15 
16 	When the videoram for a tile changes, call tilemap_mark_tile_dirty
17 	with the appropriate tile_index.
18 
19 	In the video driver, follow these steps:
20 
21 	1)	set each tilemap's scroll registers
22 
23 	2)	call tilemap_update for each tilemap.
24 
25 	3)	call palette_init_used_colors.
26 		mark the colors used by sprites.
27 		call palette recalc.  If the palette manager has compressed the palette,
28 			call tilemap_mark_all_pixels_dirty for each tilemap.
29 
30 	4)	call tilemap_render for each tilemap.
31 
32 	5)	call tilemap_draw to draw the tilemaps to the screen, from back to front
33 */
34 
35 #include "driver.h"
36 #include "tilemap.h"
37 
38 #define SWAP(X,Y) {UINT32 temp=X; X=Y; Y=temp; }
39 
40 /***********************************************************************************/
41 /* some common mappings */
42 
tilemap_scan_rows(UINT32 col,UINT32 row,UINT32 num_cols,UINT32 num_rows)43 UINT32 tilemap_scan_rows( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows ){
44 	/* logical (col,row) -> memory offset */
45 	return row*num_cols + col;
46 }
tilemap_scan_cols(UINT32 col,UINT32 row,UINT32 num_cols,UINT32 num_rows)47 UINT32 tilemap_scan_cols( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows ){
48 	/* logical (col,row) -> memory offset */
49 	return col*num_rows + row;
50 }
51 
52 /*********************************************************************************/
53 
create_tmpbitmap(int width,int height,int depth)54 static struct osd_bitmap *create_tmpbitmap( int width, int height, int depth ){
55 	return osd_alloc_bitmap( width,height,depth );
56 }
57 
create_bitmask(int width,int height)58 static struct osd_bitmap *create_bitmask( int width, int height ){
59 	width = (width+7)>>3; /* 8 bits per byte */
60 	return osd_alloc_bitmap( width,height, 8 );
61 }
62 
63 /***********************************************************************************/
64 
mappings_create(struct tilemap * tilemap)65 static int mappings_create( struct tilemap *tilemap ){
66 	int max_memory_offset = 0;
67 	UINT32 col,row;
68 	UINT32 num_logical_rows = tilemap->num_logical_rows;
69 	UINT32 num_logical_cols = tilemap->num_logical_cols;
70 	/* count offsets (might be larger than num_tiles) */
71 	for( row=0; row<num_logical_rows; row++ ){
72 		for( col=0; col<num_logical_cols; col++ ){
73 			UINT32 memory_offset = tilemap->get_memory_offset( col, row, num_logical_cols, num_logical_rows );
74 			if( memory_offset>max_memory_offset ) max_memory_offset = memory_offset;
75 		}
76 	}
77 	max_memory_offset++;
78 	tilemap->max_memory_offset = max_memory_offset;
79 	/* logical to cached (tilemap_mark_dirty) */
80 	tilemap->memory_offset_to_cached_index = (int*)malloc( sizeof(int)*max_memory_offset );
81 	if( tilemap->memory_offset_to_cached_index ){
82 		/* cached to logical (get_tile_info) */
83 		tilemap->cached_index_to_memory_offset = (UINT32*)malloc( sizeof(UINT32)*tilemap->num_tiles );
84 		if( tilemap->cached_index_to_memory_offset ) return 0; /* no error */
85 		free( tilemap->memory_offset_to_cached_index );
86 	}
87 	return -1; /* error */
88 }
89 
mappings_dispose(struct tilemap * tilemap)90 static void mappings_dispose( struct tilemap *tilemap ){
91 	free( tilemap->cached_index_to_memory_offset );
92 	free( tilemap->memory_offset_to_cached_index );
93 }
94 
mappings_update(struct tilemap * tilemap)95 static void mappings_update( struct tilemap *tilemap ){
96 	int logical_flip;
97 	UINT32 logical_index, cached_index;
98 	UINT32 num_cached_rows = tilemap->num_cached_rows;
99 	UINT32 num_cached_cols = tilemap->num_cached_cols;
100 	UINT32 num_logical_rows = tilemap->num_logical_rows;
101 	UINT32 num_logical_cols = tilemap->num_logical_cols;
102 	for( logical_index=0; logical_index<tilemap->max_memory_offset; logical_index++ ){
103 		tilemap->memory_offset_to_cached_index[logical_index] = -1;
104 	}
105 
106 	/*logerror("log size(%dx%d); cach size(%dx%d)\n",
107 			num_logical_cols,num_logical_rows,
108 			num_cached_cols,num_cached_rows);*/
109 
110 	for( logical_index=0; logical_index<tilemap->num_tiles; logical_index++ ){
111 		UINT32 logical_col = logical_index%num_logical_cols;
112 		UINT32 logical_row = logical_index/num_logical_cols;
113 		int memory_offset = tilemap->get_memory_offset( logical_col, logical_row, num_logical_cols, num_logical_rows );
114 		UINT32 cached_col = logical_col;
115 		UINT32 cached_row = logical_row;
116 		if( tilemap->orientation & ORIENTATION_SWAP_XY ) SWAP(cached_col,cached_row)
117 		if( tilemap->orientation & ORIENTATION_FLIP_X ) cached_col = (num_cached_cols-1)-cached_col;
118 		if( tilemap->orientation & ORIENTATION_FLIP_Y ) cached_row = (num_cached_rows-1)-cached_row;
119 		cached_index = cached_row*num_cached_cols+cached_col;
120 		tilemap->memory_offset_to_cached_index[memory_offset] = cached_index;
121 		tilemap->cached_index_to_memory_offset[cached_index] = memory_offset;
122 	}
123 	for( logical_flip = 0; logical_flip<4; logical_flip++ ){
124 		int cached_flip = logical_flip;
125 		if( tilemap->attributes&TILEMAP_FLIPX ) cached_flip ^= TILE_FLIPX;
126 		if( tilemap->attributes&TILEMAP_FLIPY ) cached_flip ^= TILE_FLIPY;
127 #ifndef PREROTATE_GFX
128 		if( Machine->orientation & ORIENTATION_SWAP_XY ){
129 			if( Machine->orientation & ORIENTATION_FLIP_X ) cached_flip ^= TILE_FLIPY;
130 			if( Machine->orientation & ORIENTATION_FLIP_Y ) cached_flip ^= TILE_FLIPX;
131 		}
132 		else {
133 			if( Machine->orientation & ORIENTATION_FLIP_X ) cached_flip ^= TILE_FLIPX;
134 			if( Machine->orientation & ORIENTATION_FLIP_Y ) cached_flip ^= TILE_FLIPY;
135 		}
136 #endif
137 		if( tilemap->orientation & ORIENTATION_SWAP_XY ){
138 			cached_flip = ((cached_flip&1)<<1) | ((cached_flip&2)>>1);
139 		}
140 		tilemap->logical_flip_to_cached_flip[logical_flip] = cached_flip;
141 	}
142 }
143 
144 /***********************************************************************************/
145 
146 struct osd_bitmap *priority_bitmap; /* priority buffer (corresponds to screen bitmap) */
147 int priority_bitmap_line_offset;
148 
149 static UINT8 flip_bit_table[0x100]; /* horizontal flip for 8 pixels */
150 static struct tilemap *first_tilemap; /* resource tracking */
151 static int screen_width, screen_height;
152 struct tile_info tile_info;
153 
154 enum {
155 	TILE_TRANSPARENT,
156 	TILE_MASKED,
157 	TILE_OPAQUE
158 };
159 
160 /* the following parameters are constant across tilemap_draw calls */
161 static struct {
162 	int clip_left, clip_top, clip_right, clip_bottom;
163 	int source_width, source_height;
164 	int dest_line_offset,source_line_offset,mask_line_offset;
165 	int dest_row_offset,source_row_offset,mask_row_offset;
166 	struct osd_bitmap *screen, *pixmap, *bitmask;
167 	UINT8 **mask_data_row;
168 	UINT8 **priority_data_row;
169 	int tile_priority;
170 	int tilemap_priority_code;
171 } blit;
172 
173 #define MASKROWBYTES(W) (((W)+7)>>3)
174 
memsetbitmask8(UINT8 * dest,int value,const UINT8 * bitmask,int count)175 static void memsetbitmask8( UINT8 *dest, int value, const UINT8 *bitmask, int count ){
176 /* TBA: combine with memcpybitmask */
177 	do{
178 		UINT32 data = *bitmask++;
179 		if( data&0x80 ) dest[0] |= value;
180 		if( data&0x40 ) dest[1] |= value;
181 		if( data&0x20 ) dest[2] |= value;
182 		if( data&0x10 ) dest[3] |= value;
183 		if( data&0x08 ) dest[4] |= value;
184 		if( data&0x04 ) dest[5] |= value;
185 		if( data&0x02 ) dest[6] |= value;
186 		if( data&0x01 ) dest[7] |= value;
187 		dest+=8;
188 		count--;
189 	}while (count);
190 }
191 
192 /*
193 static void memcpybitmask8( UINT8 *dest, const UINT8 *source, const UINT8 *bitmask, int count ){
194 	do{
195 		UINT32 data = *bitmask++;
196 		if( data&0x80 ) dest[0] = source[0];
197 		if( data&0x40 ) dest[1] = source[1];
198 		if( data&0x20 ) dest[2] = source[2];
199 		if( data&0x10 ) dest[3] = source[3];
200 		if( data&0x08 ) dest[4] = source[4];
201 		if( data&0x04 ) dest[5] = source[5];
202 		if( data&0x02 ) dest[6] = source[6];
203 		if( data&0x01 ) dest[7] = source[7];
204 		source+=8;
205 		dest+=8;
206 		count--;
207 	}while (count);
208 }
209 */
210 
memcpybitmask8(UINT8 * dest,const UINT32 * source,const UINT8 * bitmask,int count)211 static void memcpybitmask8( UINT8 *dest, const UINT32 *source, const UINT8 *bitmask, int count ){
212 	do{
213 		UINT32 data = *bitmask++;
214 		UINT32 src = *source++;
215 		if( data&0x80 ) dest[0] = src;
216 		if( data&0x40 ) dest[1] = src>>8;
217 		if( data&0x20 ) dest[2] = src>>16;
218 		if( data&0x10 ) dest[3] = src>>24;;
219 		src=*source++;
220 		if( data&0x08 ) dest[4] = src;
221 		if( data&0x04 ) dest[5] = src>>8;
222 		if( data&0x02 ) dest[6] = src>>16;
223 		if( data&0x01 ) dest[7] = src>>24;
224 		dest+=8;
225 		count--;
226 	}while (count);
227 }
228 
229 /***********************************************************************************/
230 
231 /*
232 static void memcpybitmask16( UINT16 *dest, const UINT16 *source, const UINT8 *bitmask, int count ){
233 	do{
234 		UINT32 data = *bitmask++;
235 		if( data&0x80 ) dest[0] = source[0];
236 		if( data&0x40 ) dest[1] = source[1];
237 		if( data&0x20 ) dest[2] = source[2];
238 		if( data&0x10 ) dest[3] = source[3];
239 		if( data&0x08 ) dest[4] = source[4];
240 		if( data&0x04 ) dest[5] = source[5];
241 		if( data&0x02 ) dest[6] = source[6];
242 		if( data&0x01 ) dest[7] = source[7];
243 		source+=8;
244 		dest+=8;
245 		count--;
246 	}while (count);
247 }
248 */
249 
memcpybitmask16(UINT16 * dest,const UINT32 * source,const UINT8 * bitmask,int count)250 static void memcpybitmask16( UINT16 *dest, const UINT32 *source, const UINT8 *bitmask, int count ){
251 	do{
252 		UINT32 data = *bitmask++;
253 		UINT32 src = *source++;
254 		if( data&0x80 ) dest[0] = src;
255 		if( data&0x40 ) dest[1] = src>>16;
256 		src=*source++;
257 		if( data&0x20 ) dest[2] = src;
258 		if( data&0x10 ) dest[3] = src>>16;
259 		src=*source++;
260 		if( data&0x08 ) dest[4] = src;
261 		if( data&0x04 ) dest[5] = src>>16;
262 		src=*source++;
263 		if( data&0x02 ) dest[6] = src;
264 		if( data&0x01 ) dest[7] = src>>16;
265 		dest+=8;
266 		count--;
267 	}while (count);
268 }
269 
270 /***********************************************************************************/
271 
272 #define TILE_WIDTH	8
273 #define TILE_HEIGHT	8
274 #define DATA_TYPE UINT8
275 #define memcpybitmask memcpybitmask8
276 #define DECLARE(function,args,body) static void function##8x8x8BPP args body
277 #include "tilemap_draw.h"
278 
279 #define TILE_WIDTH	16
280 #define TILE_HEIGHT	16
281 #define DATA_TYPE UINT8
282 #define memcpybitmask memcpybitmask8
283 #define DECLARE(function,args,body) static void function##16x16x8BPP args body
284 #include "tilemap_draw.h"
285 
286 #define TILE_WIDTH	32
287 #define TILE_HEIGHT	32
288 #define DATA_TYPE UINT8
289 #define memcpybitmask memcpybitmask8
290 #define DECLARE(function,args,body) static void function##32x32x8BPP args body
291 #include "tilemap_draw.h"
292 
293 #define TILE_WIDTH	8
294 #define TILE_HEIGHT	8
295 #define DATA_TYPE UINT16
296 #define memcpybitmask memcpybitmask16
297 #define DECLARE(function,args,body) static void function##8x8x16BPP args body
298 #include "tilemap_draw.h"
299 
300 #define TILE_WIDTH	16
301 #define TILE_HEIGHT	16
302 #define DATA_TYPE UINT16
303 #define memcpybitmask memcpybitmask16
304 #define DECLARE(function,args,body) static void function##16x16x16BPP args body
305 #include "tilemap_draw.h"
306 
307 #define TILE_WIDTH	32
308 #define TILE_HEIGHT	32
309 #define DATA_TYPE UINT16
310 #define memcpybitmask memcpybitmask16
311 #define DECLARE(function,args,body) static void function##32x32x16BPP args body
312 #include "tilemap_draw.h"
313 
314 /*********************************************************************************/
315 
mask_dispose(struct tilemap_mask * mask)316 static void mask_dispose( struct tilemap_mask *mask ){
317 	if( mask ){
318 		free( mask->data_row );
319 		free( mask->data );
320 		osd_free_bitmap( mask->bitmask );
321 		free( mask );
322 	}
323 }
324 
mask_create(struct tilemap * tilemap)325 static struct tilemap_mask *mask_create( struct tilemap *tilemap ){
326 	struct tilemap_mask *mask = (struct tilemap_mask *)malloc( sizeof(struct tilemap_mask) );
327 	if( mask ){
328 		mask->data = (UINT8*)malloc( tilemap->num_tiles );
329 		mask->data_row = (UINT8**)malloc( tilemap->num_cached_rows * sizeof(UINT8 *) );
330 		mask->bitmask = create_bitmask( tilemap->cached_width, tilemap->cached_height );
331 		if( mask->data && mask->data_row && mask->bitmask ){
332 			int row;
333 			for( row=0; row<tilemap->num_cached_rows; row++ ){
334 				mask->data_row[row] = mask->data + row*tilemap->num_cached_cols;
335 			}
336 			mask->line_offset = mask->bitmask->line[1] - mask->bitmask->line[0];
337 			return mask;
338 		}
339 	}
340 	mask_dispose( mask );
341 	return NULL;
342 }
343 
344 /***********************************************************************************/
345 
install_draw_handlers(struct tilemap * tilemap)346 static void install_draw_handlers( struct tilemap *tilemap ){
347 	int tile_width = tilemap->cached_tile_width;
348 	int tile_height = tilemap->cached_tile_height;
349 	tilemap->draw = tilemap->draw_opaque = NULL;
350 	if( Machine->scrbitmap->depth==16 ){
351 		if( tile_width==8 && tile_height==8 ){
352 			tilemap->draw = draw8x8x16BPP;
353 			tilemap->draw_opaque = draw_opaque8x8x16BPP;
354 		}
355 		else if( tile_width==16 && tile_height==16 ){
356 			tilemap->draw = draw16x16x16BPP;
357 			tilemap->draw_opaque = draw_opaque16x16x16BPP;
358 		}
359 		else if( tile_width==32 && tile_height==32 ){
360 			tilemap->draw = draw32x32x16BPP;
361 			tilemap->draw_opaque = draw_opaque32x32x16BPP;
362 		}
363 	}
364 	else {
365 		if( tile_width==8 && tile_height==8 ){
366 			tilemap->draw = draw8x8x8BPP;
367 			tilemap->draw_opaque = draw_opaque8x8x8BPP;
368 		}
369 		else if( tile_width==16 && tile_height==16 ){
370 			tilemap->draw = draw16x16x8BPP;
371 			tilemap->draw_opaque = draw_opaque16x16x8BPP;
372 		}
373 		else if( tile_width==32 && tile_height==32 ){
374 			tilemap->draw = draw32x32x8BPP;
375 			tilemap->draw_opaque = draw_opaque32x32x8BPP;
376 		}
377 	}
378 }
379 
380 /***********************************************************************************/
381 
tilemap_init(void)382 int tilemap_init( void ){
383 	UINT32 value, data, bit;
384 	for( value=0; value<0x100; value++ ){
385 		data = 0;
386 		for( bit=0; bit<8; bit++ ) if( (value>>bit)&1 ) data |= 0x80>>bit;
387 		flip_bit_table[value] = data;
388 	}
389 	screen_width = Machine->scrbitmap->width;
390 	screen_height = Machine->scrbitmap->height;
391 	first_tilemap = 0;
392 	priority_bitmap = create_tmpbitmap( screen_width, screen_height, 8 );
393 	if( priority_bitmap ){
394 		priority_bitmap_line_offset = priority_bitmap->line[1] - priority_bitmap->line[0];
395 		return 0;
396 	}
397 	return -1;
398 }
399 
tilemap_close(void)400 void tilemap_close( void ){
401 	while( first_tilemap ){
402 		struct tilemap *next = first_tilemap->next;
403 		tilemap_dispose( first_tilemap );
404 		first_tilemap = next;
405 	}
406 	osd_free_bitmap( priority_bitmap );
407 }
408 
409 /***********************************************************************************/
410 
tilemap_create(void (* tile_get_info)(int memory_offset),UINT32 (* get_memory_offset)(UINT32 col,UINT32 row,UINT32 num_cols,UINT32 num_rows),int type,int tile_width,int tile_height,int num_cols,int num_rows)411 struct tilemap *tilemap_create(
412 	void (*tile_get_info)( int memory_offset ),
413 	UINT32 (*get_memory_offset)( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows ),
414 	int type,
415 	int tile_width, int tile_height, /* in pixels */
416 	int num_cols, int num_rows /* in tiles */
417 ){
418 	struct tilemap *tilemap = (struct tilemap *)calloc( 1,sizeof( struct tilemap ) );
419 	if( tilemap ){
420 		int num_tiles = num_cols*num_rows;
421 		tilemap->num_logical_cols = num_cols;
422 		tilemap->num_logical_rows = num_rows;
423 		if( Machine->orientation & ORIENTATION_SWAP_XY ){
424 		/*logerror("swap!!\n" );*/
425 			SWAP( tile_width, tile_height )
426 			SWAP( num_cols,num_rows )
427 		}
428 		tilemap->num_cached_cols = num_cols;
429 		tilemap->num_cached_rows = num_rows;
430 		tilemap->num_tiles = num_tiles;
431 		tilemap->cached_tile_width = tile_width;
432 		tilemap->cached_tile_height = tile_height;
433 		tilemap->cached_width = tile_width*num_cols;
434 		tilemap->cached_height = tile_height*num_rows;
435 		tilemap->tile_get_info = tile_get_info;
436 		tilemap->get_memory_offset = get_memory_offset;
437 		tilemap->orientation = Machine->orientation;
438 		tilemap->enable = 1;
439 		tilemap->type = type;
440 		tilemap->scroll_rows = 1;
441 		tilemap->scroll_cols = 1;
442 		tilemap->transparent_pen = -1;
443 		tilemap->cached_tile_info = (struct cached_tile_info*)calloc( num_tiles, sizeof(struct cached_tile_info) );
444 		tilemap->priority = (UINT8*)calloc( num_tiles,1 );
445 		tilemap->visible = (UINT8*)calloc( num_tiles,1 );
446 		tilemap->dirty_vram = (UINT8*)malloc( num_tiles );
447 		tilemap->dirty_pixels = (UINT8*)malloc( num_tiles );
448 		tilemap->rowscroll = (int*)calloc(tilemap->cached_height,sizeof(int));
449 		tilemap->colscroll = (int*)calloc(tilemap->cached_width,sizeof(int));
450 		tilemap->priority_row = (UINT8**)malloc( sizeof(UINT8 *)*num_rows );
451 		tilemap->pixmap = create_tmpbitmap( tilemap->cached_width, tilemap->cached_height, Machine->scrbitmap->depth );
452 		tilemap->foreground = mask_create( tilemap );
453 		tilemap->background = (type & TILEMAP_SPLIT)?mask_create( tilemap ):NULL;
454 		if( tilemap->cached_tile_info &&
455 			tilemap->priority && tilemap->visible &&
456 			tilemap->dirty_vram && tilemap->dirty_pixels &&
457 			tilemap->rowscroll && tilemap->colscroll &&
458 			tilemap->priority_row &&
459 			tilemap->pixmap && tilemap->foreground &&
460 			((type&TILEMAP_SPLIT)==0 || tilemap->background) &&
461 			(mappings_create( tilemap )==0)
462 		){
463 			UINT32 row;
464 			for( row=0; row<num_rows; row++ ){
465 				tilemap->priority_row[row] = tilemap->priority+num_cols*row;
466 			}
467 			install_draw_handlers( tilemap );
468 			mappings_update( tilemap );
469 			tilemap_set_clip( tilemap, &Machine->visible_area );
470 			memset( tilemap->dirty_vram, 1, num_tiles );
471 			memset( tilemap->dirty_pixels, 1, num_tiles );
472 			tilemap->pixmap_line_offset = tilemap->pixmap->line[1] - tilemap->pixmap->line[0];
473 			tilemap->next = first_tilemap;
474 			first_tilemap = tilemap;
475 			return tilemap;
476 		}
477 		tilemap_dispose( tilemap );
478 	}
479 	return 0;
480 }
481 
tilemap_dispose(struct tilemap * tilemap)482 void tilemap_dispose( struct tilemap *tilemap ){
483 	if( tilemap==first_tilemap ){
484 		first_tilemap = tilemap->next;
485 	}
486 	else {
487 		struct tilemap *prev = first_tilemap;
488 		while( prev->next != tilemap ) prev = prev->next;
489 		prev->next =tilemap->next;
490 	}
491 
492 	free( tilemap->cached_tile_info );
493 	free( tilemap->priority );
494 	free( tilemap->visible );
495 	free( tilemap->dirty_vram );
496 	free( tilemap->dirty_pixels );
497 	free( tilemap->rowscroll );
498 	free( tilemap->colscroll );
499 	free( tilemap->priority_row );
500 	osd_free_bitmap( tilemap->pixmap );
501 	mask_dispose( tilemap->foreground );
502 	mask_dispose( tilemap->background );
503 	mappings_dispose( tilemap );
504 	free( tilemap );
505 }
506 
507 /***********************************************************************************/
508 
unregister_pens(struct cached_tile_info * cached_tile_info,int num_pens)509 static void unregister_pens( struct cached_tile_info *cached_tile_info, int num_pens ){
510 	const UINT16 *pal_data = cached_tile_info->pal_data;
511 	if( pal_data ){
512 		UINT32 pen_usage = cached_tile_info->pen_usage;
513 		if( pen_usage ){
514 			palette_decrease_usage_count(
515 				pal_data-Machine->remapped_colortable,
516 				pen_usage,
517 				PALETTE_COLOR_VISIBLE|PALETTE_COLOR_CACHED );
518 		}
519 		else {
520 			palette_decrease_usage_countx(
521 				pal_data-Machine->remapped_colortable,
522 				num_pens,
523 				cached_tile_info->pen_data,
524 				PALETTE_COLOR_VISIBLE|PALETTE_COLOR_CACHED );
525 		}
526 		cached_tile_info->pal_data = NULL;
527 	}
528 }
529 
register_pens(struct cached_tile_info * cached_tile_info,int num_pens)530 static void register_pens( struct cached_tile_info *cached_tile_info, int num_pens ){
531 	UINT32 pen_usage = cached_tile_info->pen_usage;
532 	if( pen_usage ){
533 		palette_increase_usage_count(
534 			cached_tile_info->pal_data-Machine->remapped_colortable,
535 			pen_usage,
536 			PALETTE_COLOR_VISIBLE|PALETTE_COLOR_CACHED );
537 	}
538 	else {
539 		palette_increase_usage_countx(
540 			cached_tile_info->pal_data-Machine->remapped_colortable,
541 			num_pens,
542 			cached_tile_info->pen_data,
543 			PALETTE_COLOR_VISIBLE|PALETTE_COLOR_CACHED );
544 	}
545 }
546 
547 /***********************************************************************************/
548 
tilemap_set_enable(struct tilemap * tilemap,int enable)549 void tilemap_set_enable( struct tilemap *tilemap, int enable ){
550 	tilemap->enable = enable;
551 }
552 
tilemap_set_transparent_pen(struct tilemap * tilemap,int pen)553 void tilemap_set_transparent_pen( struct tilemap *tilemap, int pen ){
554 	tilemap->transparent_pen = pen;
555 }
556 
tilemap_set_flip(struct tilemap * tilemap,int attributes)557 void tilemap_set_flip( struct tilemap *tilemap, int attributes ){
558 	if( tilemap==ALL_TILEMAPS ){
559 		tilemap = first_tilemap;
560 		while( tilemap ){
561 			tilemap_set_flip( tilemap, attributes );
562 			tilemap = tilemap->next;
563 		}
564 	}
565 	else if( tilemap->attributes!=attributes ){
566 		tilemap->attributes = attributes;
567 		tilemap->orientation = Machine->orientation;
568 		if( attributes&TILEMAP_FLIPY ){
569 			tilemap->orientation ^= ORIENTATION_FLIP_Y;
570 			tilemap->scrolly_delta = tilemap->dy_if_flipped;
571 		}
572 		else {
573 			tilemap->scrolly_delta = tilemap->dy;
574 		}
575 		if( attributes&TILEMAP_FLIPX ){
576 			tilemap->orientation ^= ORIENTATION_FLIP_X;
577 			tilemap->scrollx_delta = tilemap->dx_if_flipped;
578 		}
579 		else {
580 			tilemap->scrollx_delta = tilemap->dx;
581 		}
582 
583 		mappings_update( tilemap );
584 		tilemap_mark_all_tiles_dirty( tilemap );
585 	}
586 }
587 
tilemap_set_clip(struct tilemap * tilemap,const struct rectangle * clip)588 void tilemap_set_clip( struct tilemap *tilemap, const struct rectangle *clip ){
589 	int left,top,right,bottom;
590 	if( clip ){
591 		left = clip->min_x;
592 		top = clip->min_y;
593 		right = clip->max_x+1;
594 		bottom = clip->max_y+1;
595 		if( tilemap->orientation & ORIENTATION_SWAP_XY ){
596 			SWAP(left,top)
597 			SWAP(right,bottom)
598 		}
599 		if( tilemap->orientation & ORIENTATION_FLIP_X ){
600 			SWAP(left,right)
601 			left = screen_width-left;
602 			right = screen_width-right;
603 		}
604 		if( tilemap->orientation & ORIENTATION_FLIP_Y ){
605 			SWAP(top,bottom)
606 			top = screen_height-top;
607 			bottom = screen_height-bottom;
608 		}
609 	}
610 	else {
611 		left = 0;
612 		top = 0;
613 		right = tilemap->cached_width;
614 		bottom = tilemap->cached_height;
615 	}
616 	tilemap->clip_left = left;
617 	tilemap->clip_right = right;
618 	tilemap->clip_top = top;
619 	tilemap->clip_bottom = bottom;
620 //	logerror("clip: %d,%d,%d,%d\n", left,top,right,bottom );
621 }
622 
623 /***********************************************************************************/
624 
tilemap_set_scroll_cols(struct tilemap * tilemap,int n)625 void tilemap_set_scroll_cols( struct tilemap *tilemap, int n ){
626 	if( tilemap->orientation & ORIENTATION_SWAP_XY ){
627 		if (tilemap->scroll_rows != n){
628 			tilemap->scroll_rows = n;
629 		}
630 	}
631 	else {
632 		if (tilemap->scroll_cols != n){
633 			tilemap->scroll_cols = n;
634 		}
635 	}
636 }
637 
tilemap_set_scroll_rows(struct tilemap * tilemap,int n)638 void tilemap_set_scroll_rows( struct tilemap *tilemap, int n ){
639 	if( tilemap->orientation & ORIENTATION_SWAP_XY ){
640 		if (tilemap->scroll_cols != n){
641 			tilemap->scroll_cols = n;
642 		}
643 	}
644 	else {
645 		if (tilemap->scroll_rows != n){
646 			tilemap->scroll_rows = n;
647 		}
648 	}
649 }
650 
651 /***********************************************************************************/
652 
tilemap_mark_tile_dirty(struct tilemap * tilemap,int memory_offset)653 void tilemap_mark_tile_dirty( struct tilemap *tilemap, int memory_offset ){
654 	if( memory_offset<tilemap->max_memory_offset ){
655 		int cached_index = tilemap->memory_offset_to_cached_index[memory_offset];
656 		if( cached_index>=0 ){
657 			tilemap->dirty_vram[cached_index] = 1;
658 		}
659 	}
660 }
661 
tilemap_mark_all_tiles_dirty(struct tilemap * tilemap)662 void tilemap_mark_all_tiles_dirty( struct tilemap *tilemap ){
663 	if( tilemap==ALL_TILEMAPS ){
664 		tilemap = first_tilemap;
665 		while( tilemap ){
666 			tilemap_mark_all_tiles_dirty( tilemap );
667 			tilemap = tilemap->next;
668 		}
669 	}
670 	else {
671 		memset( tilemap->dirty_vram, 1, tilemap->num_tiles );
672 	}
673 }
674 
tilemap_mark_all_pixels_dirty(struct tilemap * tilemap)675 void tilemap_mark_all_pixels_dirty( struct tilemap *tilemap ){
676 	if( tilemap==ALL_TILEMAPS ){
677 		tilemap = first_tilemap;
678 		while( tilemap ){
679 			tilemap_mark_all_pixels_dirty( tilemap );
680 			tilemap = tilemap->next;
681 		}
682 	}
683 	else {
684 		/* invalidate all offscreen tiles */
685 		UINT32 cached_tile_index;
686 		UINT32 num_pens = tilemap->cached_tile_width*tilemap->cached_tile_height;
687 		for( cached_tile_index=0; cached_tile_index<tilemap->num_tiles; cached_tile_index++ ){
688 			if( !tilemap->visible[cached_tile_index] ){
689 				unregister_pens( &tilemap->cached_tile_info[cached_tile_index], num_pens );
690 				tilemap->dirty_vram[cached_tile_index] = 1;
691 			}
692 		}
693 		memset( tilemap->dirty_pixels, 1, tilemap->num_tiles );
694 	}
695 }
696 
697 /***********************************************************************************/
698 
draw_tile(struct tilemap * tilemap,UINT32 cached_index,UINT32 col,UINT32 row)699 static void draw_tile(
700 		struct tilemap *tilemap,
701 		UINT32 cached_index,
702 		UINT32 col, UINT32 row
703 ){
704 	struct osd_bitmap *pixmap = tilemap->pixmap;
705 	UINT32 tile_width = tilemap->cached_tile_width;
706 	UINT32 tile_height = tilemap->cached_tile_height;
707 	struct cached_tile_info *cached_tile_info = &tilemap->cached_tile_info[cached_index];
708 	const UINT8 *pendata = cached_tile_info->pen_data;
709 	const UINT16 *paldata = cached_tile_info->pal_data;
710 
711 	UINT32 flags = cached_tile_info->flags;
712 	int x, sx = tile_width*col;
713 	int sy,y1,y2,dy;
714 
715 	if( Machine->scrbitmap->depth==16 ){
716 		if( flags&TILE_FLIPY ){
717 			y1 = tile_height*row+tile_height-1;
718 			y2 = y1-tile_height;
719 	 		dy = -1;
720 	 	}
721 	 	else {
722 			y1 = tile_height*row;
723 			y2 = y1+tile_height;
724 	 		dy = 1;
725 	 	}
726 
727 		if( flags&TILE_FLIPX ){
728 			tile_width--;
729 			for( sy=y1; sy!=y2; sy+=dy ){
730 				UINT16 *dest  = sx + (UINT16 *)pixmap->line[sy];
731 				for( x=tile_width; x>=0; x-- ) dest[x] = paldata[*pendata++];
732 			}
733 		}
734 		else {
735 			for( sy=y1; sy!=y2; sy+=dy ){
736 				UINT16 *dest  = sx + (UINT16 *)pixmap->line[sy];
737 				for( x=0; x<tile_width; x++ ) dest[x] = paldata[*pendata++];
738 			}
739 		}
740 	}
741 	else {
742 		if( flags&TILE_FLIPY ){
743 			y1 = tile_height*row+tile_height-1;
744 			y2 = y1-tile_height;
745 	 		dy = -1;
746 	 	}
747 	 	else {
748 			y1 = tile_height*row;
749 			y2 = y1+tile_height;
750 	 		dy = 1;
751 	 	}
752 
753 		if( flags&TILE_FLIPX ){
754 			tile_width--;
755 			for( sy=y1; sy!=y2; sy+=dy ){
756 				UINT8 *dest  = sx + (UINT8 *)pixmap->line[sy];
757 				for( x=tile_width; x>=0; x-- ) dest[x] = paldata[*pendata++];
758 			}
759 		}
760 		else {
761 			for( sy=y1; sy!=y2; sy+=dy ){
762 				UINT8 *dest  = sx + (UINT8 *)pixmap->line[sy];
763 				for( x=0; x<tile_width; x++ ) dest[x] = paldata[*pendata++];
764 			}
765 		}
766 	}
767 }
768 
tilemap_render(struct tilemap * tilemap)769 void tilemap_render( struct tilemap *tilemap ){
770 profiler_mark(PROFILER_TILEMAP_RENDER);
771 	if( tilemap==ALL_TILEMAPS ){
772 		tilemap = first_tilemap;
773 		while( tilemap ){
774 			tilemap_render( tilemap );
775 			tilemap = tilemap->next;
776 		}
777 	}
778 	else if( tilemap->enable ){
779 		UINT8 *dirty_pixels = tilemap->dirty_pixels;
780 		const UINT8 *visible = tilemap->visible;
781 		UINT32 cached_index = 0;
782 		UINT32 row,col;
783 
784 		/* walk over cached rows/cols (better to walk screen coords) */
785 		for( row=0; row<tilemap->num_cached_rows; row++ ){
786 			for( col=0; col<tilemap->num_cached_cols; col++ ){
787 				if( visible[cached_index] && dirty_pixels[cached_index] ){
788 					draw_tile( tilemap, cached_index, col, row );
789 					dirty_pixels[cached_index] = 0;
790 				}
791 				cached_index++;
792 			} /* next col */
793 		} /* next row */
794 	}
795 profiler_mark(PROFILER_END);
796 }
797 
798 /***********************************************************************************/
799 
draw_bitmask(struct osd_bitmap * mask,UINT32 col,UINT32 row,UINT32 tile_width,UINT32 tile_height,const UINT8 * maskdata,UINT32 flags)800 static int draw_bitmask(
801 		struct osd_bitmap *mask,
802 		UINT32 col, UINT32 row,
803 		UINT32 tile_width, UINT32 tile_height,
804 		const UINT8 *maskdata,
805 		UINT32 flags )
806 {
807 	int is_opaque = 1, is_transparent = 1;
808 	int x,sx = tile_width*col;
809 	int sy,y1,y2,dy;
810 
811 	if( maskdata==TILEMAP_BITMASK_TRANSPARENT ) return TILE_TRANSPARENT;
812 	if( maskdata==TILEMAP_BITMASK_OPAQUE) return TILE_OPAQUE;
813 
814 	if( flags&TILE_FLIPY ){
815 		y1 = tile_height*row+tile_height-1;
816 		y2 = y1-tile_height;
817  		dy = -1;
818  	}
819  	else {
820 		y1 = tile_height*row;
821 		y2 = y1+tile_height;
822  		dy = 1;
823  	}
824 
825 	if( flags&TILE_FLIPX ){
826 		tile_width--;
827 		for( sy=y1; sy!=y2; sy+=dy ){
828 			UINT8 *mask_dest  = mask->line[sy]+(sx>>3);
829 			for( x=tile_width>>3; x>=0; x-- ){
830 				UINT8 data = flip_bit_table[*maskdata++];
831 				if( data!=0x00 ) is_transparent = 0;
832 				if( data!=0xff ) is_opaque = 0;
833 				mask_dest[x] = data;
834 			}
835 		}
836 	}
837 	else {
838 		for( sy=y1; sy!=y2; sy+=dy ){
839 			UINT8 *mask_dest  = mask->line[sy]+(sx>>3);
840 			for( x=0; x<(tile_width>>3); x++ ){
841 				UINT8 data = *maskdata++;
842 				if( data!=0x00 ) is_transparent = 0;
843 				if( data!=0xff ) is_opaque = 0;
844 				mask_dest[x] = data;
845 			}
846 		}
847 	}
848 
849 	if( is_transparent ) return TILE_TRANSPARENT;
850 	if( is_opaque ) return TILE_OPAQUE;
851 	return TILE_MASKED;
852 }
853 
draw_color_mask(struct osd_bitmap * mask,UINT32 col,UINT32 row,UINT32 tile_width,UINT32 tile_height,const UINT8 * pendata,const UINT16 * clut,int transparent_color,UINT32 flags)854 static int draw_color_mask(
855 	struct osd_bitmap *mask,
856 	UINT32 col, UINT32 row,
857 	UINT32 tile_width, UINT32 tile_height,
858 	const UINT8 *pendata,
859 	const UINT16 *clut,
860 	int transparent_color,
861 	UINT32 flags )
862 {
863 	int is_opaque = 1, is_transparent = 1;
864 
865 	int x,bit,sx = tile_width*col;
866 	int sy,y1,y2,dy;
867 
868 	if( flags&TILE_FLIPY ){
869 		y1 = tile_height*row+tile_height-1;
870 		y2 = y1-tile_height;
871  		dy = -1;
872  	}
873  	else {
874 		y1 = tile_height*row;
875 		y2 = y1+tile_height;
876  		dy = 1;
877  	}
878 
879 	if( flags&TILE_FLIPX ){
880 		tile_width--;
881 		for( sy=y1; sy!=y2; sy+=dy ){
882 			UINT8 *mask_dest  = mask->line[sy]+(sx>>3);
883 			for( x=(tile_width>>3); x>=0; x-- ){
884 				UINT32 data = 0;
885 				for( bit=0; bit<8; bit++ ){
886 					UINT32 pen = *pendata++;
887 					data = data>>1;
888 					if( clut[pen]!=transparent_color ) data |=0x80;
889 				}
890 				if( data!=0x00 ) is_transparent = 0;
891 				if( data!=0xff ) is_opaque = 0;
892 				mask_dest[x] = data;
893 			}
894 		}
895 	}
896 	else {
897 		for( sy=y1; sy!=y2; sy+=dy ){
898 			UINT8 *mask_dest  = mask->line[sy]+(sx>>3);
899 			for( x=0; x<(tile_width>>3); x++ ){
900 				UINT32 data = 0;
901 				for( bit=0; bit<8; bit++ ){
902 					UINT32 pen = *pendata++;
903 					data = data<<1;
904 					if( clut[pen]!=transparent_color ) data |=0x01;
905 				}
906 				if( data!=0x00 ) is_transparent = 0;
907 				if( data!=0xff ) is_opaque = 0;
908 				mask_dest[x] = data;
909 			}
910 		}
911 	}
912 	if( is_transparent ) return TILE_TRANSPARENT;
913 	if( is_opaque ) return TILE_OPAQUE;
914 	return TILE_MASKED;
915 }
916 
draw_pen_mask(struct osd_bitmap * mask,UINT32 col,UINT32 row,UINT32 tile_width,UINT32 tile_height,const UINT8 * pendata,int transparent_pen,UINT32 flags)917 static int draw_pen_mask(
918 	struct osd_bitmap *mask,
919 	UINT32 col, UINT32 row,
920 	UINT32 tile_width, UINT32 tile_height,
921 	const UINT8 *pendata,
922 	int transparent_pen,
923 	UINT32 flags )
924 {
925 	int is_opaque = 1, is_transparent = 1;
926 
927 	int x,bit,sx = tile_width*col;
928 	int sy,y1,y2,dy;
929 
930 	if( flags&TILE_FLIPY ){
931 		y1 = tile_height*row+tile_height-1;
932 		y2 = y1-tile_height;
933  		dy = -1;
934  	}
935  	else {
936 		y1 = tile_height*row;
937 		y2 = y1+tile_height;
938  		dy = 1;
939  	}
940 
941 	if( flags&TILE_FLIPX ){
942 		tile_width--;
943 		for( sy=y1; sy!=y2; sy+=dy ){
944 			UINT8 *mask_dest  = mask->line[sy]+(sx>>3);
945 			for( x=(tile_width>>3); x>=0; x-- ){
946 				UINT32 data = 0;
947 				for( bit=0; bit<8; bit++ ){
948 					UINT32 pen = *pendata++;
949 					data = data>>1;
950 					if( pen!=transparent_pen ) data |=0x80;
951 				}
952 				if( data!=0x00 ) is_transparent = 0;
953 				if( data!=0xff ) is_opaque = 0;
954 				mask_dest[x] = data;
955 			}
956 		}
957 	}
958 	else {
959 		for( sy=y1; sy!=y2; sy+=dy ){
960 			UINT8 *mask_dest  = mask->line[sy]+(sx>>3);
961 			for( x=0; x<(tile_width>>3); x++ ){
962 				UINT32 data = 0;
963 				for( bit=0; bit<8; bit++ ){
964 					UINT32 pen = *pendata++;
965 					data = data<<1;
966 					if( pen!=transparent_pen ) data |=0x01;
967 				}
968 				if( data!=0x00 ) is_transparent = 0;
969 				if( data!=0xff ) is_opaque = 0;
970 				mask_dest[x] = data;
971 			}
972 		}
973 	}
974 	if( is_transparent ) return TILE_TRANSPARENT;
975 	if( is_opaque ) return TILE_OPAQUE;
976 	return TILE_MASKED;
977 }
978 
draw_mask(struct osd_bitmap * mask,UINT32 col,UINT32 row,UINT32 tile_width,UINT32 tile_height,const UINT8 * pendata,UINT32 transmask,UINT32 flags)979 static void draw_mask(
980 	struct osd_bitmap *mask,
981 	UINT32 col, UINT32 row,
982 	UINT32 tile_width, UINT32 tile_height,
983 	const UINT8 *pendata,
984 	UINT32 transmask,
985 	UINT32 flags )
986 {
987 	int x,bit,sx = tile_width*col;
988 	int sy,y1,y2,dy;
989 
990 	if( flags&TILE_FLIPY ){
991 		y1 = tile_height*row+tile_height-1;
992 		y2 = y1-tile_height;
993  		dy = -1;
994  	}
995  	else {
996 		y1 = tile_height*row;
997 		y2 = y1+tile_height;
998  		dy = 1;
999  	}
1000 
1001 	if( flags&TILE_FLIPX ){
1002 		tile_width--;
1003 		for( sy=y1; sy!=y2; sy+=dy ){
1004 			UINT8 *mask_dest  = mask->line[sy]+(sx>>3);
1005 			for( x=(tile_width>>3); x>=0; x-- ){
1006 				UINT32 data = 0;
1007 				for( bit=0; bit<8; bit++ ){
1008 					UINT32 pen = *pendata++;
1009 					data = data>>1;
1010 					if( !((1<<pen)&transmask) ) data |= 0x80;
1011 				}
1012 				mask_dest[x] = data;
1013 			}
1014 		}
1015 	}
1016 	else {
1017 		for( sy=y1; sy!=y2; sy+=dy ){
1018 			UINT8 *mask_dest  = mask->line[sy]+(sx>>3);
1019 			for( x=0; x<(tile_width>>3); x++ ){
1020 				UINT32 data = 0;
1021 				for( bit=0; bit<8; bit++ ){
1022 					UINT32 pen = *pendata++;
1023 					data = (data<<1);
1024 					if( !((1<<pen)&transmask) ) data |= 0x01;
1025 				}
1026 				mask_dest[x] = data;
1027 			}
1028 		}
1029 	}
1030 }
1031 
render_mask(struct tilemap * tilemap,UINT32 cached_index)1032 static void render_mask( struct tilemap *tilemap, UINT32 cached_index ){
1033 	const struct cached_tile_info *cached_tile_info = &tilemap->cached_tile_info[cached_index];
1034 	UINT32 col = cached_index%tilemap->num_cached_cols;
1035 	UINT32 row = cached_index/tilemap->num_cached_cols;
1036 	UINT32 type = tilemap->type;
1037 
1038 	UINT32 transparent_pen = tilemap->transparent_pen;
1039 	UINT32 *transmask = tilemap->transmask;
1040 	UINT32 tile_width = tilemap->cached_tile_width;
1041 	UINT32 tile_height = tilemap->cached_tile_height;
1042 
1043 	UINT32 pen_usage = cached_tile_info->pen_usage;
1044 	const UINT8 *pen_data = cached_tile_info->pen_data;
1045 	UINT32 flags = cached_tile_info->flags;
1046 
1047 	if( type & TILEMAP_BITMASK ){
1048 		tilemap->foreground->data_row[row][col] =
1049 			draw_bitmask( tilemap->foreground->bitmask,col, row,
1050 				tile_width, tile_height,tile_info.mask_data, flags );
1051 	}
1052 	else if( type & TILEMAP_SPLIT ){
1053 		UINT32 pen_mask = (transparent_pen<0)?0:(1<<transparent_pen);
1054 		if( flags&TILE_IGNORE_TRANSPARENCY ){
1055 			tilemap->foreground->data_row[row][col] = TILE_OPAQUE;
1056 			tilemap->background->data_row[row][col] = TILE_OPAQUE;
1057 		}
1058 		else if( pen_mask == pen_usage ){ /* totally transparent */
1059 			tilemap->foreground->data_row[row][col] = TILE_TRANSPARENT;
1060 			tilemap->background->data_row[row][col] = TILE_TRANSPARENT;
1061 		}
1062 		else {
1063 			UINT32 fg_transmask = transmask[(flags>>2)&3];
1064 			UINT32 bg_transmask = (~fg_transmask)|pen_mask;
1065 			if( (pen_usage & fg_transmask)==0 ){ /* foreground totally opaque */
1066 				tilemap->foreground->data_row[row][col] = TILE_OPAQUE;
1067 				tilemap->background->data_row[row][col] = TILE_TRANSPARENT;
1068 			}
1069 			else if( (pen_usage & bg_transmask)==0 ){ /* background totally opaque */
1070 				tilemap->foreground->data_row[row][col] = TILE_TRANSPARENT;
1071 				tilemap->background->data_row[row][col] = TILE_OPAQUE;
1072 			}
1073 			else if( (pen_usage & ~bg_transmask)==0 ){ /* background transparent */
1074 				draw_mask( tilemap->foreground->bitmask,
1075 					col, row, tile_width, tile_height,
1076 					pen_data, fg_transmask, flags );
1077 				tilemap->foreground->data_row[row][col] = TILE_MASKED;
1078 				tilemap->background->data_row[row][col] = TILE_TRANSPARENT;
1079 			}
1080 			else if( (pen_usage & ~fg_transmask)==0 ){ /* foreground transparent */
1081 				draw_mask( tilemap->background->bitmask,
1082 					col, row, tile_width, tile_height,
1083 					pen_data, bg_transmask, flags );
1084 				tilemap->foreground->data_row[row][col] = TILE_TRANSPARENT;
1085 				tilemap->background->data_row[row][col] = TILE_MASKED;
1086 			}
1087 			else { /* split tile - opacity in both foreground and background */
1088 				draw_mask( tilemap->foreground->bitmask,
1089 					col, row, tile_width, tile_height,
1090 					pen_data, fg_transmask, flags );
1091 				draw_mask( tilemap->background->bitmask,
1092 					col, row, tile_width, tile_height,
1093 					pen_data, bg_transmask, flags );
1094 				tilemap->foreground->data_row[row][col] = TILE_MASKED;
1095 				tilemap->background->data_row[row][col] = TILE_MASKED;
1096 			}
1097 		}
1098 	}
1099 	else if( type==TILEMAP_TRANSPARENT ){
1100 		if( pen_usage ){
1101 			UINT32 fg_transmask = 1 << transparent_pen;
1102 		 	if( flags&TILE_IGNORE_TRANSPARENCY ) fg_transmask = 0;
1103 			if( pen_usage == fg_transmask ){
1104 				tilemap->foreground->data_row[row][col] = TILE_TRANSPARENT;
1105 			}
1106 			else if( pen_usage & fg_transmask ){
1107 				draw_mask( tilemap->foreground->bitmask,
1108 					col, row, tile_width, tile_height,
1109 					pen_data, fg_transmask, flags );
1110 				tilemap->foreground->data_row[row][col] = TILE_MASKED;
1111 			}
1112 			else {
1113 				tilemap->foreground->data_row[row][col] = TILE_OPAQUE;
1114 			}
1115 		}
1116 		else {
1117 			tilemap->foreground->data_row[row][col] =
1118 				draw_pen_mask(
1119 					tilemap->foreground->bitmask,
1120 					col, row, tile_width, tile_height,
1121 					pen_data,
1122 					transparent_pen,
1123 					flags
1124 				);
1125 		}
1126 	}
1127 	else if( type==TILEMAP_TRANSPARENT_COLOR ){
1128 		tilemap->foreground->data_row[row][col] =
1129 			draw_color_mask(
1130 				tilemap->foreground->bitmask,
1131 				col, row, tile_width, tile_height,
1132 				pen_data,
1133 				Machine->game_colortable +
1134 					(cached_tile_info->pal_data - Machine->remapped_colortable),
1135 				transparent_pen,
1136 				flags
1137 			);
1138 	}
1139 	else {
1140 		tilemap->foreground->data_row[row][col] = TILE_OPAQUE;
1141 	}
1142 }
1143 
update_tile_info(struct tilemap * tilemap)1144 static void update_tile_info( struct tilemap *tilemap ){
1145 	int *logical_flip_to_cached_flip = tilemap->logical_flip_to_cached_flip;
1146 	UINT32 num_pens = tilemap->cached_tile_width*tilemap->cached_tile_height;
1147 	UINT32 num_tiles = tilemap->num_tiles;
1148 	UINT32 cached_index;
1149 	UINT8 *visible = tilemap->visible;
1150 	UINT8 *dirty_vram = tilemap->dirty_vram;
1151 	UINT8 *dirty_pixels = tilemap->dirty_pixels;
1152 	tile_info.flags = 0;
1153 	tile_info.priority = 0;
1154 	for( cached_index=0; cached_index<num_tiles; cached_index++ ){
1155 		if( visible[cached_index] && dirty_vram[cached_index] ){
1156 			struct cached_tile_info *cached_tile_info = &tilemap->cached_tile_info[cached_index];
1157 			UINT32 memory_offset = tilemap->cached_index_to_memory_offset[cached_index];
1158 			unregister_pens( cached_tile_info, num_pens );
1159 			tilemap->tile_get_info( memory_offset );
1160 			{
1161 				UINT32 flags = tile_info.flags;
1162 				cached_tile_info->flags = (flags&0xfc)|logical_flip_to_cached_flip[flags&0x3];
1163 			}
1164 			cached_tile_info->pen_usage = tile_info.pen_usage;
1165 			cached_tile_info->pen_data = tile_info.pen_data;
1166 			cached_tile_info->pal_data = tile_info.pal_data;
1167 			tilemap->priority[cached_index] = tile_info.priority;
1168 			register_pens( cached_tile_info, num_pens );
1169 			dirty_pixels[cached_index] = 1;
1170 			dirty_vram[cached_index] = 0;
1171 			render_mask( tilemap, cached_index );
1172 		}
1173 	}
1174 }
1175 
update_visible(struct tilemap * tilemap)1176 static void update_visible( struct tilemap *tilemap ){
1177 	// temporary hack
1178 	memset( tilemap->visible, 1, tilemap->num_tiles );
1179 
1180 #if 0
1181 	int yscroll = scrolly[0];
1182 	int row0, y0;
1183 
1184 	int xscroll = scrollx[0];
1185 	int col0, x0;
1186 
1187 	if( yscroll>=0 ){
1188 		row0 = yscroll/tile_height;
1189 		y0 = -(yscroll%tile_height);
1190 	}
1191 	else {
1192 		yscroll = tile_height-1-yscroll;
1193 		row0 = num_rows - yscroll/tile_height;
1194 		y0 = (yscroll+1)%tile_height;
1195 		if( y0 ) y0 = y0-tile_height;
1196 	}
1197 
1198 	if( xscroll>=0 ){
1199 		col0 = xscroll/tile_width;
1200 		x0 = -(xscroll%tile_width);
1201 	}
1202 	else {
1203 		xscroll = tile_width-1-xscroll;
1204 		col0 = num_cols - xscroll/tile_width;
1205 		x0 = (xscroll+1)%tile_width;
1206 		if( x0 ) x0 = x0-tile_width;
1207 	}
1208 
1209 	{
1210 		int ypos = y0;
1211 		int row = row0;
1212 		while( ypos<screen_height ){
1213 			int xpos = x0;
1214 			int col = col0;
1215 			while( xpos<screen_width ){
1216 				process_visible_tile( col, row );
1217 				col++;
1218 				if( col>=num_cols ) col = 0;
1219 				xpos += tile_width;
1220 			}
1221 			row++;
1222 			if( row>=num_rows ) row = 0;
1223 			ypos += tile_height;
1224 		}
1225 	}
1226 #endif
1227 }
1228 
tilemap_update(struct tilemap * tilemap)1229 void tilemap_update( struct tilemap *tilemap ){
1230 profiler_mark(PROFILER_TILEMAP_UPDATE);
1231 	if( tilemap==ALL_TILEMAPS ){
1232 		tilemap = first_tilemap;
1233 		while( tilemap ){
1234 			tilemap_update( tilemap );
1235 			tilemap = tilemap->next;
1236 		}
1237 	}
1238 	else if( tilemap->enable ){
1239 		update_visible( tilemap );
1240 		update_tile_info( tilemap );
1241 	}
1242 profiler_mark(PROFILER_END);
1243 }
1244 
1245 /***********************************************************************************/
1246 
tilemap_set_scrolldx(struct tilemap * tilemap,int dx,int dx_if_flipped)1247 void tilemap_set_scrolldx( struct tilemap *tilemap, int dx, int dx_if_flipped ){
1248 	tilemap->dx = dx;
1249 	tilemap->dx_if_flipped = dx_if_flipped;
1250 	tilemap->scrollx_delta = ( tilemap->attributes & TILEMAP_FLIPX )?dx_if_flipped:dx;
1251 }
1252 
tilemap_set_scrolldy(struct tilemap * tilemap,int dy,int dy_if_flipped)1253 void tilemap_set_scrolldy( struct tilemap *tilemap, int dy, int dy_if_flipped ){
1254 	tilemap->dy = dy;
1255 	tilemap->dy_if_flipped = dy_if_flipped;
1256 	tilemap->scrolly_delta = ( tilemap->attributes & TILEMAP_FLIPY )?dy_if_flipped:dy;
1257 }
1258 
tilemap_set_scrollx(struct tilemap * tilemap,int which,int value)1259 void tilemap_set_scrollx( struct tilemap *tilemap, int which, int value ){
1260 	value = tilemap->scrollx_delta-value;
1261 
1262 	if( tilemap->orientation & ORIENTATION_SWAP_XY ){
1263 		if( tilemap->orientation & ORIENTATION_FLIP_X ) which = tilemap->scroll_cols-1 - which;
1264 		if( tilemap->orientation & ORIENTATION_FLIP_Y ) value = screen_height-tilemap->cached_height-value;
1265 		if( tilemap->colscroll[which]!=value ){
1266 			tilemap->colscroll[which] = value;
1267 		}
1268 	}
1269 	else {
1270 		if( tilemap->orientation & ORIENTATION_FLIP_Y ) which = tilemap->scroll_rows-1 - which;
1271 		if( tilemap->orientation & ORIENTATION_FLIP_X ) value = screen_width-tilemap->cached_width-value;
1272 		if( tilemap->rowscroll[which]!=value ){
1273 			tilemap->rowscroll[which] = value;
1274 		}
1275 	}
1276 }
tilemap_set_scrolly(struct tilemap * tilemap,int which,int value)1277 void tilemap_set_scrolly( struct tilemap *tilemap, int which, int value ){
1278 	value = tilemap->scrolly_delta - value;
1279 
1280 	if( tilemap->orientation & ORIENTATION_SWAP_XY ){
1281 		if( tilemap->orientation & ORIENTATION_FLIP_Y ) which = tilemap->scroll_rows-1 - which;
1282 		if( tilemap->orientation & ORIENTATION_FLIP_X ) value = screen_width-tilemap->cached_width-value;
1283 		if( tilemap->rowscroll[which]!=value ){
1284 			tilemap->rowscroll[which] = value;
1285 		}
1286 	}
1287 	else {
1288 		if( tilemap->orientation & ORIENTATION_FLIP_X ) which = tilemap->scroll_cols-1 - which;
1289 		if( tilemap->orientation & ORIENTATION_FLIP_Y ) value = screen_height-tilemap->cached_height-value;
1290 		if( tilemap->colscroll[which]!=value ){
1291 			tilemap->colscroll[which] = value;
1292 		}
1293 	}
1294 }
1295 /***********************************************************************************/
1296 
tilemap_draw(struct osd_bitmap * dest,struct tilemap * tilemap,UINT32 priority)1297 void tilemap_draw( struct osd_bitmap *dest, struct tilemap *tilemap, UINT32 priority ){
1298 	int xpos,ypos;
1299 
1300 profiler_mark(PROFILER_TILEMAP_DRAW);
1301 	if( tilemap->enable ){
1302 		void (*draw)( int, int );
1303 
1304 		int rows = tilemap->scroll_rows;
1305 		const int *rowscroll = tilemap->rowscroll;
1306 		int cols = tilemap->scroll_cols;
1307 		const int *colscroll = tilemap->colscroll;
1308 
1309 		int left = tilemap->clip_left;
1310 		int right = tilemap->clip_right;
1311 		int top = tilemap->clip_top;
1312 		int bottom = tilemap->clip_bottom;
1313 
1314 		int tile_height = tilemap->cached_tile_height;
1315 
1316 		blit.screen = dest;
1317 		blit.dest_line_offset = dest->line[1] - dest->line[0];
1318 
1319 		blit.pixmap = tilemap->pixmap;
1320 		blit.source_line_offset = tilemap->pixmap_line_offset;
1321 
1322 		if( tilemap->type==TILEMAP_OPAQUE || (priority&TILEMAP_IGNORE_TRANSPARENCY) ){
1323 			draw = tilemap->draw_opaque;
1324 		}
1325 		else {
1326 			draw = tilemap->draw;
1327 			if( priority&TILEMAP_BACK ){
1328 				blit.bitmask = tilemap->background->bitmask;
1329 				blit.mask_line_offset = tilemap->background->line_offset;
1330 				blit.mask_data_row = tilemap->background->data_row;
1331 			}
1332 			else {
1333 				blit.bitmask = tilemap->foreground->bitmask;
1334 				blit.mask_line_offset = tilemap->foreground->line_offset;
1335 				blit.mask_data_row = tilemap->foreground->data_row;
1336 			}
1337 
1338 			blit.mask_row_offset = tile_height*blit.mask_line_offset;
1339 		}
1340 
1341 		if( dest->depth==16 ){
1342 			blit.dest_line_offset >>= 1;
1343 			blit.source_line_offset >>= 1;
1344 		}
1345 
1346 		blit.source_row_offset = tile_height*blit.source_line_offset;
1347 		blit.dest_row_offset = tile_height*blit.dest_line_offset;
1348 
1349 		blit.priority_data_row = tilemap->priority_row;
1350 		blit.source_width = tilemap->cached_width;
1351 		blit.source_height = tilemap->cached_height;
1352 		blit.tile_priority = priority&0xf;
1353 		blit.tilemap_priority_code = priority>>16;
1354 
1355 		if( rows == 1 && cols == 1 ){ /* XY scrolling playfield */
1356 			int scrollx = rowscroll[0];
1357 			int scrolly = colscroll[0];
1358 
1359 			if( scrollx < 0 ){
1360 				scrollx = blit.source_width - (-scrollx) % blit.source_width;
1361 			}
1362 			else {
1363 				scrollx = scrollx % blit.source_width;
1364 			}
1365 
1366 			if( scrolly < 0 ){
1367 				scrolly = blit.source_height - (-scrolly) % blit.source_height;
1368 			}
1369 			else {
1370 				scrolly = scrolly % blit.source_height;
1371 			}
1372 
1373 	 		blit.clip_left = left;
1374 	 		blit.clip_top = top;
1375 	 		blit.clip_right = right;
1376 	 		blit.clip_bottom = bottom;
1377 
1378 			for(
1379 				ypos = scrolly - blit.source_height;
1380 				ypos < blit.clip_bottom;
1381 				ypos += blit.source_height
1382 			){
1383 				for(
1384 					xpos = scrollx - blit.source_width;
1385 					xpos < blit.clip_right;
1386 					xpos += blit.source_width
1387 				){
1388 					draw( xpos,ypos );
1389 				}
1390 			}
1391 		}
1392 		else if( rows == 1 ){ /* scrolling columns + horizontal scroll */
1393 			int col = 0;
1394 			int colwidth = blit.source_width / cols;
1395 			int scrollx = rowscroll[0];
1396 
1397 			if( scrollx < 0 ){
1398 				scrollx = blit.source_width - (-scrollx) % blit.source_width;
1399 			}
1400 			else {
1401 				scrollx = scrollx % blit.source_width;
1402 			}
1403 
1404 			blit.clip_top = top;
1405 			blit.clip_bottom = bottom;
1406 
1407 			while( col < cols ){
1408 				int cons = 1;
1409 				int scrolly = colscroll[col];
1410 
1411 	 			/* count consecutive columns scrolled by the same amount */
1412 				if( scrolly != TILE_LINE_DISABLED ){
1413 					while( col + cons < cols &&	colscroll[col + cons] == scrolly ) cons++;
1414 
1415 					if( scrolly < 0 ){
1416 						scrolly = blit.source_height - (-scrolly) % blit.source_height;
1417 					}
1418 					else {
1419 						scrolly %= blit.source_height;
1420 					}
1421 
1422 					blit.clip_left = col * colwidth + scrollx;
1423 					if (blit.clip_left < left) blit.clip_left = left;
1424 					blit.clip_right = (col + cons) * colwidth + scrollx;
1425 					if (blit.clip_right > right) blit.clip_right = right;
1426 
1427 					for(
1428 						ypos = scrolly - blit.source_height;
1429 						ypos < blit.clip_bottom;
1430 						ypos += blit.source_height
1431 					){
1432 						draw( scrollx,ypos );
1433 					}
1434 
1435 					blit.clip_left = col * colwidth + scrollx - blit.source_width;
1436 					if (blit.clip_left < left) blit.clip_left = left;
1437 					blit.clip_right = (col + cons) * colwidth + scrollx - blit.source_width;
1438 					if (blit.clip_right > right) blit.clip_right = right;
1439 
1440 					for(
1441 						ypos = scrolly - blit.source_height;
1442 						ypos < blit.clip_bottom;
1443 						ypos += blit.source_height
1444 					){
1445 						draw( scrollx - blit.source_width,ypos );
1446 					}
1447 				}
1448 				col += cons;
1449 			}
1450 		}
1451 		else if( cols == 1 ){ /* scrolling rows + vertical scroll */
1452 			int row = 0;
1453 			int rowheight = blit.source_height / rows;
1454 			int scrolly = colscroll[0];
1455 			if( scrolly < 0 ){
1456 				scrolly = blit.source_height - (-scrolly) % blit.source_height;
1457 			}
1458 			else {
1459 				scrolly = scrolly % blit.source_height;
1460 			}
1461 			blit.clip_left = left;
1462 			blit.clip_right = right;
1463 			while( row < rows ){
1464 				int cons = 1;
1465 				int scrollx = rowscroll[row];
1466 				/* count consecutive rows scrolled by the same amount */
1467 				if( scrollx != TILE_LINE_DISABLED ){
1468 					while( row + cons < rows &&	rowscroll[row + cons] == scrollx ) cons++;
1469 					if( scrollx < 0){
1470 						scrollx = blit.source_width - (-scrollx) % blit.source_width;
1471 					}
1472 					else {
1473 						scrollx %= blit.source_width;
1474 					}
1475 					blit.clip_top = row * rowheight + scrolly;
1476 					if (blit.clip_top < top) blit.clip_top = top;
1477 					blit.clip_bottom = (row + cons) * rowheight + scrolly;
1478 					if (blit.clip_bottom > bottom) blit.clip_bottom = bottom;
1479 					for(
1480 						xpos = scrollx - blit.source_width;
1481 						xpos < blit.clip_right;
1482 						xpos += blit.source_width
1483 					){
1484 						draw( xpos,scrolly );
1485 					}
1486 					blit.clip_top = row * rowheight + scrolly - blit.source_height;
1487 					if (blit.clip_top < top) blit.clip_top = top;
1488 					blit.clip_bottom = (row + cons) * rowheight + scrolly - blit.source_height;
1489 					if (blit.clip_bottom > bottom) blit.clip_bottom = bottom;
1490 					for(
1491 						xpos = scrollx - blit.source_width;
1492 						xpos < blit.clip_right;
1493 						xpos += blit.source_width
1494 					){
1495 						draw( xpos,scrolly - blit.source_height );
1496 					}
1497 				}
1498 				row += cons;
1499 			}
1500 		}
1501 	}
1502 profiler_mark(PROFILER_END);
1503 }
1504