summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/render.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/render.cpp')
-rw-r--r--src/emu/render.cpp319
1 files changed, 199 insertions, 120 deletions
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index fe62b3c0bf8..4d621508a20 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,46 @@ 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));
+ }
+ }
+
+ if (&current_view() == &view->first.get())
+ current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+ }
}
@@ -2615,9 +2671,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 +2699,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 +3051,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 +3284,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 +3362,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();
}