More new features for UI graphics viewer

- Mouse over GFX tiles to reveal pixel values
- Mouse over tilemap to reveal tile codes and colors
- UI tilemap scrolling controls are now orientation-relative
- Make mouse visible everywhere in UI graphics viewer by treating it like a menu
- Add all necessary getters to tilemap_t and a few more (nw)
- Add comment about role of decoder in tilemap creation (nw)
This commit is contained in:
AJR 2016-09-02 18:04:38 -04:00
parent c357acd3df
commit 0a8652e03f
5 changed files with 157 additions and 36 deletions

View File

@ -1475,6 +1475,27 @@ void tilemap_t::draw_debug(screen_device &screen, bitmap_rgb32 &dest, UINT32 scr
} }
//-------------------------------------------------
// get_info_debug - extract info for one tile
//-------------------------------------------------
void tilemap_t::get_info_debug(UINT32 col, UINT32 row, int &gfxnum, int &code, int &color)
{
// first map to the memory index
tilemap_memory_index memindex = memory_index(col, row);
// next invoke the get info callback
m_tile_get_info(*this, m_tileinfo, memindex);
// get the GFX number and code
gfxnum = m_tileinfo.gfxnum;
code = m_tileinfo.code;
// work back from the palette base to get the color
gfx_element *gfx = m_tileinfo.decoder->gfx(gfxnum);
color = (m_tileinfo.palette_base - gfx->colorbase()) / gfx->granularity();
}
//************************************************************************** //**************************************************************************
// TILEMAP MANAGER // TILEMAP MANAGER

View File

@ -91,7 +91,11 @@
1. First create a new tilemap by calling tilemap_manager::create(). 1. First create a new tilemap by calling tilemap_manager::create().
The parameters are as follows: The parameters are as follows:
decoder = reference to your device_gfx_interface 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 tile_get_info = callback function which accepts a memory index
and in return fills in a tile_data structure that describes and in return fills in a tile_data structure that describes
@ -444,11 +448,12 @@ struct tile_data
UINT8 flags; // defaults to 0; one or more of TILE_* flags above UINT8 flags; // defaults to 0; one or more of TILE_* flags above
UINT8 pen_mask; // defaults to 0xff; mask to apply to pen_data while rendering the tile UINT8 pen_mask; // defaults to 0xff; mask to apply to pen_data while rendering the tile
UINT8 gfxnum; // defaults to 0xff; specify index of gfx for auto-invalidation on dirty UINT8 gfxnum; // defaults to 0xff; specify index of gfx for auto-invalidation on dirty
UINT32 code;
void set(int _gfxnum, int rawcode, int rawcolor, int _flags) void set(int _gfxnum, int rawcode, int rawcolor, int _flags)
{ {
gfx_element *gfx = decoder->gfx(_gfxnum); gfx_element *gfx = decoder->gfx(_gfxnum);
int code = rawcode % gfx->elements(); code = rawcode % gfx->elements();
pen_data = gfx->get_data(code); pen_data = gfx->get_data(code);
palette_base = gfx->colorbase() + gfx->granularity() * (rawcolor % gfx->colors()); palette_base = gfx->colorbase() + gfx->granularity() * (rawcolor % gfx->colors());
flags = _flags; flags = _flags;
@ -498,10 +503,16 @@ public:
running_machine &machine() const; running_machine &machine() const;
tilemap_device *device() const { return m_device; } tilemap_device *device() const { return m_device; }
palette_device &palette() const { return *m_palette; } palette_device &palette() const { return *m_palette; }
device_gfx_interface &decoder() const { return *m_tileinfo.decoder; }
tilemap_t *next() const { return m_next; } tilemap_t *next() const { return m_next; }
void *user_data() const { return m_user_data; } void *user_data() const { return m_user_data; }
memory_array &basemem() { return m_basemem; } memory_array &basemem() { return m_basemem; }
memory_array &extmem() { return m_extmem; } memory_array &extmem() { return m_extmem; }
UINT32 rows() const { return m_rows; }
UINT32 cols() const { return m_cols; }
UINT32 tilewidth() const { return m_tilewidth; }
UINT32 tileheight() const { return m_tileheight; }
UINT32 width() const { return m_width; } UINT32 width() const { return m_width; }
UINT32 height() const { return m_height; } UINT32 height() const { return m_height; }
bool enabled() const { return m_enable; } bool enabled() const { return m_enable; }
@ -514,6 +525,7 @@ public:
bitmap_ind8 &flagsmap() { pixmap_update(); return m_flagsmap; } bitmap_ind8 &flagsmap() { pixmap_update(); return m_flagsmap; }
UINT8 *tile_flags() { pixmap_update(); return &m_tileflags[0]; } UINT8 *tile_flags() { pixmap_update(); return &m_tileflags[0]; }
tilemap_memory_index memory_index(UINT32 col, UINT32 row) { return m_mapper(col, row, m_cols, m_rows); } tilemap_memory_index memory_index(UINT32 col, UINT32 row) { return m_mapper(col, row, m_cols, m_rows); }
void get_info_debug(UINT32 col, UINT32 row, int &gfxnum, int &code, int &color);
// setters // setters
void enable(bool enable = true) { m_enable = enable; } void enable(bool enable = true) { m_enable = enable; }

View File

@ -754,7 +754,8 @@ void mame_ui_manager::show_mouse(bool status)
bool mame_ui_manager::is_menu_active(void) bool mame_ui_manager::is_menu_active(void)
{ {
return m_handler_callback_type == ui_callback_type::MENU; return m_handler_callback_type == ui_callback_type::MENU
|| m_handler_callback_type == ui_callback_type::VIEWER;
} }
@ -1155,7 +1156,7 @@ UINT32 mame_ui_manager::handler_ingame(render_container &container)
if (!is_paused) if (!is_paused)
machine().pause(); machine().pause();
using namespace std::placeholders; using namespace std::placeholders;
set_handler(ui_callback_type::GENERAL, std::bind(&ui_gfx_ui_handler, _1, std::ref(*this), is_paused)); set_handler(ui_callback_type::VIEWER, std::bind(&ui_gfx_ui_handler, _1, std::ref(*this), is_paused));
return is_paused ? 1 : 0; return is_paused ? 1 : 0;
} }

