// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
tilemap.h
Generic tilemap management system.
****************************************************************************
Core concepts:
Tilemap = a 2-dimensional array of tiles; each tile has its own
independent characteristics which describe how that tile is
rendered. A tilemap is described by the number of rows and
columns in the map. Each tile in the tilemap is a fixed size
specified as width and height in pixels.
Tile = a single rectangular element in a tilemap; tiles can be
any size, but all tiles in a tilemap are the same size. Each
tile is described by the following parameters:
pen_data (required): pointer to an array of 8bpp pen data
describing the raw pixels to be rendered for a tile;
for example, an 8x8 tile requires 64 bytes of pen_data
palette_base (required): the base index in the global palette;
each pixel fetched from pen_data will have this base added
to it before it is stored in the pixmap
mask_data (optional): pointer to an array of 1bpp mask data
which controls which pixels are to be considered visible
or transparent (part of no layer); data is packed MSB
first with no padding, so an 8x8 tile requires 64 bits or
8 bytes data
category (optional): specifies one of 16 categories for the
pixels in the tile; the category controls which tiles are
rendered during a tilemap::draw() call
group (optional): specifies one of 256 groups for pen mapping;
each pen in the tile is looked up in a table to determine
which layer(s) it belongs to, and the group selects one of
256 different tables to use for this mapping
flags (optional): specifies one or more of the following bits:
TILE_FLIPX means render the tile flipped horizontally
TILE_FLIPY means render the tile flipped vertically
TILE_FORCE_LAYERn means all pixels are forced to be in
layer n, where n = 0,1,2
Pen = another name for pixel value; tilemap graphics are either
4 or 8 bits per pixel, meaning that pen values range from
0-15 (4bpp) or 0-255 (8bpp).
Logical index = index of a tile in a tilemap, assuming perfect
packing in row-major order; this is always equal to
(rownum * tilemap_columns + colnum).
Memory index = index of a tile in memory; this often does not
map 1:1 to the logical index (though it can). A mapper
function is provided when creating a new tilemap that can
map from (column,row) to memory index.
Layer = one of 3 categories each pixel can belong to, based on
the pens in a tile; traditionally, layer 0 is the only
one used. If a pixel does not belong to any layers, it is
considered transparent.
Group = one of 256 per-tile selectable means of mapping from
pens to layers; traditionally only group 0 is used.
Category = a 4-bit value specified per-tile which allows for
separating tiles into categories which can be rendered
independently.
Pixmap = a 16bpp bitmap containing the full tilemap with
all tiles rendered.
Flagsmap = an 8bpp bitmap containing per-pixel flags,
specifically the category (specified in bits 0-3) and the
layer (specified in bits 4-6).
****************************************************************************
How to use a tilemap:
1. First create a new tilemap by calling tilemap_manager::create().
The parameters are as follows:
decoder = reference to your device_gfx_interface; note that the
graphics the tilemap will use do not have to be decoded
first, but the decoder must be ready to provide a palette,
which means device_missing_dependencies must be thrown if
the decoder has not already started
tile_get_info = callback function which accepts a memory index
and in return fills in a tile_data structure that describes
the characteristics of a tile; this function will be called
whenever a dirty tile needs to be rendered
mapper = callback function which maps the logical column and row
to a memory index; several standard mappers are provided,
with TILEMAP_SCAN_ROWS being the most common
tilewidth = the width, in pixels, of each individual tile
tileheight = the height, in pixels, of each individual tile
cols = the number of columns in the tilemap
rows = the number of rows in the tilemap
2. Once you have created your tilemap, you need to configure it.
Common configuration tasks include:
* marking one of the pens as transparent via
tilemap_t::set_transparent_pen()
* performing more complex pen-to-layer mapping via
tilemap_t::map_pen_to_layer() or
tilemap_t::map_pens_to_layer()
* configuring global scroll offsets via
tilemap_t::set_scrolldx() and tilemap_t::set_scrolldy()
* specifying a pointer that can be read back later (e.g. in
your tile_get_info callback) via
tilemap_t::set_user_data()
* setting a global palette offset via
tilemap_t::set_palette_offset()
3. In your memory write handlers for the tile memory, anytime tile
data is modified, you need to mark the tile dirty so that it is
re-rendered with the new data the next time the tilemap is drawn.
Use tilemap_t::mark_tile_dirty() and pass in the memory index.
4. In your handlers for scrolling, update the scroll values for the
tilemap via tilemap_t::set_scrollx() and tilemap_t::set_scrolly().
5. If any other major characteristics of the tilemap change (generally
any global state that is used by the tile_get_info callback but
which is not reported via other calls to the tilemap code), you
should invalidate the entire tilemap. You can do this by calling
tilemap_t::mark_all_dirty().
6. In your VIDEO_UPDATE callback, render the tiles by calling
tilemap_t::draw() or tilemap_t::draw_roz(). If you need to do
custom rendering and want access to the raw pixels, call
tilemap_t::pixmap() to get a reference to the updated bitmap_ind16
containing the tilemap graphics.
****************************************************************************
The following example shows how to use the tilemap system to create
a simple tilemap where pen 0 is transparent. Each tile is 8x8 pixels
in size, and there are 32 rows and 64 columns, stored in row-major
order. Based on bits in the tile memory, tiles can be drawn either
behind or in front of sprites.
tilemap_t *tmap;
u16 *my_tmap_memory;
required_device<gfxdecode_device> gfxdecode;
TILE_GET_INFO_MEMBER( my_state::my_get_info )
{
u16 tiledata = my_tmap_memory[tile_index];
u8 code = tiledata & 0xff;
u8 color = (tiledata >> 8) & 0x1f;
u8 flipx = (tiledata >> 13) & 1;
u8 flipy = (tiledata >> 14) & 1;
u8 category = (tiledata >> 15) & 1;
// set the common info for the tile
tileinfo.set(
1, // use gfxdecode->gfx(1) for tile graphics
code, // the index of the graphics for this tile
color, // the color to use for this tile
(flipx ? TILE_FLIPX : 0) | // flags for this tile; also
(flipy ? TILE_FLIPY : 0) // see the FLIP_YX macro
);
// set the category of each tile based on the high bit; this
// allows us to draw each category independently
tileinfo.category = category;
}
VIDEO_START_MEMBER( my_state, my_driver )
{
// first create the tilemap
tmap = &machine().tilemap().create(
gfxdecode,
tilemap_get_info_delegate(FUNC(my_state::my_get_info), this),
TILEMAP_SCAN_ROWS, // standard row-major mapper
8,8, // 8x8 tiles
64,32); // 64 columns, 32 rows
// then set the transparent pen; all other pens will default
// to being part of layer 0
tmap.set_transparent_pen(0);
}
u32 my_state::screen_update_mydriver(
screen_device &screen,
bitmap_ind16 &bitmap,
const rectangle &cliprect)
{
// draw the tilemap first, fully opaque since it needs to
// erase all previous pixels
tmap->draw(
screen, // destination screen
bitmap, // destination bitmap
cliprect, // clipping rectangle
TILEMAP_DRAW_OPAQUE); // flags
// next draw the sprites
my_draw_sprites();
// then draw the tiles which have priority over sprites
tmap->draw(
screen, // destination screen
bitmap, // destination bitmap
cliprect, // clipping rectangle
TILEMAP_DRAW_CATEGORY(1));// flags: draw category 1
return 0;
}
****************************************************************************
Tilemap techniques:
* The previous tilemap code specified a number of different tilemap
types that were fundamentally similar. This has been collapsed
into just two types now. Here is how to replicate that
functionality with the new system:
TILEMAP_OPAQUE: If you want a tilemap with no transparency,
you don't need to do anything; by default all pens map to
layer 0 and are thus non-transparent. Note that a lot of
code used to create OPAQUE tilemaps and then set the
transparent pen for them; this no longer works.
TILEMAP_TRANSPARENT: This described a tilemap with a single
transparent pen. To create the same effect, call
tilemap_t::set_transparent_pen() to specify which pen is
transparent; all other pens will map to layer 0.
TILEMAP_BITMASK: This type is no longer special; with the new
code, any tile_get_info callback can specify a bitmask which
will be processed after rendering to make some pixels
transparent.
TILEMAP_SPLIT: This type used to let you map pens into two
layers (called "front" and "back") based on their pens. It
also allowed for you to choose one of 4 mappings on a per-tile
basis. All of this functionality is now expanded: you can
specify one of 3 layers and can choose from one of 256 mappings
on a per-tile basis. You just call tilemap_t::set_transmask(),
which still exists but maps onto the new behavior. The "front"
layer is now "layer 0" and the "back" layer is now "layer 1".
TILEMAP_SPLIT_PENBIT: This type was only used in one driver
and is not worth describing in detail how the new mapping
works. :)
* By far the most common usage of layers is the simplest: layer 0 is
the only one used and rendered. If you want a particular tile to
render opaque, you can set the TILE_FORCE_LAYER0 file in your
tile_get_info callback.
* When drawing, you can specify in the flags which classes of pixels
to draw. In the low 4 bits, you specify the category; this must
match exactly the category specified for the tile in order to
render. In addition, the flags TILEMAP_DRAW_LAYERn allow you to
control which layer pattern to draw; note that combining these
flags may produce interesting results. Specifying both layer 0
and layer 1 will render only pixels that are in *both* layers.
If you want to render everything, regardless of layer, specify
the TILEMAP_DRAW_OPAQUE flag. If you don't specify any layers,
TILEMAP_DRAW_LAYER0 is assumed.
* If you want to render with alpha blending, you can call
tilemap_t::draw() with the TILEMAP_DRAW_ALPHA flag.
* To configure more complex pen-to-layer mapping, use the
tilemap_t::map_pens_to_layer() call. This call takes a group
number so that you can configure 1 of the 256 groups
independently. It also takes a pen and a mask; the mapping is
updated for all pens where ((pennum & mask) == pen). To set all
the pens in a group to the same value, pass a mask of 0. To set
a single pen in a group, pass a mask of ~0. The helper function
tilemap_t::map_pen_to_layer() does this for you.
***************************************************************************/
#pragma once
#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif
#ifndef MAME_EMU_TILEMAP_H
#define MAME_EMU_TILEMAP_H
//**************************************************************************
// CONSTANTS
//**************************************************************************
// maximum number of groups
constexpr size_t TILEMAP_NUM_GROUPS = 256;
// these flags control tilemap_t::draw() behavior
constexpr u32 TILEMAP_DRAW_CATEGORY_MASK = 0x0f; // specify the category to draw
constexpr u32 TILEMAP_DRAW_LAYER0 = 0x10; // draw layer 0
constexpr u32 TILEMAP_DRAW_LAYER1 = 0x20; // draw layer 1
constexpr u32 TILEMAP_DRAW_LAYER2 = 0x40; // draw layer 2
constexpr u32 TILEMAP_DRAW_OPAQUE = 0x80; // draw everything, even transparent stuff
constexpr u32 TILEMAP_DRAW_ALPHA_FLAG = 0x100; // draw with alpha blending (in the upper 8 bits)
constexpr u32 TILEMAP_DRAW_ALL_CATEGORIES = 0x200; // draw all categories
// per-pixel flags in the transparency_bitmap
constexpr u8 TILEMAP_PIXEL_CATEGORY_MASK = 0x0f; // category is stored in the low 4 bits
constexpr u8 TILEMAP_PIXEL_TRANSPARENT = 0x00; // transparent if in none of the layers below
constexpr u8 TILEMAP_PIXEL_LAYER0 = 0x10; // pixel is opaque in layer 0
constexpr u8 TILEMAP_PIXEL_LAYER1 = 0x20; // pixel is opaque in layer 1
constexpr u8 TILEMAP_PIXEL_LAYER2 = 0x40; // pixel is opaque in layer 2
// per-tile flags, set by get_tile_info callback
constexpr u8 TILE_FLIPX = 0x01; // draw this tile horizontally flipped
constexpr u8 TILE_FLIPY = 0x02; // draw this tile vertically flipped
constexpr u8 TILE_FORCE_LAYER0 = TILEMAP_PIXEL_LAYER0; // force all pixels to be layer 0 (no transparency)
constexpr u8 TILE_FORCE_LAYER1 = TILEMAP_PIXEL_LAYER1; // force all pixels to be layer 1 (no transparency)
constexpr u8 TILE_FORCE_LAYER2 = TILEMAP_PIXEL_LAYER2; // force all pixels to be layer 2 (no transparency)
// tilemap global flags, used by tilemap_t::set_flip()
constexpr u32 TILEMAP_FLIPX = TILE_FLIPX; // draw the tilemap horizontally flipped
constexpr u32 TILEMAP_FLIPY = TILE_FLIPY; // draw the tilemap vertically flipped
// set this value for a scroll row/column to fully disable it
constexpr u32 TILE_LINE_DISABLED = 0x80000000;
// standard mappers
enum tilemap_standard_mapper
{
TILEMAP_SCAN_ROWS = 0,
TILEMAP_SCAN_ROWS_FLIP_X,
TILEMAP_SCAN_ROWS_FLIP_Y,
TILEMAP_SCAN_ROWS_FLIP_XY,
TILEMAP_SCAN_COLS,
TILEMAP_SCAN_COLS_FLIP_X,
TILEMAP_SCAN_COLS_FLIP_Y,
TILEMAP_SCAN_COLS_FLIP_XY,
TILEMAP_STANDARD_COUNT
};
//**************************************************************************
// DEVICE CONFIGURATION MACROS
//**************************************************************************
// primitives
#define MCFG_TILEMAP_ADD(_tag) \
MCFG_DEVICE_ADD(_tag, TILEMAP)
#define MCFG_TILEMAP_GFXDECODE(_gfxtag) \
downcast<tilemap_device &>(*device).set_gfxdecode(_gfxtag);
#define MCFG_TILEMAP_BYTES_PER_ENTRY(_bpe) \
downcast<tilemap_device &>(*device).set_bytes_per_entry(_bpe);
#define MCFG_TILEMAP_INFO_CB_DRIVER(_class, _method) \
downcast<tilemap_device &>(*device).set_info_callback(tilemap_get_info_delegate(&_class::_method, #_class "::" #_method, nullptr, (_class *)nullptr));
#define MCFG_TILEMAP_INFO_CB_DEVICE(_device, _class, _method) \
downcast<tilemap_device &>(*device).set_info_callback(tilemap_get_info_delegate(&_class::_method, #_class "::" #_method, _device, (_class *)nullptr));
#define MCFG_TILEMAP_LAYOUT_STANDARD(_standard, _columns, _rows) \
downcast<tilemap_device &>(*device).set_layout(TILEMAP_##_standard, _columns, _rows);
#define MCFG_TILEMAP_LAYOUT_CB_DRIVER(_class, _method, _columns, _rows) \
downcast<tilemap_device &>(*device).set_layout(tilemap_mapper_delegate(&_class::_method, #_class "::" #_method, nullptr, (_class *)nullptr), _columns, _rows);
#define MCFG_TILEMAP_LAYOUT_CB_DEVICE(_device, _class, _method, _columns, _rows) \
downcast<tilemap_device &>(*device).set_layout(tilemap_mapper_delegate(&_class::_method, #_class "::" #_method, _device, (_class *)nullptr), _columns, _rows);
#define MCFG_TILEMAP_TILE_SIZE(_width, _height) \
downcast<tilemap_device &>(*device).set_tile_size(_width, _height);
#define MCFG_TILEMAP_TRANSPARENT_PEN(_pen) \
downcast<tilemap_device &>(*device).set_configured_transparent_pen(_pen);
// common cases
#define MCFG_TILEMAP_ADD_STANDARD(_tag, _gfxtag, _bytes_per_entry, _class, _method, _tilewidth, _tileheight, _mapper, _columns, _rows) \
MCFG_TILEMAP_ADD(_tag) \
MCFG_TILEMAP_GFXDECODE(_gfxtag) \
MCFG_TILEMAP_BYTES_PER_ENTRY(_bytes_per_entry) \
MCFG_TILEMAP_INFO_CB_DRIVER(_class, _method) \
MCFG_TILEMAP_LAYOUT_STANDARD(_mapper, _columns, _rows) \
MCFG_TILEMAP_TILE_SIZE(_tilewidth, _tileheight)
#define MCFG_TILEMAP_ADD_CUSTOM(_tag, _gfxtag, _bytes_per_entry, _class, _method, _tilewidth, _tileheight, _mapper, _columns, _rows) \
MCFG_TILEMAP_ADD(_tag) \
MCFG_TILEMAP_GFXDECODE(_gfxtag) \
MCFG_TILEMAP_BYTES_PER_ENTRY(_bytes_per_entry) \
MCFG_TILEMAP_INFO_CB_DRIVER(_class, _method) \
MCFG_TILEMAP_LAYOUT_CB_DRIVER(_class, _mapper, _columns, _rows) \
MCFG_TILEMAP_TILE_SIZE(_tilewidth, _tileheight)
#define MCFG_TILEMAP_ADD_STANDARD_TRANSPEN(_tag, _gfxtag, _bytes_per_entry, _class, _method, _tilewidth, _tileheight, _mapper, _columns, _rows, _transpen) \
MCFG_TILEMAP_ADD(_tag) \
MCFG_TILEMAP_GFXDECODE(_gfxtag) \
MCFG_TILEMAP_BYTES_PER_ENTRY(_bytes_per_entry) \
MCFG_TILEMAP_INFO_CB_DRIVER(_class, _method) \
MCFG_TILEMAP_LAYOUT_STANDARD(_mapper, _columns, _rows) \
MCFG_TILEMAP_TILE_SIZE(_tilewidth, _tileheight) \
MCFG_TILEMAP_TRANSPARENT_PEN(_transpen)
#define MCFG_TILEMAP_ADD_CUSTOM_TRANSPEN(_tag, _gfxtag, _bytes_per_entry, _class, _method, _tilewidth, _tileheight, _mapper, _columns, _rows, _transpen) \
MCFG_TILEMAP_ADD(_tag) \
MCFG_TILEMAP_GFXDECODE(_gfxtag) \
MCFG_TILEMAP_BYTES_PER_ENTRY(_bytes_per_entry) \
MCFG_TILEMAP_INFO_CB_DRIVER(_class, _method) \
MCFG_TILEMAP_LAYOUT_CB_DRIVER(_columns, _mapper, _rows, _class) \
MCFG_TILEMAP_TILE_SIZE(_tilewidth, _tileheight) \
MCFG_TILEMAP_TRANSPARENT_PEN(_transpen)
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// global types
typedef u32 tilemap_memory_index;
// tile_data is filled in by the get_tile_info callback
struct tile_data
{
device_gfx_interface *decoder; // set in tilemap_t::init()
const u8 * pen_data; // required
const u8 * mask_data; // required
pen_t palette_base; // defaults to 0
u8 category; // defaults to 0; range from 0..15
u8 group; // defaults to 0; range from 0..TILEMAP_NUM_GROUPS
u8 flags; // defaults to 0; one or more of TILE_* flags above
u8 pen_mask; // defaults to 0xff; mask to apply to pen_data while rendering the tile
u8 gfxnum; // defaults to 0xff; specify index of gfx for auto-invalidation on dirty
u32 code;
void set(u8 _gfxnum, u32 rawcode, u32 rawcolor, u8 _flags)
{
gfx_element *gfx = decoder->gfx(_gfxnum);
code = rawcode % gfx->elements();
pen_data = gfx->get_data(code);
palette_base = gfx->colorbase() + gfx->granularity() * (rawcolor % gfx->colors());
flags = _flags;
gfxnum = _gfxnum;
}
};
// modern delegates
typedef device_delegate<void (tilemap_t &, tile_data &, tilemap_memory_index)> tilemap_get_info_delegate;
typedef device_delegate<tilemap_memory_index (u32, u32, u32, u32)> tilemap_mapper_delegate;
// ======================> tilemap_t
// core tilemap structure
class tilemap_t
{
DISABLE_COPYING(tilemap_t);
friend class tilemap_device;
friend class tilemap_manager;
friend class simple_list<tilemap_t>;
friend resource_pool_object<tilemap_t>::~resource_pool_object();
// logical index
typedef u32 logical_index;
// internal usage to mark tiles dirty
static const u8 TILE_FLAG_DIRTY = 0xff;
// invalid logical index
static const logical_index INVALID_LOGICAL_INDEX = (logical_index)~0;
// maximum index in each array
static const pen_t MAX_PEN_TO_FLAGS = 256;
protected:
// tilemap_manager controls our allocations
tilemap_t();
virtual ~tilemap_t();
tilemap_t &init(tilemap_manager &manager, device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_mapper_delegate mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows);
public:
// getters
running_machine &machine() const;
tilemap_device *device() const { return m_device; }
device_palette_interface &palette() const { return *m_palette; }
device_gfx_interface &decoder() const { return *m_tileinfo.decoder; }
tilemap_t *next() const { return m_next; }
void *user_data() const { return m_user_data; }
u32 rows() const { return m_rows; }
u32 cols() const { return m_cols; }
u16 tilewidth() const { return m_tilewidth; }
u16 tileheight() const { return m_tileheight; }
u32 width() const { return m_width; }
u32 height() const { return m_height; }
bool enabled() const { return m_enable; }
u32 palette_offset() const { return m_palette_offset; }
int scrolldx() const { return (m_attributes & TILEMAP_FLIPX) ? m_dx_flipped : m_dx; }
int scrolldy() const { return (m_attributes & TILEMAP_FLIPY) ? m_dy_flipped : m_dy; }
int scrollx(int which = 0) const { return (which < m_scrollrows) ? m_rowscroll[which] : 0; }
int scrolly(int which = 0) const { return (which < m_scrollcols) ? m_colscroll[which] : 0; }
bitmap_ind16 &pixmap() { pixmap_update(); return m_pixmap; }
bitmap_ind8 &flagsmap() { pixmap_update(); return m_flagsmap; }
u8 *tile_flags() { pixmap_update(); return &m_tileflags[0]; }
tilemap_memory_index memory_index(u32 col, u32 row) { return m_mapper(col, row, m_cols, m_rows); }
void get_info_debug(u32 col, u32 row, u8 &gfxnum, u32 &code, u32 &color);
// setters
void enable(bool enable = true) { m_enable = enable; }
void set_user_data(void *user_data) { m_user_data = user_data; }
void set_palette(device_palette_interface &palette) { m_palette = &palette; }
void set_palette_offset(u32 offset) { m_palette_offset = offset; }
void set_scrolldx(int dx, int dx_flipped) { m_dx = dx; m_dx_flipped = dx_flipped; }
void set_scrolldy(int dy, int dy_flipped) { m_dy = dy; m_dy_flipped = dy_flipped; }
void set_scrollx(int which, int value) { if (which < m_scrollrows) m_rowscroll[which] = value; }
void set_scrolly(int which, int value) { if (which < m_scrollcols) m_colscroll[which] = value; }
void set_scrollx(int value) { set_scrollx(0, value); }
void set_scrolly(int value) { set_scrolly(0, value); }
void set_scroll_rows(u32 scroll_rows) { assert(scroll_rows <= m_height); m_scrollrows = scroll_rows; }
void set_scroll_cols(u32 scroll_cols) { assert(scroll_cols <= m_width); m_scrollcols = scroll_cols; }
void set_flip(u32 attributes) { if (m_attributes != attributes) { m_attributes = attributes; mappings_update(); } }
// dirtying
void mark_mapping_dirty() { mappings_update(); }
void mark_tile_dirty(tilemap_memory_index memindex);
void mark_all_dirty() { m_all_tiles_dirty = true; m_all_tiles_clean = false; }
// pen mapping
void map_pens_to_layer(int group, pen_t pen, pen_t mask, u8 layermask);
void map_pen_to_layer(int group, pen_t pen, u8 layermask) { map_pens_to_layer(group, pen, ~0, layermask); }
void set_transparent_pen(pen_t pen);
void set_transmask(int group, u32 fgmask, u32 bgmask);
void configure_groups(gfx_element &gfx, indirect_pen_t transcolor);
// drawing
void draw(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect, u32 flags, u8 priority = 0, u8 priority_mask = 0xff);
void draw(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, u32 flags, u8 priority = 0, u8 priority_mask = 0xff);
void draw_roz(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect, u32 startx, u32 starty, int incxx, int incxy, int incyx, int incyy, bool wraparound, u32 flags, u8 priority = 0, u8 priority_mask = 0xff);
void draw_roz(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, u32 startx, u32 starty, int incxx, int incxy, int incyx, int incyy, bool wraparound, u32 flags, u8 priority = 0, u8 priority_mask = 0xff);
void draw_debug(screen_device &screen, bitmap_rgb32 &dest, u32 scrollx, u32 scrolly, u32 flags = TILEMAP_DRAW_ALL_CATEGORIES);
// mappers
// scan in row-major order with optional flipping
tilemap_memory_index scan_rows(u32 col, u32 row, u32 num_cols, u32 num_rows);
tilemap_memory_index scan_rows_flip_x(u32 col, u32 row, u32 num_cols, u32 num_rows);
tilemap_memory_index scan_rows_flip_y(u32 col, u32 row, u32 num_cols, u32 num_rows);
tilemap_memory_index scan_rows_flip_xy(u32 col, u32 row, u32 num_cols, u32 num_rows);
// scan in column-major order with optional flipping
tilemap_memory_index scan_cols(u32 col, u32 row, u32 num_cols, u32 num_rows);
tilemap_memory_index scan_cols_flip_x(u32 col, u32 row, u32 num_cols, u32 num_rows);
tilemap_memory_index scan_cols_flip_y(u32 col, u32 row, u32 num_cols, u32 num_rows);
tilemap_memory_index scan_cols_flip_xy(u32 col, u32 row, u32 num_cols, u32 num_rows);
private:
// internal set of transparency states for rendering
enum trans_t
{
WHOLLY_TRANSPARENT,
WHOLLY_OPAQUE,
MASKED
};
// blitting parameters for rendering
struct blit_parameters
{
bitmap_ind8 * priority;
rectangle cliprect;
u32 tilemap_priority_code;
u8 mask;
u8 value;
u8 alpha;
};
// inline helpers
s32 effective_rowscroll(int index, u32 screen_width);
s32 effective_colscroll(int index, u32 screen_height);
bool gfx_elements_changed();
// inline scanline rasterizers
void scanline_draw_opaque_null(int count, u8 *pri, u32 pcode);
void scanline_draw_masked_null(const u8 *maskptr, int mask, int value, int count, u8 *pri, u32 pcode);
void scanline_draw_opaque_ind16(u16 *dest, const u16 *source, int count, u8 *pri, u32 pcode);
void scanline_draw_masked_ind16(u16 *dest, const u16 *source, const u8 *maskptr, int mask, int value, int count, u8 *pri, u32 pcode);
void scanline_draw_opaque_rgb32(u32 *dest, const u16 *source, int count, const rgb_t *pens, u8 *pri, u32 pcode);
void scanline_draw_masked_rgb32(u32 *dest, const u16 *source, const u8 *maskptr, int mask, int value, int count, const rgb_t *pens, u8 *pri, u32 pcode);
void scanline_draw_opaque_rgb32_alpha(u32 *dest, const u16 *source, int count, const rgb_t *pens, u8 *pri, u32 pcode, u8 alpha);
void scanline_draw_masked_rgb32_alpha(u32 *dest, const u16 *source, const u8 *maskptr, int mask, int value, int count, const rgb_t *pens, u8 *pri, u32 pcode, u8 alpha);
// internal helpers
void postload();
void mappings_create();
void mappings_update();
void realize_all_dirty_tiles();
// internal drawing
void pixmap_update();
void tile_update(logical_index logindex, u32 col, u32 row);
u8 tile_draw(const u8 *pendata, u32 x0, u32 y0, u32 palette_base, u8 category, u8 group, u8 flags, u8 pen_mask);
u8 tile_apply_bitmask(const u8 *maskdata, u32 x0, u32 y0, u8 category, u8 flags);
void configure_blit_parameters(blit_parameters &blit, bitmap_ind8 &priority_bitmap, const rectangle &cliprect, u32 flags, u8 priority, u8 priority_mask);
template<class _BitmapClass> void draw_common(screen_device &screen, _BitmapClass &dest, const rectangle &cliprect, u32 flags, u8 priority, u8 priority_mask);
template<class _BitmapClass> void draw_roz_common(screen_device &screen, _BitmapClass &dest, const rectangle &cliprect, u32 startx, u32 starty, int incxx, int incxy, int incyx, int incyy, bool wraparound, u32 flags, u8 priority, u8 priority_mask);
template<class _BitmapClass> void draw_instance(screen_device &screen, _BitmapClass &dest, const blit_parameters &blit, int xpos, int ypos);
template<class _BitmapClass> void draw_roz_core(screen_device &screen, _BitmapClass &destbitmap, const blit_parameters &blit, u32 startx, u32 starty, int incxx, int incxy, int incyx, int incyy, bool wraparound);
// managers and devices
tilemap_manager * m_manager; // reference to the owning manager
tilemap_device * m_device; // pointer to our owning device
device_palette_interface * m_palette; // palette used for drawing
tilemap_t * m_next; // pointer to next tilemap
void * m_user_data; // user data value
// basic tilemap metrics
u32 m_rows; // number of tile rows
u32 m_cols; // number of tile columns
u16 m_tilewidth; // width of a single tile in pixels
u16 m_tileheight; // height of a single tile in pixels
u32 m_width; // width of the full tilemap in pixels
u32 m_height; // height of the full tilemap in pixels
// logical <-> memory mappings
tilemap_mapper_delegate m_mapper; // callback to map a row/column to a memory index
std::vector<logical_index> m_memory_to_logical; // map from memory index to logical index
std::vector<tilemap_memory_index> m_logical_to_memory; // map from logical index to memory index
// callback to interpret video RAM for the tilemap
tilemap_get_info_delegate m_tile_get_info; // callback to get information about a tile
tile_data m_tileinfo; // structure to hold the data for a tile
// global tilemap states
bool m_enable; // true if we are enabled
u8 m_attributes; // global attributes (flipx/y)
bool m_all_tiles_dirty; // true if all tiles are dirty
bool m_all_tiles_clean; // true if all tiles are clean
u32 m_palette_offset; // palette offset
u32 m_gfx_used; // bitmask of gfx items used
u32 m_gfx_dirtyseq[MAX_GFX_ELEMENTS]; // dirtyseq values from last check
// scroll information
u32 m_scrollrows; // number of independently scrolled rows
u32 m_scrollcols; // number of independently scrolled columns
std::vector<s32> m_rowscroll; // array of rowscroll values
std::vector<s32> m_colscroll; // array of colscroll values
s32 m_dx; // global horizontal scroll offset
s32 m_dx_flipped; // global horizontal scroll offset when flipped
s32 m_dy; // global vertical scroll offset
s32 m_dy_flipped; // global vertical scroll offset when flipped
// pixel data
bitmap_ind16 m_pixmap; // cached pixel data
// transparency mapping
bitmap_ind8 m_flagsmap; // per-pixel flags
std::vector<u8> m_tileflags; // per-tile flags
u8 m_pen_to_flags[MAX_PEN_TO_FLAGS * TILEMAP_NUM_GROUPS]; // mapping of pens to flags
};
// ======================> tilemap_manager
// tilemap manager
class tilemap_manager
{
friend class tilemap_t;
public:
// construction/destruction
tilemap_manager(running_machine &machine);
~tilemap_manager();
// getters
running_machine &machine() const { return m_machine; }
// tilemap creation
tilemap_t &create(device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_mapper_delegate mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows, tilemap_t *allocated = nullptr);
tilemap_t &create(device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_standard_mapper mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows, tilemap_t *allocated = nullptr);
// tilemap list information
tilemap_t *find(int index) { return m_tilemap_list.find(index); }
int count() const { return m_tilemap_list.count(); }
// global operations on all tilemaps
void mark_all_dirty();
void set_flip_all(u32 attributes);
private:
// allocate an instance index
int alloc_instance() { return ++m_instance; }
// internal state
running_machine & m_machine;
simple_list<tilemap_t> m_tilemap_list;
int m_instance;
};
// ======================> tilemap_device
// device type definition
DECLARE_DEVICE_TYPE(TILEMAP, tilemap_device)
class tilemap_device : public device_t,
public tilemap_t
{
public:
template <typename T>
tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&gfxtag, int entrybytes
, u16 tilewidth, u16 tileheight, tilemap_standard_mapper mapper, u32 columns, u32 rows, pen_t transpen)
: tilemap_device(mconfig, tag, owner, (u32)0)
{
set_gfxdecode(std::forward<T>(gfxtag));
set_bytes_per_entry(entrybytes);
set_layout(mapper, columns, rows);
set_tile_size(tilewidth, tileheight);
set_configured_transparent_pen(transpen);
}
template <typename T>
tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&gfxtag, int entrybytes
, u16 tilewidth, u16 tileheight, tilemap_standard_mapper mapper, u32 columns, u32 rows)
: tilemap_device(mconfig, tag, owner, (u32)0)
{
set_gfxdecode(std::forward<T>(gfxtag));
set_bytes_per_entry(entrybytes);
set_layout(mapper, columns, rows);
set_tile_size(tilewidth, tileheight);
}
tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
template <typename T> void set_gfxdecode(T &&tag) { m_gfxdecode.set_tag(std::forward<T>(tag)); }
void set_bytes_per_entry(int bpe) { m_bytes_per_entry = bpe; }
void set_info_callback(tilemap_get_info_delegate tile_get_info) { m_get_info = tile_get_info; }
template <class FunctionClass> void set_info_callback(const char *devname, void (FunctionClass::*callback)(tilemap_t &, tile_data &, tilemap_memory_index), const char *name)
{
set_info_callback(tilemap_get_info_delegate(callback, name, devname, static_cast<FunctionClass *>(nullptr)));
}
template <class FunctionClass> void set_info_callback(void (FunctionClass::*callback)(tilemap_t &, tile_data &, tilemap_memory_index), const char *name)
{
set_info_callback(tilemap_get_info_delegate(callback, name, nullptr, static_cast<FunctionClass *>(nullptr)));
}
void set_layout(tilemap_standard_mapper mapper, u32 columns, u32 rows) {
m_standard_mapper = mapper;
m_num_columns = columns;
m_num_rows = rows;
}
void set_layout(tilemap_mapper_delegate mapper, u32 columns, u32 rows) {
m_standard_mapper = TILEMAP_STANDARD_COUNT;
m_mapper = mapper;
m_num_columns = columns;
m_num_rows = rows;
}
void set_tile_size(u16 width, u16 height) { m_tile_width = width; m_tile_height = height; }
void set_configured_transparent_pen(pen_t pen) { m_transparent_pen_set = true; m_transparent_pen = pen; }
// getters
memory_array &basemem() { return m_basemem; }
memory_array &extmem() { return m_extmem; }
// write handlers
DECLARE_WRITE8_MEMBER(write8);
DECLARE_WRITE16_MEMBER(write16);
DECLARE_WRITE32_MEMBER(write32);
DECLARE_WRITE8_MEMBER(write8_ext);
DECLARE_WRITE16_MEMBER(write16_ext);
DECLARE_WRITE32_MEMBER(write32_ext);
// optional memory accessors
u32 basemem_read(int index) { return m_basemem.read(index); }
u32 extmem_read(int index) { return m_extmem.read(index); }
void basemem_write(int index, u32 data) { m_basemem.write(index, data); mark_tile_dirty(index); }
void extmem_write(int index, u32 data) { m_extmem.write(index, data); mark_tile_dirty(index); }
// pick one to use to avoid ambiguity errors
using device_t::machine;
protected:
// device-level overrides
virtual void device_start() override;
private:
// devices
required_device<gfxdecode_device> m_gfxdecode;
// configuration state
tilemap_get_info_delegate m_get_info;
tilemap_standard_mapper m_standard_mapper;
tilemap_mapper_delegate m_mapper;
int m_bytes_per_entry;
u16 m_tile_width;
u16 m_tile_height;
u32 m_num_columns;
u32 m_num_rows;
bool m_transparent_pen_set;
pen_t m_transparent_pen;
// optional memory info
memory_array m_basemem; // info about base memory
memory_array m_extmem; // info about extension memory
};
//**************************************************************************
// MACROS
//**************************************************************************
// macros to help form flags for tilemap_t::draw
#define TILEMAP_DRAW_CATEGORY(x) (x) // specify category to draw
#define TILEMAP_DRAW_ALPHA(x) (TILEMAP_DRAW_ALPHA_FLAG | (rgb_t::clamp(x) << 24))
// function definition for a get info callback
#define TILE_GET_INFO_MEMBER(_name) void _name(tilemap_t &tilemap, tile_data &tileinfo, tilemap_memory_index tile_index)
// function definition for a logical-to-memory mapper
#define TILEMAP_MAPPER_MEMBER(_name) tilemap_memory_index _name(u32 col, u32 row, u32 num_cols, u32 num_rows)
// useful macro inside of a TILE_GET_INFO callback to set tile information
#define SET_TILE_INFO_MEMBER(GFX,CODE,COLOR,FLAGS) tileinfo.set(GFX, CODE, COLOR, FLAGS)
// Macros for setting tile attributes in the TILE_GET_INFO callback:
// TILE_FLIP_YX assumes that flipy is in bit 1 and flipx is in bit 0
// TILE_FLIP_XY assumes that flipy is in bit 0 and flipx is in bit 1
#define TILE_FLIPYX(YX) ((YX) & 3)
#define TILE_FLIPXY(XY) ((((XY) & 2) >> 1) | (((XY) & 1) << 1))
//**************************************************************************
// INLINE FUNCTIONS
//**************************************************************************
inline running_machine &tilemap_t::machine() const
{
return m_manager->machine();
}
#endif // MAME_EMU_TILEMAP_H