diff options
author | 2007-12-17 15:19:59 +0000 | |
---|---|---|
committer | 2007-12-17 15:19:59 +0000 | |
commit | 7b77f1218624ea26dbb2efd85a19f795f5d4e02e (patch) | |
tree | 19209304095572b4fd61c2a2d6a5aa75c4e471ad /src/emu/tilemap.c | |
parent | 3da7f476068b3ffef713218ba2fc1bd5030f2c38 (diff) |
Initial checkin of MAME 0.121.mame0121
Diffstat (limited to 'src/emu/tilemap.c')
-rw-r--r-- | src/emu/tilemap.c | 2402 |
1 files changed, 2402 insertions, 0 deletions
diff --git a/src/emu/tilemap.c b/src/emu/tilemap.c new file mode 100644 index 00000000000..d2d0f9cbe83 --- /dev/null +++ b/src/emu/tilemap.c @@ -0,0 +1,2402 @@ +/*************************************************************************** + + tilemap.c + + Generic tilemap management system. + + Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include "driver.h" +#include "tilemap.h" +#include "profiler.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* internal usage to mark tiles dirty */ +#define TILE_FLAG_DIRTY 0xff + +/* invalid logical index */ +#define INVALID_LOGICAL_INDEX ((tilemap_logical_index)~0) + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* logical index */ +typedef UINT32 tilemap_logical_index; + + +/* internal set of transparency states for rendering */ +typedef enum +{ + WHOLLY_TRANSPARENT, + WHOLLY_OPAQUE, + MASKED +} trans_t; + + +/* internal blitting callbacks */ +typedef void (*blitmask_t)(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode); +typedef void (*blitopaque_t)(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode); + + +/* blitting parameters for rendering */ +typedef struct _blit_parameters blit_parameters; +struct _blit_parameters +{ + mame_bitmap * bitmap; + rectangle cliprect; + blitmask_t draw_masked; + blitopaque_t draw_opaque; + UINT32 tilemap_priority_code; + UINT8 mask; + UINT8 value; +}; + + +/* core tilemap structure */ +struct _tilemap +{ + tilemap * next; /* pointer to next tilemap */ + + /* basic tilemap metrics */ + tilemap_type type; /* type of tilemap */ + UINT32 rows; /* number of tile rows */ + UINT32 cols; /* number of tile columns */ + UINT32 tilewidth; /* width of a single tile in pixels */ + UINT32 tileheight; /* height of a single tile in pixels */ + UINT32 width; /* width of the full tilemap in pixels */ + UINT32 height; /* height of the full tilemap in pixels */ + + /* logical <-> memory mappings */ + tilemap_mapper_callback mapper; /* callback to map a row/column to a memory index */ + tilemap_logical_index * memory_to_logical; /* map from memory index to logical index */ + tilemap_logical_index max_logical_index; /* maximum valid logical index */ + tilemap_memory_index * logical_to_memory; /* map from logical index to memory index */ + tilemap_memory_index max_memory_index; /* maximum valid memory index */ + + /* callback to interpret video RAM for the tilemap */ + tile_get_info_callback tile_get_info; /* callback to get information about a tile */ + tile_data tileinfo; /* structure to hold the data for a tile */ + void * user_data; /* user data value passed to the callback */ + + /* global tilemap states */ + UINT8 enable; /* true if we are enabled */ + UINT8 attributes; /* global attributes (flipx/y) */ + UINT8 all_tiles_dirty; /* true if all tiles are dirty */ + UINT8 all_tiles_clean; /* true if all tiles are clean */ + UINT32 palette_offset; /* palette offset */ + + /* scroll information */ + UINT32 scrollrows; /* number of independently scrolled rows */ + UINT32 scrollcols; /* number of independently scrolled colums */ + INT32 * rowscroll; /* array of rowscroll values */ + INT32 * colscroll; /* array of colscroll values */ + INT32 dx; /* global horizontal scroll offset */ + INT32 dx_flipped; /* global horizontal scroll offset when flipped */ + INT32 dy; /* global vertical scroll offset */ + INT32 dy_flipped; /* global vertical scroll offset when flipped */ + + /* pixel data */ + mame_bitmap * pixmap; /* cached pixel data */ + + /* transparency mapping */ + mame_bitmap * flagsmap; /* per-pixel flags */ + UINT8 * tileflags; /* per-tile flags */ + UINT8 * pen_to_flags; /* mapping of pens to flags */ + UINT32 max_pen_to_flags; /* maximum index in each array */ +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +mame_bitmap * priority_bitmap; + +static tilemap * tilemap_list; +static tilemap ** tilemap_tailptr; +static int tilemap_instance; + +static UINT32 screen_width, screen_height; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +/* system management helpers */ +static void tilemap_exit(running_machine *machine); +static void tilemap_postload(void *param); +static void tilemap_dispose(tilemap *tmap); + +/* logical <-> memory index mapping */ +static void mappings_create(tilemap *tmap); +static void mappings_update(tilemap *tmap); + +/* tile rendering */ +static void pixmap_update(tilemap *tmap, const rectangle *cliprect); +static void tile_update(tilemap *tmap, tilemap_logical_index logindex, UINT32 cached_col, UINT32 cached_row); +static UINT8 tile_draw(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags); +static UINT8 tile_draw_colortable(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags); +static UINT8 tile_draw_colortrans(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags); +static UINT8 tile_apply_bitmask(tilemap *tmap, const UINT8 *maskdata, UINT32 x0, UINT32 y0, UINT8 category, UINT8 flags); + +/* drawing helpers */ +static void configure_blit_parameters(blit_parameters *blit, tilemap *tmap, mame_bitmap *dest, const rectangle *cliprect, UINT32 flags, UINT8 priority, UINT8 priority_mask); +static void tilemap_draw_instance(tilemap *tmap, const blit_parameters *blit, int xpos, int ypos); +static void tilemap_draw_roz_core(tilemap *tmap, const blit_parameters *blit, + UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, int wraparound); + +/* scanline rasterizers for drawing to the pixmap */ +static void scanline_draw_opaque_null(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_masked_null(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_opaque_ind16(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_masked_ind16(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_opaque_rgb16(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_masked_rgb16(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_opaque_rgb16_alpha(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_masked_rgb16_alpha(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_opaque_rgb32(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_masked_rgb32(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_opaque_rgb32_alpha(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode); +static void scanline_draw_masked_rgb32_alpha(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode); + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + effective_rowscroll - return the effective + rowscroll value for a given index, taking into + account tilemap flip states +-------------------------------------------------*/ + +INLINE INT32 effective_rowscroll(tilemap *tmap, int index) +{ + INT32 value; + + /* if we're flipping vertically, adjust the row number */ + if (tmap->attributes & TILEMAP_FLIPY) + index = tmap->scrollrows - 1 - index; + + /* adjust final result based on the horizontal flip and dx values */ + if (!(tmap->attributes & TILEMAP_FLIPX)) + value = tmap->dx - tmap->rowscroll[index]; + else + value = screen_width - tmap->width - (tmap->dx_flipped - tmap->rowscroll[index]); + + /* clamp to 0..width */ + if (value < 0) + value = tmap->width - (-value) % tmap->width; + else + value %= tmap->width; + return value; +} + + +/*------------------------------------------------- + effective_colscroll - return the effective + colscroll value for a given index, taking into + account tilemap flip states +-------------------------------------------------*/ + +INLINE INT32 effective_colscroll(tilemap *tmap, int index) +{ + INT32 value; + + /* if we're flipping horizontally, adjust the column number */ + if (tmap->attributes & TILEMAP_FLIPX) + index = tmap->scrollcols - 1 - index; + + /* adjust final result based on the vertical flip and dx values */ + if (!(tmap->attributes & TILEMAP_FLIPY)) + value = tmap->dy - tmap->colscroll[index]; + else + value = screen_height - tmap->height - (tmap->dy_flipped - tmap->colscroll[index]); + + /* clamp to 0..height */ + if (value < 0) + value = tmap->height - (-value) % tmap->height; + else + value %= tmap->height; + return value; +} + + +/*------------------------------------------------- + indexed_tilemap - return a tilemap by index +-------------------------------------------------*/ + +INLINE tilemap *indexed_tilemap(int index) +{ + tilemap *tmap; + + /* find by the tilemap index */ + for (tmap = tilemap_list; tmap != NULL; tmap = tmap->next) + if (index-- == 0) + return tmap; + + return NULL; +} + + + +/*************************************************************************** + SYSTEM-WIDE MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + tilemap_init - initialize the tilemap system +-------------------------------------------------*/ + +void tilemap_init(running_machine *machine) +{ + screen_width = Machine->screen[0].width; + screen_height = Machine->screen[0].height; + + tilemap_list = NULL; + tilemap_tailptr = &tilemap_list; + tilemap_instance = 0; + + priority_bitmap = auto_bitmap_alloc(screen_width, screen_height, BITMAP_FORMAT_INDEXED8); + add_exit_callback(machine, tilemap_exit); +} + + + +/*************************************************************************** + TILEMAP CREATION AND CONFIGURATION +***************************************************************************/ + +/*------------------------------------------------- + tilemap_create - allocate a new tilemap +-------------------------------------------------*/ + +tilemap *tilemap_create(tile_get_info_callback tile_get_info, tilemap_mapper_callback mapper, tilemap_type type, int tilewidth, int tileheight, int cols, int rows) +{ + tilemap *tmap; + int group; + + /* allocate the tilemap itself */ + tmap = malloc_or_die(sizeof(tilemap)); + memset(tmap, 0, sizeof(tilemap)); + + /* fill in the basic metrics */ + tmap->type = type; + tmap->rows = rows; + tmap->cols = cols; + tmap->tilewidth = tilewidth; + tmap->tileheight = tileheight; + tmap->width = cols * tilewidth; + tmap->height = rows * tileheight; + + /* set up the logical <-> memory mappings */ + tmap->mapper = mapper; + mappings_create(tmap); + + /* set up the tile map callbacks */ + tmap->tile_get_info = tile_get_info; + + /* initialize global states */ + tmap->enable = TRUE; + tmap->all_tiles_dirty = TRUE; + + /* initialize scroll information */ + tmap->scrollrows = 1; + tmap->scrollcols = 1; + tmap->rowscroll = malloc_or_die(tmap->height * sizeof(*tmap->rowscroll)); + memset(tmap->rowscroll, 0, tmap->height * sizeof(*tmap->rowscroll)); + tmap->colscroll = malloc_or_die(tmap->width * sizeof(*tmap->colscroll)); + memset(tmap->colscroll, 0, tmap->width * sizeof(*tmap->colscroll)); + + /* allocate the pixel data cache */ + tmap->pixmap = bitmap_alloc(tmap->width, tmap->height, BITMAP_FORMAT_INDEXED16); + + /* allocate transparency mapping data */ + tmap->tileflags = malloc_or_die(tmap->max_logical_index); + tmap->flagsmap = bitmap_alloc(tmap->width, tmap->height, BITMAP_FORMAT_INDEXED8); + tmap->max_pen_to_flags = (tmap->type != TILEMAP_TYPE_COLORTABLE) ? 256 : Machine->drv->color_table_len; + tmap->pen_to_flags = malloc_or_die(sizeof(tmap->pen_to_flags[0]) * tmap->max_pen_to_flags * TILEMAP_NUM_GROUPS); + for (group = 0; group < TILEMAP_NUM_GROUPS; group++) + tilemap_map_pens_to_layer(tmap, group, 0, 0, TILEMAP_PIXEL_LAYER0); + + /* add us to the end of the list of tilemaps */ + *tilemap_tailptr = tmap; + tilemap_tailptr = &tmap->next; + + /* save relevant state */ + state_save_register_item("tilemap", tilemap_instance, tmap->enable); + state_save_register_item("tilemap", tilemap_instance, tmap->attributes); + state_save_register_item("tilemap", tilemap_instance, tmap->palette_offset); + state_save_register_item("tilemap", tilemap_instance, tmap->scrollrows); + state_save_register_item("tilemap", tilemap_instance, tmap->scrollcols); + state_save_register_item_pointer("tilemap", tilemap_instance, tmap->rowscroll, rows * tileheight); + state_save_register_item_pointer("tilemap", tilemap_instance, tmap->colscroll, cols * tilewidth); + state_save_register_item("tilemap", tilemap_instance, tmap->dx); + state_save_register_item("tilemap", tilemap_instance, tmap->dx_flipped); + state_save_register_item("tilemap", tilemap_instance, tmap->dy); + state_save_register_item("tilemap", tilemap_instance, tmap->dy_flipped); + tilemap_instance++; + + /* reset everything after a load */ + state_save_register_func_postload_ptr(tilemap_postload, tmap); + return tmap; +} + + +/*------------------------------------------------- + tilemap_set_user_data - specify a parameter + to be passed into the tile_get_info callback +-------------------------------------------------*/ + +void tilemap_set_user_data(tilemap *tmap, void *user_data) +{ + tmap->user_data = user_data; +} + + +/*------------------------------------------------- + tilemap_set_palette_offset - specify an offset + to be added to each pixel before looking up + the palette +-------------------------------------------------*/ + +void tilemap_set_palette_offset(tilemap *tmap, UINT32 offset) +{ + if (tmap->palette_offset != offset) + { + tmap->palette_offset = offset; + tilemap_mark_all_tiles_dirty(tmap); + } +} + + +/*------------------------------------------------- + tilemap_set_enable - set an enable flag for + the tilemap; if 0, requests to draw the + tilemap are ignored +-------------------------------------------------*/ + +void tilemap_set_enable(tilemap *tmap, int enable) +{ + tmap->enable = (enable != 0); +} + + +/*------------------------------------------------- + tilemap_set_flip - set a global flip for the + tilemap; ALL_TILEMAPS can be passed here as + well +-------------------------------------------------*/ + +void tilemap_set_flip(tilemap *tmap, UINT32 attributes) +{ + /* handle ALL_TILEMAPS */ + if (tmap == ALL_TILEMAPS) + { + for (tmap = tilemap_list; tmap != NULL; tmap = tmap->next) + tilemap_set_flip(tmap, attributes); + } + + /* if we're changing things, force a refresh of the mappings and mark it all dirty */ + else if (tmap->attributes != attributes) + { + tmap->attributes = attributes; + mappings_update(tmap); + } +} + + + +/*************************************************************************** + DIRTY TILE MARKING +***************************************************************************/ + +/*------------------------------------------------- + tilemap_mark_tile_dirty - mark a single tile + dirty based on its memory index +-------------------------------------------------*/ + +void tilemap_mark_tile_dirty(tilemap *tmap, tilemap_memory_index memindex) +{ + /* only mark if within range */ + if (memindex < tmap->max_memory_index) + { + tilemap_logical_index logindex = tmap->memory_to_logical[memindex]; + + /* there may be no logical index for a given memory index */ + if (logindex != INVALID_LOGICAL_INDEX) + { + tmap->tileflags[logindex] = TILE_FLAG_DIRTY; + tmap->all_tiles_clean = FALSE; + } + } +} + + +/*------------------------------------------------- + tilemap_mark_all_tiles_dirty - mark all the + tiles in a tilemap dirty +-------------------------------------------------*/ + +void tilemap_mark_all_tiles_dirty(tilemap *tmap) +{ + /* handle ALL_TILEMAPS */ + if (tmap == ALL_TILEMAPS) + { + for (tmap = tilemap_list; tmap != NULL; tmap = tmap->next) + tilemap_mark_all_tiles_dirty(tmap); + } + + /* mark all tiles dirty and clear the clean flag */ + else + { + tmap->all_tiles_dirty = TRUE; + tmap->all_tiles_clean = FALSE; + } +} + + + +/*************************************************************************** + PEN-TO-LAYER MAPPING +***************************************************************************/ + +/*------------------------------------------------- + tilemap_map_pens_to_layer - specify the + mapping of one or more pens (where + (<pen> & mask) == pen) to a layer +-------------------------------------------------*/ + +void tilemap_map_pens_to_layer(tilemap *tmap, int group, pen_t pen, pen_t mask, UINT8 layermask) +{ + UINT8 *array = tmap->pen_to_flags + group * tmap->max_pen_to_flags; + pen_t start, stop, cur; + UINT8 changed = FALSE; + + assert(group < TILEMAP_NUM_GROUPS); + assert((layermask & TILEMAP_PIXEL_CATEGORY_MASK) == 0); + + /* we start at the index where (pen & mask) == pen, and all other bits are 0 */ + start = pen & mask; + + /* we stop at the index where (pen & mask) == pen, and all other bits are 1 */ + stop = start | ~mask; + + /* clamp to the number of entries actually there */ + stop = MIN(stop, tmap->max_pen_to_flags - 1); + + /* iterate and set */ + for (cur = start; cur <= stop; cur++) + if ((cur & mask) == pen && array[cur] != layermask) + { + changed = TRUE; + array[cur] = layermask; + } + + /* everything gets dirty if anything changed */ + if (changed) + tilemap_mark_all_tiles_dirty(tmap); +} + + +/*------------------------------------------------- + tilemap_set_transparent_pen - set a single + transparent pen into the tilemap, mapping + all other pens to layer 0 +-------------------------------------------------*/ + +void tilemap_set_transparent_pen(tilemap *tmap, pen_t pen) +{ + /* reset the whole pen map to opaque */ + tilemap_map_pens_to_layer(tmap, 0, 0, 0, TILEMAP_PIXEL_LAYER0); + + /* set the single pen to transparent */ + tilemap_map_pen_to_layer(tmap, 0, pen, TILEMAP_PIXEL_TRANSPARENT); +} + + +/*------------------------------------------------- + tilemap_set_transmask - set up the first 32 + pens using a foreground mask (mapping to + layer 0) and a background mask (mapping to + layer 1) +-------------------------------------------------*/ + +void tilemap_set_transmask(tilemap *tmap, int group, UINT32 fgmask, UINT32 bgmask) +{ + pen_t pen; + + /* iterate over all 32 pens specified */ + for (pen = 0; pen < 32; pen++) + { + UINT8 fgbits = ((fgmask >> pen) & 1) ? TILEMAP_PIXEL_TRANSPARENT : TILEMAP_PIXEL_LAYER0; + UINT8 bgbits = ((bgmask >> pen) & 1) ? TILEMAP_PIXEL_TRANSPARENT : TILEMAP_PIXEL_LAYER1; + tilemap_map_pen_to_layer(tmap, group, pen, fgbits | bgbits); + } +} + + + +/*************************************************************************** + TILEMAP SCROLLING +***************************************************************************/ + +/*------------------------------------------------- + tilemap_set_scroll_rows - specify the number of + independently scrollable row units; each unit + covers height/scroll_rows pixels +-------------------------------------------------*/ + +void tilemap_set_scroll_rows(tilemap *tmap, UINT32 scroll_rows) +{ + assert(scroll_rows <= tmap->height); + tmap->scrollrows = scroll_rows; +} + + +/*------------------------------------------------- + tilemap_set_scroll_cols - specify the number of + independently scrollable column units; each + unit covers width/scroll_cols pixels +-------------------------------------------------*/ + +void tilemap_set_scroll_cols(tilemap *tmap, UINT32 scroll_cols) +{ + assert(scroll_cols <= tmap->width); + tmap->scrollcols = scroll_cols; +} + + +/*------------------------------------------------- + tilemap_set_scrolldx - specify global + horizontal scroll offset, for non-flipped and + flipped cases +-------------------------------------------------*/ + +void tilemap_set_scrolldx(tilemap *tmap, int dx, int dx_flipped) +{ + tmap->dx = dx; + tmap->dx_flipped = dx_flipped; +} + + +/*------------------------------------------------- + tilemap_set_scrolldy - specify global + vertical scroll offset, for non-flipped and + flipped cases +-------------------------------------------------*/ + +void tilemap_set_scrolldy(tilemap *tmap, int dy, int dy_flipped) +{ + tmap->dy = dy; + tmap->dy_flipped = dy_flipped; +} + + +/*------------------------------------------------- + tilemap_get_scrolldx - return the global + horizontal scroll offset, based on current + flip state +-------------------------------------------------*/ + +int tilemap_get_scrolldx(tilemap *tmap) +{ + return (tmap->attributes & TILEMAP_FLIPX) ? tmap->dx_flipped : tmap->dx; +} + + +/*------------------------------------------------- + tilemap_get_scrolldy - return the global + vertical scroll offset, based on current + flip state +-------------------------------------------------*/ + +int tilemap_get_scrolldy(tilemap *tmap) +{ + return (tmap->attributes & TILEMAP_FLIPY) ? tmap->dy_flipped : tmap->dy; +} + + +/*------------------------------------------------- + tilemap_set_scrollx - specify the scroll value + for a row unit +-------------------------------------------------*/ + +void tilemap_set_scrollx(tilemap *tmap, int which, int value) +{ + if (which < tmap->scrollrows) + tmap->rowscroll[which] = value; +} + + +/*------------------------------------------------- + tilemap_set_scrolly - specify the scroll value + for a column unit +-------------------------------------------------*/ + +void tilemap_set_scrolly(tilemap *tmap, int which, int value) +{ + if (which < tmap->scrollcols) + tmap->colscroll[which] = value; +} + + + +/*************************************************************************** + INTERNAL MAP ACCESS +***************************************************************************/ + +/*------------------------------------------------- + tilemap_get_pixmap - return a pointer to the + (updated) internal pixmap for a tilemap +-------------------------------------------------*/ + +mame_bitmap *tilemap_get_pixmap(tilemap *tmap) +{ + /* ensure all the tiles are up-to-date and then return the pixmap */ + pixmap_update(tmap, NULL); + return tmap->pixmap; +} + + +/*------------------------------------------------- + tilemap_get_flagsmap - return a pointer to the + (updated) internal flagsmap for a tilemap +-------------------------------------------------*/ + +mame_bitmap *tilemap_get_flagsmap(tilemap *tmap) +{ + /* ensure all the tiles are up-to-date and then return the pixmap */ + pixmap_update(tmap, NULL); + return tmap->flagsmap; +} + + +/*------------------------------------------------- + tilemap_get_pixmap - return a pointer to the + (updated) internal per-tile flags for a tilemap +-------------------------------------------------*/ + +UINT8 *tilemap_get_tile_flags(tilemap *tmap) +{ + /* ensure all the tiles are up-to-date and then return the pixmap */ + pixmap_update(tmap, NULL); + return tmap->tileflags; +} + + + +/*************************************************************************** + TILEMAP RENDERING +***************************************************************************/ + +/*------------------------------------------------- + tilemap_draw_primask - draw a tilemap to the + destination with clipping; pixels apply + priority/priority_mask to the priority bitmap +-------------------------------------------------*/ + +void tilemap_draw_primask(mame_bitmap *dest, const rectangle *cliprect, tilemap *tmap, UINT32 flags, UINT8 priority, UINT8 priority_mask) +{ + rectangle original_cliprect; + blit_parameters blit; + int xpos, ypos; + + /* skip if disabled */ + if (!tmap->enable) + return; + +profiler_mark(PROFILER_TILEMAP_DRAW); + /* configure the blit parameters based on the input parameters */ + configure_blit_parameters(&blit, tmap, dest, cliprect, flags, priority, priority_mask); + original_cliprect = blit.cliprect; + + /* if the whole map is dirty, mark it as such */ + if (tmap->all_tiles_dirty) + { + memset(tmap->tileflags, TILE_FLAG_DIRTY, tmap->max_logical_index); + tmap->all_tiles_dirty = FALSE; + } + + /* XY scrolling playfield */ + if (tmap->scrollrows == 1 && tmap->scrollcols == 1) + { + int scrollx = effective_rowscroll(tmap, 0); + int scrolly = effective_colscroll(tmap, 0); + + /* iterate to handle wraparound */ + for (ypos = scrolly - tmap->height; ypos <= blit.cliprect.max_y; ypos += tmap->height) + for (xpos = scrollx - tmap->width; xpos <= blit.cliprect.max_x; xpos += tmap->width) + tilemap_draw_instance(tmap, &blit, xpos, ypos); + } + + /* scrolling rows + vertical scroll */ + else if (tmap->scrollcols == 1) + { + const rectangle original_cliprect = blit.cliprect; + int rowheight = tmap->height / tmap->scrollrows; + int scrolly = effective_colscroll(tmap, 0); + int currow, nextrow; + + /* iterate over rows in the tilemap */ + for (currow = 0; currow < tmap->scrollrows; currow = nextrow) + { + int scrollx = effective_rowscroll(tmap, currow); + + /* scan forward until we find a non-matching row */ + for (nextrow = currow + 1; nextrow < tmap->scrollrows; nextrow++) + if (effective_rowscroll(tmap, nextrow) != scrollx) + break; + + /* skip if disabled */ + if (scrollx == TILE_LINE_DISABLED) + continue; + + /* iterate over Y to handle wraparound */ + for (ypos = scrolly - tmap->height; ypos <= original_cliprect.max_y; ypos += tmap->height) + { + /* update the cliprect just for this set of rows */ + blit.cliprect.min_y = currow * rowheight + ypos; + blit.cliprect.max_y = nextrow * rowheight - 1 + ypos; + sect_rect(&blit.cliprect, &original_cliprect); + + /* iterate over X to handle wraparound */ + for (xpos = scrollx - tmap->width; xpos <= original_cliprect.max_x; xpos += tmap->width) + tilemap_draw_instance(tmap, &blit, xpos, ypos); + } + } + } + + /* scrolling columns + horizontal scroll */ + else if (tmap->scrollrows == 1) + { + const rectangle original_cliprect = blit.cliprect; + int colwidth = tmap->width / tmap->scrollcols; + int scrollx = effective_rowscroll(tmap, 0); + int curcol, nextcol; + + /* iterate over columns in the tilemap */ + for (curcol = 0; curcol < tmap->scrollcols; curcol = nextcol) + { + int scrolly = effective_colscroll(tmap, curcol); + + /* scan forward until we find a non-matching column */ + for (nextcol = curcol + 1; nextcol < tmap->scrollcols; nextcol++) + if (effective_colscroll(tmap, nextcol) != scrolly) + break; + + /* skip if disabled */ + if (scrolly == TILE_LINE_DISABLED) + continue; + + /* iterate over X to handle wraparound */ + for (xpos = scrollx - tmap->width; xpos <= original_cliprect.max_x; xpos += tmap->width) + { + /* update the cliprect just for this set of columns */ + blit.cliprect.min_x = curcol * colwidth + xpos; + blit.cliprect.max_x = nextcol * colwidth - 1 + xpos; + sect_rect(&blit.cliprect, &original_cliprect); + + /* iterate over Y to handle wraparound */ + for (ypos = scrolly - tmap->height; ypos <= original_cliprect.max_y; ypos += tmap->height) + tilemap_draw_instance(tmap, &blit, xpos, ypos); + } + } + } +profiler_mark(PROFILER_END); +} + + +/*------------------------------------------------- + tilemap_draw_primask - draw a tilemap to the + destination with clipping and arbitrary + rotate/zoom; pixels apply priority/ + priority_mask to the priority bitmap +-------------------------------------------------*/ + +void tilemap_draw_roz_primask(mame_bitmap *dest, const rectangle *cliprect, tilemap *tmap, + UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, + int wraparound, UINT32 flags, UINT8 priority, UINT8 priority_mask) +{ + blit_parameters blit; + +/* notes: + - startx and starty MUST be UINT32 for calculations to work correctly + - srcbitmap->width and height are assumed to be a power of 2 to speed up wraparound + */ + + /* skip if disabled */ + if (!tmap->enable) + return; + + /* see if this is just a regular render and if so, do a regular render */ + if (incxx == (1 << 16) && incxy == 0 && incyx == 0 && incyy == (1 << 16) && wraparound) + { + tilemap_set_scrollx(tmap, 0, startx >> 16); + tilemap_set_scrolly(tmap, 0, starty >> 16); + tilemap_draw(dest, cliprect, tmap, flags, priority); + return; + } + +profiler_mark(PROFILER_TILEMAP_DRAW_ROZ); + /* configure the blit parameters */ + configure_blit_parameters(&blit, tmap, dest, cliprect, flags, priority, priority_mask); + + /* get the full pixmap for the tilemap */ + tilemap_get_pixmap(tmap); + + /* then do the roz copy */ + tilemap_draw_roz_core(tmap, &blit, startx, starty, incxx, incxy, incyx, incyy, wraparound); +profiler_mark(PROFILER_END); +} + + + +/*************************************************************************** + INDEXED TILEMAP HANDLING +***************************************************************************/ + +/*------------------------------------------------- + tilemap_count - return the number of tilemaps +-------------------------------------------------*/ + +int tilemap_count(void) +{ + tilemap *tmap; + int count = 0; + + /* find by the tilemap index */ + for (tmap = tilemap_list; tmap != NULL; tmap = tmap->next) + count++; + return count; +} + + +/*------------------------------------------------- + tilemap_size_by_index - return the size of an + indexed tilemap +-------------------------------------------------*/ + +void tilemap_size_by_index(int number, UINT32 *width, UINT32 *height) +{ + tilemap *tmap = indexed_tilemap(number); + *width = tmap->width; + *height = tmap->height; +} + + +/*------------------------------------------------- + tilemap_draw_by_index - render an indexed + tilemap with fixed characteristics (no + priority) +-------------------------------------------------*/ + +void tilemap_draw_by_index(mame_bitmap *dest, int number, UINT32 scrollx, UINT32 scrolly) +{ + tilemap *tmap = indexed_tilemap(number); + blit_parameters blit; + int xpos,ypos; + + /* set up for the blit, using hard-coded parameters (no priority, etc) */ + configure_blit_parameters(&blit, tmap, dest, NULL, TILEMAP_DRAW_OPAQUE, 0, 0xff); + + /* compute the effective scroll positions */ + scrollx = tmap->width - scrollx % tmap->width; + scrolly = tmap->height - scrolly % tmap->height; + + /* if the whole map is dirty, mark it as such */ + if (tmap->all_tiles_dirty) + { + memset(tmap->tileflags, TILE_FLAG_DIRTY, tmap->max_logical_index); + tmap->all_tiles_dirty = FALSE; + } + + /* iterate to handle wraparound */ + for (ypos = scrolly - tmap->height; ypos <= blit.cliprect.max_y; ypos += tmap->height) + for (xpos = scrollx - tmap->width; xpos <= blit.cliprect.max_x; xpos += tmap->width) + tilemap_draw_instance(tmap, &blit, xpos, ypos); +} + + + +/*************************************************************************** + COMMON LOGICAL-TO-MEMORY MAPPERS +***************************************************************************/ + +/*------------------------------------------------- + tilemap_scan_rows + tilemap_scan_rows_flip_x + tilemap_scan_rows_flip_y + tilemap_scan_rows_flip_xy - scan in row-major + order with optional flipping +-------------------------------------------------*/ + +TILEMAP_MAPPER( tilemap_scan_rows ) +{ + return row * num_cols + col; +} + +TILEMAP_MAPPER( tilemap_scan_rows_flip_x ) +{ + return row * num_cols + (num_cols - 1 - col); +} + +TILEMAP_MAPPER( tilemap_scan_rows_flip_y ) +{ + return (num_rows - 1 - row) * num_cols + col; +} + +TILEMAP_MAPPER( tilemap_scan_rows_flip_xy ) +{ + return (num_rows - 1 - row) * num_cols + (num_cols - 1 - col); +} + + +/*------------------------------------------------- + tilemap_scan_cols + tilemap_scan_cols_flip_x + tilemap_scan_cols_flip_y + tilemap_scan_cols_flip_xy - scan in column- + major order with optional flipping +-------------------------------------------------*/ + +TILEMAP_MAPPER( tilemap_scan_cols ) +{ + return col * num_rows + row; +} + +TILEMAP_MAPPER( tilemap_scan_cols_flip_x ) +{ + return (num_cols - 1 - col) * num_rows + row; +} + +TILEMAP_MAPPER( tilemap_scan_cols_flip_y ) +{ + return col * num_rows + (num_rows - 1 - row); +} + +TILEMAP_MAPPER( tilemap_scan_cols_flip_xy ) +{ + return (num_cols - 1 - col) * num_rows + (num_rows - 1 - row); +} + + + +/*************************************************************************** + SYSTEM MANAGEMENT HELPERS +***************************************************************************/ + +/*------------------------------------------------- + tilemap_exit - free memory allocated by the + tilemap system +-------------------------------------------------*/ + +static void tilemap_exit(running_machine *machine) +{ + /* free all the tilemaps in the list */ + while (tilemap_list != NULL) + { + tilemap *next = tilemap_list->next; + tilemap_dispose(tilemap_list); + tilemap_list = next; + } + tilemap_tailptr = NULL; +} + + +/*------------------------------------------------- + tilemap_postload - after loading a save state + invalidate everything +-------------------------------------------------*/ + +static void tilemap_postload(void *param) +{ + /* recompute the mappings for this tilemap */ + tilemap *tmap = param; + mappings_update(tmap); +} + + +/*------------------------------------------------- + tilemap_dispose - dispose of a tilemap +-------------------------------------------------*/ + +static void tilemap_dispose(tilemap *tmap) +{ + tilemap **tmapptr; + + /* walk the list of tilemaps; when we find ourself, remove it */ + for (tmapptr = &tilemap_list; *tmapptr != NULL; tmapptr = &(*tmapptr)->next) + if (*tmapptr == tmap) + { + *tmapptr = tmap->next; + break; + } + + /* free allocated memory */ + free(tmap->pen_to_flags); + free(tmap->tileflags); + bitmap_free(tmap->flagsmap); + bitmap_free(tmap->pixmap); + free(tmap->colscroll); + free(tmap->rowscroll); + free(tmap->logical_to_memory); + free(tmap->memory_to_logical); + free(tmap); +} + + + +/*************************************************************************** + LOGICAL <-> MEMORY INDEX MAPPING +***************************************************************************/ + +/*------------------------------------------------- + mappings_create - allocate memory for the + mapping tables and compute their extents +-------------------------------------------------*/ + +static void mappings_create(tilemap *tmap) +{ + UINT32 col, row; + + /* compute the maximum logical index */ + tmap->max_logical_index = tmap->rows * tmap->cols; + + /* compute the maximum memory index */ + tmap->max_memory_index = 0; + for (row = 0; row < tmap->rows; row++) + for (col = 0; col < tmap->cols; col++) + { + tilemap_memory_index memindex = (*tmap->mapper)(col, row, tmap->cols, tmap->rows); + tmap->max_memory_index = MAX(tmap->max_memory_index, memindex); + } + tmap->max_memory_index++; + + /* allocate the necessary mappings */ + tmap->memory_to_logical = malloc_or_die(tmap->max_memory_index * sizeof(*tmap->memory_to_logical)); + tmap->logical_to_memory = malloc_or_die(tmap->max_logical_index * sizeof(*tmap->logical_to_memory)); + + /* update the mappings */ + mappings_update(tmap); +} + + +/*------------------------------------------------- + mappings_update - update the mappings after + a major change (flip x/y changes) +-------------------------------------------------*/ + +static void mappings_update(tilemap *tmap) +{ + tilemap_logical_index logindex; + tilemap_memory_index memindex; + + /* initialize all the mappings to invalid values */ + for (memindex = 0; memindex < tmap->max_memory_index; memindex++) + tmap->memory_to_logical[memindex] = -1; + + /* now iterate over all logical indexes and populate the memory index */ + for (logindex = 0; logindex < tmap->max_logical_index; logindex++) + { + UINT32 logical_col = logindex % tmap->cols; + UINT32 logical_row = logindex / tmap->cols; + tilemap_memory_index memindex = (*tmap->mapper)(logical_col, logical_row, tmap->cols, tmap->rows); + UINT32 flipped_logindex; + + /* apply tilemap flip to get the final location to store */ + if (tmap->attributes & TILEMAP_FLIPX) + logical_col = (tmap->cols - 1) - logical_col; + if (tmap->attributes & TILEMAP_FLIPY) + logical_row = (tmap->rows - 1) - logical_row; + flipped_logindex = logical_row * tmap->cols + logical_col; + + /* fill in entries in both arrays */ + tmap->memory_to_logical[memindex] = flipped_logindex; + tmap->logical_to_memory[flipped_logindex] = memindex; + } + + /* mark the whole tilemap dirty */ + tilemap_mark_all_tiles_dirty(tmap); +} + + + +/*************************************************************************** + TILE RENDERING +***************************************************************************/ + +/*------------------------------------------------- + pixmap_update - update the portion of the + pixmap described by the cliprect +-------------------------------------------------*/ + +static void pixmap_update(tilemap *tmap, const rectangle *cliprect) +{ + int mincol, maxcol, minrow, maxrow; + int row, col; + + /* if everything is clean, do nothing */ + if (tmap->all_tiles_clean) + return; + +profiler_mark(PROFILER_TILEMAP_DRAW); + + /* compute which columns and rows to update */ + if (cliprect != NULL) + { + mincol = cliprect->min_x / tmap->tilewidth; + maxcol = cliprect->max_x / tmap->tilewidth; + minrow = cliprect->min_y / tmap->tileheight; + maxrow = cliprect->max_y / tmap->tileheight; + } + else + { + mincol = minrow = 0; + maxcol = tmap->cols - 1; + maxrow = tmap->rows - 1; + } + + /* if the whole map is dirty, mark it as such */ + if (tmap->all_tiles_dirty) + { + memset(tmap->tileflags, TILE_FLAG_DIRTY, tmap->max_logical_index); + tmap->all_tiles_dirty = FALSE; + } + + /* iterate over rows */ + for (row = minrow; row <= maxrow; row++) + { + tilemap_logical_index logindex = row * tmap->cols; + + /* iterate over colums */ + for (col = mincol; col <= maxcol; col++) + if (tmap->tileflags[logindex + col] == TILE_FLAG_DIRTY) + tile_update(tmap, logindex + col, col, row); + } + + /* mark it all clean */ + if (mincol == 0 && minrow == 0 && maxcol == tmap->cols - 1 && maxcol == tmap->rows - 1) + tmap->all_tiles_clean = TRUE; + +profiler_mark(PROFILER_END); +} + + +/*------------------------------------------------- + tile_update - update a single dirty tile +-------------------------------------------------*/ + +static void tile_update(tilemap *tmap, tilemap_logical_index logindex, UINT32 col, UINT32 row) +{ + UINT32 x0 = tmap->tilewidth * col; + UINT32 y0 = tmap->tileheight * row; + tilemap_memory_index memindex; + UINT32 flags; + +profiler_mark(PROFILER_TILEMAP_UPDATE); + + /* call the get info callback for the associated memory index */ + memindex = tmap->logical_to_memory[logindex]; + (*tmap->tile_get_info)(Machine, &tmap->tileinfo, memindex, tmap->user_data); + + /* apply the global tilemap flip to the returned flip flags */ + flags = tmap->tileinfo.flags ^ (tmap->attributes & 0x03); + + /* draw the tile, using either direct or transparent */ + if (Machine->game_colortable != NULL) + { + if (tmap->type != TILEMAP_TYPE_COLORTABLE) + tmap->tileflags[logindex] = tile_draw_colortable(tmap, tmap->tileinfo.pen_data, x0, y0, tmap->tileinfo.palette_base, tmap->tileinfo.category, tmap->tileinfo.group, flags); + else + tmap->tileflags[logindex] = tile_draw_colortrans(tmap, tmap->tileinfo.pen_data, x0, y0, tmap->tileinfo.palette_base, tmap->tileinfo.category, tmap->tileinfo.group, flags); + } + else + tmap->tileflags[logindex] = tile_draw(tmap, tmap->tileinfo.pen_data, x0, y0, tmap->tileinfo.palette_base, tmap->tileinfo.category, tmap->tileinfo.group, flags); + + /* if mask data is specified, apply it */ + if ((flags & (TILE_FORCE_LAYER0 | TILE_FORCE_LAYER1 | TILE_FORCE_LAYER2)) == 0 && tmap->tileinfo.mask_data != NULL) + tmap->tileflags[logindex] = tile_apply_bitmask(tmap, tmap->tileinfo.mask_data, x0, y0, tmap->tileinfo.category, flags); + +profiler_mark(PROFILER_END); +} + + +/*------------------------------------------------- + tile_draw - draw a single tile to the + tilemap's internal pixmap, using the pen as + the pen_to_flags lookup value, and adding + the palette_base +-------------------------------------------------*/ + +static UINT8 tile_draw(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags) +{ + const UINT8 *penmap = tmap->pen_to_flags + group * tmap->max_pen_to_flags; + mame_bitmap *flagsmap = tmap->flagsmap; + mame_bitmap *pixmap = tmap->pixmap; + int height = tmap->tileheight; + int width = tmap->tilewidth; + UINT8 andmask = ~0, ormask = 0; + int dx0 = 1, dy0 = 1; + int tx, ty; + + /* OR in the force layer flags */ + category |= flags & (TILE_FORCE_LAYER0 | TILE_FORCE_LAYER1 | TILE_FORCE_LAYER2); + + /* if we're vertically flipped, point to the bottom row and work backwards */ + if (flags & TILE_FLIPY) + { + y0 += height - 1; + dy0 = -1; + } + + /* if we're horizontally flipped, point to the rightmost column and work backwards */ + if (flags & TILE_FLIPX) + { + x0 += width - 1; + dx0 = -1; + } + + /* in 4bpp mode, we draw in groups of 2 pixels, so halve the width now */ + if (flags & TILE_4BPP) + { + assert(width % 2 == 0); + width /= 2; + } + + /* iterate over rows */ + for (ty = 0; ty < height; ty++) + { + UINT16 *pixptr = BITMAP_ADDR16(pixmap, y0, x0); + UINT8 *flagsptr = BITMAP_ADDR8(flagsmap, y0, x0); + int xoffs = 0; + + /* pre-advance to the next row */ + y0 += dy0; + + /* 8bpp data */ + if (!(flags & TILE_4BPP)) + { + for (tx = 0; tx < width; tx++) + { + UINT8 pen = *pendata++; + UINT8 map = penmap[pen]; + pixptr[xoffs] = palette_base + pen; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + } + } + + /* 4bpp data */ + else + { + for (tx = 0; tx < width; tx++) + { + UINT8 data = *pendata++; + UINT8 pen, map; + + pen = data & 0x0f; + map = penmap[pen]; + pixptr[xoffs] = palette_base + pen; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + + pen = data >> 4; + map = penmap[pen]; + pixptr[xoffs] = palette_base + pen; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + } + } + } + return andmask ^ ormask; +} + + +/*------------------------------------------------- + tile_draw_colortable - draw a single tile to + the tilemap's internal pixmap, using the pen + as the pen_to_flags lookup value, and using + the machine's remapped_colortable +-------------------------------------------------*/ + +static UINT8 tile_draw_colortable(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags) +{ + const UINT8 *penmap = tmap->pen_to_flags + group * tmap->max_pen_to_flags; + const pen_t *palette_lookup = Machine->remapped_colortable + palette_base; + mame_bitmap *flagsmap = tmap->flagsmap; + mame_bitmap *pixmap = tmap->pixmap; + int height = tmap->tileheight; + int width = tmap->tilewidth; + UINT8 andmask = ~0, ormask = 0; + int dx0 = 1, dy0 = 1; + int tx, ty; + + /* OR in the force layer flags */ + category |= flags & (TILE_FORCE_LAYER0 | TILE_FORCE_LAYER1 | TILE_FORCE_LAYER2); + + /* if we're vertically flipped, point to the bottom row and work backwards */ + if (flags & TILE_FLIPY) + { + y0 += height - 1; + dy0 = -1; + } + + /* if we're horizontally flipped, point to the rightmost column and work backwards */ + if (flags & TILE_FLIPX) + { + x0 += width - 1; + dx0 = -1; + } + + /* in 4bpp mode, we draw in groups of 2 pixels, so halve the width now */ + if (flags & TILE_4BPP) + { + assert(width % 2 == 0); + width /= 2; + } + + /* iterate over rows */ + for (ty = 0; ty < height; ty++) + { + UINT16 *pixptr = BITMAP_ADDR16(pixmap, y0, x0); + UINT8 *flagsptr = BITMAP_ADDR8(flagsmap, y0, x0); + int xoffs = 0; + + /* pre-advance to the next row */ + y0 += dy0; + + /* 8bpp data */ + if (!(flags & TILE_4BPP)) + { + for (tx = 0; tx < width; tx++) + { + UINT8 pen = *pendata++; + UINT8 map = penmap[pen]; + pixptr[xoffs] = palette_lookup[pen]; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + } + } + + /* 4bpp data */ + else + { + for (tx = 0; tx < width; tx++) + { + UINT8 data = *pendata++; + pen_t pen; + UINT8 map; + + pen = data & 0x0f; + map = penmap[pen]; + pixptr[xoffs] = palette_lookup[pen]; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + + pen = data >> 4; + map = penmap[pen]; + pixptr[xoffs] = palette_lookup[pen]; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + } + } + } + return andmask ^ ormask; +} + + +/*------------------------------------------------- + tile_draw_colortrans - draw a single tile to + the tilemap's internal pixmap, using the + remapped pen as the pen_to_flags lookup value +-------------------------------------------------*/ + +static UINT8 tile_draw_colortrans(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags) +{ + const UINT8 *penmap = tmap->pen_to_flags + group * tmap->max_pen_to_flags; + const pen_t *palette_lookup = Machine->remapped_colortable + palette_base; + mame_bitmap *flagsmap = tmap->flagsmap; + mame_bitmap *pixmap = tmap->pixmap; + int height = tmap->tileheight; + int width = tmap->tilewidth; + UINT8 andmask = ~0, ormask = 0; + int dx0 = 1, dy0 = 1; + int tx, ty; + + /* OR in the force layer flags */ + category |= flags & (TILE_FORCE_LAYER0 | TILE_FORCE_LAYER1 | TILE_FORCE_LAYER2); + + /* if we're vertically flipped, point to the bottom row and work backwards */ + if (flags & TILE_FLIPY) + { + y0 += height - 1; + dy0 = -1; + } + + /* if we're horizontally flipped, point to the rightmost column and work backwards */ + if (flags & TILE_FLIPX) + { + x0 += width - 1; + dx0 = -1; + } + + /* in 4bpp mode, we draw in groups of 2 pixels, so halve the width now */ + if (flags & TILE_4BPP) + { + assert(width % 2 == 0); + width /= 2; + } + + /* iterate over rows */ + for (ty = 0; ty < height; ty++) + { + UINT16 *pixptr = BITMAP_ADDR16(pixmap, y0, x0); + UINT8 *flagsptr = BITMAP_ADDR8(flagsmap, y0, x0); + int xoffs = 0; + + /* pre-advance to the next row */ + y0 += dy0; + + /* 8bpp data */ + if (!(flags & TILE_4BPP)) + { + for (tx = 0; tx < width; tx++) + { + pen_t pen = palette_lookup[*pendata++]; + UINT8 map = penmap[pen]; + pixptr[xoffs] = pen; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + } + } + + /* 4bpp data */ + else + { + for (tx = 0; tx < width; tx++) + { + UINT8 data = *pendata++; + pen_t pen; + UINT8 map; + + pen = palette_lookup[data & 0x0f]; + map = penmap[pen]; + pixptr[xoffs] = pen; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + + pen = palette_lookup[data >> 4]; + map = penmap[pen]; + pixptr[xoffs] = pen; + flagsptr[xoffs] = map | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + } + } + } + return andmask ^ ormask; +} + + +/*------------------------------------------------- + tile_apply_bitmask - apply a bitmask to an + already-rendered tile by modifying the + flagsmap appropriately +-------------------------------------------------*/ + +static UINT8 tile_apply_bitmask(tilemap *tmap, const UINT8 *maskdata, UINT32 x0, UINT32 y0, UINT8 category, UINT8 flags) +{ + mame_bitmap *flagsmap = tmap->flagsmap; + int height = tmap->tileheight; + int width = tmap->tilewidth; + UINT8 andmask = ~0, ormask = 0; + int dx0 = 1, dy0 = 1; + int bitoffs = 0; + int tx, ty; + + /* if we're vertically flipped, point to the bottom row and work backwards */ + if (flags & TILE_FLIPY) + { + y0 += height - 1; + dy0 = -1; + } + + /* if we're horizontally flipped, point to the rightmost column and work backwards */ + if (flags & TILE_FLIPX) + { + x0 += width - 1; + dx0 = -1; + } + + /* iterate over rows */ + for (ty = 0; ty < height; ty++) + { + UINT8 *flagsptr = BITMAP_ADDR8(flagsmap, y0, x0); + int xoffs = 0; + + /* pre-advance to the next row */ + y0 += dy0; + + /* anywhere the bitmask is 0 should be transparent */ + for (tx = 0; tx < width; tx++) + { + UINT8 map = flagsptr[xoffs]; + + if ((maskdata[bitoffs / 8] & (0x80 >> (bitoffs & 7))) == 0) + map = flagsptr[xoffs] = TILEMAP_PIXEL_TRANSPARENT | category; + andmask &= map; + ormask |= map; + xoffs += dx0; + bitoffs++; + } + } + return andmask ^ ormask; +} + + + +/*************************************************************************** + DRAWING HELPERS +***************************************************************************/ + +/*------------------------------------------------- + configure_blit_parameters - fill in the + standard blit parameters based on the input + data; this code is shared by normal, roz, + and indexed drawing code +-------------------------------------------------*/ + +static void configure_blit_parameters(blit_parameters *blit, tilemap *tmap, mame_bitmap *dest, const rectangle *cliprect, UINT32 flags, UINT8 priority, UINT8 priority_mask) +{ + /* start with nothing */ + memset(blit, 0, sizeof(*blit)); + + /* set the target bitmap */ + blit->bitmap = dest; + + /* if we have a cliprect, copy */ + if (cliprect != NULL) + blit->cliprect = *cliprect; + + /* otherwise, make one up */ + else + { + blit->cliprect.min_x = blit->cliprect.min_y = 0; + blit->cliprect.max_x = dest->width - 1; + blit->cliprect.max_y = dest->height - 1; + } + + /* set the priority code */ + blit->tilemap_priority_code = priority | (priority_mask << 8) | (tmap->palette_offset << 16); + + /* if no destination, just render priority */ + if (dest == NULL) + { + blit->draw_masked = scanline_draw_masked_null; + blit->draw_opaque = scanline_draw_opaque_null; + } + + /* otherwise get the appropriate callbacks for the format and flags */ + else + { + switch (dest->format) + { + case BITMAP_FORMAT_RGB32: + blit->draw_masked = (flags & TILEMAP_DRAW_ALPHA) ? scanline_draw_masked_rgb32_alpha : scanline_draw_masked_rgb32; + blit->draw_opaque = (flags & TILEMAP_DRAW_ALPHA) ? scanline_draw_opaque_rgb32_alpha : scanline_draw_opaque_rgb32; + break; + + case BITMAP_FORMAT_RGB15: + blit->draw_masked = (flags & TILEMAP_DRAW_ALPHA) ? scanline_draw_masked_rgb16_alpha : scanline_draw_masked_rgb16; + blit->draw_opaque = (flags & TILEMAP_DRAW_ALPHA) ? scanline_draw_opaque_rgb16_alpha : scanline_draw_opaque_rgb16; + break; + + case BITMAP_FORMAT_INDEXED16: + blit->draw_masked = scanline_draw_masked_ind16; + blit->draw_opaque = scanline_draw_opaque_ind16; + break; + + default: + fatalerror("tilemap_draw_primask: Invalid bitmap format"); + break; + } + } + + /* tile priority; unless otherwise specified, draw anything in layer 0 */ + blit->mask = TILEMAP_PIXEL_CATEGORY_MASK; + blit->value = flags & TILEMAP_PIXEL_CATEGORY_MASK; + + /* if no layers specified, draw layer 0 */ + if ((flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2)) == 0) + flags |= TILEMAP_DRAW_LAYER0; + + /* OR in the bits from the draw masks */ + blit->mask |= flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2); + blit->value |= flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2); + + /* for all-opaque rendering, don't check any of the layer bits */ + if (flags & TILEMAP_DRAW_OPAQUE) + { + blit->mask &= ~(TILEMAP_PIXEL_LAYER0 | TILEMAP_PIXEL_LAYER1 | TILEMAP_PIXEL_LAYER2); + blit->value &= ~(TILEMAP_PIXEL_LAYER0 | TILEMAP_PIXEL_LAYER1 | TILEMAP_PIXEL_LAYER2); + } +} + + +/*------------------------------------------------- + tilemap_draw_instance - draw a single + instance of the tilemap to the internal + pixmap at the given xpos,ypos +-------------------------------------------------*/ + +static void tilemap_draw_instance(tilemap *tmap, const blit_parameters *blit, int xpos, int ypos) +{ + mame_bitmap *dest = blit->bitmap; + const UINT16 *source_baseaddr; + const UINT8 *mask_baseaddr; + void *dest_baseaddr = NULL; + UINT8 *priority_baseaddr; + int dest_line_pitch_bytes = 0; + int dest_bytespp = 0; + int mincol, maxcol; + int x1, y1, x2, y2; + int y, nexty; + + /* clip destination coordinates to the tilemap */ + /* note that x2/y2 are exclusive, not inclusive */ + x1 = MAX(xpos, blit->cliprect.min_x); + x2 = MIN(xpos + (int)tmap->width, blit->cliprect.max_x + 1); + y1 = MAX(ypos, blit->cliprect.min_y); + y2 = MIN(ypos + (int)tmap->height, blit->cliprect.max_y + 1); + + /* if totally clipped, stop here */ + if (x1 >= x2 || y1 >= y2) + return; + + /* look up priority and destination base addresses for y1 */ + priority_baseaddr = BITMAP_ADDR8(priority_bitmap, y1, xpos); + if (dest != NULL) + { + dest_bytespp = dest->bpp / 8; + dest_line_pitch_bytes = dest->rowpixels * dest_bytespp; + dest_baseaddr = (UINT8 *)dest->base + (y1 * dest->rowpixels + xpos) * dest_bytespp; + } + + /* convert screen coordinates to source tilemap coordinates */ + x1 -= xpos; + y1 -= ypos; + x2 -= xpos; + y2 -= ypos; + + /* get tilemap pixels */ + source_baseaddr = BITMAP_ADDR16(tmap->pixmap, y1, 0); + mask_baseaddr = BITMAP_ADDR8(tmap->flagsmap, y1, 0); + + /* get start/stop columns, rounding outward */ + mincol = x1 / tmap->tilewidth; + maxcol = (x2 + tmap->tilewidth - 1) / tmap->tilewidth; + + /* set up row counter */ + y = y1; + nexty = tmap->tileheight * (y1 / tmap->tileheight) + tmap->tileheight; + nexty = MIN(nexty, y2); + + /* loop over tilemap rows */ + for (;;) + { + int row = y / tmap->tileheight; + trans_t prev_trans = WHOLLY_TRANSPARENT; + trans_t cur_trans; + int x_start = x1; + int column; + + /* iterate across the applicable tilemap columns */ + for (column = mincol; column <= maxcol; column++) + { + int x_end; + + /* we don't actually render the last column; it is always just used for flushing */ + if (column == maxcol) + cur_trans = WHOLLY_TRANSPARENT; + + /* for other columns we look up the transparency information */ + else + { + tilemap_logical_index logindex = row * tmap->cols + column; + + /* if the current tile is dirty, fix it */ + if (tmap->tileflags[logindex] == TILE_FLAG_DIRTY) + tile_update(tmap, logindex, column, row); + + /* if the current summary data is non-zero, we must draw masked */ + if ((tmap->tileflags[logindex] & blit->mask) != 0) + cur_trans = MASKED; + + /* otherwise, our transparency state is constant across the tile; fetch it */ + else + cur_trans = ((mask_baseaddr[column * tmap->tilewidth] & blit->mask) == blit->value) ? WHOLLY_OPAQUE : WHOLLY_TRANSPARENT; + } + + /* if the transparency state is the same as last time, don't render yet */ + if (cur_trans == prev_trans) + continue; + + /* compute the end of this run, in pixels */ + x_end = column * tmap->tilewidth; + x_end = MAX(x_end, x1); + x_end = MIN(x_end, x2); + + /* if we're rendering something, compute the pointers */ + if (prev_trans != WHOLLY_TRANSPARENT) + { + const UINT16 *source0 = source_baseaddr + x_start; + void *dest0 = (UINT8 *)dest_baseaddr + x_start * dest_bytespp; + UINT8 *pmap0 = priority_baseaddr + x_start; + int cury; + + /* if we were opaque, use the opaque renderer */ + if (prev_trans == WHOLLY_OPAQUE) + { + for (cury = y; cury < nexty; cury++) + { + (*blit->draw_opaque)(dest0, source0, x_end - x_start, pmap0, blit->tilemap_priority_code); + + dest0 = (UINT8 *)dest0 + dest_line_pitch_bytes; + source0 += tmap->pixmap->rowpixels; + pmap0 += priority_bitmap->rowpixels; + } + } + + /* otherwise use the masked renderer */ + else + { + const UINT8 *mask0 = mask_baseaddr + x_start; + for (cury = y; cury < nexty; cury++) + { + (*blit->draw_masked)(dest0, source0, mask0, blit->mask, blit->value, x_end - x_start, pmap0, blit->tilemap_priority_code); + + dest0 = (UINT8 *)dest0 + dest_line_pitch_bytes; + source0 += tmap->pixmap->rowpixels; + mask0 += tmap->flagsmap->rowpixels; + pmap0 += priority_bitmap->rowpixels; + } + } + } + + /* the new start is the end */ + x_start = x_end; + prev_trans = cur_trans; + } + + /* if this was the last row, stop */ + if (nexty == y2) + break; + + /* advance to the next row on all our bitmaps */ + priority_baseaddr += priority_bitmap->rowpixels * (nexty - y); + source_baseaddr += tmap->pixmap->rowpixels * (nexty - y); + mask_baseaddr += tmap->flagsmap->rowpixels * (nexty - y); + dest_baseaddr = (UINT8 *)dest_baseaddr + dest_line_pitch_bytes * (nexty - y); + + /* increment the Y counter */ + y = nexty; + nexty += tmap->tileheight; + nexty = MIN(nexty, y2); + } +} + + +/*------------------------------------------------- + tilemap_draw_roz_core - render the tilemap's + pixmap to the destination with rotation + and zoom +-------------------------------------------------*/ + +#define ROZ_PLOT_PIXEL(INPUT_VAL) \ +do { \ + if (blit->draw_masked == scanline_draw_masked_ind16) \ + *(UINT16 *)dest = (INPUT_VAL) + (priority >> 16); \ + else if (blit->draw_masked == scanline_draw_masked_rgb32) \ + *(UINT32 *)dest = clut[INPUT_VAL]; \ + else if (blit->draw_masked == scanline_draw_masked_rgb16) \ + *(UINT16 *)dest = clut[INPUT_VAL]; \ + else if (blit->draw_masked == scanline_draw_masked_rgb32_alpha) \ + *(UINT32 *)dest = alpha_blend32(*(UINT32 *)dest, clut[INPUT_VAL]); \ + else if (blit->draw_masked == scanline_draw_masked_rgb16_alpha) \ + *(UINT16 *)dest = alpha_blend16(*(UINT16 *)dest, clut[INPUT_VAL]); \ +} while (0) + +static void tilemap_draw_roz_core(tilemap *tmap, const blit_parameters *blit, + UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, int wraparound) +{ + const pen_t *clut = &Machine->remapped_colortable[blit->tilemap_priority_code >> 16]; + mame_bitmap *destbitmap = blit->bitmap; + mame_bitmap *srcbitmap = tmap->pixmap; + mame_bitmap *flagsmap = tmap->flagsmap; + const int xmask = srcbitmap->width-1; + const int ymask = srcbitmap->height-1; + const int widthshifted = srcbitmap->width << 16; + const int heightshifted = srcbitmap->height << 16; + UINT32 priority = blit->tilemap_priority_code; + UINT8 mask = blit->mask; + UINT8 value = blit->value; + UINT32 cx; + UINT32 cy; + int x; + int sx; + int sy; + int ex; + int ey; + void *dest; + UINT8 *pri; + const UINT16 *src; + const UINT8 *maskptr; + int destadvance = destbitmap->bpp / 8; + + /* pre-advance based on the cliprect */ + startx += blit->cliprect.min_x * incxx + blit->cliprect.min_y * incyx; + starty += blit->cliprect.min_x * incxy + blit->cliprect.min_y * incyy; + + /* extract start/end points */ + sx = blit->cliprect.min_x; + sy = blit->cliprect.min_y; + ex = blit->cliprect.max_x; + ey = blit->cliprect.max_y; + + /* optimized loop for the not rotated case */ + if (incxy == 0 && incyx == 0 && !wraparound) + { + /* skip without drawing until we are within the bitmap */ + while (startx >= widthshifted && sx <= ex) + { + startx += incxx; + sx++; + } + + /* early exit if we're done already */ + if (sx > ex) + return; + + /* loop over rows */ + while (sy <= ey) + { + /* only draw if Y is within range */ + if (starty < heightshifted) + { + /* initialize X counters */ + x = sx; + cx = startx; + cy = starty >> 16; + + /* get source and priority pointers */ + pri = BITMAP_ADDR8(priority_bitmap, sy, sx); + src = BITMAP_ADDR16(srcbitmap, cy, 0); + maskptr = BITMAP_ADDR8(flagsmap, cy, 0); + dest = (UINT8 *)destbitmap->base + (destbitmap->rowpixels * sy + sx) * destadvance; + + /* loop over columns */ + while (x <= ex && cx < widthshifted) + { + /* plot if we match the mask */ + if ((maskptr[cx >> 16] & mask) == value) + { + ROZ_PLOT_PIXEL(src[cx >> 16]); + *pri = (*pri & (priority >> 8)) | priority; + } + + /* advance in X */ + cx += incxx; + x++; + dest = (UINT8 *)dest + destadvance; + pri++; + } + } + + /* advance in Y */ + starty += incyy; + sy++; + } + } + + /* wraparound case */ + else if (wraparound) + { + /* loop over rows */ + while (sy <= ey) + { + /* initialize X counters */ + x = sx; + cx = startx; + cy = starty; + + /* get dest and priority pointers */ + dest = (UINT8 *)destbitmap->base + (destbitmap->rowpixels * sy + sx) * destadvance; + pri = BITMAP_ADDR8(priority_bitmap, sy, sx); + + /* loop over columns */ + while (x <= ex) + { + /* plot if we match the mask */ + if ((*BITMAP_ADDR8(flagsmap, (cy >> 16) & ymask, (cx >> 16) & xmask) & mask) == value) + { + ROZ_PLOT_PIXEL(*BITMAP_ADDR16(srcbitmap, (cy >> 16) & ymask, (cx >> 16) & xmask)); + *pri = (*pri & (priority >> 8)) | priority; + } + + /* advance in X */ + cx += incxx; + cy += incxy; + x++; + dest = (UINT8 *)dest + destadvance; + pri++; + } + + /* advance in Y */ + startx += incyx; + starty += incyy; + sy++; + } + } + + /* non-wraparound case */ + else + { + /* loop over rows */ + while (sy <= ey) + { + /* initialize X counters */ + x = sx; + cx = startx; + cy = starty; + + /* get dest and priority pointers */ + dest = (UINT8 *)destbitmap->base + (destbitmap->rowpixels * sy + sx) * destadvance; + pri = BITMAP_ADDR8(priority_bitmap, sy, sx); + + /* loop over columns */ + while (x <= ex) + { + /* plot if we're within the bitmap and we match the mask */ + if (cx < widthshifted && cy < heightshifted) + if ((*BITMAP_ADDR8(flagsmap, cy >> 16, cx >> 16) & mask) == value) + { + ROZ_PLOT_PIXEL(*BITMAP_ADDR16(srcbitmap, cy >> 16, cx >> 16)); + *pri = (*pri & (priority >> 8)) | priority; + } + + /* advance in X */ + cx += incxx; + cy += incxy; + x++; + dest = (UINT8 *)dest + destadvance; + pri++; + } + + /* advance in Y */ + startx += incyx; + starty += incyy; + sy++; + } + } +} + + + +/*************************************************************************** + SCANLINE RASTERIZERS +***************************************************************************/ + +/*------------------------------------------------- + scanline_draw_opaque_null - draw to a NULL + bitmap, setting priority only +-------------------------------------------------*/ + +static void scanline_draw_opaque_null(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode) +{ + int i; + + /* skip entirely if not changing priority */ + if (pcode != 0xff00) + { + for (i = 0; i < count; i++) + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } +} + + +/*------------------------------------------------- + scanline_draw_masked_null - draw to a NULL + bitmap using a mask, setting priority only +-------------------------------------------------*/ + +static void scanline_draw_masked_null(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode) +{ + int i; + + /* skip entirely if not changing priority */ + if (pcode != 0xff00) + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } +} + + + +/*------------------------------------------------- + scanline_draw_opaque_ind16 - draw to a 16bpp + indexed bitmap +-------------------------------------------------*/ + +static void scanline_draw_opaque_ind16(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode) +{ + UINT16 *dest = _dest; + int pal = pcode >> 16; + int i; + + /* special case for no palette offset */ + if (pal == 0) + { + memcpy(dest, source, count * 2); + + /* priority if necessary */ + if (pcode != 0xff00) + { + for (i = 0; i < count; i++) + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* priority case */ + else if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + { + dest[i] = source[i] + pal; + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + dest[i] = source[i] + pal; + } +} + + +/*------------------------------------------------- + scanline_draw_masked_ind16 - draw to a 16bpp + indexed bitmap using a mask +-------------------------------------------------*/ + +static void scanline_draw_masked_ind16(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode) +{ + UINT16 *dest = _dest; + int pal = pcode >> 16; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + { + dest[i] = source[i] + pal; + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + dest[i] = source[i] + pal; + } +} + + + +/*------------------------------------------------- + scanline_draw_opaque_rgb16 - draw to a 16bpp + RGB bitmap +-------------------------------------------------*/ + +static void scanline_draw_opaque_rgb16(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode) +{ + const pen_t *clut = &Machine->remapped_colortable[pcode >> 16]; + UINT16 *dest = _dest; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + { + dest[i] = clut[source[i]]; + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + dest[i] = clut[source[i]]; + } +} + + +/*------------------------------------------------- + scanline_draw_masked_rgb16 - draw to a 16bpp + RGB bitmap using a mask +-------------------------------------------------*/ + +static void scanline_draw_masked_rgb16(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode) +{ + const pen_t *clut = &Machine->remapped_colortable[pcode >> 16]; + UINT16 *dest = _dest; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + { + dest[i] = clut[source[i]]; + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + dest[i] = clut[source[i]]; + } +} + + +/*------------------------------------------------- + scanline_draw_opaque_rgb16_alpha - draw to a + 16bpp RGB bitmap with alpha blending +-------------------------------------------------*/ + +static void scanline_draw_opaque_rgb16_alpha(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode) +{ + const pen_t *clut = &Machine->remapped_colortable[pcode >> 16]; + UINT16 *dest = _dest; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + { + dest[i] = alpha_blend16(dest[i], clut[source[i]]); + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + dest[i] = alpha_blend16(dest[i], clut[source[i]]); + } +} + + +/*------------------------------------------------- + scanline_draw_masked_rgb16_alpha - draw to a + 16bpp RGB bitmap using a mask and alpha + blending +-------------------------------------------------*/ + +static void scanline_draw_masked_rgb16_alpha(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode) +{ + const pen_t *clut = &Machine->remapped_colortable[pcode >> 16]; + UINT16 *dest = _dest; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + { + dest[i] = alpha_blend16(dest[i], clut[source[i]]); + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + dest[i] = alpha_blend16(dest[i], clut[source[i]]); + } +} + + +/*------------------------------------------------- + scanline_draw_opaque_rgb32 - draw to a 32bpp + RGB bitmap +-------------------------------------------------*/ + +static void scanline_draw_opaque_rgb32(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode) +{ + const pen_t *clut = &Machine->remapped_colortable[pcode >> 16]; + UINT32 *dest = _dest; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + { + dest[i] = clut[source[i]]; + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + dest[i] = clut[source[i]]; + } +} + + +/*------------------------------------------------- + scanline_draw_masked_rgb32 - draw to a 32bpp + RGB bitmap using a mask +-------------------------------------------------*/ + +static void scanline_draw_masked_rgb32(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode) +{ + const pen_t *clut = &Machine->remapped_colortable[pcode >> 16]; + UINT32 *dest = _dest; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + { + dest[i] = clut[source[i]]; + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + dest[i] = clut[source[i]]; + } +} + + +/*------------------------------------------------- + scanline_draw_opaque_rgb32_alpha - draw to a + 32bpp RGB bitmap with alpha blending +-------------------------------------------------*/ + +static void scanline_draw_opaque_rgb32_alpha(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode) +{ + const pen_t *clut = &Machine->remapped_colortable[pcode >> 16]; + UINT32 *dest = _dest; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + { + dest[i] = alpha_blend32(dest[i], clut[source[i]]); + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + dest[i] = alpha_blend32(dest[i], clut[source[i]]); + } +} + + +/*------------------------------------------------- + scanline_draw_masked_rgb32_alpha - draw to a + 32bpp RGB bitmap using a mask and alpha + blending +-------------------------------------------------*/ + +static void scanline_draw_masked_rgb32_alpha(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode) +{ + const pen_t *clut = &Machine->remapped_colortable[pcode >> 16]; + UINT32 *dest = _dest; + int i; + + /* priority case */ + if ((pcode & 0xffff) != 0xff00) + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + { + dest[i] = alpha_blend32(dest[i], clut[source[i]]); + pri[i] = (pri[i] & (pcode >> 8)) | pcode; + } + } + + /* no priority case */ + else + { + for (i = 0; i < count; i++) + if ((maskptr[i] & mask) == value) + dest[i] = alpha_blend32(dest[i], clut[source[i]]); + } +} |