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