mame/src/emu/tilemap.c
Aaron Giles 9cae38e0d8 Converted bitmap_t and rectangle into proper classes. Replaced BITMAP_ADDR*
macros with bitmap->pix* functions, and moved bitmap_fill() to bitmap->fill()
among other similar changes. Bitmap fields now only available via accessors.
Replaced sect_rect with &= and union_rect with |= operators for rectangle
classes. Some general cleanup as a result of these changes. [Aaron Giles]
2011-12-31 07:52:26 +00:00

2339 lines
70 KiB
C

/***************************************************************************
tilemap.c
Generic tilemap management system.
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
***************************************************************************/
#include "emu.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)
/* maximum index in each array */
#define MAX_PEN_TO_FLAGS 256
/***************************************************************************
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_func)(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
typedef void (*blitopaque_func)(void *dest, const UINT16 *source, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
/* blitting parameters for rendering */
typedef struct _blit_parameters blit_parameters;
struct _blit_parameters
{
bitmap_t * bitmap;
rectangle cliprect;
blitmask_func draw_masked;
blitopaque_func draw_opaque;
UINT32 tilemap_priority_code;
UINT8 mask;
UINT8 value;
UINT8 alpha;
};
/* core tilemap structure */
class tilemap_t
{
public:
tilemap_t(running_machine &machine)
: m_machine(machine) { }
running_machine &machine() const { return m_machine; }
tilemap_t * next; /* pointer to next tilemap */
/* basic tilemap metrics */
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_func 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_func tile_get_info; /* callback to get information about a tile */
void * tile_get_info_object;/* object passed as the first parameter to the get_info functon */
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 */
UINT32 pen_data_offset; /* pen data offset */
UINT32 gfx_used; /* bitmask of gfx items used */
UINT32 gfx_dirtyseq[MAX_GFX_ELEMENTS]; /* dirtyseq values from last check */
/* 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 */
bitmap_t * pixmap; /* cached pixel data */
/* transparency mapping */
bitmap_t * flagsmap; /* per-pixel flags */
UINT8 * tileflags; /* per-tile flags */
UINT8 * pen_to_flags; /* mapping of pens to flags */
private:
running_machine & m_machine; /* pointer back to the owning machine */
};
struct _tilemap_private
{
tilemap_t * list;
tilemap_t ** tailptr;
int instance;
};
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
/* system management helpers */
static tilemap_t *tilemap_create_common(running_machine &machine, void *get_info_object, tile_get_info_func tile_get_info, tilemap_mapper_func mapper, int tilewidth, int tileheight, int cols, int rows);
static void tilemap_exit(running_machine &machine);
static void tilemap_postload(tilemap_t *tmap);
static void tilemap_dispose(tilemap_t *tmap);
/* logical <-> memory index mapping */
static void mappings_create(tilemap_t *tmap);
static void mappings_update(tilemap_t *tmap);
/* tile rendering */
static void pixmap_update(tilemap_t *tmap, const rectangle *cliprect);
static void tile_update(tilemap_t *tmap, tilemap_logical_index logindex, UINT32 cached_col, UINT32 cached_row);
static UINT8 tile_draw(tilemap_t *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags, UINT8 pen_mask);
static UINT8 tile_apply_bitmask(tilemap_t *tmap, const UINT8 *maskdata, UINT32 x0, UINT32 y0, UINT8 category, UINT8 flags);
/* drawing helpers */
static void configure_blit_parameters(blit_parameters *blit, tilemap_t *tmap, bitmap_t *dest, const rectangle *cliprect, UINT32 flags, UINT8 priority, UINT8 priority_mask);
static void tilemap_draw_instance(tilemap_t *tmap, const blit_parameters *blit, int xpos, int ypos);
static void tilemap_draw_roz_core(tilemap_t *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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_masked_null(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_opaque_ind16(void *dest, const UINT16 *source, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_masked_ind16(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_opaque_rgb16(void *dest, const UINT16 *source, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_masked_rgb16(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_opaque_rgb16_alpha(void *dest, const UINT16 *source, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_masked_rgb16_alpha(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_opaque_rgb32(void *dest, const UINT16 *source, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_masked_rgb32(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_opaque_rgb32_alpha(void *dest, const UINT16 *source, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
static void scanline_draw_masked_rgb32_alpha(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha);
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
effective_rowscroll - return the effective
rowscroll value for a given index, taking into
account tilemap flip states
-------------------------------------------------*/
INLINE INT32 effective_rowscroll(tilemap_t *tmap, int index, UINT32 screen_width)
{
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_t *tmap, int index, UINT32 screen_height)
{
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_t *indexed_tilemap(running_machine &machine, int index)
{
tilemap_t *tmap;
/* find by the tilemap index */
for (tmap = machine.tilemap_data->list; tmap != NULL; tmap = tmap->next)
if (index-- == 0)
return tmap;
return NULL;
}
/*-------------------------------------------------
gfx_tiles_changed - return TRUE if any
gfx_elements used by this tilemap have
changed
-------------------------------------------------*/
INLINE int gfx_elements_changed(tilemap_t *tmap)
{
UINT32 usedmask = tmap->gfx_used;
int isdirty = FALSE;
int gfxnum;
/* iterate over all used gfx types and set the dirty flag if any of them have changed */
for (gfxnum = 0; usedmask != 0; usedmask >>= 1, gfxnum++)
if ((usedmask & 1) != 0)
if (tmap->gfx_dirtyseq[gfxnum] != tmap->machine().gfx[gfxnum]->dirtyseq)
{
tmap->gfx_dirtyseq[gfxnum] = tmap->machine().gfx[gfxnum]->dirtyseq;
isdirty = TRUE;
}
return isdirty;
}
/***************************************************************************
SYSTEM-WIDE MANAGEMENT
***************************************************************************/
/*-------------------------------------------------
tilemap_init - initialize the tilemap system
-------------------------------------------------*/
void tilemap_init(running_machine &machine)
{
UINT32 screen_width, screen_height;
if (machine.primary_screen == NULL)
return;
screen_width = machine.primary_screen->width();
screen_height = machine.primary_screen->height();
if (screen_width != 0 && screen_height != 0)
{
machine.priority_bitmap = auto_bitmap_alloc(machine, screen_width, screen_height, BITMAP_FORMAT_INDEXED8);
machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(tilemap_exit), &machine));
}
}
/***************************************************************************
TILEMAP CREATION AND CONFIGURATION
***************************************************************************/
/*-------------------------------------------------
tilemap_create - create a new tilemap
-------------------------------------------------*/
tilemap_t *tilemap_create(running_machine &machine, tile_get_info_func tile_get_info, tilemap_mapper_func mapper, int tilewidth, int tileheight, int cols, int rows)
{
return tilemap_create_common(machine, (void *)&machine, tile_get_info, mapper, tilewidth, tileheight, cols, rows);
}
/*-------------------------------------------------
tilemap_create - create a new tilemap that
is owned by a device
-------------------------------------------------*/
tilemap_t *tilemap_create_device(device_t *device, tile_get_info_device_func tile_get_info, tilemap_mapper_func mapper, int tilewidth, int tileheight, int cols, int rows)
{
return tilemap_create_common(device->machine(), (void *)device, (tile_get_info_func)tile_get_info, mapper, tilewidth, tileheight, cols, rows);
}
/*-------------------------------------------------
tilemap_create_common - shared creation
function
-------------------------------------------------*/
static tilemap_t *tilemap_create_common(running_machine &machine, void *get_info_object, tile_get_info_func tile_get_info, tilemap_mapper_func mapper, int tilewidth, int tileheight, int cols, int rows)
{
tilemap_t *tmap;
int tilemap_instance;
int group;
/* if no tilemap private data yet, allocate it */
if (machine.tilemap_data == NULL)
{
machine.tilemap_data = auto_alloc_clear(machine, tilemap_private);
machine.tilemap_data->tailptr = &machine.tilemap_data->list;
}
tilemap_instance = machine.tilemap_data->instance;
/* allocate the tilemap itself */
tmap = auto_alloc_clear(machine, tilemap_t(machine));
/* fill in the basic metrics */
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;
tmap->tile_get_info_object = get_info_object;
/* set up the default pen mask */
tmap->tileinfo.pen_mask = 0xff;
tmap->tileinfo.gfxnum = 0xff;
/* initialize global states */
tmap->enable = TRUE;
tmap->all_tiles_dirty = TRUE;
/* initialize scroll information */
tmap->scrollrows = 1;
tmap->scrollcols = 1;
tmap->rowscroll = auto_alloc_array_clear(machine, INT32, tmap->height);
tmap->colscroll = auto_alloc_array_clear(machine, INT32, tmap->width);
/* allocate the pixel data cache */
tmap->pixmap = auto_bitmap_alloc(machine, tmap->width, tmap->height, BITMAP_FORMAT_INDEXED16);
/* allocate transparency mapping data */
tmap->tileflags = auto_alloc_array(machine, UINT8, tmap->max_logical_index);
tmap->flagsmap = auto_bitmap_alloc(machine, tmap->width, tmap->height, BITMAP_FORMAT_INDEXED8);
tmap->pen_to_flags = auto_alloc_array_clear(machine, UINT8, 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 */
*machine.tilemap_data->tailptr = tmap;
machine.tilemap_data->tailptr = &tmap->next;
/* save relevant state */
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->enable));
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->attributes));
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->palette_offset));
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->pen_data_offset));
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->scrollrows));
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->scrollcols));
machine.save().save_pointer("tilemap", NULL, tilemap_instance, NAME(tmap->rowscroll), rows * tileheight);
machine.save().save_pointer("tilemap", NULL, tilemap_instance, NAME(tmap->colscroll), cols * tilewidth);
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->dx));
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->dx_flipped));
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->dy));
machine.save().save_item("tilemap", NULL, tilemap_instance, NAME(tmap->dy_flipped));
machine.tilemap_data->instance++;
/* reset everything after a load */
machine.save().register_postload(save_prepost_delegate(FUNC(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_t *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_t *tmap, UINT32 offset)
{
tmap->palette_offset = offset;
}
/*-------------------------------------------------
tilemap_set_enable - set an enable flag for
the tilemap; if 0, requests to draw the
tilemap are ignored
-------------------------------------------------*/
void tilemap_set_enable(tilemap_t *tmap, int enable)
{
tmap->enable = (enable != 0);
}
/*-------------------------------------------------
tilemap_get_scrolldx - return the enable flag
for the tilemap
-------------------------------------------------*/
int tilemap_get_enable(tilemap_t *tmap)
{
return tmap->enable;
}
/*-------------------------------------------------
tilemap_set_flip - set a global flip for the
tilemap
-------------------------------------------------*/
void tilemap_set_flip(tilemap_t *tmap, UINT32 attributes)
{
/* if we're changing things, force a refresh of the mappings and mark it all dirty */
if (tmap->attributes != attributes)
{
tmap->attributes = attributes;
mappings_update(tmap);
}
}
/*-------------------------------------------------
tilemap_set_flip_all - set a global flip for all
the tilemaps
-------------------------------------------------*/
void tilemap_set_flip_all(running_machine &machine, UINT32 attributes)
{
tilemap_t *tmap;
if (machine.tilemap_data == NULL)
return;
for (tmap = machine.tilemap_data->list; tmap != NULL; tmap = tmap->next)
tilemap_set_flip(tmap, attributes);
}
/***************************************************************************
DIRTY TILE MARKING
***************************************************************************/
/*-------------------------------------------------
tilemap_mark_tile_dirty - mark a single tile
dirty based on its memory index
-------------------------------------------------*/
void tilemap_mark_tile_dirty(tilemap_t *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_t *tmap)
{
/* mark all tiles dirty and clear the clean flag */
tmap->all_tiles_dirty = TRUE;
tmap->all_tiles_clean = FALSE;
}
/*-------------------------------------------------
tilemap_mark_all_tiles_dirty_all - mark all the
tiles in all the tilemaps dirty
-------------------------------------------------*/
void tilemap_mark_all_tiles_dirty_all(running_machine &machine)
{
tilemap_t *tmap;
for (tmap = machine.tilemap_data->list; tmap != NULL; tmap = tmap->next)
tilemap_mark_all_tiles_dirty(tmap);
}
/***************************************************************************
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_t *tmap, int group, pen_t pen, pen_t mask, UINT8 layermask)
{
UINT8 *array = tmap->pen_to_flags + group * 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, 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_t *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_t *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_t *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_t *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_t *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_t *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_t *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_t *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_t *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_t *tmap, int which, int value)
{
if (which < tmap->scrollcols)
tmap->colscroll[which] = value;
}
/*-------------------------------------------------
tilemap_get_scrollx - return the scroll value
for a row unit
-------------------------------------------------*/
int tilemap_get_scrollx(tilemap_t *tmap, int which)
{
if (which < tmap->scrollrows)
return tmap->rowscroll[which];
else
return 0;
}
/*-------------------------------------------------
tilemap_get_scrolly - return the scroll value
for a column unit
-------------------------------------------------*/
int tilemap_get_scrolly(tilemap_t *tmap, int which)
{
if (which < tmap->scrollcols)
return tmap->colscroll[which];
else
return 0;
}
/***************************************************************************
INTERNAL MAP ACCESS
***************************************************************************/
/*-------------------------------------------------
tilemap_get_pixmap - return a pointer to the
(updated) internal pixmap for a tilemap
-------------------------------------------------*/
bitmap_t *tilemap_get_pixmap(tilemap_t *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
-------------------------------------------------*/
bitmap_t *tilemap_get_flagsmap(tilemap_t *tmap)
{
/* ensure all the tiles are up-to-date and then return the flagsmap */
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_t *tmap)
{
/* ensure all the tiles are up-to-date and then return the per-tile flags */
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(bitmap_t *dest, const rectangle *cliprect, tilemap_t *tmap, UINT32 flags, UINT8 priority, UINT8 priority_mask)
{
UINT32 width, height;
blit_parameters blit;
int xpos, ypos;
/* skip if disabled */
if (!tmap->enable)
return;
g_profiler.start(PROFILER_TILEMAP_DRAW);
/* configure the blit parameters based on the input parameters */
configure_blit_parameters(&blit, tmap, dest, cliprect, flags, priority, priority_mask);
/* if the whole map is dirty, mark it as such */
if (tmap->all_tiles_dirty || gfx_elements_changed(tmap))
{
memset(tmap->tileflags, TILE_FLAG_DIRTY, tmap->max_logical_index);
tmap->all_tiles_dirty = FALSE;
tmap->gfx_used = 0;
}
width = tmap->machine().primary_screen->width();
height = tmap->machine().primary_screen->height();
/* XY scrolling playfield */
if (tmap->scrollrows == 1 && tmap->scrollcols == 1)
{
int scrollx = effective_rowscroll(tmap, 0, width);
int scrolly = effective_colscroll(tmap, 0, height);
/* 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, height);
int currow, nextrow;
/* iterate over Y to handle wraparound */
for (ypos = scrolly - tmap->height; ypos <= original_cliprect.max_y; ypos += tmap->height)
{
int const firstrow = MAX((original_cliprect.min_y - ypos) / rowheight, 0);
int const lastrow = MIN((original_cliprect.max_y - ypos) / rowheight, tmap->scrollrows - 1);
/* iterate over rows in the tilemap */
for (currow = firstrow; currow <= lastrow; currow = nextrow)
{
int scrollx = effective_rowscroll(tmap, currow, width);
/* scan forward until we find a non-matching row */
for (nextrow = currow + 1; nextrow <= lastrow; nextrow++)
if (effective_rowscroll(tmap, nextrow, width) != scrollx)
break;
/* skip if disabled */
if (scrollx == TILE_LINE_DISABLED)
continue;
/* update the cliprect just for this set of rows */
blit.cliprect.min_y = currow * rowheight + ypos;
blit.cliprect.max_y = nextrow * rowheight - 1 + ypos;
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, width);
int curcol, nextcol;
/* iterate over columns in the tilemap */
for (curcol = 0; curcol < tmap->scrollcols; curcol = nextcol)
{
int scrolly = effective_colscroll(tmap, curcol, height);
/* scan forward until we find a non-matching column */
for (nextcol = curcol + 1; nextcol < tmap->scrollcols; nextcol++)
if (effective_colscroll(tmap, nextcol, height) != 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;
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);
}
}
}
g_profiler.stop();
}
/*-------------------------------------------------
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(bitmap_t *dest, const rectangle *cliprect, tilemap_t *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;
}
g_profiler.start(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);
g_profiler.stop();
}
/***************************************************************************
INDEXED TILEMAP HANDLING
***************************************************************************/
/*-------------------------------------------------
tilemap_count - return the number of tilemaps
-------------------------------------------------*/
int tilemap_count(running_machine &machine)
{
tilemap_t *tmap;
int count = 0;
if (machine.tilemap_data == NULL)
return 0;
/* find by the tilemap index */
for (tmap = machine.tilemap_data->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(running_machine &machine, int number, UINT32 *width, UINT32 *height)
{
tilemap_t *tmap = indexed_tilemap(machine, 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(running_machine &machine, bitmap_t *dest, int number, UINT32 scrollx, UINT32 scrolly)
{
tilemap_t *tmap = indexed_tilemap(machine, 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 | TILEMAP_DRAW_ALL_CATEGORIES, 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 || gfx_elements_changed(tmap))
{
memset(tmap->tileflags, TILE_FLAG_DIRTY, tmap->max_logical_index);
tmap->all_tiles_dirty = FALSE;
tmap->gfx_used = 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);
}
/***************************************************************************
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)
{
tilemap_private *tilemap_data = machine.tilemap_data;
/* free all the tilemaps in the list */
if (tilemap_data != NULL)
while (tilemap_data->list != NULL)
{
tilemap_t *next = tilemap_data->list->next;
tilemap_dispose(tilemap_data->list);
tilemap_data->list = next;
}
}
/*-------------------------------------------------
tilemap_postload - after loading a save state
invalidate everything
-------------------------------------------------*/
static void tilemap_postload(tilemap_t *tmap)
{
mappings_update(tmap);
}
/*-------------------------------------------------
tilemap_dispose - dispose of a tilemap
-------------------------------------------------*/
static void tilemap_dispose(tilemap_t *tmap)
{
tilemap_t **tmapptr;
/* walk the list of tilemaps; when we find ourself, remove it */
for (tmapptr = &tmap->machine().tilemap_data->list; *tmapptr != NULL; tmapptr = &(*tmapptr)->next)
if (*tmapptr == tmap)
{
*tmapptr = tmap->next;
break;
}
/* free allocated memory */
auto_free(tmap->machine(), tmap->pen_to_flags);
auto_free(tmap->machine(), tmap->tileflags);
auto_free(tmap->machine(), tmap->flagsmap);
auto_free(tmap->machine(), tmap->pixmap);
auto_free(tmap->machine(), tmap->colscroll);
auto_free(tmap->machine(), tmap->rowscroll);
auto_free(tmap->machine(), tmap->logical_to_memory);
auto_free(tmap->machine(), tmap->memory_to_logical);
auto_free(tmap->machine(), tmap);
}
/***************************************************************************
LOGICAL <-> MEMORY INDEX MAPPING
***************************************************************************/
/*-------------------------------------------------
mappings_create - allocate memory for the
mapping tables and compute their extents
-------------------------------------------------*/
static void mappings_create(tilemap_t *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 = auto_alloc_array(tmap->machine(), tilemap_logical_index, tmap->max_memory_index);
tmap->logical_to_memory = auto_alloc_array(tmap->machine(), tilemap_memory_index, tmap->max_logical_index);
/* update the mappings */
mappings_update(tmap);
}
/*-------------------------------------------------
mappings_update - update the mappings after
a major change (flip x/y changes)
-------------------------------------------------*/
static void mappings_update(tilemap_t *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;
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_t *tmap, const rectangle *cliprect)
{
int mincol, maxcol, minrow, maxrow;
int row, col;
/* if the graphics changed, we need to mark everything dirty */
if (gfx_elements_changed(tmap))
tilemap_mark_all_tiles_dirty(tmap);
/* if everything is clean, do nothing */
if (tmap->all_tiles_clean)
return;
g_profiler.start(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;
tmap->gfx_used = 0;
}
/* 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;
g_profiler.stop();
}
/*-------------------------------------------------
tile_update - update a single dirty tile
-------------------------------------------------*/
static void tile_update(tilemap_t *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;
g_profiler.start(PROFILER_TILEMAP_UPDATE);
/* call the get info callback for the associated memory index */
memindex = tmap->logical_to_memory[logindex];
(*tmap->tile_get_info)(*(running_machine *)tmap->tile_get_info_object, &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 */
tmap->tileflags[logindex] = tile_draw(tmap, tmap->tileinfo.pen_data + tmap->pen_data_offset, x0, y0,
tmap->tileinfo.palette_base, tmap->tileinfo.category, tmap->tileinfo.group, flags, tmap->tileinfo.pen_mask);
/* 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);
/* track which gfx have been used for this tilemap */
if (tmap->tileinfo.gfxnum != 0xff && (tmap->gfx_used & (1 << tmap->tileinfo.gfxnum)) == 0)
{
tmap->gfx_used |= 1 << tmap->tileinfo.gfxnum;
tmap->gfx_dirtyseq[tmap->tileinfo.gfxnum] = tmap->machine().gfx[tmap->tileinfo.gfxnum]->dirtyseq;
}
g_profiler.stop();
}
/*-------------------------------------------------
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_t *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags, UINT8 pen_mask)
{
const UINT8 *penmap = tmap->pen_to_flags + group * MAX_PEN_TO_FLAGS;
bitmap_t *flagsmap = tmap->flagsmap;
bitmap_t *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 = &pixmap->pix16(y0, x0);
UINT8 *flagsptr = &flagsmap->pix8(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++) & pen_mask;
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) & pen_mask;
map = penmap[pen];
pixptr[xoffs] = palette_base + pen;
flagsptr[xoffs] = map | category;
andmask &= map;
ormask |= map;
xoffs += dx0;
pen = (data >> 4) & pen_mask;
map = penmap[pen];
pixptr[xoffs] = palette_base + 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_t *tmap, const UINT8 *maskdata, UINT32 x0, UINT32 y0, UINT8 category, UINT8 flags)
{
bitmap_t *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 = &flagsmap->pix8(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_t *tmap, bitmap_t *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 = dest->cliprect();
/* set the priority code and alpha */
blit->tilemap_priority_code = priority | (priority_mask << 8) | (tmap->palette_offset << 16);
blit->alpha = (flags & TILEMAP_DRAW_ALPHA_FLAG) ? (flags >> 24) : 0xff;
/* 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 = (blit->alpha < 0xff) ? scanline_draw_masked_rgb32_alpha : scanline_draw_masked_rgb32;
blit->draw_opaque = (blit->alpha < 0xff) ? scanline_draw_opaque_rgb32_alpha : scanline_draw_opaque_rgb32;
break;
case BITMAP_FORMAT_RGB15:
blit->draw_masked = (blit->alpha < 0xff) ? scanline_draw_masked_rgb16_alpha : scanline_draw_masked_rgb16;
blit->draw_opaque = (blit->alpha < 0xff) ? 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);
}
/* don't check category if requested */
if (flags & TILEMAP_DRAW_ALL_CATEGORIES)
{
blit->mask &= ~TILEMAP_PIXEL_CATEGORY_MASK;
blit->value &= ~TILEMAP_PIXEL_CATEGORY_MASK;
}
}
/*-------------------------------------------------
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_t *tmap, const blit_parameters *blit, int xpos, int ypos)
{
bitmap_t *priority_bitmap = tmap->machine().priority_bitmap;
bitmap_t *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 = &priority_bitmap->pix8(y1, xpos);
if (dest != NULL)
{
dest_bytespp = dest->bpp() / 8;
dest_line_pitch_bytes = dest->rowbytes();
dest_baseaddr = dest->raw_pixptr(y1, xpos);
}
/* convert screen coordinates to source tilemap coordinates */
x1 -= xpos;
y1 -= ypos;
x2 -= xpos;
y2 -= ypos;
/* get tilemap pixels */
source_baseaddr = &tmap->pixmap->pix16(y1);
mask_baseaddr = &tmap->flagsmap->pix8(y1);
/* 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, tmap->machine().pens, pmap0, blit->tilemap_priority_code, blit->alpha);
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, tmap->machine().pens, pmap0, blit->tilemap_priority_code, blit->alpha);
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_blend_r32(*(UINT32 *)dest, clut[INPUT_VAL], alpha); \
else if (blit->draw_masked == scanline_draw_masked_rgb16_alpha) \
*(UINT16 *)dest = alpha_blend_r16(*(UINT16 *)dest, clut[INPUT_VAL], alpha); \
} while (0)
static void tilemap_draw_roz_core(tilemap_t *tmap, const blit_parameters *blit,
UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, int wraparound)
{
const pen_t *clut = &tmap->machine().pens[blit->tilemap_priority_code >> 16];
bitmap_t *priority_bitmap = tmap->machine().priority_bitmap;
bitmap_t *destbitmap = blit->bitmap;
bitmap_t *srcbitmap = tmap->pixmap;
bitmap_t *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;
UINT8 alpha = blit->alpha;
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 = &priority_bitmap->pix8(sy, sx);
src = &srcbitmap->pix16(cy);
maskptr = &flagsmap->pix8(cy);
dest = destbitmap->raw_pixptr(sy, sx);
/* 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 = destbitmap->raw_pixptr(sy, sx);
pri = &priority_bitmap->pix8(sy, sx);
/* loop over columns */
while (x <= ex)
{
/* plot if we match the mask */
if ((flagsmap->pix8((cy >> 16) & ymask, (cx >> 16) & xmask) & mask) == value)
{
ROZ_PLOT_PIXEL(srcbitmap->pix16((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 = destbitmap->raw_pixptr(sy, sx);
pri = &priority_bitmap->pix8(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 ((flagsmap->pix8(cy >> 16, cx >> 16) & mask) == value)
{
ROZ_PLOT_PIXEL(srcbitmap->pix16(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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
UINT16 *dest = (UINT16 *)_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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
UINT16 *dest = (UINT16 *)_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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
const pen_t *clut = &pens[pcode >> 16];
UINT16 *dest = (UINT16 *)_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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
const pen_t *clut = &pens[pcode >> 16];
UINT16 *dest = (UINT16 *)_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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
const pen_t *clut = &pens[pcode >> 16];
UINT16 *dest = (UINT16 *)_dest;
int i;
/* priority case */
if ((pcode & 0xffff) != 0xff00)
{
for (i = 0; i < count; i++)
{
dest[i] = alpha_blend_r16(dest[i], clut[source[i]], alpha);
pri[i] = (pri[i] & (pcode >> 8)) | pcode;
}
}
/* no priority case */
else
{
for (i = 0; i < count; i++)
dest[i] = alpha_blend_r16(dest[i], clut[source[i]], alpha);
}
}
/*-------------------------------------------------
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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
const pen_t *clut = &pens[pcode >> 16];
UINT16 *dest = (UINT16 *)_dest;
int i;
/* priority case */
if ((pcode & 0xffff) != 0xff00)
{
for (i = 0; i < count; i++)
if ((maskptr[i] & mask) == value)
{
dest[i] = alpha_blend_r16(dest[i], clut[source[i]], alpha);
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_blend_r16(dest[i], clut[source[i]], alpha);
}
}
/*-------------------------------------------------
scanline_draw_opaque_rgb32 - draw to a 32bpp
RGB bitmap
-------------------------------------------------*/
static void scanline_draw_opaque_rgb32(void *_dest, const UINT16 *source, int count, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
const pen_t *clut = &pens[pcode >> 16];
UINT32 *dest = (UINT32 *)_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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
const pen_t *clut = &pens[pcode >> 16];
UINT32 *dest = (UINT32 *)_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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
const pen_t *clut = &pens[pcode >> 16];
UINT32 *dest = (UINT32 *)_dest;
int i;
/* priority case */
if ((pcode & 0xffff) != 0xff00)
{
for (i = 0; i < count; i++)
{
dest[i] = alpha_blend_r32(dest[i], clut[source[i]], alpha);
pri[i] = (pri[i] & (pcode >> 8)) | pcode;
}
}
/* no priority case */
else
{
for (i = 0; i < count; i++)
dest[i] = alpha_blend_r32(dest[i], clut[source[i]], alpha);
}
}
/*-------------------------------------------------
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, const pen_t *pens, UINT8 *pri, UINT32 pcode, UINT8 alpha)
{
const pen_t *clut = &pens[pcode >> 16];
UINT32 *dest = (UINT32 *)_dest;
int i;
/* priority case */
if ((pcode & 0xffff) != 0xff00)
{
for (i = 0; i < count; i++)
if ((maskptr[i] & mask) == value)
{
dest[i] = alpha_blend_r32(dest[i], clut[source[i]], alpha);
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_blend_r32(dest[i], clut[source[i]], alpha);
}
}