summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2017-09-29 19:57:47 +1000
committer Vas Crabb <vas@vastheman.com>2017-09-29 19:57:47 +1000
commitb75264927beafd7e872e0f5f7c70c1dee8365136 (patch)
tree3c7693be6f1a98eb8fd62cc21208dd51298e1810
parentdcc1c1ead5cd2bbb4227da17c614351f370cda66 (diff)
Generate layouts for systems with three or more screens
-rw-r--r--src/emu/main.h2
-rw-r--r--src/emu/render.cpp183
-rw-r--r--src/emu/render.h1
-rw-r--r--src/frontend/mame/mame.cpp4
4 files changed, 166 insertions, 24 deletions
diff --git a/src/emu/main.h b/src/emu/main.h
index 9a01a73af24..0bc95eb036b 100644
--- a/src/emu/main.h
+++ b/src/emu/main.h
@@ -60,7 +60,7 @@ public:
static void draw_user_interface(running_machine& machine);
static void periodic_check();
static bool frame_hook();
- static void layout_file_cb(util::xml::data_node &layout);
+ static void layout_file_cb(util::xml::data_node const &layout);
static bool standalone();
};
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 31994f19595..5fa3fb5a32b 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -1575,9 +1575,10 @@ void render_target::update_layer_config()
void render_target::load_layout_files(const internal_layout *layoutfile, bool singlefile)
{
bool have_default = false;
+
// if there's an explicit file, load that first
const char *basename = m_manager.machine().basename();
- if (layoutfile != nullptr)
+ if (layoutfile)
have_default |= load_layout_file(basename, layoutfile);
// if we're only loading this file, we know our final result
@@ -1606,7 +1607,8 @@ void render_target::load_layout_files(const internal_layout *layoutfile, bool si
have_default |= true;
}
screen_device_iterator iter(m_manager.machine().root_device());
- int screens = iter.count();
+ unsigned const screens = iter.count();
+
// now do the built-in layouts for single-screen games
if (screens == 1)
{
@@ -1617,6 +1619,7 @@ void render_target::load_layout_files(const internal_layout *layoutfile, bool si
if (m_filelist.empty())
throw emu_fatalerror("Couldn't parse default layout??");
}
+
if (!have_default)
{
if (screens == 0)
@@ -1631,18 +1634,157 @@ void render_target::load_layout_files(const internal_layout *layoutfile, bool si
if (m_filelist.empty())
throw emu_fatalerror("Couldn't parse default layout??");
}
- else if (screens == 3)
+ }
+
+ // generate default layouts for larger numbers of screens
+ if (screens >= 3)
+ {
+ util::xml::file::ptr const root(util::xml::file::create());
+ if (!root)
+ throw emu_fatalerror("Couldn't create XML document??");
+ util::xml::data_node *const layoutnode(root->add_child("mamelayout", nullptr));
+ if (!layoutnode)
+ throw emu_fatalerror("Couldn't create XML node??");
+ layoutnode->set_attribute_int("version", 2);
+
+ // get standard width/height assuming 4:3 screens
+ unsigned const stdwidth((system.flags & ORIENTATION_SWAP_XY) ? 3 : 4);
+ unsigned const stdheight((system.flags & ORIENTATION_SWAP_XY) ? 4 : 3);
+
+ // generate individual 4:3 views
+ for (unsigned i = 0; screens > i; ++i)
{
- load_layout_file(nullptr, &layout_triphsxs);
- if (m_filelist.empty())
- throw emu_fatalerror("Couldn't parse default layout??");
+ 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("Screen %1$u Standard (%2$u:%3$u)", i, stdwidth, stdheight).c_str()));
+ util::xml::data_node *const screennode(viewnode->add_child("screen", nullptr));
+ if (!screennode)
+ throw emu_fatalerror("Couldn't create XML node??");
+ screennode->set_attribute_int("index", i);
+ util::xml::data_node *const boundsnode(screennode->add_child("bounds", nullptr));
+ if (!boundsnode)
+ throw emu_fatalerror("Couldn't create XML node??");
+ boundsnode->set_attribute_int("x", 0);
+ boundsnode->set_attribute_int("y", 0);
+ boundsnode->set_attribute_int("width", stdwidth);
+ boundsnode->set_attribute_int("height", stdheight);
}
- else if (screens == 4)
+
+ // generate individual pixel aspect views
+ for (unsigned i = 0; screens > i; ++i)
{
- load_layout_file(nullptr, &layout_quadhsxs);
- if (m_filelist.empty())
- throw emu_fatalerror("Couldn't parse default layout??");
+ 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("Screen %1$u Pixel Aspect (~scr%1$unativexaspect~:~scr%1$unativeyaspect~)", i).c_str()));
+ util::xml::data_node *const screennode(viewnode->add_child("screen", nullptr));
+ if (!screennode)
+ throw emu_fatalerror("Couldn't create XML node??");
+ screennode->set_attribute_int("index", i);
+ util::xml::data_node *const boundsnode(screennode->add_child("bounds", nullptr));
+ if (!boundsnode)
+ throw emu_fatalerror("Couldn't create XML node??");
+ boundsnode->set_attribute_int("x", 0);
+ boundsnode->set_attribute_int("y", 0);
+ boundsnode->set_attribute("width", util::xml::normalize_string(util::string_format("~scr%1$uwidth~", i).c_str()));
+ boundsnode->set_attribute("height", util::xml::normalize_string(util::string_format("~scr%1$uheight~", i).c_str()));
}
+
+ // helper for generating a view since we do this a lot
+ auto const generate_view =
+ [&layoutnode, screens, stdwidth, stdheight] (char const *title, auto &&bounds_callback)
+ {
+ 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));
+ for (unsigned i = 0; screens > i; ++i)
+ {
+ util::xml::data_node *const screennode(viewnode->add_child("screen", nullptr));
+ if (!screennode)
+ throw emu_fatalerror("Couldn't create XML node??");
+ screennode->set_attribute_int("index", i);
+ util::xml::data_node *const boundsnode(screennode->add_child("bounds", nullptr));
+ if (!boundsnode)
+ throw emu_fatalerror("Couldn't create XML node??");
+ bounds_callback(*boundsnode, i);
+ boundsnode->set_attribute_int("width", stdwidth);
+ boundsnode->set_attribute_int("height", stdheight);
+ }
+ };
+
+ // generate linear views
+ generate_view(
+ "Left-to-Right",
+ [stdwidth] (util::xml::data_node &boundsnode, unsigned i)
+ {
+ boundsnode.set_attribute_float("x", i * (stdwidth + 0.03f));
+ boundsnode.set_attribute_int("y", 0);
+ });
+ generate_view(
+ "Left-to-Right (Gapless)",
+ [stdwidth] (util::xml::data_node &boundsnode, unsigned i)
+ {
+ boundsnode.set_attribute_int("x", i * stdwidth);
+ boundsnode.set_attribute_int("y", 0);
+ });
+ generate_view(
+ "Top-to-Bottom",
+ [stdheight] (util::xml::data_node &boundsnode, unsigned i)
+ {
+ boundsnode.set_attribute_int("x", 0);
+ boundsnode.set_attribute_float("y", i * (stdheight + 0.03f));
+ });
+ generate_view(
+ "Top-to-Bottom (Gapless)",
+ [stdheight] (util::xml::data_node &boundsnode, unsigned i)
+ {
+ boundsnode.set_attribute_int("x", 0);
+ boundsnode.set_attribute_int("y", i * stdheight);
+ });
+
+ // generate tiled views
+ for (unsigned minor = 2; ((screens + minor - 1) / minor) >= minor; ++minor)
+ {
+ unsigned const major((screens + minor - 1) / minor);
+ unsigned const remainder(screens % major);
+ if (!remainder || (((major + 1) / 2) <= remainder))
+ {
+ generate_view(
+ util::string_format("%1$u\xC3\x97%2$u Left-to-Right, Top-to-Bottom", major, minor).c_str(),
+ [major, stdwidth, stdheight] (util::xml::data_node &boundsnode, unsigned i)
+ {
+ boundsnode.set_attribute_float("x", (i % major) * (stdwidth + 0.03f));
+ boundsnode.set_attribute_float("y", (i / major) * (stdheight + 0.03f));
+ });
+ generate_view(
+ util::string_format("%1$u\xC3\x97%2$u Left-to-Right, Top-to-Bottom (Gapless)", major, minor).c_str(),
+ [major, stdwidth, stdheight] (util::xml::data_node &boundsnode, unsigned i)
+ {
+ boundsnode.set_attribute_int("x", (i % major) * stdwidth);
+ boundsnode.set_attribute_int("y", (i / major) * stdheight);
+ });
+ generate_view(
+ util::string_format("%1$u\xC3\x97%2$u Top-to-Bottom, Left-to-Right", minor, major).c_str(),
+ [major, stdwidth, stdheight] (util::xml::data_node &boundsnode, unsigned i)
+ {
+ boundsnode.set_attribute_float("x", (i / major) * (stdwidth + 0.03f));
+ boundsnode.set_attribute_float("y", (i % major) * (stdheight + 0.03f));
+ });
+ generate_view(
+ util::string_format("%1$u\xC3\x97%2$u Top-to-Bottom, Left-to-Right (Gapless)", minor, major).c_str(),
+ [major, stdwidth, stdheight] (util::xml::data_node &boundsnode, unsigned i)
+ {
+ boundsnode.set_attribute_int("x", (i / major) * stdwidth);
+ boundsnode.set_attribute_int("y", (i % major) * stdheight);
+ });
+ }
+ }
+
+ // try to parse it
+ if (!load_layout_file(nullptr, *root))
+ throw emu_fatalerror("Couldn't parse generated layout??");
}
}
@@ -1729,7 +1871,7 @@ bool render_target::load_layout_file(const char *dirname, const char *filename)
}
// if we didn't get a properly-formatted XML file, record a warning and exit
- if (rootnode == nullptr)
+ if (!load_layout_file(dirname, *rootnode))
{
if (filename[0] != '<')
osd_printf_warning("Improperly formatted XML file '%s', ignoring\n", filename);
@@ -1738,25 +1880,24 @@ bool render_target::load_layout_file(const char *dirname, const char *filename)
return false;
}
+ return true;
+}
+
+bool render_target::load_layout_file(const char *dirname, util::xml::data_node const &rootnode)
+{
// parse and catch any errors
- bool result = true;
try
{
- m_filelist.emplace_back(m_manager.machine(), *rootnode, dirname);
+ m_filelist.emplace_back(m_manager.machine(), rootnode, dirname);
}
catch (emu_fatalerror &err)
{
- if (filename[0] != '<')
- osd_printf_warning("Error in XML file '%s': %s\n", filename, err.string());
- else
- osd_printf_warning("Error in XML string: %s\n", err.string());
- result = false;
+ return false;
}
- emulator_info::layout_file_cb(*rootnode);
+ emulator_info::layout_file_cb(rootnode);
- // free the root node
- return result;
+ return true;
}
diff --git a/src/emu/render.h b/src/emu/render.h
index 9dbbb385cb2..e7ac98e8dfb 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -1016,6 +1016,7 @@ private:
void load_layout_files(const internal_layout *layoutfile, bool singlefile);
bool load_layout_file(const char *dirname, const char *filename);
bool load_layout_file(const char *dirname, const internal_layout *layout_data);
+ bool load_layout_file(const char *dirname, util::xml::data_node const &rootnode);
void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode);
void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode);
bool map_point_internal(s32 target_x, s32 target_y, render_container *container, float &mapped_x, float &mapped_y, ioport_port *&mapped_input_port, ioport_value &mapped_input_mask);
diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp
index bc9d9b334b7..8e6a0614260 100644
--- a/src/frontend/mame/mame.cpp
+++ b/src/frontend/mame/mame.cpp
@@ -350,13 +350,13 @@ bool emulator_info::frame_hook()
return mame_machine_manager::instance()->lua()->frame_hook();
}
-void emulator_info::layout_file_cb(util::xml::data_node &layout)
+void emulator_info::layout_file_cb(util::xml::data_node const &layout)
{
util::xml::data_node const *const mamelayout = layout.get_child("mamelayout");
if (mamelayout)
{
util::xml::data_node const *const script = mamelayout->get_child("script");
- if(script)
+ if (script)
mame_machine_manager::instance()->lua()->call_plugin_set("layout", script->get_value());
}
}