Generate layouts for systems with three or more screens

This commit is contained in:
Vas Crabb 2017-09-29 19:57:47 +10:00
parent dcc1c1ead5
commit b75264927b
4 changed files with 166 additions and 24 deletions

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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);

View File

@ -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());
}
}