View File

@ -135,7 +135,8 @@ enum class ui_callback_type
{ {
GENERAL, GENERAL,
MODAL, MODAL,
MENU MENU,
VIEWER
}; };
// ======================> mame_ui_manager // ======================> mame_ui_manager

View File

@ -387,8 +387,8 @@ static void palette_handler(mame_ui_manager &mui, render_container &container, u
// if the mouse pointer is over one of our cells, add some info about the corresponding palette entry // if the mouse pointer is over one of our cells, add some info about the corresponding palette entry
INT32 mouse_target_x, mouse_target_y; INT32 mouse_target_x, mouse_target_y;
bool mouse_button;
float mouse_x, mouse_y; float mouse_x, mouse_y;
bool mouse_button;
render_target *mouse_target = mui.machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button); render_target *mouse_target = mui.machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button);
if (mouse_target != nullptr && mouse_target->map_point_container(mouse_target_x, mouse_target_y, container, mouse_x, mouse_y) if (mouse_target != nullptr && mouse_target->map_point_container(mouse_target_x, mouse_target_y, container, mouse_x, mouse_y)
&& cellboxbounds.x0 <= mouse_x && cellboxbounds.x1 > mouse_x && cellboxbounds.x0 <= mouse_x && cellboxbounds.x1 > mouse_x
@ -661,12 +661,49 @@ static void gfxset_handler(mame_ui_manager &mui, render_container &container, ui
boxbounds.y0 = (1.0f - fullheight) * 0.5f; boxbounds.y0 = (1.0f - fullheight) * 0.5f;
boxbounds.y1 = boxbounds.y0 + fullheight; boxbounds.y1 = boxbounds.y0 + fullheight;
// figure out the title and expand the outer box to fit // recompute cellboxbounds
const std::string title = string_format("'%s' %d/%d %dx%d COLOR %X", cellboxbounds.x0 = boxbounds.x0 + 6.0f * chwidth;
interface.device().tag(), cellboxbounds.x1 = cellboxbounds.x0 + (float)cellboxwidth / (float)targwidth;
set, info.setcount - 1, cellboxbounds.y0 = boxbounds.y0 + 3.5f * chheight;
gfx.width(), gfx.height(), cellboxbounds.y1 = cellboxbounds.y0 + (float)cellboxheight / (float)targheight;
info.color[set]);
// figure out the title
std::ostringstream title_buf;
util::stream_format(title_buf, "'%s' %d/%d", interface.device().tag(), set, info.setcount - 1);
// if the mouse pointer is over a pixel in a tile, add some info about the tile and pixel
bool found_pixel = false;
INT32 mouse_target_x, mouse_target_y;
float mouse_x, mouse_y;
bool mouse_button;
render_target *mouse_target = mui.machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button);
if (mouse_target != nullptr && mouse_target->map_point_container(mouse_target_x, mouse_target_y, container, mouse_x, mouse_y)
&& cellboxbounds.x0 <= mouse_x && cellboxbounds.x1 > mouse_x
&& cellboxbounds.y0 <= mouse_y && cellboxbounds.y1 > mouse_y)
{
int code = info.offset[set] + int((mouse_x - cellboxbounds.x0) / cellwidth) + int((mouse_y - cellboxbounds.y0) / cellheight) * xcells;
int xpixel = int((mouse_x - cellboxbounds.x0) / (cellwidth / cellxpix)) % cellxpix;
int ypixel = int((mouse_y - cellboxbounds.y0) / (cellheight / cellypix)) % cellypix;
if (code < gfx.elements() && xpixel < (cellxpix - 1) && ypixel < (cellypix - 1))
{
found_pixel = true;
if (info.rotate[set] & ORIENTATION_FLIP_X)
xpixel = (cellxpix - 2) - xpixel;
if (info.rotate[set] & ORIENTATION_FLIP_Y)
ypixel = (cellypix - 2) - ypixel;
if (info.rotate[set] & ORIENTATION_SWAP_XY)
std::swap(xpixel, ypixel);
UINT8 pixdata = gfx.get_data(code)[xpixel + ypixel * gfx.rowbytes()];
util::stream_format(title_buf, " #%X:%X @ %d,%d = %X",
code, info.color[set], xpixel, ypixel,
gfx.colorbase() + info.color[set] * gfx.granularity() + pixdata);
}
}
if (!found_pixel)
util::stream_format(title_buf, " %dx%d COLOR %X/%X", gfx.width(), gfx.height(), info.color[set], gfx.colors());
// expand the outer box to fit the title
const std::string title = title_buf.str();
titlewidth = ui_font->string_width(chheight, mui.machine().render().ui_aspect(), title.c_str()); titlewidth = ui_font->string_width(chheight, mui.machine().render().ui_aspect(), title.c_str());
x0 = 0.0f; x0 = 0.0f;
if (boxbounds.x1 - boxbounds.x0 < titlewidth + chwidth) if (boxbounds.x1 - boxbounds.x0 < titlewidth + chwidth)
@ -727,9 +764,7 @@ static void gfxset_handler(mame_ui_manager &mui, render_container &container, ui
gfxset_update_bitmap(mui.machine(), state, xcells, ycells, gfx); gfxset_update_bitmap(mui.machine(), state, xcells, ycells, gfx);
// add the final quad // add the final quad
container.add_quad(boxbounds.x0 + 6.0f * chwidth, boxbounds.y0 + 3.5f * chheight, container.add_quad(cellboxbounds.x0, cellboxbounds.y0, cellboxbounds.x1, cellboxbounds.y1,
boxbounds.x0 + 6.0f * chwidth + (float)cellboxwidth / (float)targwidth,
boxbounds.y0 + 3.5f * chheight + (float)cellboxheight / (float)targheight,
rgb_t::white, state.texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); rgb_t::white, state.texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
// handle keyboard navigation before drawing // handle keyboard navigation before drawing
@ -943,12 +978,11 @@ static void gfxset_draw_item(running_machine &machine, gfx_element &gfx, int ind
} }
else else
{ {
int temp;
if (rotate & ORIENTATION_FLIP_X) if (rotate & ORIENTATION_FLIP_X)
effx = gfx.height() - 1 - effx; effx = gfx.height() - 1 - effx;
if (rotate & ORIENTATION_FLIP_Y) if (rotate & ORIENTATION_FLIP_Y)
effy = gfx.width() - 1 - effy; effy = gfx.width() - 1 - effy;
temp = effx; effx = effy; effy = temp; std::swap(effx, effy);
} }
// get a pointer to the start of this source row // get a pointer to the start of this source row
@ -982,15 +1016,13 @@ static void tilemap_handler(mame_ui_manager &mui, render_container &container, u
float titlewidth; float titlewidth;
float x0, y0; float x0, y0;
int mapboxwidth, mapboxheight; int mapboxwidth, mapboxheight;
int maxxscale, maxyscale;
UINT32 mapwidth, mapheight;
// get the size of the tilemap itself // get the size of the tilemap itself
tilemap_t *tilemap = mui.machine().tilemap().find(state.tilemap.which); tilemap_t *tilemap = mui.machine().tilemap().find(state.tilemap.which);
mapwidth = tilemap->width(); UINT32 mapwidth = tilemap->width();
mapheight = tilemap->height(); UINT32 mapheight = tilemap->height();
if (state.tilemap.rotate & ORIENTATION_SWAP_XY) if (state.tilemap.rotate & ORIENTATION_SWAP_XY)
{ UINT32 temp = mapwidth; mapwidth = mapheight; mapheight = temp; } std::swap(mapwidth, mapheight);
// add a half character padding for the box // add a half character padding for the box
chheight = mui.get_line_height(); chheight = mui.get_line_height();
@ -1018,6 +1050,7 @@ static void tilemap_handler(mame_ui_manager &mui, render_container &container, u
int pixelscale = state.tilemap.zoom; int pixelscale = state.tilemap.zoom;
if (pixelscale == 0) if (pixelscale == 0)
{ {
int maxxscale, maxyscale;
for (maxxscale = 1; mapwidth * (maxxscale + 1) < mapboxwidth; maxxscale++) { } for (maxxscale = 1; mapwidth * (maxxscale + 1) < mapboxwidth; maxxscale++) { }
for (maxyscale = 1; mapheight * (maxyscale + 1) < mapboxheight; maxyscale++) { } for (maxyscale = 1; mapheight * (maxyscale + 1) < mapboxheight; maxyscale++) { }
pixelscale = std::min(maxxscale, maxyscale); pixelscale = std::min(maxxscale, maxyscale);
@ -1039,8 +1072,40 @@ static void tilemap_handler(mame_ui_manager &mui, render_container &container, u
boxbounds.y0 = mapboxbounds.y0 - 2.0f * chheight; boxbounds.y0 = mapboxbounds.y0 - 2.0f * chheight;
boxbounds.y1 = mapboxbounds.y1 + 0.5f * chheight; boxbounds.y1 = mapboxbounds.y1 + 0.5f * chheight;
// figure out the title and expand the outer box to fit // figure out the title
const std::string title = string_format("TILEMAP %d/%d %dx%d OFFS %d,%d", state.tilemap.which, mui.machine().tilemap().count() - 1, mapwidth, mapheight, state.tilemap.xoffs, state.tilemap.yoffs); std::ostringstream title_buf;
util::stream_format(title_buf, "TILEMAP %d/%d", state.tilemap.which, mui.machine().tilemap().count() - 1);
// if the mouse pointer is over a tile, add some info about its coordinates and color
INT32 mouse_target_x, mouse_target_y;
float mouse_x, mouse_y;
bool mouse_button;
render_target *mouse_target = mui.machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button);
if (mouse_target != nullptr && mouse_target->map_point_container(mouse_target_x, mouse_target_y, container, mouse_x, mouse_y)
&& mapboxbounds.x0 <= mouse_x && mapboxbounds.x1 > mouse_x
&& mapboxbounds.y0 <= mouse_y && mapboxbounds.y1 > mouse_y)
{
int xpixel = (mouse_x - mapboxbounds.x0) * targwidth;
int ypixel = (mouse_y - mapboxbounds.y0) * targheight;
if (state.tilemap.rotate & ORIENTATION_FLIP_X)
xpixel = (mapboxwidth - 1) - xpixel;
if (state.tilemap.rotate & ORIENTATION_FLIP_Y)
ypixel = (mapboxheight - 1) - ypixel;
if (state.tilemap.rotate & ORIENTATION_SWAP_XY)
std::swap(xpixel, ypixel);
int col = ((xpixel / pixelscale + state.tilemap.xoffs) / tilemap->tilewidth()) % tilemap->cols();
int row = ((ypixel / pixelscale + state.tilemap.yoffs) / tilemap->tileheight()) % tilemap->rows();
int gfxnum, code, color;
tilemap->get_info_debug(col, row, gfxnum, code, color);
util::stream_format(title_buf, " @ %d,%d = GFX%d #%X:%X",
col * tilemap->tilewidth(), row * tilemap->tileheight(),
gfxnum, code, color);
}
else
util::stream_format(title_buf, " %dx%d OFFS %d,%d", tilemap->width(), tilemap->height(), state.tilemap.xoffs, state.tilemap.yoffs);
// expand the outer box to fit the title
const std::string title = title_buf.str();
titlewidth = ui_font->string_width(chheight, mui.machine().render().ui_aspect(), title.c_str()); titlewidth = ui_font->string_width(chheight, mui.machine().render().ui_aspect(), title.c_str());
if (boxbounds.x1 - boxbounds.x0 < titlewidth + chwidth) if (boxbounds.x1 - boxbounds.x0 < titlewidth + chwidth)
{ {
@ -1081,9 +1146,6 @@ static void tilemap_handler(mame_ui_manager &mui, render_container &container, u
static void tilemap_handle_keys(running_machine &machine, ui_gfx_state &state, int viswidth, int visheight) static void tilemap_handle_keys(running_machine &machine, ui_gfx_state &state, int viswidth, int visheight)
{ {
UINT32 mapwidth, mapheight;
int step;
// handle tilemap selection (open bracket,close bracket) // handle tilemap selection (open bracket,close bracket)
if (machine.ui_input().pressed(IPT_UI_PREV_GROUP) && state.tilemap.which > 0) if (machine.ui_input().pressed(IPT_UI_PREV_GROUP) && state.tilemap.which > 0)
{ state.tilemap.which--; state.bitmap_dirty = true; } { state.tilemap.which--; state.bitmap_dirty = true; }
@ -1092,8 +1154,8 @@ static void tilemap_handle_keys(running_machine &machine, ui_gfx_state &state, i
// cache some info in locals // cache some info in locals
tilemap_t *tilemap = machine.tilemap().find(state.tilemap.which); tilemap_t *tilemap = machine.tilemap().find(state.tilemap.which);
mapwidth = tilemap->width(); UINT32 mapwidth = tilemap->width();
mapheight = tilemap->height(); UINT32 mapheight = tilemap->height();
// handle zoom (minus,plus) // handle zoom (minus,plus)
if (machine.ui_input().pressed(IPT_UI_ZOOM_OUT) && state.tilemap.zoom > 0) if (machine.ui_input().pressed(IPT_UI_ZOOM_OUT) && state.tilemap.zoom > 0)
@ -1127,18 +1189,42 @@ static void tilemap_handle_keys(running_machine &machine, ui_gfx_state &state, i
state.bitmap_dirty = true; state.bitmap_dirty = true;
} }
// handle navigation (up,down,left,right) // handle navigation (up,down,left,right), taking orientation into account
step = 8; int step = 8; // this may be applied more than once if multiple directions are pressed
if (machine.input().code_pressed(KEYCODE_LSHIFT)) step = 1; if (machine.input().code_pressed(KEYCODE_LSHIFT)) step = 1;
if (machine.input().code_pressed(KEYCODE_LCONTROL)) step = 64; if (machine.input().code_pressed(KEYCODE_LCONTROL)) step = 64;
if (machine.ui_input().pressed_repeat(IPT_UI_UP, 4)) if (machine.ui_input().pressed_repeat(IPT_UI_UP, 4))
{ state.tilemap.yoffs -= step; state.bitmap_dirty = true; } {
if (state.tilemap.rotate & ORIENTATION_SWAP_XY)
state.tilemap.xoffs -= (state.tilemap.rotate & ORIENTATION_FLIP_Y) ? -step : step;
else
state.tilemap.yoffs -= (state.tilemap.rotate & ORIENTATION_FLIP_Y) ? -step : step;
state.bitmap_dirty = true;
}
if (machine.ui_input().pressed_repeat(IPT_UI_DOWN, 4)) if (machine.ui_input().pressed_repeat(IPT_UI_DOWN, 4))
{ state.tilemap.yoffs += step; state.bitmap_dirty = true; } {
if (state.tilemap.rotate & ORIENTATION_SWAP_XY)
state.tilemap.xoffs += (state.tilemap.rotate & ORIENTATION_FLIP_Y) ? -step : step;
else
state.tilemap.yoffs += (state.tilemap.rotate & ORIENTATION_FLIP_Y) ? -step : step;
state.bitmap_dirty = true;
}
if (machine.ui_input().pressed_repeat(IPT_UI_LEFT, 6)) if (machine.ui_input().pressed_repeat(IPT_UI_LEFT, 6))
{ state.tilemap.xoffs -= step; state.bitmap_dirty = true; } {
if (state.tilemap.rotate & ORIENTATION_SWAP_XY)
state.tilemap.yoffs -= (state.tilemap.rotate & ORIENTATION_FLIP_X) ? -step : step;
else
state.tilemap.xoffs -= (state.tilemap.rotate & ORIENTATION_FLIP_X) ? -step : step;
state.bitmap_dirty = true;
}
if (machine.ui_input().pressed_repeat(IPT_UI_RIGHT, 6)) if (machine.ui_input().pressed_repeat(IPT_UI_RIGHT, 6))
{ state.tilemap.xoffs += step; state.bitmap_dirty = true; } {
if (state.tilemap.rotate & ORIENTATION_SWAP_XY)
state.tilemap.yoffs += (state.tilemap.rotate & ORIENTATION_FLIP_X) ? -step : step;
else
state.tilemap.xoffs += (state.tilemap.rotate & ORIENTATION_FLIP_X) ? -step : step;
state.bitmap_dirty = true;
}
// clamp within range // clamp within range
while (state.tilemap.xoffs < 0) while (state.tilemap.xoffs < 0)
@ -1161,7 +1247,7 @@ static void tilemap_update_bitmap(running_machine &machine, ui_gfx_state &state,
{ {
// swap the coordinates back if they were talking about a rotated surface // swap the coordinates back if they were talking about a rotated surface
if (state.tilemap.rotate & ORIENTATION_SWAP_XY) if (state.tilemap.rotate & ORIENTATION_SWAP_XY)
{ UINT32 temp = width; width = height; height = temp; } std::swap(width, height);
// realloc the bitmap if it is too small // realloc the bitmap if it is too small
if (state.bitmap == nullptr || state.texture == nullptr || state.bitmap->width() != width || state.bitmap->height() != height) if (state.bitmap == nullptr || state.texture == nullptr || state.bitmap->width() != width || state.bitmap->height() != height)