summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/emu/debug/debugcpu.cpp2
-rw-r--r--src/emu/render.cpp316
-rw-r--r--src/emu/render.h111
-rw-r--r--src/emu/rendlay.cpp321
-rw-r--r--src/emu/video.cpp2
-rw-r--r--src/frontend/mame/luaengine.cpp2
-rw-r--r--src/frontend/mame/ui/mainmenu.cpp2
-rw-r--r--src/frontend/mame/ui/videoopt.cpp205
-rw-r--r--src/frontend/mame/ui/videoopt.h20
-rw-r--r--src/lib/util/xmlfile.cpp46
-rw-r--r--src/osd/modules/debugger/osx/debugwindowhandler.mm2
-rw-r--r--src/osd/modules/render/bgfx/chain.cpp2
-rw-r--r--src/osd/modules/render/d3d/d3dhlsl.cpp2
-rw-r--r--src/osd/uwp/window.cpp15
-rw-r--r--src/osd/uwp/window.h3
-rw-r--r--src/osd/windows/window.cpp15
-rw-r--r--src/osd/windows/window.h3
17 files changed, 694 insertions, 375 deletions
diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp
index 6dacf7acee1..c3dd9a0c3a6 100644
--- a/src/emu/debug/debugcpu.cpp
+++ b/src/emu/debug/debugcpu.cpp
@@ -1490,7 +1490,7 @@ bool device_debug::comment_export(util::xml::data_node &curnode)
// iterate through the comments
for (const auto & elem : m_comment_set)
{
- util::xml::data_node *datanode = curnode.add_child("comment", util::xml::normalize_string(elem.m_text.c_str()));
+ util::xml::data_node *datanode = curnode.add_child("comment", elem.m_text.c_str());
if (datanode == nullptr)
return false;
datanode->set_attribute_int("address", elem.m_address);
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index fe62b3c0bf8..cc94bc053da 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -37,20 +37,22 @@
***************************************************************************/
#include "emu.h"
-#include "emuopts.h"
#include "render.h"
+
+#include "emuopts.h"
#include "rendfont.h"
#include "rendlay.h"
#include "rendutil.h"
#include "config.h"
#include "drivenum.h"
-#include "xmlfile.h"
+
#include "ui/uimain.h"
+#include "xmlfile.h"
+
#include <zlib.h>
#include <algorithm>
-#include <functional>
@@ -893,7 +895,7 @@ render_target::render_target(render_manager &manager, util::xml::data_node const
template <typename T> render_target::render_target(render_manager &manager, T &&layout, u32 flags, constructor_impl_t)
: m_next(nullptr)
, m_manager(manager)
- , m_curview(nullptr)
+ , m_curview(0U)
, m_flags(flags)
, m_listindex(0)
, m_width(640)
@@ -949,6 +951,10 @@ template <typename T> render_target::render_target(render_manager &manager, T &&
// load the layout files
load_layout_files(std::forward<T>(layout), flags & RENDER_CREATE_SINGLE_FILE);
+ for (layout_file &file : m_filelist)
+ for (layout_view &view : file.views())
+ if (!(m_flags & RENDER_CREATE_NO_ART) || !view.has_art())
+ m_views.emplace_back(view, view.default_visibility_mask());
// set the current view to the first one
set_view(0);
@@ -1010,13 +1016,12 @@ void render_target::set_bounds(s32 width, s32 height, float pixel_aspect)
// a target
//-------------------------------------------------
-void render_target::set_view(int viewindex)
+void render_target::set_view(unsigned viewindex)
{
- layout_view *view = view_by_index(viewindex);
- if (view)
+ if (m_views.size() > viewindex)
{
- m_curview = view;
- view->recompute(m_layerconfig);
+ m_curview = viewindex;
+ current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
}
}
@@ -1034,38 +1039,54 @@ void render_target::set_max_texture_size(int maxwidth, int maxheight)
//-------------------------------------------------
+// set_visibility_toggle - show or hide selected
+// parts of a view
+//-------------------------------------------------
+
+void render_target::set_visibility_toggle(unsigned index, bool enable)
+{
+ assert(visibility_toggles().size() > index);
+ if (enable)
+ m_views[m_curview].second |= u32(1) << index;
+ else
+ m_views[m_curview].second &= ~(u32(1) << index);
+ current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+}
+
+
+//-------------------------------------------------
// configured_view - select a view for this
// target based on the configuration parameters
//-------------------------------------------------
-int render_target::configured_view(const char *viewname, int targetindex, int numtargets)
+unsigned render_target::configured_view(const char *viewname, int targetindex, int numtargets)
{
layout_view *view = nullptr;
- int viewindex;
// auto view just selects the nth view
if (strcmp(viewname, "auto") != 0)
{
// scan for a matching view name
size_t viewlen = strlen(viewname);
- for (view = view_by_index(viewindex = 0); view != nullptr; view = view_by_index(++viewindex))
- if (core_strnicmp(view->name().c_str(), viewname, viewlen) == 0)
- break;
+ for (unsigned i = 0; !view && (m_views.size() > i); ++i)
+ if (!core_strnicmp(m_views[i].first.get().name().c_str(), viewname, viewlen))
+ view = &m_views[i].first.get();
}
// if we don't have a match, default to the nth view
- screen_device_iterator iter(m_manager.machine().root_device());
- int scrcount = iter.count();
- if (view == nullptr && scrcount > 0)
+ std::vector<std::reference_wrapper<screen_device> > screens;
+ for (screen_device &screen : screen_device_iterator(m_manager.machine().root_device()))
+ screens.push_back(screen);
+ if (!view && !screens.empty())
{
// if we have enough targets to be one per screen, assign in order
- if (numtargets >= scrcount)
+ if (numtargets >= screens.size())
{
- int ourindex = index() % scrcount;
- screen_device *screen = iter.byindex(ourindex);
- assert(screen != nullptr);
+ int const ourindex = index() % screens.size();
+ screen_device &screen = screens[ourindex];
// find the first view with this screen and this screen only
+ unsigned viewindex;
for (view = view_by_index(viewindex = 0); view != nullptr; view = view_by_index(++viewindex))
{
auto const &viewscreens = view->screens();
@@ -1074,36 +1095,34 @@ int render_target::configured_view(const char *viewname, int targetindex, int nu
view = nullptr;
break;
}
- else if (std::find_if(viewscreens.begin(), viewscreens.end(), [&screen](auto const &scr) { return &scr.get() != screen; }) == viewscreens.end())
+ else if (std::find_if(viewscreens.begin(), viewscreens.end(), [&screen] (auto const &scr) { return &scr.get() != &screen; }) == viewscreens.end())
break;
}
}
// otherwise, find the first view that has all the screens
- if (view == nullptr)
+ if (!view)
{
- for (view = view_by_index(viewindex = 0); view != nullptr; view = view_by_index(++viewindex))
+ for (unsigned i = 0; !view && (m_views.size() > i); ++i)
{
- if (view->screen_count() >= scrcount)
+ view = &m_views[i].first.get();
+ if (view->screen_count() >= screens.size())
{
- bool screen_missing(false);
- for (screen_device &screen : iter)
+ for (screen_device &screen : screens)
{
if (!view->has_screen(screen))
{
- screen_missing = true;
+ view = nullptr;
break;
}
}
- if (!screen_missing)
- break;
}
}
}
}
// make sure it's a valid view
- return (view != nullptr) ? view_index(*view) : 0;
+ return view ? view_index(*view) : 0;
}
@@ -1111,10 +1130,14 @@ int render_target::configured_view(const char *viewname, int targetindex, int nu
// view_name - return the name of the given view
//-------------------------------------------------
-const char *render_target::view_name(int viewindex)
+const char *render_target::view_name(unsigned viewindex)
+{
+ return (m_views.size() > viewindex) ? m_views[viewindex].first.get().name().c_str() : nullptr;
+}
+
+layout_view::visibility_toggle_vector const &render_target::visibility_toggles()
{
- layout_view const *const view = view_by_index(viewindex);
- return view ? view->name().c_str() : nullptr;
+ return current_view().visibility_toggles();
}
@@ -1137,7 +1160,7 @@ void render_target::compute_visible_area(s32 target_width, s32 target_height, fl
if (m_keepaspect)
{
// start with the aspect ratio of the square pixel layout
- width = m_curview->effective_aspect(m_layerconfig);
+ width = current_view().effective_aspect();
height = 1.0f;
// first apply target orientation
@@ -1173,7 +1196,7 @@ void render_target::compute_visible_area(s32 target_width, s32 target_height, fl
// get source size and aspect
s32 src_width, src_height;
compute_minimum_size(src_width, src_height);
- float src_aspect = m_curview->effective_aspect(m_layerconfig);
+ float src_aspect = current_view().effective_aspect();
// apply orientation if required
if (target_orientation & ORIENTATION_SWAP_XY)
@@ -1242,11 +1265,11 @@ void render_target::compute_minimum_size(s32 &minwidth, s32 &minheight)
return;
}
- if (!m_curview)
+ if (m_views.empty())
throw emu_fatalerror("Mandatory artwork is missing");
// scan the current view for all screens
- for (layout_view::item &curitem : m_curview->items())
+ for (layout_view::item &curitem : current_view().items())
{
if (curitem.screen())
{
@@ -1301,8 +1324,8 @@ void render_target::compute_minimum_size(s32 &minwidth, s32 &minheight)
render_primitive_list &render_target::get_primitives()
{
// remember the base values if this is the first frame
- if (m_base_view == nullptr)
- m_base_view = m_curview;
+ if (!m_base_view)
+ m_base_view = &current_view();
// switch to the next primitive list
render_primitive_list &list = m_primlist[m_listindex];
@@ -1326,38 +1349,42 @@ render_primitive_list &render_target::get_primitives()
root_xform.orientation = m_orientation;
root_xform.no_center = false;
- // iterate over items in the view, but only if we're running
if (m_manager.machine().phase() >= machine_phase::RESET)
- for (layout_view::item &curitem : m_curview->items())
+ {
+ // we're running - iterate over items in the view
+ for (layout_view::item &curitem : current_view().items())
{
- // first apply orientation to the bounds
- render_bounds bounds = curitem.bounds();
- apply_orientation(bounds, root_xform.orientation);
- normalize_bounds(bounds);
-
- // apply the transform to the item
- object_transform item_xform;
- item_xform.xoffs = root_xform.xoffs + bounds.x0 * root_xform.xscale;
- item_xform.yoffs = root_xform.yoffs + bounds.y0 * root_xform.yscale;
- item_xform.xscale = (bounds.x1 - bounds.x0) * root_xform.xscale;
- item_xform.yscale = (bounds.y1 - bounds.y0) * root_xform.yscale;
- item_xform.color.r = curitem.color().r * root_xform.color.r;
- item_xform.color.g = curitem.color().g * root_xform.color.g;
- item_xform.color.b = curitem.color().b * root_xform.color.b;
- item_xform.color.a = curitem.color().a * root_xform.color.a;
- item_xform.orientation = orientation_add(curitem.orientation(), root_xform.orientation);
- item_xform.no_center = false;
-
- // if there is no associated element, it must be a screen element
- if (curitem.screen() != nullptr)
- add_container_primitives(list, root_xform, item_xform, curitem.screen()->container(), curitem.blend_mode());
- else
- add_element_primitives(list, item_xform, *curitem.element(), curitem.state(), curitem.blend_mode());
+ if ((visibility_mask() & curitem.visibility_mask()) == curitem.visibility_mask())
+ {
+ // first apply orientation to the bounds
+ render_bounds bounds = curitem.bounds();
+ apply_orientation(bounds, root_xform.orientation);
+ normalize_bounds(bounds);
+
+ // apply the transform to the item
+ object_transform item_xform;
+ item_xform.xoffs = root_xform.xoffs + bounds.x0 * root_xform.xscale;
+ item_xform.yoffs = root_xform.yoffs + bounds.y0 * root_xform.yscale;
+ item_xform.xscale = (bounds.x1 - bounds.x0) * root_xform.xscale;
+ item_xform.yscale = (bounds.y1 - bounds.y0) * root_xform.yscale;
+ item_xform.color.r = curitem.color().r * root_xform.color.r;
+ item_xform.color.g = curitem.color().g * root_xform.color.g;
+ item_xform.color.b = curitem.color().b * root_xform.color.b;
+ item_xform.color.a = curitem.color().a * root_xform.color.a;
+ item_xform.orientation = orientation_add(curitem.orientation(), root_xform.orientation);
+ item_xform.no_center = false;
+
+ // if there is no associated element, it must be a screen element
+ if (curitem.screen())
+ add_container_primitives(list, root_xform, item_xform, curitem.screen()->container(), curitem.blend_mode());
+ else
+ add_element_primitives(list, item_xform, *curitem.element(), curitem.state(), curitem.blend_mode());
+ }
}
-
- // if we are not in the running stage, draw an outer box
+ }
else
{
+ // if we are not in the running stage, draw an outer box
render_primitive *prim = list.alloc(render_primitive::QUAD);
set_render_bounds_xy(prim->bounds, 0.0f, 0.0f, (float)m_width, (float)m_height);
prim->full_bounds = prim->bounds;
@@ -1520,7 +1547,7 @@ void render_target::resolve_tags()
void render_target::update_layer_config()
{
- m_curview->recompute(m_layerconfig);
+ current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
}
@@ -1694,10 +1721,9 @@ void render_target::load_additional_layout_files(const char *basename, bool have
throw emu_fatalerror("Couldn't create XML node??");
viewnode->set_attribute(
"name",
- util::xml::normalize_string(
- util::string_format(
- "Screen %1$u Standard (%2$u:%3$u)",
- i, screens[i].physical_x(), screens[i].physical_y()).c_str()));
+ util::string_format(
+ "Screen %1$u Standard (%2$u:%3$u)",
+ i, screens[i].physical_x(), screens[i].physical_y()).c_str());
util::xml::data_node *const screennode(viewnode->add_child("screen", nullptr));
if (!screennode)
throw emu_fatalerror("Couldn't create XML node??");
@@ -1721,10 +1747,9 @@ void render_target::load_additional_layout_files(const char *basename, bool have
throw emu_fatalerror("Couldn't create XML node??");
viewnode->set_attribute(
"name",
- util::xml::normalize_string(
- util::string_format(
- "Screen %1$u Pixel Aspect (%2$u:%3$u)",
- i, screens[i].native_x(), screens[i].native_y()).c_str()));
+ util::string_format(
+ "Screen %1$u Pixel Aspect (%2$u:%3$u)",
+ i, screens[i].native_x(), screens[i].native_y()).c_str());
util::xml::data_node *const screennode(viewnode->add_child("screen", nullptr));
if (!screennode)
throw emu_fatalerror("Couldn't create XML node??");
@@ -1841,7 +1866,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
util::xml::data_node *viewnode = layoutnode->add_child("view", nullptr);
if (!viewnode)
throw emu_fatalerror("Couldn't create XML node??");
- viewnode->set_attribute("name", util::xml::normalize_string(title));
+ viewnode->set_attribute("name", title);
float ypos(0.0F);
for (unsigned y = 0U; rows > y; ypos += heights[y] + spacing, ++y)
{
@@ -2479,8 +2504,11 @@ bool render_target::map_point_internal(s32 target_x, s32 target_y, render_contai
}
// iterate over items in the view
- for (layout_view::item &item : m_curview->items())
+ 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
@@ -2511,15 +2539,9 @@ bool render_target::map_point_internal(s32 target_x, s32 target_y, render_contai
// view, or nullptr if it doesn't exist
//-------------------------------------------------
-layout_view *render_target::view_by_index(int index)
+layout_view *render_target::view_by_index(unsigned index)
{
- // scan the list of views within each layout, skipping those that don't apply
- for (layout_file &file : m_filelist)
- for (layout_view &view : file.views())
- if (!(m_flags & RENDER_CREATE_NO_ART) || !view.has_art())
- if (index-- == 0)
- return &view;
- return nullptr;
+ return (m_views.size() > index) ? &m_views[index].first.get() : nullptr;
}
@@ -2552,8 +2574,6 @@ int render_target::view_index(layout_view &targetview) const
void render_target::config_load(util::xml::data_node const &targetnode)
{
- int tmpint;
-
// find the view
const char *viewname = targetnode.get_attribute_string("view", nullptr);
if (viewname != nullptr)
@@ -2570,23 +2590,23 @@ void render_target::config_load(util::xml::data_node const &targetnode)
}
// modify the artwork config
- tmpint = targetnode.get_attribute_int("zoom", -1);
- if (tmpint == 0 || tmpint == 1)
- set_zoom_to_screen(tmpint);
+ int const zoom = targetnode.get_attribute_int("zoom", -1);
+ if (zoom == 0 || zoom == 1)
+ set_zoom_to_screen(zoom);
// apply orientation
- tmpint = targetnode.get_attribute_int("rotate", -1);
- if (tmpint != -1)
- {
- if (tmpint == 90)
- tmpint = ROT90;
- else if (tmpint == 180)
- tmpint = ROT180;
- else if (tmpint == 270)
- tmpint = ROT270;
+ int rotate = targetnode.get_attribute_int("rotate", -1);
+ if (rotate != -1)
+ {
+ if (rotate == 90)
+ rotate = ROT90;
+ else if (rotate == 180)
+ rotate = ROT180;
+ else if (rotate == 270)
+ rotate = ROT270;
else
- tmpint = ROT0;
- set_orientation(orientation_add(tmpint, orientation()));
+ rotate = ROT0;
+ set_orientation(orientation_add(rotate, orientation()));
// apply the opposite orientation to the UI
if (is_ui_target())
@@ -2595,10 +2615,43 @@ void render_target::config_load(util::xml::data_node const &targetnode)
render_container &ui_container = m_manager.ui_container();
ui_container.get_user_settings(settings);
- settings.m_orientation = orientation_add(orientation_reverse(tmpint), settings.m_orientation);
+ settings.m_orientation = orientation_add(orientation_reverse(rotate), settings.m_orientation);
ui_container.set_user_settings(settings);
}
}
+
+ // apply per-view settings
+ for (util::xml::data_node const *viewnode = targetnode.get_child("view"); viewnode; viewnode = viewnode->get_next_sibling("view"))
+ {
+ char const *const viewname = viewnode->get_attribute_string("name", nullptr);
+ if (!viewname)
+ continue;
+
+ auto const view = std::find_if(m_views.begin(), m_views.end(), [viewname] (auto const &x) { return x.first.get().name() == viewname; });
+ if (m_views.end() == view)
+ continue;
+
+ for (util::xml::data_node const *vistogglenode = viewnode->get_child("vistoggle"); vistogglenode; vistogglenode = vistogglenode->get_next_sibling("vistoggle"))
+ {
+ char const *const vistogglename = vistogglenode->get_attribute_string("name", nullptr);
+ if (!vistogglename)
+ continue;
+
+ auto const &vistoggles = view->first.get().visibility_toggles();
+ auto const vistoggle = std::find_if(vistoggles.begin(), vistoggles.end(), [vistogglename] (auto const &x) { return x.name() == vistogglename; });
+ if (vistoggles.end() == vistoggle)
+ continue;
+
+ int const enable = vistogglenode->get_attribute_int("enabled", -1);
+ if (0 <= enable)
+ {
+ if (enable)
+ view->second |= u32(1) << std::distance(vistoggles.begin(), vistoggle);
+ else
+ view->second &= ~(u32(1) << std::distance(vistoggles.begin(), vistoggle));
+ }
+ }
+ }
}
@@ -2615,9 +2668,9 @@ bool render_target::config_save(util::xml::data_node &targetnode)
targetnode.set_attribute_int("index", index());
// output the view
- if (m_curview != m_base_view)
+ if (&current_view() != m_base_view)
{
- targetnode.set_attribute("view", m_curview->name().c_str());
+ targetnode.set_attribute("view", current_view().name().c_str());
changed = true;
}
@@ -2643,6 +2696,33 @@ bool render_target::config_save(util::xml::data_node &targetnode)
changed = true;
}
+ // output layer configuration
+ for (auto const &view : m_views)
+ {
+ u32 const defvismask = view.first.get().default_visibility_mask();
+ if (defvismask != view.second)
+ {
+ util::xml::data_node *viewnode = nullptr;
+ unsigned i = 0;
+ for (layout_view::visibility_toggle const &toggle : view.first.get().visibility_toggles())
+ {
+ if (BIT(defvismask, i) != BIT(view.second, i))
+ {
+ if (!viewnode)
+ {
+ viewnode = targetnode.add_child("view", nullptr);
+ viewnode->set_attribute("name", view.first.get().name().c_str());
+ }
+ util::xml::data_node *const vistogglenode = viewnode->add_child("vistoggle", nullptr);
+ vistogglenode->set_attribute("name", toggle.name().c_str());
+ vistogglenode->set_attribute_int("enabled", BIT(view.second, i));
+ changed = true;
+ }
+ ++i;
+ }
+ }
+ }
+
return changed;
}
@@ -2968,8 +3048,8 @@ bool render_manager::is_live(screen_device &screen) const
{
if (!target.hidden())
{
- layout_view const *view = target.current_view();
- if (view != nullptr && view->has_screen(screen))
+ layout_view const *view = &target.current_view();
+ if (view->has_screen(screen))
return true;
}
}
@@ -3201,35 +3281,31 @@ void render_manager::container_free(render_container *container)
void render_manager::config_load(config_type cfg_type, util::xml::data_node const *parentnode)
{
- // we only care about game files
- if (cfg_type != config_type::GAME)
- return;
-
- // might not have any data
- if (parentnode == nullptr)
+ // we only care about game files with matching nodes
+ if ((cfg_type != config_type::GAME) || !parentnode)
return;
// check the UI target
util::xml::data_node const *const uinode = parentnode->get_child("interface");
- if (uinode != nullptr)
+ if (uinode)
{
- render_target *target = target_by_index(uinode->get_attribute_int("target", 0));
- if (target != nullptr)
+ render_target *const target = target_by_index(uinode->get_attribute_int("target", 0));
+ if (target)
set_ui_target(*target);
}
// iterate over target nodes
for (util::xml::data_node const *targetnode = parentnode->get_child("target"); targetnode; targetnode = targetnode->get_next_sibling("target"))
{
- render_target *target = target_by_index(targetnode->get_attribute_int("index", -1));
- if (target != nullptr)
+ render_target *const target = target_by_index(targetnode->get_attribute_int("index", -1));
+ if (target)
target->config_load(*targetnode);
}
// iterate over screen nodes
for (util::xml::data_node const *screennode = parentnode->get_child("screen"); screennode; screennode = screennode->get_next_sibling("screen"))
{
- int index = screennode->get_attribute_int("index", -1);
+ int const index = screennode->get_attribute_int("index", -1);
render_container *container = m_screen_container_list.find(index);
render_container::user_settings settings;
@@ -3283,7 +3359,7 @@ void render_manager::config_save(config_type cfg_type, util::xml::data_node *par
// create a node
util::xml::data_node *const targetnode = parentnode->add_child("target", nullptr);
- if (targetnode != nullptr && !target->config_save(*targetnode))
+ if (targetnode && !target->config_save(*targetnode))
targetnode->delete_node();
}
diff --git a/src/emu/render.h b/src/emu/render.h
index 0a59d7d894e..d846dce58c1 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -48,17 +48,24 @@
#include "screen.h"
-#include <cmath>
#include <array>
+#include <cmath>
+#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
+#include <utility>
#include <vector>
-namespace emu { namespace render { namespace detail { class layout_environment; } } }
+namespace emu { namespace render { namespace detail {
+
+class layout_environment;
+class view_environment;
+
+} } } // namespace emu::render::detail
//**************************************************************************
@@ -176,6 +183,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(); }
};
@@ -725,20 +733,17 @@ private:
class layout_view
{
public:
- using environment = emu::render::detail::layout_environment;
+ using layout_environment = emu::render::detail::layout_environment;
+ 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>>;
- /// \brief A single backdrop/screen/overlay/bezel/cpanel/marquee item
+ /// \brief A single item in a view
///
- /// Each view has four lists of view_items, one for each "layer."
- /// Each view item is specified using floating point coordinates in
- /// arbitrary units, and is assumed to have square pixels. Each
- /// view item can control its orientation independently. Each item
- /// can also have an optional name, and can be set at runtime into
- /// different "states", which control how the embedded elements are
- /// displayed.
+ /// Each view has a list of item structures describing the visual
+ /// elements to draw, where they are located, additional blending
+ /// modes, and bindings for inputs and outputs.
class item
{
friend class layout_view;
@@ -746,7 +751,7 @@ public:
public:
// construction/destruction
item(
- environment &env,
+ view_environment &env,
util::xml::data_node const &itemnode,
element_map &elemmap,
int orientation,
@@ -760,6 +765,7 @@ public:
const render_bounds &bounds() const { return m_bounds; }
const render_color &color() const { return m_color; }
int blend_mode() const { return m_blend_mode; }
+ u32 visibility_mask() const { return m_visibility_mask; }
int orientation() const { return m_orientation; }
render_container *screen_container(running_machine &machine) const;
bool has_input() const { return bool(m_input_port); }
@@ -775,10 +781,10 @@ public:
void set_blend_mode(int mode) { m_blend_mode = mode; }
private:
- static layout_element *find_element(environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
- static render_bounds make_bounds(environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
- static std::string make_input_tag(environment &env, util::xml::data_node const &itemnode);
- static int get_blend_mode(environment &env, util::xml::data_node const &itemnode);
+ 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);
// internal state
layout_element *const m_element; // pointer to the associated element (non-screens only)
@@ -796,12 +802,37 @@ public:
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
};
using item_list = std::list<item>;
+ /// \brief A subset of items in a view that can be hidden or shown
+ ///
+ /// Visibility toggles allow the user to show or hide selected parts
+ /// of a view.
+ class visibility_toggle
+ {
+ public:
+ // construction/destruction/assignment
+ visibility_toggle(std::string &&name, u32 mask);
+ visibility_toggle(visibility_toggle const &) = default;
+ visibility_toggle(visibility_toggle &&) = default;
+ visibility_toggle &operator=(visibility_toggle const &) = default;
+ visibility_toggle &operator=(visibility_toggle &&) = default;
+
+ // getters
+ std::string const &name() const { return m_name; }
+ u32 mask() const { return m_mask; }
+
+ private:
+ std::string m_name; // display name for the toggle
+ u32 m_mask; // toggle combination to show
+ };
+ using visibility_toggle_vector = std::vector<visibility_toggle>;
+
// construction/destruction
layout_view(
- environment &env,
+ layout_environment &env,
util::xml::data_node const &viewnode,
element_map &elemmap,
group_map &groupmap);
@@ -810,18 +841,17 @@ public:
// getters
item_list &items() { return m_items; }
const std::string &name() const { return m_name; }
- const render_bounds &bounds() const { return m_bounds; }
- const render_bounds &screen_bounds() const { return m_scrbounds; }
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; }
- float effective_aspect(render_layer_config config) const { return (config.zoom_to_screen() && !m_screens.empty()) ? m_scraspect : m_aspect; }
+ u32 default_visibility_mask() const { return m_defvismask; }
+ const visibility_toggle_vector &visibility_toggles() const { return m_vistoggles; }
// operations
- void recompute(render_layer_config layerconfig);
+ void recompute(u32 visibility_mask, bool zoom_to_screens);
// resolve tags, if any
void resolve_tags();
@@ -832,7 +862,7 @@ private:
// add items, recursing for groups
void add_items(
layer_lists &layers,
- environment &env,
+ view_environment &env,
util::xml::data_node const &parentnode,
element_map &elemmap,
group_map &groupmap,
@@ -843,18 +873,18 @@ private:
bool repeat,
bool init);
- static std::string make_name(environment &env, util::xml::data_node const &viewnode);
+ static std::string make_name(layout_environment &env, util::xml::data_node const &viewnode);
// internal state
std::string m_name; // name of the layout
- float m_aspect; // X/Y of the layout
- float m_scraspect; // X/Y of the screen areas
- render_screen_list m_screens; // list of active screens
- render_bounds m_bounds; // computed bounds of the view
- render_bounds m_scrbounds; // computed bounds of the screens within the view
+ 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;
};
@@ -920,8 +950,8 @@ public:
float max_update_rate() const { return m_max_refresh; }
int orientation() const { return m_orientation; }
render_layer_config layer_config() const { return m_layerconfig; }
- layout_view *current_view() const { return m_curview; }
- int view() const { return view_index(*m_curview); }
+ layout_view &current_view() const { return m_views[m_curview].first.get(); }
+ unsigned view() const { return m_curview; }
bool external_artwork() const { return m_external_artwork; }
bool hidden() const { return ((m_flags & RENDER_CREATE_HIDDEN) != 0); }
bool is_ui_target() const;
@@ -931,7 +961,7 @@ public:
void set_bounds(s32 width, s32 height, float pixel_aspect = 0);
void set_max_update_rate(float updates_per_second) { m_max_refresh = updates_per_second; }
void set_orientation(int orientation) { m_orientation = orientation; }
- void set_view(int viewindex);
+ void set_view(unsigned viewindex);
void set_max_texture_size(int maxwidth, int maxheight);
void set_transform_container(bool transform_container) { m_transform_container = transform_container; }
void set_keepaspect(bool keepaspect) { m_keepaspect = keepaspect; }
@@ -940,16 +970,19 @@ public:
// layer config getters
bool screen_overlay_enabled() const { return m_layerconfig.screen_overlay_enabled(); }
bool zoom_to_screen() const { return m_layerconfig.zoom_to_screen(); }
+ u32 visibility_mask() const { return m_views[m_curview].second; }
// layer config setters
+ void set_visibility_toggle(unsigned index, bool enable);
void set_screen_overlay_enabled(bool enable) { m_layerconfig.set_screen_overlay_enabled(enable); update_layer_config(); }
void set_zoom_to_screen(bool zoom) { m_layerconfig.set_zoom_to_screen(zoom); update_layer_config(); }
// view configuration helper
- int configured_view(const char *viewname, int targetindex, int numtargets);
+ unsigned configured_view(const char *viewname, int targetindex, int numtargets);
// view information
- const char *view_name(int viewindex);
+ char const *view_name(unsigned index);
+ layout_view::visibility_toggle_vector const &visibility_toggles();
// bounds computations
void compute_visible_area(s32 target_width, s32 target_height, float target_pixel_aspect, int target_orientation, s32 &visible_width, s32 &visible_height);
@@ -974,6 +1007,9 @@ public:
void resolve_tags();
private:
+ using view_mask_pair = std::pair<std::reference_wrapper<layout_view>, u32>;
+ using view_mask_vector = std::vector<view_mask_pair>;
+
// private classes declared in render.cpp
struct object_transform;
@@ -996,7 +1032,7 @@ private:
bool config_save(util::xml::data_node &targetnode);
// view lookups
- layout_view *view_by_index(int index);
+ layout_view *view_by_index(unsigned index);
int view_index(layout_view &view) const;
// optimized clearing
@@ -1012,8 +1048,9 @@ private:
// internal state
render_target * m_next; // link to next target
render_manager & m_manager; // reference to our owning manager
- layout_view * m_curview; // current view
std::list<layout_file> m_filelist; // list of layout files
+ view_mask_vector m_views; // views we consider
+ unsigned m_curview; // current view index
u32 m_flags; // creation flags
render_primitive_list m_primlist[NUM_PRIMLISTS]; // list of primitives
int m_listindex; // index of next primlist to use
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index 4db27e47762..1d4a8f23265 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -518,6 +518,39 @@ private:
return expand(str, str + strlen(str));
}
+ int parse_int(char const *begin, char const *end, int defvalue)
+ {
+ std::istringstream stream;
+ stream.imbue(f_portable_locale);
+ int result;
+ if (begin[0] == '$')
+ {
+ stream.str(std::string(begin + 1, end));
+ unsigned uvalue;
+ stream >> std::hex >> uvalue;
+ result = int(uvalue);
+ }
+ else if ((begin[0] == '0') && ((begin[1] == 'x') || (begin[1] == 'X')))
+ {
+ stream.str(std::string(begin + 2, end));
+ unsigned uvalue;
+ stream >> std::hex >> uvalue;
+ result = int(uvalue);
+ }
+ else if (begin[0] == '#')
+ {
+ stream.str(std::string(begin + 1, end));
+ stream >> result;
+ }
+ else
+ {
+ stream.str(std::string(begin, end));
+ stream >> result;
+ }
+
+ return stream ? result : defvalue;
+ }
+
std::string parameter_name(util::xml::data_node const &node)
{
char const *const attrib(node.get_attribute_string("name", nullptr));
@@ -547,8 +580,15 @@ private:
bool m_cached = false;
public:
- explicit layout_environment(device_t &device) : m_device(device) { }
- explicit layout_environment(layout_environment &next) : m_device(next.m_device), m_next(&next) { }
+ explicit layout_environment(device_t &device)
+ : m_device(device)
+ {
+ }
+ explicit layout_environment(layout_environment &next)
+ : m_device(next.m_device)
+ , m_next(&next)
+ {
+ }
layout_environment(layout_environment const &) = delete;
device_t &device() { return m_device; }
@@ -706,35 +746,7 @@ public:
// similar to what XML nodes do
std::pair<char const *, char const *> const expanded(expand(attrib));
- std::istringstream stream;
- stream.imbue(f_portable_locale);
- int result;
- if (expanded.first[0] == '$')
- {
- stream.str(std::string(expanded.first + 1, expanded.second));
- unsigned uvalue;
- stream >> std::hex >> uvalue;
- result = int(uvalue);
- }
- else if ((expanded.first[0] == '0') && ((expanded.first[1] == 'x') || (expanded.first[1] == 'X')))
- {
- stream.str(std::string(expanded.first + 2, expanded.second));
- unsigned uvalue;
- stream >> std::hex >> uvalue;
- result = int(uvalue);
- }
- else if (expanded.first[0] == '#')
- {
- stream.str(std::string(expanded.first + 1, expanded.second));
- stream >> result;
- }
- else
- {
- stream.str(std::string(expanded.first, expanded.second));
- stream >> result;
- }
-
- return stream ? result : defvalue;
+ return parse_int(expanded.first, expanded.second, defvalue);
}
float get_attribute_float(util::xml::data_node const &node, char const *name, float defvalue)
@@ -751,6 +763,23 @@ public:
return (stream >> result) ? result : defvalue;
}
+ bool get_attribute_bool(util::xml::data_node const &node, char const *name, bool defvalue)
+ {
+ char const *const attrib(node.get_attribute_string(name, nullptr));
+ if (!attrib)
+ return defvalue;
+
+ // first try yes/no strings
+ std::pair<char const *, char const *> const expanded(expand(attrib));
+ if (!std::strcmp("yes", expanded.first) || !std::strcmp("true", expanded.first))
+ return true;
+ if (!std::strcmp("no", expanded.first) || !std::strcmp("false", expanded.first))
+ return false;
+
+ // fall back to integer parsing
+ return parse_int(expanded.first, expanded.second, defvalue ? 1 : 0) != 0;
+ }
+
void parse_bounds(util::xml::data_node const *node, render_bounds &result)
{
// default to unit rectangle
@@ -826,16 +855,50 @@ public:
case 270: result = ROT270; break;
default: throw layout_syntax_error(util::string_format("invalid rotate attribute %d", rotate));
}
- if (!std::strcmp("yes", get_attribute_string(*node, "swapxy", "no")))
+ if (get_attribute_bool(*node, "swapxy", false))
result ^= ORIENTATION_SWAP_XY;
- if (!std::strcmp("yes", get_attribute_string(*node, "flipx", "no")))
+ if (get_attribute_bool(*node, "flipx", false))
result ^= ORIENTATION_FLIP_X;
- if (!std::strcmp("yes", get_attribute_string(*node, "flipy", "no")))
+ if (get_attribute_bool(*node, "flipy", false))
result ^= ORIENTATION_FLIP_Y;
return result;
}
};
+
+class view_environment : public layout_environment
+{
+private:
+ view_environment *const m_next_view = nullptr;
+ char const *const m_name;
+ u32 const m_visibility_mask = 0U;
+ unsigned m_next_visibility_bit = 0U;
+
+public:
+ view_environment(layout_environment &next, char const *name)
+ : layout_environment(next)
+ , m_name(name)
+ {
+ }
+ view_environment(view_environment &next, bool visibility)
+ : layout_environment(next)
+ , m_next_view(&next)
+ , m_name(next.m_name)
+ , m_visibility_mask(next.m_visibility_mask | (u32(visibility ? 1 : 0) << next.m_next_visibility_bit))
+ , m_next_visibility_bit(next.m_next_visibility_bit + (visibility ? 1 : 0))
+ {
+ if (32U < m_next_visibility_bit)
+ throw layout_syntax_error(util::string_format("view '%s' contains too many visibility toggles", m_name));
+ }
+ ~view_environment()
+ {
+ if (m_next_view)
+ m_next_view->m_next_visibility_bit = m_next_visibility_bit;
+ }
+
+ u32 visibility_mask() const { return m_visibility_mask; }
+};
+
} } } // namespace emu::render::detail
@@ -1157,6 +1220,13 @@ void layout_group::resolve_bounds(
local.increment_parameters();
}
}
+ else if (!strcmp(itemnode->get_name(), "vistoggle"))
+ {
+ if (!env.get_attribute_string(*itemnode, "name", nullptr))
+ throw layout_syntax_error("vistoggle must have name attribute");
+ environment local(env);
+ resolve_bounds(local, *itemnode, groupmap, seen, empty, false, true);
+ }
else
{
throw layout_syntax_error(util::string_format("unknown group element %s", itemnode->get_name()));
@@ -2955,23 +3025,70 @@ struct layout_view::layer_lists { item_list backdrops, screens, overlays, bezels
//-------------------------------------------------
layout_view::layout_view(
- environment &env,
+ layout_environment &env,
util::xml::data_node const &viewnode,
element_map &elemmap,
group_map &groupmap)
: m_name(make_name(env, viewnode))
- , m_aspect(1.0f)
- , m_scraspect(1.0f)
+ , m_effaspect(1.0f)
, m_items()
, m_has_art(false)
+ , m_defvismask(0U)
{
// parse the layout
m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0;
- environment local(env);
+ view_environment local(env, m_name.c_str());
layer_lists layers;
local.set_parameter("viewname", std::string(m_name));
add_items(layers, local, viewnode, elemmap, groupmap, ROT0, identity_transform, render_color{ 1.0F, 1.0F, 1.0F, 1.0F }, true, false, true);
+ // can't support legacy layers and modern visibility toggles at the same time
+ if (!m_vistoggles.empty() && (!layers.backdrops.empty() || !layers.overlays.empty() || !layers.bezels.empty() || !layers.cpanels.empty() || !layers.marquees.empty()))
+ throw layout_syntax_error("view contains visibility toggles as well as legacy backdrop, overlay, bezel, cpanel and/or marquee elements");
+
+ // create visibility toggles for legacy layers
+ u32 mask(1U);
+ if (!layers.backdrops.empty())
+ {
+ m_vistoggles.emplace_back("Backdrops", mask);
+ for (item &backdrop : layers.backdrops)
+ backdrop.m_visibility_mask = mask;
+ m_defvismask |= mask;
+ mask <<= 1;
+ }
+ if (!layers.overlays.empty())
+ {
+ m_vistoggles.emplace_back("Overlays", mask);
+ for (item &overlay : layers.overlays)
+ overlay.m_visibility_mask = mask;
+ m_defvismask |= mask;
+ mask <<= 1;
+ }
+ if (!layers.bezels.empty())
+ {
+ m_vistoggles.emplace_back("Bezels", mask);
+ for (item &bezel : layers.bezels)
+ bezel.m_visibility_mask = mask;
+ m_defvismask |= mask;
+ mask <<= 1;
+ }
+ if (!layers.cpanels.empty())
+ {
+ m_vistoggles.emplace_back("Control Panels", mask);
+ for (item &cpanel : layers.cpanels)
+ cpanel.m_visibility_mask = mask;
+ m_defvismask |= mask;
+ mask <<= 1;
+ }
+ if (!layers.marquees.empty())
+ {
+ m_vistoggles.emplace_back("Backdrops", mask);
+ for (item &marquee : layers.marquees)
+ marquee.m_visibility_mask = mask;
+ m_defvismask |= mask;
+ mask <<= 1;
+ }
+
// deal with legacy element groupings
if (!layers.overlays.empty() || (layers.backdrops.size() <= 1))
{
@@ -3002,7 +3119,7 @@ layout_view::layout_view(
}
// calculate metrics
- recompute(render_layer_config());
+ recompute(default_visibility_mask(), false);
for (group_map::value_type &group : groupmap)
group.second.set_bounds_unresolved();
}
@@ -3024,7 +3141,7 @@ layout_view::~layout_view()
bool layout_view::has_screen(screen_device &screen) const
{
- return std::find_if(m_screens.begin(), m_screens.end(), [&screen](auto const &scr) { return &scr.get() == &screen; }) != m_screens.end();
+ return std::find_if(m_screens.begin(), m_screens.end(), [&screen] (auto const &scr) { return &scr.get() == &screen; }) != m_screens.end();
}
@@ -3033,36 +3150,39 @@ bool layout_view::has_screen(screen_device &screen) const
// ratio of a view and all of its contained items
//-------------------------------------------------
-void layout_view::recompute(render_layer_config layerconfig)
+void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
{
// reset the bounds
- m_bounds.x0 = m_bounds.y0 = m_bounds.x1 = m_bounds.y1 = 0.0f;
- m_scrbounds.x0 = m_scrbounds.y0 = m_scrbounds.x1 = m_scrbounds.y1 = 0.0f;
+ render_bounds scrbounds{ 0.0f, 0.0f, 0.0f, 0.0f };
+ m_bounds = scrbounds;
m_screens.clear();
- // loop over all layers
+ // loop over items and filter by visibility mask
bool first = true;
bool scrfirst = true;
for (item &curitem : m_items)
{
- // accumulate bounds
- if (first)
- m_bounds = curitem.m_rawbounds;
- else
- union_render_bounds(m_bounds, curitem.m_rawbounds);
- first = false;
-
- // accumulate screen bounds
- if (curitem.m_screen)
+ if ((visibility_mask & curitem.visibility_mask()) == curitem.visibility_mask())
{
- if (scrfirst)
- m_scrbounds = curitem.m_rawbounds;
+ // accumulate bounds
+ if (first)
+ m_bounds = curitem.m_rawbounds;
else
- union_render_bounds(m_scrbounds, curitem.m_rawbounds);
- scrfirst = false;
+ union_render_bounds(m_bounds, curitem.m_rawbounds);
+ first = false;
- // accumulate the screens in use while we're scanning
- m_screens.emplace_back(*curitem.m_screen);
+ // accumulate visible screens and their bounds bounds
+ if (curitem.m_screen)
+ {
+ if (scrfirst)
+ scrbounds = curitem.m_rawbounds;
+ else
+ 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);
+ }
}
}
@@ -3070,36 +3190,29 @@ void layout_view::recompute(render_layer_config layerconfig)
if (m_expbounds.x1 > m_expbounds.x0)
m_bounds = m_expbounds;
- // if we're handling things normally, the target bounds are (0,0)-(1,1)
render_bounds target_bounds;
- if (!layerconfig.zoom_to_screen() || m_screens.empty())
+ if (!zoom_to_screen || scrfirst)
{
- // compute the aspect ratio of the view
- m_aspect = (m_bounds.x1 - m_bounds.x0) / (m_bounds.y1 - m_bounds.y0);
-
+ // if we're handling things normally, the target bounds are (0,0)-(1,1)
+ m_effaspect = ((m_bounds.x1 > m_bounds.x0) && (m_bounds.y1 > m_bounds.y0)) ? m_bounds.aspect() : 1.0f;
target_bounds.x0 = target_bounds.y0 = 0.0f;
target_bounds.x1 = target_bounds.y1 = 1.0f;
}
-
- // if we're cropping, we want the screen area to fill (0,0)-(1,1)
else
{
- // compute the aspect ratio of the screen
- m_scraspect = (m_scrbounds.x1 - m_scrbounds.x0) / (m_scrbounds.y1 - m_scrbounds.y0);
-
- float targwidth = (m_bounds.x1 - m_bounds.x0) / (m_scrbounds.x1 - m_scrbounds.x0);
- float targheight = (m_bounds.y1 - m_bounds.y0) / (m_scrbounds.y1 - m_scrbounds.y0);
- target_bounds.x0 = (m_bounds.x0 - m_scrbounds.x0) / (m_bounds.x1 - m_bounds.x0) * targwidth;
- target_bounds.y0 = (m_bounds.y0 - m_scrbounds.y0) / (m_bounds.y1 - m_bounds.y0) * targheight;
- target_bounds.x1 = target_bounds.x0 + targwidth;
- target_bounds.y1 = target_bounds.y0 + targheight;
+ // if we're cropping, we want the screen area to fill (0,0)-(1,1)
+ m_effaspect = ((scrbounds.x1 > scrbounds.x0) && (scrbounds.y1 > scrbounds.y0)) ? scrbounds.aspect() : 1.0f;
+ target_bounds.x0 = (m_bounds.x0 - scrbounds.x0) / scrbounds.width();
+ target_bounds.y0 = (m_bounds.y0 - scrbounds.y0) / scrbounds.height();
+ target_bounds.x1 = target_bounds.x0 + (m_bounds.width() / scrbounds.width());
+ target_bounds.y1 = target_bounds.y0 + (m_bounds.height() / scrbounds.height());
}
// determine the scale/offset for normalization
- float xoffs = m_bounds.x0;
- float yoffs = m_bounds.y0;
- float xscale = (target_bounds.x1 - target_bounds.x0) / (m_bounds.x1 - m_bounds.x0);
- float yscale = (target_bounds.y1 - target_bounds.y0) / (m_bounds.y1 - m_bounds.y0);
+ 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);
// normalize all the item bounds
for (item &curitem : items())
@@ -3129,7 +3242,7 @@ void layout_view::resolve_tags()
void layout_view::add_items(
layer_lists &layers,
- environment &env,
+ view_environment &env,
util::xml::data_node const &parentnode,
element_map &elemmap,
group_map &groupmap,
@@ -3202,7 +3315,7 @@ void layout_view::add_items(
{
char const *ref(env.get_attribute_string(*itemnode, "ref", nullptr));
if (!ref)
- throw layout_syntax_error("nested group must have ref attribute");
+ throw layout_syntax_error("group instantiation must have ref attribute");
group_map::iterator const found(groupmap.find(ref));
if (groupmap.end() == found)
@@ -3225,7 +3338,7 @@ void layout_view::add_items(
grouptrans = found->second.make_transform(grouporient, trans);
}
- environment local(env);
+ view_environment local(env, false);
add_items(
layers,
local,
@@ -3244,13 +3357,23 @@ void layout_view::add_items(
int const count(env.get_attribute_int(*itemnode, "count", -1));
if (0 >= count)
throw layout_syntax_error("repeat must have positive integer count attribute");
- environment local(env);
+ view_environment local(env, false);
for (int i = 0; count > i; ++i)
{
add_items(layers, local, *itemnode, elemmap, groupmap, orientation, trans, color, false, true, !i);
local.increment_parameters();
}
}
+ else if (!strcmp(itemnode->get_name(), "vistoggle"))
+ {
+ char const *name(env.get_attribute_string(*itemnode, "name", nullptr));
+ if (!name)
+ throw layout_syntax_error("vistoggle must have name attribute");
+ m_defvismask |= u32(env.get_attribute_bool(*itemnode, "enabled", true) ? 1 : 0) << m_vistoggles.size(); // TODO: make this less hacky
+ view_environment local(env, true);
+ m_vistoggles.emplace_back(name, local.visibility_mask());
+ add_items(layers, local, *itemnode, elemmap, groupmap, orientation, trans, color, false, false, true);
+ }
else
{
throw layout_syntax_error(util::string_format("unknown view item %s", itemnode->get_name()));
@@ -3264,7 +3387,7 @@ void layout_view::add_items(
}
}
-std::string layout_view::make_name(environment &env, util::xml::data_node const &viewnode)
+std::string layout_view::make_name(layout_environment &env, util::xml::data_node const &viewnode)
{
char const *const name(env.get_attribute_string(viewnode, "name", nullptr));
if (!name)
@@ -3294,7 +3417,7 @@ std::string layout_view::make_name(environment &env, util::xml::data_node const
//-------------------------------------------------
layout_view::item::item(
- environment &env,
+ view_environment &env,
util::xml::data_node const &itemnode,
element_map &elemmap,
int orientation,
@@ -3314,6 +3437,7 @@ layout_view::item::item(
, 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())
{
// fetch common data
int index = env.get_attribute_int(itemnode, "index", -1);
@@ -3435,7 +3559,7 @@ void layout_view::item::resolve_tags()
// find_element - find element definition
//---------------------------------------------
-layout_element *layout_view::item::find_element(environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
+layout_element *layout_view::item::find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
{
char const *const name(env.get_attribute_string(itemnode, !strcmp(itemnode.get_name(), "element") ? "ref" : "element", nullptr));
if (!name)
@@ -3455,7 +3579,7 @@ layout_element *layout_view::item::find_element(environment &env, util::xml::dat
//---------------------------------------------
render_bounds layout_view::item::make_bounds(
- environment &env,
+ view_environment &env,
util::xml::data_node const &itemnode,
layout_group::transform const &trans)
{
@@ -3474,7 +3598,7 @@ render_bounds layout_view::item::make_bounds(
// make_input_tag - get absolute input tag
//---------------------------------------------
-std::string layout_view::item::make_input_tag(environment &env, util::xml::data_node const &itemnode)
+std::string layout_view::item::make_input_tag(view_environment &env, util::xml::data_node const &itemnode)
{
char const *tag(env.get_attribute_string(itemnode, "inputtag", nullptr));
return tag ? env.device().subtag(tag) : std::string();
@@ -3485,7 +3609,7 @@ std::string layout_view::item::make_input_tag(environment &env, util::xml::data_
// get_blend_mode - explicit or implicit blend
//---------------------------------------------
-int layout_view::item::get_blend_mode(environment &env, util::xml::data_node const &itemnode)
+int layout_view::item::get_blend_mode(view_environment &env, util::xml::data_node const &itemnode)
{
// see if there's a blend mode attribute
char const *const mode(env.get_attribute_string(itemnode, "blend", nullptr));
@@ -3515,6 +3639,23 @@ int layout_view::item::get_blend_mode(environment &env, util::xml::data_node con
//**************************************************************************
+// LAYOUT VIEW VISIBILITY TOGGLE
+//**************************************************************************
+
+//-------------------------------------------------
+// visibility_toggle - constructor
+//-------------------------------------------------
+
+layout_view::visibility_toggle::visibility_toggle(std::string &&name, u32 mask)
+ : m_name(std::move(name))
+ , m_mask(mask)
+{
+ assert(mask);
+}
+
+
+
+//**************************************************************************
// LAYOUT FILE
//**************************************************************************
@@ -3548,7 +3689,7 @@ layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode,
for (util::xml::data_node const *viewnode = mamelayoutnode->get_child("view"); viewnode != nullptr; viewnode = viewnode->get_next_sibling("view"))
{
// the trouble with allowing errors to propagate here is that it wreaks havoc with screenless systems that use a terminal by default
- // e.g. intlc44 and intlc440 have a terminal on the tty port by default and have a view with the front panel with the terminal screen
+ // e.g. intlc44 and intlc440 have a terminal on the TTY port by default and have a view with the front panel with the terminal screen
// however, they have a second view with just the front panel which is very useful if you're using e.g. -tty null_modem with a socket
// if the error is allowed to propagate, the entire layout is dropped so you can't select the useful view
try
diff --git a/src/emu/video.cpp b/src/emu/video.cpp
index e14ad211f23..e28e6aa1bae 100644
--- a/src/emu/video.cpp
+++ b/src/emu/video.cpp
@@ -138,7 +138,7 @@ video_manager::video_manager(running_machine &machine)
util::xml::data_node *const viewnode(layoutnode->add_child("view", nullptr));
if (!viewnode)
throw emu_fatalerror("Couldn't create XML node??");
- viewnode->set_attribute("name", util::xml::normalize_string(util::string_format("s%1$u", i).c_str()));
+ viewnode->set_attribute("name", util::string_format("s%1$u", i).c_str());
util::xml::data_node *const screennode(viewnode->add_child("screen", nullptr));
if (!screennode)
throw emu_fatalerror("Couldn't create XML node??");
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 93f4fa85e94..022d88f6515 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -2495,7 +2495,7 @@ void lua_engine::initialize()
auto target_type = sol().registry().create_simple_usertype<render_target>("new", sol::no_constructor);
target_type.set("view_bounds", [](render_target &rt) {
- const render_bounds b = rt.current_view()->bounds();
+ const render_bounds b = rt.current_view().bounds();
return std::tuple<float, float, float, float>(b.x0, b.x1, b.y0, b.y1);
});
target_type.set("width", &render_target::width);
diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp
index beca0b10a6e..bd7f274da29 100644
--- a/src/frontend/mame/ui/mainmenu.cpp
+++ b/src/frontend/mame/ui/mainmenu.cpp
@@ -228,7 +228,7 @@ void menu_main::handle()
break;
case VIDEO_OPTIONS:
- menu::stack_push<menu_video_options>(ui(), container(), machine().render().first_target());
+ menu::stack_push<menu_video_options>(ui(), container(), *machine().render().first_target());
break;
case CROSSHAIR:
diff --git a/src/frontend/mame/ui/videoopt.cpp b/src/frontend/mame/ui/videoopt.cpp
index baa0a265cb6..58818328d41 100644
--- a/src/frontend/mame/ui/videoopt.cpp
+++ b/src/frontend/mame/ui/videoopt.cpp
@@ -9,12 +9,52 @@
*********************************************************************/
#include "emu.h"
-
#include "ui/videoopt.h"
#include "rendutil.h"
+
namespace ui {
+
+namespace {
+
+constexpr uintptr_t ITEM_ROTATE = 0x00000100;
+constexpr uintptr_t ITEM_ZOOM = 0x00000101;
+constexpr uintptr_t ITEM_TOGGLE_FIRST = 0x00000200;
+constexpr uintptr_t ITEM_VIEW_FIRST = 0x00000300;
+
+} // anonymous namespace
+
+
+/*-------------------------------------------------
+ menu_video_targets_populate - populate the
+ video targets menu
+-------------------------------------------------*/
+
+menu_video_targets::menu_video_targets(mame_ui_manager &mui, render_container &container)
+ : menu(mui, container)
+{
+}
+
+menu_video_targets::~menu_video_targets()
+{
+}
+
+void menu_video_targets::populate(float &customtop, float &custombottom)
+{
+ // find the targets
+ for (unsigned targetnum = 0; ; targetnum++)
+ {
+ // stop when we run out
+ render_target *const target = machine().render().target_by_index(targetnum);
+ if (!target)
+ break;
+
+ // add a menu item
+ item_append(util::string_format(_("Screen #%d"), targetnum), "", 0, target);
+ }
+}
+
/*-------------------------------------------------
menu_video_targets - handle the video targets
menu
@@ -22,46 +62,74 @@ namespace ui {
void menu_video_targets::handle()
{
- /* process the menu */
- const event *menu_event = process(0);
- if (menu_event != nullptr && menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<menu_video_options>(ui(), container(), static_cast<render_target *>(menu_event->itemref));
+ event const *const menu_event = process(0);
+ if (menu_event && (menu_event->iptkey == IPT_UI_SELECT))
+ menu::stack_push<menu_video_options>(ui(), container(), *reinterpret_cast<render_target *>(menu_event->itemref));
}
/*-------------------------------------------------
- menu_video_targets_populate - populate the
- video targets menu
+ menu_video_options_populate - populate the
+ video options menu
-------------------------------------------------*/
-menu_video_targets::menu_video_targets(mame_ui_manager &mui, render_container &container) : menu(mui, container)
+menu_video_options::menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target)
+ : menu(mui, container)
+ , m_target(target)
{
}
-void menu_video_targets::populate(float &customtop, float &custombottom)
+menu_video_options::~menu_video_options()
{
- int targetnum;
+}
+
+void menu_video_options::populate(float &customtop, float &custombottom)
+{
+ uintptr_t ref;
- /* find the targets */
- for (targetnum = 0; ; targetnum++)
+ // add items for each view
+ for (char const *name = m_target.view_name(ref = 0); name; name = m_target.view_name(++ref))
+ item_append(name, "", 0, reinterpret_cast<void *>(ITEM_VIEW_FIRST + ref));
+ item_append(menu_item_type::SEPARATOR);
+
+ // add items for visibility toggles
+ auto const &toggles = m_target.visibility_toggles();
+ if (!toggles.empty())
{
- render_target *target = machine().render().target_by_index(targetnum);
- char buffer[40];
+ ref = 0U;
+ auto const current_mask(m_target.visibility_mask());
+ for (auto toggle = toggles.begin(); toggles.end() != toggle; ++toggle, ++ref)
+ {
+ auto const toggle_mask(toggle->mask());
+ bool const enabled(BIT(current_mask, ref));
+ bool eclipsed(false);
+ for (auto it = toggles.begin(); !eclipsed && (toggle != it); ++it)
+ eclipsed = ((current_mask & it->mask()) != it->mask()) && ((toggle_mask & it->mask()) == it->mask());
+ u32 const flags((enabled ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW) | (eclipsed ? (FLAG_INVERT | FLAG_DISABLE) : 0U));
+ item_append(toggle->name(), enabled ? _("On") : _("Off"), flags, reinterpret_cast<void *>(ITEM_TOGGLE_FIRST + ref));
+ }
+ item_append(menu_item_type::SEPARATOR);
+ }
- /* stop when we run out */
- if (target == nullptr)
- break;
+ const char *subtext = "";
- /* add a menu item */
- sprintf(buffer, _("Screen #%d"), targetnum);
- item_append(buffer, "", 0, target);
+ // add a rotate item
+ switch (m_target.orientation())
+ {
+ case ROT0: subtext = "None"; break;
+ case ROT90: subtext = "CW 90" UTF8_DEGREES; break;
+ case ROT180: subtext = "180" UTF8_DEGREES; break;
+ case ROT270: subtext = "CCW 90" UTF8_DEGREES; break;
}
-}
+ item_append(_("Rotate"), subtext, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, reinterpret_cast<void *>(ITEM_ROTATE));
-menu_video_targets::~menu_video_targets()
-{
+ // cropping
+ int enabled;
+ enabled = m_target.zoom_to_screen();
+ item_append(_("Zoom to Screen Area"), enabled ? _("On") : _("Off"), enabled ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW, reinterpret_cast<void *>(ITEM_ZOOM));
}
+
/*-------------------------------------------------
menu_video_options - handle the video options
menu
@@ -69,21 +137,21 @@ menu_video_targets::~menu_video_targets()
void menu_video_options::handle()
{
- bool changed = false;
+ bool changed(false);
// process the menu
- const event *menu_event = process(0);
- if (menu_event != nullptr && menu_event->itemref != nullptr)
+ event const *const menu_event(process(0));
+ if (menu_event && menu_event->itemref)
{
- switch ((uintptr_t)menu_event->itemref)
+ switch (reinterpret_cast<uintptr_t>(menu_event->itemref))
{
// rotate adds rotation depending on the direction
- case VIDEO_ITEM_ROTATE:
+ case ITEM_ROTATE:
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
{
- int delta = (menu_event->iptkey == IPT_UI_LEFT) ? ROT270 : ROT90;
- target->set_orientation(orientation_add(delta, target->orientation()));
- if (target->is_ui_target())
+ int const delta((menu_event->iptkey == IPT_UI_LEFT) ? ROT270 : ROT90);
+ m_target.set_orientation(orientation_add(delta, m_target.orientation()));
+ if (m_target.is_ui_target())
{
render_container::user_settings settings;
container().get_user_settings(settings);
@@ -95,20 +163,31 @@ void menu_video_options::handle()
break;
// layer config bitmasks handle left/right keys the same (toggle)
- case VIDEO_ITEM_ZOOM:
- if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
+ case ITEM_ZOOM:
+ if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT))
{
- target->set_zoom_to_screen(!target->zoom_to_screen());
+ m_target.set_zoom_to_screen(menu_event->iptkey == IPT_UI_RIGHT);
changed = true;
}
break;
// anything else is a view item
default:
- if (menu_event->iptkey == IPT_UI_SELECT && (int)(uintptr_t)menu_event->itemref >= VIDEO_ITEM_VIEW)
+ if (reinterpret_cast<uintptr_t>(menu_event->itemref) >= ITEM_VIEW_FIRST)
{
- target->set_view((uintptr_t)menu_event->itemref - VIDEO_ITEM_VIEW);
- changed = true;
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ m_target.set_view(reinterpret_cast<uintptr_t>(menu_event->itemref) - ITEM_VIEW_FIRST);
+ changed = true;
+ }
+ }
+ else if (reinterpret_cast<uintptr_t>(menu_event->itemref) >= ITEM_TOGGLE_FIRST)
+ {
+ if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT))
+ {
+ m_target.set_visibility_toggle(reinterpret_cast<uintptr_t>(menu_event->itemref) - ITEM_TOGGLE_FIRST, menu_event->iptkey == IPT_UI_RIGHT);
+ changed = true;
+ }
}
break;
}
@@ -119,56 +198,4 @@ void menu_video_options::handle()
reset(reset_options::REMEMBER_REF);
}
-
-/*-------------------------------------------------
- menu_video_options_populate - populate the
- video options menu
--------------------------------------------------*/
-
-menu_video_options::menu_video_options(mame_ui_manager &mui, render_container &container, render_target *_target) : menu(mui, container)
-{
- target = _target;
-}
-
-void menu_video_options::populate(float &customtop, float &custombottom)
-{
- const char *subtext = "";
- std::string tempstring;
- int enabled;
-
- // add items for each view
- for (int viewnum = 0; ; viewnum++)
- {
- const char *name = target->view_name(viewnum);
- if (name == nullptr)
- break;
-
- // create a string for the item, replacing underscores with spaces
- tempstring.assign(name);
- strreplace(tempstring, "_", " ");
- item_append(tempstring, "", 0, (void *)(uintptr_t)(VIDEO_ITEM_VIEW + viewnum));
- }
-
- // add a separator
- item_append(menu_item_type::SEPARATOR);
-
- // add a rotate item
- switch (target->orientation())
- {
- case ROT0: subtext = "None"; break;
- case ROT90: subtext = "CW 90" UTF8_DEGREES; break;
- case ROT180: subtext = "180" UTF8_DEGREES; break;
- case ROT270: subtext = "CCW 90" UTF8_DEGREES; break;
- }
- item_append(_("Rotate"), subtext, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, (void *)VIDEO_ITEM_ROTATE);
-
- // cropping
- enabled = target->zoom_to_screen();
- item_append(_("View"), enabled ? _("Cropped") : _("Full"), enabled ? FLAG_RIGHT_ARROW : FLAG_LEFT_ARROW, (void *)VIDEO_ITEM_ZOOM);
-}
-
-menu_video_options::~menu_video_options()
-{
-}
-
} // namespace ui
diff --git a/src/frontend/mame/ui/videoopt.h b/src/frontend/mame/ui/videoopt.h
index 6e07e14a029..a70e7b8aa94 100644
--- a/src/frontend/mame/ui/videoopt.h
+++ b/src/frontend/mame/ui/videoopt.h
@@ -7,15 +7,16 @@
Internal menus for video options
***************************************************************************/
-
-#pragma once
-
#ifndef MAME_FRONTEND_UI_VIDEOOPT_H
#define MAME_FRONTEND_UI_VIDEOOPT_H
+#pragma once
+
#include "ui/menu.h"
+
namespace ui {
+
class menu_video_targets : public menu
{
public:
@@ -27,25 +28,20 @@ private:
virtual void handle() override;
};
+
class menu_video_options : public menu
{
public:
- menu_video_options(mame_ui_manager &mui, render_container &container, render_target *target);
+ menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target);
virtual ~menu_video_options() override;
private:
- enum : uint32_t {
- VIDEO_ITEM_ROTATE = 0x80000000,
- VIDEO_ITEM_ZOOM,
- VIDEO_ITEM_VIEW
- };
-
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
- render_target *target;
+ render_target &m_target;
};
} // namespace ui
-#endif /* MAME_FRONTEND_UI_VIDEOOPT_H */
+#endif // MAME_FRONTEND_UI_VIDEOOPT_H
diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp
index ad4d4e1e8f8..af5f36fae0d 100644
--- a/src/lib/util/xmlfile.cpp
+++ b/src/lib/util/xmlfile.cpp
@@ -33,6 +33,37 @@ namespace {
constexpr unsigned TEMP_BUFFER_SIZE(4096U);
std::locale const f_portable_locale("C");
+
+/***************************************************************************
+ UTILITY FUNCTIONS
+***************************************************************************/
+
+void write_escaped(core_file &file, std::string const &str)
+{
+ std::string::size_type pos = 0;
+ while ((str.size() > pos) && (std::string::npos != pos))
+ {
+ std::string::size_type const found = str.find_first_of("\"&<>", pos);
+ if (found != std::string::npos)
+ {
+ file.write(&str[pos], found - pos);
+ switch (str[found])
+ {
+ case '"': file.puts("&quot;"); pos = found + 1; break;
+ case '&': file.puts("&amp;"); pos = found + 1; break;
+ case '<': file.puts("&lt;"); pos = found + 1; break;
+ case '>': file.puts("&gt;"); pos = found + 1; break;
+ default: pos = found;
+ }
+ }
+ else
+ {
+ file.write(&str[pos], str.size() - pos);
+ pos = found;
+ }
+ }
+}
+
} // anonymous namespace
@@ -950,9 +981,13 @@ void data_node::write_recursive(int indent, util::core_file &file) const
/* output this tag */
file.printf("%*s<%s", indent, "", get_name());
- /* output any attributes */
+ /* output any attributes, escaping as necessary */
for (attribute_node const &anode : m_attributes)
- file.printf(" %s=\"%s\"", anode.name, anode.value);
+ {
+ file.printf(" %s=\"", anode.name);
+ write_escaped(file, anode.value);
+ file.puts("\"");
+ }
if (!get_first_child() && !get_value())
{
@@ -965,8 +1000,11 @@ void data_node::write_recursive(int indent, util::core_file &file) const
file.printf(">\n");
/* if there is a value, output that here */
- if (get_value())
- file.printf("%*s%s\n", indent + 4, "", get_value());
+ if (!m_value.empty())
+ {
+ file.printf("%*s\n", indent + 4, "");
+ write_escaped(file, m_value);
+ }
/* loop over children and output them as well */
if (get_first_child())
diff --git a/src/osd/modules/debugger/osx/debugwindowhandler.mm b/src/osd/modules/debugger/osx/debugwindowhandler.mm
index fd1eb44f6d3..67910f92f99 100644
--- a/src/osd/modules/debugger/osx/debugwindowhandler.mm
+++ b/src/osd/modules/debugger/osx/debugwindowhandler.mm
@@ -493,7 +493,7 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->add_child("expression", util::xml::normalize_string([[self expression] UTF8String]));
+ node->add_child("expression", [[self expression] UTF8String]);
}
diff --git a/src/osd/modules/render/bgfx/chain.cpp b/src/osd/modules/render/bgfx/chain.cpp
index c5bb7cf94b6..297d7686837 100644
--- a/src/osd/modules/render/bgfx/chain.cpp
+++ b/src/osd/modules/render/bgfx/chain.cpp
@@ -81,7 +81,7 @@ void bgfx_chain::process(chain_manager::screen_prim &prim, int view, int screen,
screen_device_iterator screen_iterator(window.machine().root_device());
screen_device* screen_device = screen_iterator.byindex(screen);
- uint16_t screen_count(window.target()->current_view()->screen_count());
+ uint16_t screen_count(window.target()->current_view().screen_count());
uint16_t screen_width = prim.m_quad_width;
uint16_t screen_height = prim.m_quad_height;
uint32_t rotation_type =
diff --git a/src/osd/modules/render/d3d/d3dhlsl.cpp b/src/osd/modules/render/d3d/d3dhlsl.cpp
index 9233aabc002..78e3e2f226f 100644
--- a/src/osd/modules/render/d3d/d3dhlsl.cpp
+++ b/src/osd/modules/render/d3d/d3dhlsl.cpp
@@ -2431,7 +2431,7 @@ void uniform::update()
}
case CU_SCREEN_COUNT:
{
- int screen_count = win->target()->current_view()->screen_count();
+ int screen_count = win->target()->current_view().screen_count();
m_shader->set_int("ScreenCount", screen_count);
break;
}
diff --git a/src/osd/uwp/window.cpp b/src/osd/uwp/window.cpp
index 12c67308f22..7aae818b958 100644
--- a/src/osd/uwp/window.cpp
+++ b/src/osd/uwp/window.cpp
@@ -257,6 +257,7 @@ uwp_window_info::uwp_window_info(
m_target(nullptr),
m_targetview(0),
m_targetorient(0),
+ m_targetvismask(0),
m_lastclicktime(std::chrono::system_clock::time_point::min()),
m_lastclickx(0),
m_lastclicky(0),
@@ -403,6 +404,7 @@ void uwp_window_info::create(running_machine &machine, int index, std::shared_pt
window->m_targetview = window->m_target->view();
window->m_targetorient = window->m_target->orientation();
window->m_targetlayerconfig = window->m_target->layer_config();
+ window->m_targetvismask = window->m_target->visibility_mask();
// make the window title
if (video_config.numscreens == 1)
@@ -472,20 +474,19 @@ void uwp_window_info::destroy()
void uwp_window_info::update()
{
- int targetview, targetorient;
- render_layer_config targetlayerconfig;
-
assert(GetCurrentThreadId() == main_threadid);
// see if the target has changed significantly in window mode
- targetview = m_target->view();
- targetorient = m_target->orientation();
- targetlayerconfig = m_target->layer_config();
- if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig)
+ unsigned const targetview = m_target->view();
+ int const targetorient = m_target->orientation();
+ render_layer_config const targetlayerconfig = m_target->layer_config();
+ u32 const targetvismask = m_target->visibility_mask();
+ if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig || targetvismask != m_targetvismask)
{
m_targetview = targetview;
m_targetorient = targetorient;
m_targetlayerconfig = targetlayerconfig;
+ m_targetvismask = targetvismask;
// in window mode, reminimize/maximize
if (!fullscreen())
diff --git a/src/osd/uwp/window.h b/src/osd/uwp/window.h
index 21948028343..a58a163284e 100644
--- a/src/osd/uwp/window.h
+++ b/src/osd/uwp/window.h
@@ -101,9 +101,10 @@ public:
// rendering info
std::mutex m_render_lock;
render_target * m_target;
- int m_targetview;
+ unsigned m_targetview;
int m_targetorient;
render_layer_config m_targetlayerconfig;
+ u32 m_targetvismask;
// input info
std::chrono::system_clock::time_point m_lastclicktime;
diff --git a/src/osd/windows/window.cpp b/src/osd/windows/window.cpp
index 8e6d3665e82..ac4349cf36b 100644
--- a/src/osd/windows/window.cpp
+++ b/src/osd/windows/window.cpp
@@ -312,6 +312,7 @@ win_window_info::win_window_info(
m_target(nullptr),
m_targetview(0),
m_targetorient(0),
+ m_targetvismask(0),
m_lastclicktime(std::chrono::system_clock::time_point::min()),
m_lastclickx(0),
m_lastclicky(0),
@@ -790,6 +791,7 @@ void win_window_info::create(running_machine &machine, int index, std::shared_pt
window->m_targetview = window->m_target->view();
window->m_targetorient = window->m_target->orientation();
window->m_targetlayerconfig = window->m_target->layer_config();
+ window->m_targetvismask = window->m_target->visibility_mask();
// make the window title
if (video_config.numscreens == 1)
@@ -859,20 +861,19 @@ void win_window_info::destroy()
void win_window_info::update()
{
- int targetview, targetorient;
- render_layer_config targetlayerconfig;
-
assert(GetCurrentThreadId() == main_threadid);
// see if the target has changed significantly in window mode
- targetview = m_target->view();
- targetorient = m_target->orientation();
- targetlayerconfig = m_target->layer_config();
- if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig)
+ unsigned const targetview = m_target->view();
+ int const targetorient = m_target->orientation();
+ render_layer_config const targetlayerconfig = m_target->layer_config();
+ u32 const targetvismask = m_target->visibility_mask();
+ if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig || targetvismask != m_targetvismask)
{
m_targetview = targetview;
m_targetorient = targetorient;
m_targetlayerconfig = targetlayerconfig;
+ m_targetvismask = targetvismask;
// in window mode, reminimize/maximize
if (!fullscreen())
diff --git a/src/osd/windows/window.h b/src/osd/windows/window.h
index b04e35aa110..3dccc520a83 100644
--- a/src/osd/windows/window.h
+++ b/src/osd/windows/window.h
@@ -122,9 +122,10 @@ public:
// rendering info
std::mutex m_render_lock;
render_target * m_target;
- int m_targetview;
+ unsigned m_targetview;
int m_targetorient;
render_layer_config m_targetlayerconfig;
+ u32 m_targetvismask;
// input info
std::chrono::system_clock::time_point m_lastclicktime;