diff options
Diffstat (limited to 'src/emu/render.cpp')
-rw-r--r-- | src/emu/render.cpp | 316 |
1 files changed, 196 insertions, 120 deletions
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 = ¤t_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 (¤t_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(); } |