summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2020-09-12 02:03:47 +1000
committer Vas Crabb <vas@vastheman.com>2020-09-12 02:03:47 +1000
commit34cbb3a25e65201f2884d54c78ef96b6a3997ad9 (patch)
tree2f275be6f682b32b581342de07c8a5e78d989f15 /src
parent4c9244504a59999b0f04c4b267beb90696f4e54a (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/emu/render.cpp191
-rw-r--r--src/emu/render.h89
-rw-r--r--src/emu/rendlay.cpp111
3 files changed, 267 insertions, 124 deletions
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 5a22b919e1c..221ce9fc929 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -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 (&current_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;
}
diff --git a/src/emu/render.h b/src/emu/render.h
index 8aff6b73af9..b0d0df82d3c 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -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
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index 7d9eed28bf3..72c50a3db3b 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -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