mirror of
https://github.com/holub/mame
synced 2025-05-07 14:54:35 +03:00

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]
2339 lines
70 KiB
C
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);
|
|
}
|
|
}
|