mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
emu/render.cpp: Apply target orientation when mapping points to layout elements.
Addresses MT07375. Also increase efficiency when layouts contain large numbers of non-interactive elements (e.g. thousands of matrix display dots). Also includes work in progress for future improvements.
This commit is contained in:
parent
4c9244504a
commit
34cbb3a25e
@ -1447,21 +1447,115 @@ render_primitive_list &render_target::get_primitives()
|
||||
|
||||
bool render_target::map_point_container(s32 target_x, s32 target_y, render_container &container, float &container_x, float &container_y)
|
||||
{
|
||||
ioport_port *input_port;
|
||||
ioport_value input_mask;
|
||||
return map_point_internal(target_x, target_y, &container, container_x, container_y, input_port, input_mask);
|
||||
std::pair<float, float> target_f(map_point_internal(target_x, target_y));
|
||||
|
||||
// explicitly check for the UI container
|
||||
if (&container == &m_manager.ui_container())
|
||||
{
|
||||
// this hit test went against the UI container
|
||||
if ((target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f))
|
||||
{
|
||||
// this point was successfully mapped
|
||||
container_x = float(target_x) / m_width;
|
||||
container_y = float(target_y) / m_height;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_orientation & ORIENTATION_FLIP_X)
|
||||
target_f.first = 1.0f - target_f.first;
|
||||
if (m_orientation & ORIENTATION_FLIP_Y)
|
||||
target_f.second = 1.0f - target_f.second;
|
||||
if (m_orientation & ORIENTATION_SWAP_XY)
|
||||
std::swap(target_f.first, target_f.second);
|
||||
|
||||
// try to find the right container
|
||||
auto const &items(current_view().screen_items());
|
||||
auto const found(std::find_if(
|
||||
items.begin(),
|
||||
items.end(),
|
||||
[&container] (layout_view::item &item) { return &item.screen()->container() == &container; }));
|
||||
if (items.end() != found)
|
||||
{
|
||||
layout_view::item &item(*found);
|
||||
if (item.bounds().includes(target_f.first, target_f.second))
|
||||
{
|
||||
// point successfully mapped
|
||||
container_x = (target_f.first - item.bounds().x0) / item.bounds().width();
|
||||
container_y = (target_f.second - item.bounds().y0) / item.bounds().height();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default to point not mapped
|
||||
container_x = container_y = -1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// map_point_input - attempts to map a point on
|
||||
// the specified render_target to the specified
|
||||
// container, if possible
|
||||
// the specified render_target to an input port
|
||||
// field, if possible
|
||||
//-------------------------------------------------
|
||||
|
||||
bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y)
|
||||
{
|
||||
return map_point_internal(target_x, target_y, nullptr, input_x, input_y, input_port, input_mask);
|
||||
std::pair<float, float> target_f(map_point_internal(target_x, target_y));
|
||||
if (m_orientation & ORIENTATION_FLIP_X)
|
||||
target_f.first = 1.0f - target_f.first;
|
||||
if (m_orientation & ORIENTATION_FLIP_Y)
|
||||
target_f.second = 1.0f - target_f.second;
|
||||
if (m_orientation & ORIENTATION_SWAP_XY)
|
||||
std::swap(target_f.first, target_f.second);
|
||||
|
||||
auto const &items(current_view().interactive_items());
|
||||
m_hit_test.resize(items.size() * 2);
|
||||
std::fill(m_hit_test.begin(), m_hit_test.end(), false);
|
||||
|
||||
for (auto const &edge : current_view().interactive_edges_x())
|
||||
{
|
||||
if ((edge.position() > target_f.first) || ((edge.position() == target_f.first) && edge.trailing()))
|
||||
break;
|
||||
else
|
||||
m_hit_test[edge.index()] = !edge.trailing();
|
||||
}
|
||||
|
||||
for (auto const &edge : current_view().interactive_edges_y())
|
||||
{
|
||||
if ((edge.position() > target_f.second) || ((edge.position() == target_f.second) && edge.trailing()))
|
||||
break;
|
||||
else
|
||||
m_hit_test[items.size() + edge.index()] = !edge.trailing();
|
||||
}
|
||||
|
||||
for (unsigned i = 0; items.size() > i; ++i)
|
||||
{
|
||||
if (m_hit_test[i] && m_hit_test[items.size() + i])
|
||||
{
|
||||
layout_view::item &item(items[i]);
|
||||
if (item.has_input())
|
||||
{
|
||||
// point successfully mapped
|
||||
input_port = item.input_tag_and_mask(input_mask);
|
||||
input_x = (target_f.first - item.bounds().x0) / item.bounds().width();
|
||||
input_y = (target_f.second - item.bounds().y0) / item.bounds().height();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default to point not mapped
|
||||
input_port = nullptr;
|
||||
input_mask = 0;
|
||||
input_x = input_y = -1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -1528,6 +1622,8 @@ void render_target::resolve_tags()
|
||||
for (layout_view &view : file.views())
|
||||
{
|
||||
view.resolve_tags();
|
||||
if (¤t_view() == &view)
|
||||
view.recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2468,7 +2564,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob
|
||||
// mapping points
|
||||
//-------------------------------------------------
|
||||
|
||||
bool render_target::map_point_internal(s32 target_x, s32 target_y, render_container *container, float &mapped_x, float &mapped_y, ioport_port *&mapped_input_port, ioport_value &mapped_input_mask)
|
||||
std::pair<float, float> render_target::map_point_internal(s32 target_x, s32 target_y)
|
||||
{
|
||||
// compute the visible width/height
|
||||
s32 viswidth, visheight;
|
||||
@ -2476,65 +2572,14 @@ bool render_target::map_point_internal(s32 target_x, s32 target_y, render_contai
|
||||
|
||||
// create a root transform for the target
|
||||
object_transform root_xform;
|
||||
root_xform.xoffs = (float)(m_width - viswidth) / 2;
|
||||
root_xform.yoffs = (float)(m_height - visheight) / 2;
|
||||
|
||||
// default to point not mapped
|
||||
mapped_x = -1.0;
|
||||
mapped_y = -1.0;
|
||||
mapped_input_port = nullptr;
|
||||
mapped_input_mask = 0;
|
||||
root_xform.xoffs = float(m_width - viswidth) / 2;
|
||||
root_xform.yoffs = float(m_height - visheight) / 2;
|
||||
|
||||
// convert target coordinates to float
|
||||
float target_fx = (float)(target_x - root_xform.xoffs) / viswidth;
|
||||
float target_fy = (float)(target_y - root_xform.yoffs) / visheight;
|
||||
if (m_manager.machine().ui().is_menu_active())
|
||||
{
|
||||
target_fx = (float)target_x / m_width;
|
||||
target_fy = (float)target_y / m_height;
|
||||
}
|
||||
// explicitly check for the UI container
|
||||
if (container != nullptr && container == &m_manager.ui_container())
|
||||
{
|
||||
// this hit test went against the UI container
|
||||
if (target_fx >= 0.0f && target_fx < 1.0f && target_fy >= 0.0f && target_fy < 1.0f)
|
||||
{
|
||||
// this point was successfully mapped
|
||||
mapped_x = (float)target_x / m_width;
|
||||
mapped_y = (float)target_y / m_height;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// iterate over items in the view
|
||||
for (layout_view::item &item : current_view().items())
|
||||
{
|
||||
if ((visibility_mask() & item.visibility_mask()) != item.visibility_mask())
|
||||
continue;
|
||||
|
||||
bool checkit;
|
||||
|
||||
// if we're looking for a particular container, verify that we have the right one
|
||||
if (container != nullptr)
|
||||
checkit = (item.screen() != nullptr && &item.screen()->container() == container);
|
||||
|
||||
// otherwise, assume we're looking for an input
|
||||
else
|
||||
checkit = item.has_input();
|
||||
|
||||
// this target is worth looking at; now check the point
|
||||
if (checkit && target_fx >= item.bounds().x0 && target_fx < item.bounds().x1 && target_fy >= item.bounds().y0 && target_fy < item.bounds().y1)
|
||||
{
|
||||
// point successfully mapped
|
||||
mapped_x = (target_fx - item.bounds().x0) / (item.bounds().x1 - item.bounds().x0);
|
||||
mapped_y = (target_fy - item.bounds().y0) / (item.bounds().y1 - item.bounds().y0);
|
||||
mapped_input_port = item.input_tag_and_mask(mapped_input_mask);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!m_manager.machine().ui().is_menu_active())
|
||||
return std::make_pair(float(target_x - root_xform.xoffs) / viswidth, float(target_y - root_xform.yoffs) / visheight);
|
||||
else
|
||||
return std::make_pair(float(target_x) / m_width, float(target_y) / m_height);
|
||||
}
|
||||
|
||||
|
||||
@ -2556,18 +2601,12 @@ layout_view *render_target::view_by_index(unsigned index)
|
||||
|
||||
int render_target::view_index(layout_view &targetview) const
|
||||
{
|
||||
// find the first named match
|
||||
int index = 0;
|
||||
|
||||
// scan the list of views within each layout, skipping those that don't apply
|
||||
for (layout_file const &file : m_filelist)
|
||||
for (layout_view const &view : file.views())
|
||||
if (!(m_flags & RENDER_CREATE_NO_ART) || !view.has_art())
|
||||
{
|
||||
if (&targetview == &view)
|
||||
return index;
|
||||
index++;
|
||||
}
|
||||
// return index of view, or zero if not found
|
||||
for (int index = 0; m_views.size() > index; ++index)
|
||||
{
|
||||
if (&m_views[index].first.get() == &targetview)
|
||||
return index;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@ -184,6 +185,7 @@ struct render_bounds
|
||||
constexpr float width() const { return x1 - x0; }
|
||||
constexpr float height() const { return y1 - y0; }
|
||||
constexpr float aspect() const { return width() / height(); }
|
||||
constexpr bool includes(float x, float y) const { return (x >= x0) && (x <= x1) && (y >= y0) && (y <= y1); }
|
||||
};
|
||||
|
||||
|
||||
@ -738,7 +740,7 @@ public:
|
||||
using view_environment = emu::render::detail::view_environment;
|
||||
using element_map = std::unordered_map<std::string, layout_element>;
|
||||
using group_map = std::unordered_map<std::string, layout_group>;
|
||||
using render_screen_list = std::list<std::reference_wrapper<screen_device>>;
|
||||
using screen_ref_vector = std::vector<std::reference_wrapper<screen_device> >;
|
||||
|
||||
/// \brief A single item in a view
|
||||
///
|
||||
@ -769,8 +771,11 @@ public:
|
||||
u32 visibility_mask() const { return m_visibility_mask; }
|
||||
int orientation() const { return m_orientation; }
|
||||
render_container *screen_container(running_machine &machine) const;
|
||||
|
||||
// interactivity
|
||||
bool has_input() const { return bool(m_input_port); }
|
||||
ioport_port *input_tag_and_mask(ioport_value &mask) const { mask = m_input_mask; return m_input_port; };
|
||||
bool clickthrough() const { return m_clickthrough; }
|
||||
|
||||
// fetch state based on configured source
|
||||
int state() const;
|
||||
@ -778,34 +783,37 @@ public:
|
||||
// resolve tags, if any
|
||||
void resolve_tags();
|
||||
|
||||
// setters
|
||||
void set_blend_mode(int mode) { m_blend_mode = mode; }
|
||||
|
||||
private:
|
||||
static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
|
||||
static render_bounds make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
|
||||
static std::string make_input_tag(view_environment &env, util::xml::data_node const &itemnode);
|
||||
static int get_blend_mode(view_environment &env, util::xml::data_node const &itemnode);
|
||||
static unsigned get_input_shift(ioport_value mask);
|
||||
|
||||
// internal state
|
||||
layout_element *const m_element; // pointer to the associated element (non-screens only)
|
||||
output_finder<> m_output; // associated output
|
||||
bool const m_have_output; // whether we actually have an output
|
||||
std::string const m_input_tag; // input tag of this item
|
||||
ioport_port * m_input_port; // input port of this item
|
||||
ioport_field const * m_input_field; // input port field of this item
|
||||
ioport_value const m_input_mask; // input mask of this item
|
||||
u8 m_input_shift; // input mask rightshift for raw (trailing 0s)
|
||||
u8 const m_input_shift; // input mask rightshift for raw (trailing 0s)
|
||||
bool const m_input_raw; // get raw data from input port
|
||||
bool m_clickthrough; // should click pass through to lower elements
|
||||
screen_device * m_screen; // pointer to screen
|
||||
int m_orientation; // orientation of this item
|
||||
render_bounds m_bounds; // bounds of the item
|
||||
render_bounds const m_rawbounds; // raw (original) bounds of the item
|
||||
render_color m_color; // color of the item
|
||||
int m_blend_mode; // blending mode to use when drawing
|
||||
u32 m_visibility_mask; // combined mask of parent visibility groups
|
||||
|
||||
// cold items
|
||||
std::string const m_input_tag; // input tag of this item
|
||||
render_bounds const m_rawbounds; // raw (original) bounds of the item
|
||||
bool const m_has_clickthrough; // whether clickthrough was explicitly configured
|
||||
};
|
||||
using item_list = std::list<item>;
|
||||
using item_ref_vector = std::vector<std::reference_wrapper<item> >;
|
||||
|
||||
/// \brief A subset of items in a view that can be hidden or shown
|
||||
///
|
||||
@ -831,6 +839,36 @@ public:
|
||||
};
|
||||
using visibility_toggle_vector = std::vector<visibility_toggle>;
|
||||
|
||||
/// \brief An edge of an item in a view
|
||||
class edge
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
constexpr edge(unsigned index, float position, bool trailing)
|
||||
: m_index(index)
|
||||
, m_position(position)
|
||||
, m_trailing(trailing)
|
||||
{
|
||||
}
|
||||
|
||||
// getters
|
||||
constexpr unsigned index() const { return m_index; }
|
||||
constexpr float position() const { return m_position; }
|
||||
constexpr bool trailing() const { return m_trailing; }
|
||||
|
||||
// comparison
|
||||
constexpr bool operator<(edge const &that) const
|
||||
{
|
||||
return std::make_tuple(m_position, m_trailing, m_index) < std::make_tuple(that.m_position, that.m_trailing, that.m_index);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned m_index; // index of item in some collection
|
||||
float m_position; // position of edge on given axis
|
||||
bool m_trailing; // false for edge at lower position on axis
|
||||
};
|
||||
using edge_vector = std::vector<edge>;
|
||||
|
||||
// construction/destruction
|
||||
layout_view(
|
||||
layout_environment &env,
|
||||
@ -842,14 +880,18 @@ public:
|
||||
// getters
|
||||
item_list &items() { return m_items; }
|
||||
const std::string &name() const { return m_name; }
|
||||
const render_screen_list &screens() const { return m_screens; }
|
||||
size_t screen_count() const { return m_screens.size(); }
|
||||
float effective_aspect() const { return m_effaspect; }
|
||||
const render_bounds &bounds() const { return m_bounds; }
|
||||
bool has_screen(screen_device &screen) const;
|
||||
bool has_art() const { return m_has_art; }
|
||||
u32 default_visibility_mask() const { return m_defvismask; }
|
||||
const item_ref_vector &screen_items() const { return m_screen_items; }
|
||||
const item_ref_vector &interactive_items() const { return m_interactive_items; }
|
||||
const edge_vector &interactive_edges_x() const { return m_interactive_edges_x; }
|
||||
const edge_vector &interactive_edges_y() const { return m_interactive_edges_y; }
|
||||
const screen_ref_vector &screens() const { return m_screens; }
|
||||
const visibility_toggle_vector &visibility_toggles() const { return m_vistoggles; }
|
||||
u32 default_visibility_mask() const { return m_defvismask; }
|
||||
bool has_art() const { return m_has_art; }
|
||||
|
||||
// operations
|
||||
void recompute(u32 visibility_mask, bool zoom_to_screens);
|
||||
@ -877,15 +919,21 @@ private:
|
||||
static std::string make_name(layout_environment &env, util::xml::data_node const &viewnode);
|
||||
|
||||
// internal state
|
||||
std::string m_name; // name of the layout
|
||||
render_screen_list m_screens; // list screens visible in current configuration
|
||||
float m_effaspect; // X/Y of the layout in current configuration
|
||||
render_bounds m_bounds; // computed bounds of the view in current configuration
|
||||
render_bounds m_expbounds; // explicit bounds of the view
|
||||
item_list m_items; // list of layout items
|
||||
bool m_has_art; // true if the layout contains non-screen elements
|
||||
u32 m_defvismask; // default visibility mask
|
||||
visibility_toggle_vector m_vistoggles;
|
||||
std::string m_name; // name of the layout
|
||||
float m_effaspect; // X/Y of the layout in current configuration
|
||||
render_bounds m_bounds; // computed bounds of the view in current configuration
|
||||
item_list m_items; // list of layout items
|
||||
item_ref_vector m_screen_items; // visible items that represent screens to draw
|
||||
item_ref_vector m_interactive_items;// visible items that can accept pointer input
|
||||
edge_vector m_interactive_edges_x;
|
||||
edge_vector m_interactive_edges_y;
|
||||
screen_ref_vector m_screens; // list screens visible in current configuration
|
||||
|
||||
// cold items
|
||||
visibility_toggle_vector m_vistoggles; // collections of items that can be shown/hidden
|
||||
render_bounds m_expbounds; // explicit bounds of the view
|
||||
u32 m_defvismask; // default visibility mask
|
||||
bool m_has_art; // true if the layout contains non-screen elements
|
||||
};
|
||||
|
||||
|
||||
@ -1026,7 +1074,7 @@ private:
|
||||
bool load_layout_file(device_t &device, const char *dirname, util::xml::data_node const &rootnode);
|
||||
void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode);
|
||||
void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode);
|
||||
bool map_point_internal(s32 target_x, s32 target_y, render_container *container, float &mapped_x, float &mapped_y, ioport_port *&mapped_input_port, ioport_value &mapped_input_mask);
|
||||
std::pair<float, float> map_point_internal(s32 target_x, s32 target_y);
|
||||
|
||||
// config callbacks
|
||||
void config_load(util::xml::data_node const &targetnode);
|
||||
@ -1067,6 +1115,7 @@ private:
|
||||
float m_max_refresh; // maximum refresh rate, 0 or if none
|
||||
int m_orientation; // orientation
|
||||
render_layer_config m_layerconfig; // layer configuration
|
||||
std::vector<bool> m_hit_test; // used when mapping points to inputs
|
||||
layout_view * m_base_view; // the view at the time of first frame
|
||||
int m_base_orientation; // the orientation at the time of first frame
|
||||
render_layer_config m_base_layerconfig; // the layer configuration at the time of first frame
|
||||
|
@ -33,8 +33,9 @@
|
||||
#include <utility>
|
||||
|
||||
#define LOG_GROUP_BOUNDS_RESOLUTION (1U << 1)
|
||||
#define LOG_INTERACTIVE_ITEMS (1U << 2)
|
||||
|
||||
//#define VERBOSE (LOG_GROUP_BOUNDS_RESOLUTION)
|
||||
//#define VERBOSE (LOG_GROUP_BOUNDS_RESOLUTION | LOG_INTERACTIVE_ITEMS)
|
||||
#define LOG_OUTPUT_FUNC osd_printf_verbose
|
||||
#include "logmacro.h"
|
||||
|
||||
@ -3060,8 +3061,8 @@ layout_view::layout_view(
|
||||
: m_name(make_name(env, viewnode))
|
||||
, m_effaspect(1.0f)
|
||||
, m_items()
|
||||
, m_has_art(false)
|
||||
, m_defvismask(0U)
|
||||
, m_has_art(false)
|
||||
{
|
||||
// parse the layout
|
||||
m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0;
|
||||
@ -3122,7 +3123,7 @@ layout_view::layout_view(
|
||||
{
|
||||
// screens (-1) + overlays (RGB multiply) + backdrop (add) + bezels (alpha) + cpanels (alpha) + marquees (alpha)
|
||||
for (item &backdrop : layers.backdrops)
|
||||
backdrop.set_blend_mode(BLENDMODE_ADD);
|
||||
backdrop.m_blend_mode = BLENDMODE_ADD;
|
||||
m_items.splice(m_items.end(), layers.screens);
|
||||
m_items.splice(m_items.end(), layers.overlays);
|
||||
m_items.splice(m_items.end(), layers.backdrops);
|
||||
@ -3137,7 +3138,7 @@ layout_view::layout_view(
|
||||
for (item &screen : layers.screens)
|
||||
{
|
||||
if (screen.blend_mode() == -1)
|
||||
screen.set_blend_mode(BLENDMODE_ADD);
|
||||
screen.m_blend_mode = BLENDMODE_ADD;
|
||||
}
|
||||
m_items.splice(m_items.end(), layers.backdrops);
|
||||
m_items.splice(m_items.end(), layers.screens);
|
||||
@ -3180,9 +3181,13 @@ bool layout_view::has_screen(screen_device &screen) const
|
||||
|
||||
void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
|
||||
{
|
||||
// reset the bounds
|
||||
// reset the bounds and collected active items
|
||||
render_bounds scrbounds{ 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
m_bounds = scrbounds;
|
||||
m_screen_items.clear();
|
||||
m_interactive_items.clear();
|
||||
m_interactive_edges_x.clear();
|
||||
m_interactive_edges_y.clear();
|
||||
m_screens.clear();
|
||||
|
||||
// loop over items and filter by visibility mask
|
||||
@ -3200,7 +3205,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
|
||||
first = false;
|
||||
|
||||
// accumulate visible screens and their bounds bounds
|
||||
if (curitem.m_screen)
|
||||
if (curitem.screen())
|
||||
{
|
||||
if (scrfirst)
|
||||
scrbounds = curitem.m_rawbounds;
|
||||
@ -3208,9 +3213,14 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
|
||||
union_render_bounds(scrbounds, curitem.m_rawbounds);
|
||||
scrfirst = false;
|
||||
|
||||
// accumulate the screens in use while we're scanning
|
||||
m_screens.emplace_back(*curitem.m_screen);
|
||||
// accumulate active screens
|
||||
m_screen_items.emplace_back(curitem);
|
||||
m_screens.emplace_back(*curitem.screen());
|
||||
}
|
||||
|
||||
// accumulate interactive elements
|
||||
if (!curitem.clickthrough() || curitem.has_input())
|
||||
m_interactive_items.emplace_back(curitem);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3239,8 +3249,8 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
|
||||
// determine the scale/offset for normalization
|
||||
float const xoffs = m_bounds.x0;
|
||||
float const yoffs = m_bounds.y0;
|
||||
float const xscale = (target_bounds.x1 - target_bounds.x0) / (m_bounds.x1 - m_bounds.x0);
|
||||
float const yscale = (target_bounds.y1 - target_bounds.y0) / (m_bounds.y1 - m_bounds.y0);
|
||||
float const xscale = target_bounds.width() / m_bounds.width();
|
||||
float const yscale = target_bounds.height() / m_bounds.height();
|
||||
|
||||
// normalize all the item bounds
|
||||
for (item &curitem : items())
|
||||
@ -3250,6 +3260,32 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
|
||||
curitem.m_bounds.y0 = target_bounds.y0 + (curitem.m_rawbounds.y0 - yoffs) * yscale;
|
||||
curitem.m_bounds.y1 = target_bounds.y0 + (curitem.m_rawbounds.y1 - yoffs) * yscale;
|
||||
}
|
||||
|
||||
// sort edges of interactive items
|
||||
LOGMASKED(LOG_INTERACTIVE_ITEMS, "Recalculated view '%s' with %u interactive items\n",
|
||||
name(), m_interactive_items.size());
|
||||
m_interactive_edges_x.reserve(m_interactive_items.size() * 2);
|
||||
m_interactive_edges_y.reserve(m_interactive_items.size() * 2);
|
||||
for (unsigned i = 0; m_interactive_items.size() > i; ++i)
|
||||
{
|
||||
item &curitem(m_interactive_items[i]);
|
||||
LOGMASKED(LOG_INTERACTIVE_ITEMS, "%u: (%s %s %s %s) hasinput=%s clickthrough=%s\n",
|
||||
i, curitem.bounds().x0, curitem.bounds().y0, curitem.bounds().x1, curitem.bounds().y1, curitem.has_input(), curitem.clickthrough());
|
||||
m_interactive_edges_x.emplace_back(i, curitem.bounds().x0, false);
|
||||
m_interactive_edges_x.emplace_back(i, curitem.bounds().x1, true);
|
||||
m_interactive_edges_y.emplace_back(i, curitem.bounds().y0, false);
|
||||
m_interactive_edges_y.emplace_back(i, curitem.bounds().y1, true);
|
||||
}
|
||||
std::sort(m_interactive_edges_x.begin(), m_interactive_edges_x.end());
|
||||
std::sort(m_interactive_edges_y.begin(), m_interactive_edges_y.end());
|
||||
|
||||
if (VERBOSE & LOG_INTERACTIVE_ITEMS)
|
||||
{
|
||||
for (edge const &e : m_interactive_edges_x)
|
||||
LOGMASKED(LOG_INTERACTIVE_ITEMS, "x=%s %c%u\n", e.position(), e.trailing() ? ']' : '[', e.index());
|
||||
for (edge const &e : m_interactive_edges_y)
|
||||
LOGMASKED(LOG_INTERACTIVE_ITEMS, "y=%s %c%u\n", e.position(), e.trailing() ? ']' : '[', e.index());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3469,25 +3505,25 @@ layout_view::item::item(
|
||||
: m_element(find_element(env, itemnode, elemmap))
|
||||
, m_output(env.device(), env.get_attribute_string(itemnode, "name", ""))
|
||||
, m_have_output(env.get_attribute_string(itemnode, "name", "")[0])
|
||||
, m_input_tag(make_input_tag(env, itemnode))
|
||||
, m_input_port(nullptr)
|
||||
, m_input_field(nullptr)
|
||||
, m_input_mask(env.get_attribute_int(itemnode, "inputmask", 0))
|
||||
, m_input_shift(0)
|
||||
, m_input_raw(0 != env.get_attribute_int(itemnode, "inputraw", 0))
|
||||
, m_input_shift(get_input_shift(m_input_mask))
|
||||
, m_input_raw(env.get_attribute_bool(itemnode, "inputraw", 0))
|
||||
, m_clickthrough(env.get_attribute_bool(itemnode, "clickthrough", "yes"))
|
||||
, m_screen(nullptr)
|
||||
, m_orientation(orientation_add(env.parse_orientation(itemnode.get_child("orientation")), orientation))
|
||||
, m_rawbounds(make_bounds(env, itemnode, trans))
|
||||
, m_color(render_color_multiply(env.parse_color(itemnode.get_child("color")), color))
|
||||
, m_blend_mode(get_blend_mode(env, itemnode))
|
||||
, m_visibility_mask(env.visibility_mask())
|
||||
, m_input_tag(make_input_tag(env, itemnode))
|
||||
, m_rawbounds(make_bounds(env, itemnode, trans))
|
||||
, m_has_clickthrough(env.get_attribute_string(itemnode, "clickthrough", "")[0])
|
||||
{
|
||||
// fetch common data
|
||||
int index = env.get_attribute_int(itemnode, "index", -1);
|
||||
if (index != -1)
|
||||
m_screen = screen_device_iterator(env.machine().root_device()).byindex(index);
|
||||
for (u32 mask = m_input_mask; (mask != 0) && (~mask & 1); mask >>= 1)
|
||||
m_input_shift++;
|
||||
|
||||
// sanity checks
|
||||
if (strcmp(itemnode.get_name(), "screen") == 0)
|
||||
@ -3544,24 +3580,22 @@ int layout_view::item::state() const
|
||||
// if configured to track an output, fetch its value
|
||||
return m_output;
|
||||
}
|
||||
else if (!m_input_tag.empty())
|
||||
else if (m_input_port)
|
||||
{
|
||||
// if configured to an input, fetch the input value
|
||||
if (m_input_port)
|
||||
if (m_input_raw)
|
||||
{
|
||||
if (m_input_raw)
|
||||
{
|
||||
return (m_input_port->read() & m_input_mask) >> m_input_shift;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioport_field const *const field(m_input_field ? m_input_field : m_input_port->field(m_input_mask));
|
||||
if (field)
|
||||
return ((m_input_port->read() ^ field->defvalue()) & m_input_mask) ? 1 : 0;
|
||||
}
|
||||
return (m_input_port->read() & m_input_mask) >> m_input_shift;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioport_field const *const field(m_input_field ? m_input_field : m_input_port->field(m_input_mask));
|
||||
if (field)
|
||||
return ((m_input_port->read() ^ field->defvalue()) & m_input_mask) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// default to zero
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3584,6 +3618,7 @@ void layout_view::item::resolve_tags()
|
||||
m_input_port = m_element->machine().root_device().ioport(m_input_tag);
|
||||
if (m_input_port)
|
||||
{
|
||||
// if there's a matching unconditional field, cache it
|
||||
for (ioport_field &field : m_input_port->fields())
|
||||
{
|
||||
if (field.mask() & m_input_mask)
|
||||
@ -3593,6 +3628,10 @@ void layout_view::item::resolve_tags()
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if clickthrough isn't explicitly configured, having an I/O port implies false
|
||||
if (!m_has_clickthrough)
|
||||
m_clickthrough = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3680,6 +3719,22 @@ int layout_view::item::get_blend_mode(view_environment &env, util::xml::data_nod
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------
|
||||
// get_input_shift - shift to right-align LSB
|
||||
//---------------------------------------------
|
||||
|
||||
unsigned layout_view::item::get_input_shift(ioport_value mask)
|
||||
{
|
||||
unsigned result(0U);
|
||||
while (mask && !BIT(mask, 0))
|
||||
{
|
||||
++result;
|
||||
mask >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LAYOUT VIEW VISIBILITY TOGGLE
|
||||
|
Loading…
Reference in New Issue
Block a user