-emu/render.cpp: Load from all external artwork paths.

-emu/rendlay.cpp: Made real component drawing code a bit less gross.

-emu/debugcon.cpp: Less screaming now that things aren't macros.
This commit is contained in:
Vas Crabb 2020-10-13 01:48:49 +11:00
parent d6f7c7febf
commit 853fdf7542
6 changed files with 259 additions and 257 deletions

View File

@ -650,12 +650,12 @@ bool debugger_commands::debug_command_parameter_command(const char *param)
/* validate the comment; success if no error */
CMDERR err = m_console.validate_command(param);
if (err.ERROR_CLASS() == CMDERR::NONE)
if (err.error_class() == CMDERR::NONE)
return true;
/* output an error */
m_console.printf("Error in command: %s\n", param);
m_console.printf(" %*s^", err.ERROR_OFFSET(), "");
m_console.printf(" %*s^", err.error_offset(), "");
m_console.printf("%s\n", debugger_console::cmderr_to_string(err));
return 0;
}

View File

@ -250,7 +250,7 @@ CMDERR debugger_console::internal_execute_command(bool execute, int params, char
/* no params is an error */
if (params == 0)
return CMDERR(CMDERR::NONE, 0);
return CMDERR::none();
/* the first parameter has the command and the real first parameter; separate them */
for (p = param[0]; *p && isspace(u8(*p)); p++) { }
@ -287,9 +287,9 @@ CMDERR debugger_console::internal_execute_command(bool execute, int params, char
/* error if not found */
if (!found)
return CMDERR::MAKE_UNKNOWN_COMMAND(0);
return CMDERR::unknown_command(0);
if (foundcount > 1)
return CMDERR::MAKE_AMBIGUOUS_COMMAND(0);
return CMDERR::ambiguous_command(0);
/* NULL-terminate and trim space around all the parameters */
for (i = 1; i < params; i++)
@ -301,9 +301,9 @@ CMDERR debugger_console::internal_execute_command(bool execute, int params, char
/* see if we have the right number of parameters */
if (params < found->minparams)
return CMDERR::MAKE_NOT_ENOUGH_PARAMS(0);
return CMDERR::not_enough_params(0);
if (params > found->maxparams)
return CMDERR::MAKE_TOO_MANY_PARAMS(0);
return CMDERR::too_many_params(0);
/* execute the handler */
if (execute)
@ -311,7 +311,7 @@ CMDERR debugger_console::internal_execute_command(bool execute, int params, char
std::vector<std::string> params_vec(param, param + params);
found->handler(found->ref, params_vec);
}
return CMDERR(CMDERR::NONE, 0);
return CMDERR::none();
}
@ -353,9 +353,9 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
case '(':
case '[':
case '{': parens[parendex++] = c; break;
case ')': if (parendex == 0 || parens[--parendex] != '(') return CMDERR::MAKE_UNBALANCED_PARENS(p - command); break;
case ']': if (parendex == 0 || parens[--parendex] != '[') return CMDERR::MAKE_UNBALANCED_PARENS(p - command); break;
case '}': if (parendex == 0 || parens[--parendex] != '{') return CMDERR::MAKE_UNBALANCED_PARENS(p - command); break;
case ')': if (parendex == 0 || parens[--parendex] != '(') return CMDERR::unbalanced_parens(p - command); break;
case ']': if (parendex == 0 || parens[--parendex] != '[') return CMDERR::unbalanced_parens(p - command); break;
case '}': if (parendex == 0 || parens[--parendex] != '{') return CMDERR::unbalanced_parens(p - command); break;
case ',': if (parendex == 0) params[paramcount++] = p; break;
case ';': if (parendex == 0) foundend = true; break;
case '-': if (parendex == 0 && paramcount == 1 && p[1] == '-') isexpr = true; *p = c; break;
@ -369,9 +369,9 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
/* check for unbalanced parentheses or quotes */
if (instring)
return CMDERR::MAKE_UNBALANCED_QUOTES(p - command);
return CMDERR::unbalanced_quotes(p - command);
if (parendex != 0)
return CMDERR::MAKE_UNBALANCED_PARENS(p - command);
return CMDERR::unbalanced_parens(p - command);
/* NULL-terminate if we ended in a semicolon */
p--;
@ -396,17 +396,17 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
}
catch (expression_error &err)
{
return CMDERR::MAKE_EXPRESSION_ERROR(err);
return CMDERR::expression_error(err);
}
}
else
{
const CMDERR result = internal_execute_command(execute, paramcount, &params[0]);
if (result.ERROR_CLASS() != CMDERR::NONE)
return CMDERR(result.ERROR_CLASS(), command_start - command);
if (result.error_class() != CMDERR::NONE)
return CMDERR(result.error_class(), command_start - command);
}
}
return CMDERR(CMDERR::NONE, 0);
return CMDERR::none();
}
@ -424,11 +424,11 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo)
const CMDERR result = internal_parse_command(command, true);
/* display errors */
if (result.ERROR_CLASS() != CMDERR::NONE)
if (result.error_class() != CMDERR::NONE)
{
if (!echo)
printf(">%s\n", command.c_str());
printf(" %*s^\n", result.ERROR_OFFSET(), "");
printf(" %*s^\n", result.error_offset(), "");
printf("%s\n", cmderr_to_string(result).c_str());
}
@ -547,8 +547,8 @@ void debugger_console::process_source_file()
std::string debugger_console::cmderr_to_string(CMDERR error)
{
const int offset = error.ERROR_OFFSET();
switch (error.ERROR_CLASS())
const int offset = error.error_offset();
switch (error.error_class())
{
case CMDERR::UNKNOWN_COMMAND: return "unknown command";
case CMDERR::AMBIGUOUS_COMMAND: return "ambiguous command";

View File

@ -41,33 +41,37 @@ constexpr u32 CMDFLAG_CUSTOM_HELP = 0x0002;
***************************************************************************/
// CMDERR is an error code for command evaluation
struct CMDERR
class CMDERR
{
public:
// values for the error code in a command error
static constexpr u32 NONE = 0;
static constexpr u32 UNKNOWN_COMMAND = 1;
static constexpr u32 AMBIGUOUS_COMMAND = 2;
static constexpr u32 UNBALANCED_PARENS = 3;
static constexpr u32 UNBALANCED_QUOTES = 4;
static constexpr u32 NOT_ENOUGH_PARAMS = 5;
static constexpr u32 TOO_MANY_PARAMS = 6;
static constexpr u32 EXPRESSION_ERROR = 7;
u32 val;
static constexpr u16 NONE = 0;
static constexpr u16 UNKNOWN_COMMAND = 1;
static constexpr u16 AMBIGUOUS_COMMAND = 2;
static constexpr u16 UNBALANCED_PARENS = 3;
static constexpr u16 UNBALANCED_QUOTES = 4;
static constexpr u16 NOT_ENOUGH_PARAMS = 5;
static constexpr u16 TOO_MANY_PARAMS = 6;
static constexpr u16 EXPRESSION_ERROR = 7;
// command error assembly/disassembly
constexpr CMDERR(u32 a, u32 b) : val((a << 16) | (b & 0xffff)) { }
constexpr u32 ERROR_CLASS() const { return val >> 16; }
constexpr u32 ERROR_OFFSET() const { return val & 0xffff; }
constexpr CMDERR(u16 c, u16 o) : m_error_class(c), m_error_offset(o) { }
constexpr u16 error_class() const { return m_error_class; }
constexpr u16 error_offset() const { return m_error_offset; }
// assemble specific error conditions
static constexpr CMDERR MAKE_UNKNOWN_COMMAND(u32 x) { return CMDERR(UNKNOWN_COMMAND, x); }
static constexpr CMDERR MAKE_AMBIGUOUS_COMMAND(u32 x) { return CMDERR(AMBIGUOUS_COMMAND, x); }
static constexpr CMDERR MAKE_UNBALANCED_PARENS(u32 x) { return CMDERR(UNBALANCED_PARENS, x); }
static constexpr CMDERR MAKE_UNBALANCED_QUOTES(u32 x) { return CMDERR(UNBALANCED_QUOTES, x); }
static constexpr CMDERR MAKE_NOT_ENOUGH_PARAMS(u32 x) { return CMDERR(NOT_ENOUGH_PARAMS, x); }
static constexpr CMDERR MAKE_TOO_MANY_PARAMS(u32 x) { return CMDERR(TOO_MANY_PARAMS, x); }
static constexpr CMDERR MAKE_EXPRESSION_ERROR(u32 x) { return CMDERR(EXPRESSION_ERROR, x); }
static constexpr CMDERR none() { return CMDERR(NONE, 0); }
static constexpr CMDERR unknown_command(u16 x) { return CMDERR(UNKNOWN_COMMAND, x); }
static constexpr CMDERR ambiguous_command(u16 x) { return CMDERR(AMBIGUOUS_COMMAND, x); }
static constexpr CMDERR unbalanced_parens(u16 x) { return CMDERR(UNBALANCED_PARENS, x); }
static constexpr CMDERR unbalanced_quotes(u16 x) { return CMDERR(UNBALANCED_QUOTES, x); }
static constexpr CMDERR not_enough_params(u16 x) { return CMDERR(NOT_ENOUGH_PARAMS, x); }
static constexpr CMDERR too_many_params(u16 x) { return CMDERR(TOO_MANY_PARAMS, x); }
static constexpr CMDERR expression_error(u16 x) { return CMDERR(EXPRESSION_ERROR, x); }
private:
u16 m_error_class, m_error_offset;
};

View File

@ -1665,7 +1665,7 @@ void render_target::load_layout_files(util::xml::data_node const &rootnode, bool
// if there's an explicit file, load that first
const std::string &basename = m_manager.machine().basename();
have_artwork |= load_layout_file(m_manager.machine().root_device(), basename.c_str(), rootnode);
have_artwork |= load_layout_file(m_manager.machine().root_device(), rootnode, m_manager.machine().options().art_path(), basename.c_str());
// if we're only loading this file, we know our final result
if (!singlefile)
@ -2084,7 +2084,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
}
// try to parse it
if (!load_layout_file(m_manager.machine().root_device(), nullptr, *root))
if (!load_layout_file(m_manager.machine().root_device(), *root, m_manager.machine().options().art_path(), nullptr))
throw emu_fatalerror("Couldn't parse generated layout??");
}
}
@ -2111,7 +2111,7 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
zerr = inflateInit(&stream);
if (zerr != Z_OK)
{
fatalerror("could not inflateInit");
osd_printf_error("render_target::load_layout_file: zlib initialization error\n");
return false;
}
@ -2127,23 +2127,21 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
}
else if (zerr != Z_OK)
{
fatalerror("decompression error\n");
osd_printf_error("render_target::load_layout_file: zlib decompression error\n");
inflateEnd(&stream);
return false;
}
// clean up
zerr = inflateEnd(&stream);
if (zerr != Z_OK)
{
fatalerror("inflateEnd error\n");
return false;
}
osd_printf_error("render_target::load_layout_file: zlib cleanup error\n");
util::xml::file::ptr rootnode(util::xml::file::string_read(reinterpret_cast<char const *>(tempout.get()), nullptr));
tempout.reset();
// if we didn't get a properly-formatted XML file, record a warning and exit
if (!load_layout_file(device ? *device : m_manager.machine().root_device(), dirname, *rootnode))
if (!load_layout_file(device ? *device : m_manager.machine().root_device(), *rootnode, m_manager.machine().options().art_path(), dirname))
{
osd_printf_warning("Improperly formatted XML string, ignoring\n");
return false;
@ -2157,28 +2155,39 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
bool render_target::load_layout_file(const char *dirname, const char *filename)
{
// build the path and optionally prepend the directory
std::string fname = std::string(filename).append(".lay");
std::string fname;
if (dirname)
fname.insert(0, PATH_SEPARATOR).insert(0, dirname);
fname.append(dirname).append(PATH_SEPARATOR);
fname.append(filename).append(".lay");
// attempt to open the file; bail if we can't
emu_file layoutfile(m_manager.machine().options().art_path(), OPEN_FLAG_READ);
layoutfile.set_restrict_to_mediapath(1);
osd_file::error const filerr(layoutfile.open(fname));
if (filerr != osd_file::error::NONE)
return false;
// read the file
// attempt to open matching files
util::xml::parse_options parseopt;
util::xml::parse_error parseerr;
parseopt.error = &parseerr;
util::xml::file::ptr rootnode(util::xml::file::read(layoutfile, &parseopt));
if (!rootnode)
emu_file layoutfile(m_manager.machine().options().art_path(), OPEN_FLAG_READ);
layoutfile.set_restrict_to_mediapath(1);
bool result(false);
for (osd_file::error filerr = layoutfile.open(fname); osd_file::error::NONE == filerr; filerr = layoutfile.open_next())
{
if (parseerr.error_message)
// read the file and parse as XML
util::xml::file::ptr const rootnode(util::xml::file::read(layoutfile, &parseopt));
if (rootnode)
{
// extract directory name from location of layout file
std::string artdir(layoutfile.fullpath());
auto const dirsep(std::find_if(artdir.rbegin(), artdir.rend(), &util::is_directory_separator));
artdir.erase(dirsep.base(), artdir.end());
// record a warning if we didn't get a properly-formatted XML file
if (!load_layout_file(m_manager.machine().root_device(), *rootnode, nullptr, artdir.c_str()))
osd_printf_warning("Improperly formatted XML layout file '%s', ignoring\n", filename);
else
result = true;
}
else if (parseerr.error_message)
{
osd_printf_warning(
"Error parsing XML file '%s' at line %d column %d: %s, ignoring\n",
"Error parsing XML layout file '%s' at line %d column %d: %s, ignoring\n",
filename,
parseerr.error_line,
parseerr.error_column,
@ -2186,29 +2195,18 @@ bool render_target::load_layout_file(const char *dirname, const char *filename)
}
else
{
osd_printf_warning("Error parsing XML file '%s', ignorning\n", filename);
osd_printf_warning("Error parsing XML layout file '%s', ignorning\n", filename);
}
return false;
}
// if we didn't get a properly-formatted XML file, record a warning and exit
if (!load_layout_file(m_manager.machine().root_device(), dirname, *rootnode))
{
osd_printf_warning("Improperly formatted XML file '%s', ignoring\n", filename);
return false;
}
else
{
return true;
}
return result;
}
bool render_target::load_layout_file(device_t &device, const char *dirname, util::xml::data_node const &rootnode)
bool render_target::load_layout_file(device_t &device, util::xml::data_node const &rootnode, const char *searchpath, const char *dirname)
{
// parse and catch any errors
try
{
m_filelist.emplace_back(device, rootnode, dirname);
m_filelist.emplace_back(device, rootnode, searchpath, dirname);
}
catch (emu_fatalerror &)
{

View File

@ -538,7 +538,7 @@ public:
using environment = emu::render::detail::layout_environment;
// construction/destruction
layout_element(environment &env, util::xml::data_node const &elemnode, const char *dirname);
layout_element(environment &env, util::xml::data_node const &elemnode);
virtual ~layout_element();
// getters
@ -563,7 +563,7 @@ private:
typedef std::unique_ptr<component> ptr;
// construction/destruction
component(environment &env, util::xml::data_node const &compnode, const char *dirname);
component(environment &env, util::xml::data_node const &compnode);
virtual ~component() = default;
// setup
@ -641,13 +641,13 @@ private:
int m_state; // associated state number
};
typedef component::ptr (*make_component_func)(environment &env, util::xml::data_node const &compnode, const char *dirname);
typedef component::ptr (*make_component_func)(environment &env, util::xml::data_node const &compnode);
typedef std::map<std::string, make_component_func> make_component_map;
// internal helpers
static void element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param);
template <typename T> static component::ptr make_component(environment &env, util::xml::data_node const &compnode, const char *dirname);
template <int D> static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode, const char *dirname);
template <typename T> static component::ptr make_component(environment &env, util::xml::data_node const &compnode);
template <int D> static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode);
static make_component_map const s_make_component; // maps component XML names to creator functions
@ -946,7 +946,7 @@ public:
using view_list = std::list<layout_view>;
// construction/destruction
layout_file(device_t &device, util::xml::data_node const &rootnode, char const *dirname);
layout_file(device_t &device, util::xml::data_node const &rootnode, char const *searchpath, char const *dirname);
~layout_file();
// getters
@ -959,7 +959,6 @@ private:
// add elements and parameters
void add_elements(
char const *dirname,
environment &env,
util::xml::data_node const &parentnode,
group_map &groupmap,
@ -1068,7 +1067,7 @@ private:
void load_additional_layout_files(const char *basename, bool have_artwork);
bool load_layout_file(const char *dirname, const char *filename);
bool load_layout_file(const char *dirname, const internal_layout &layout_data, device_t *device = nullptr);
bool load_layout_file(device_t &device, const char *dirname, util::xml::data_node const &rootnode);
bool load_layout_file(device_t &device, util::xml::data_node const &rootnode, const char *searchpath, const char *dirname);
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);
std::pair<float, float> map_point_internal(s32 target_x, s32 target_y);

View File

@ -582,18 +582,24 @@ private:
util::ovectorstream m_buffer;
std::shared_ptr<NSVGrasterizer> const m_svg_rasterizer;
device_t &m_device;
char const *const m_search_path;
char const *const m_directory_name;
layout_environment *const m_next = nullptr;
bool m_cached = false;
public:
explicit layout_environment(device_t &device)
layout_environment(device_t &device, char const *searchpath, char const *dirname)
: m_svg_rasterizer(nsvgCreateRasterizer(), util::nsvg_deleter())
, m_device(device)
, m_search_path(searchpath)
, m_directory_name(dirname)
{
}
explicit layout_environment(layout_environment &next)
: m_svg_rasterizer(next.m_svg_rasterizer)
, m_device(next.m_device)
, m_search_path(next.m_search_path)
, m_directory_name(next.m_directory_name)
, m_next(&next)
{
}
@ -602,6 +608,8 @@ public:
device_t &device() const { return m_device; }
running_machine &machine() const { return device().machine(); }
bool is_root_device() const { return &device() == &machine().root_device(); }
char const *search_path() const { return m_search_path; }
char const *directory_name() const { return m_directory_name; }
std::shared_ptr<NSVGrasterizer> const &svg_rasterizer() const { return m_svg_rasterizer; }
void set_parameter(std::string &&name, std::string &&value)
@ -1117,7 +1125,7 @@ layout_element::make_component_map const layout_element::s_make_component{
// layout_element - constructor
//-------------------------------------------------
layout_element::layout_element(environment &env, util::xml::data_node const &elemnode, const char *dirname)
layout_element::layout_element(environment &env, util::xml::data_node const &elemnode)
: m_machine(env.machine())
, m_defstate(env.get_attribute_int(elemnode, "defstate", -1))
, m_statemask(0)
@ -1133,7 +1141,7 @@ layout_element::layout_element(environment &env, util::xml::data_node const &ele
throw layout_syntax_error(util::string_format("unknown element component %s", compnode->get_name()));
// insert the new component into the list
component const &newcomp(**m_complist.emplace(m_complist.end(), make_func->second(env, *compnode, dirname)));
component const &newcomp(**m_complist.emplace(m_complist.end(), make_func->second(env, *compnode)));
// accumulate bounds
if (first)
@ -1539,10 +1547,11 @@ class layout_element::image_component : public component
{
public:
// construction/destruction
image_component(environment &env, util::xml::data_node const &compnode, char const *dirname)
: component(env, compnode, dirname)
image_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
, m_rasterizer(env.svg_rasterizer())
, m_dirname(dirname ? dirname : "")
, m_searchpath(env.search_path() ? env.search_path() : "")
, m_dirname(env.directory_name() ? env.directory_name() : "")
, m_imagefile(env.get_attribute_string(compnode, "file", ""))
, m_alphafile(env.get_attribute_string(compnode, "alphafile", ""))
, m_data(get_data(compnode))
@ -1552,7 +1561,7 @@ public:
// overrides
virtual void preload(running_machine &machine) override
{
if (!m_bitmap.valid())
if (!m_bitmap.valid() && !m_svg)
load_image(machine);
}
@ -1685,11 +1694,17 @@ private:
void load_image(running_machine &machine)
{
// if we have a filename, go with that
emu_file file(machine.options().art_path(), OPEN_FLAG_READ);
emu_file file(m_searchpath.empty() ? m_dirname : m_searchpath, OPEN_FLAG_READ);
if (!m_imagefile.empty())
{
LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load image file '%s%s%s'\n", m_dirname, PATH_SEPARATOR, m_imagefile);
osd_file::error const imgerr = file.open(m_dirname.empty() ? m_imagefile : (m_dirname + PATH_SEPARATOR + m_imagefile));
std::string filename;
if (!m_searchpath.empty())
filename = m_dirname;
if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
filename.append(PATH_SEPARATOR);
filename.append(m_imagefile);
LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load image file '%s'\n", filename);
osd_file::error const imgerr = file.open(filename);
if (osd_file::error::NONE == imgerr)
{
if (!load_bitmap(file))
@ -1701,10 +1716,10 @@ private:
}
else
{
LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open image file '%s%s%s'\n", m_dirname, PATH_SEPARATOR, m_imagefile);
LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open image file '%s'\n", filename);
}
}
else
else if (!m_data.empty())
{
load_image_data();
}
@ -1714,8 +1729,14 @@ private:
{
if (m_bitmap.valid())
{
LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load alpha channel from file '%s%s%s'\n", m_dirname, PATH_SEPARATOR, m_alphafile);
osd_file::error const alferr = file.open(m_dirname.empty() ? m_alphafile : (m_dirname + PATH_SEPARATOR + m_alphafile));
std::string filename;
if (!m_searchpath.empty())
filename = m_dirname;
if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
filename.append(PATH_SEPARATOR);
filename.append(m_alphafile);
LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load alpha channel from file '%s'\n", filename);
osd_file::error const alferr = file.open(filename);
if (osd_file::error::NONE == alferr)
{
// TODO: no way to detect corner case where we had alpha from the image but the alpha PNG makes it entirely opaque
@ -1725,7 +1746,7 @@ private:
}
else
{
LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open alpha channel file '%s%s%s'\n", m_dirname, PATH_SEPARATOR, m_alphafile);
LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open alpha channel file '%s'\n", filename);
}
}
else if (m_svg)
@ -1754,6 +1775,7 @@ private:
// clear out this stuff in case it's large
if (!m_svg)
m_rasterizer.reset();
m_searchpath.clear();
m_dirname.clear();
m_imagefile.clear();
m_alphafile.clear();
@ -1773,7 +1795,7 @@ private:
std::string::size_type const end(m_data.find_first_not_of(base64tail, tail));
if (std::string::npos == end)
{
LOGMASKED(LOG_IMAGE_LOAD, "Image component decoding Base64 image m_data\n");
LOGMASKED(LOG_IMAGE_LOAD, "Image component decoding Base64 image data\n");
char *dst(&m_data[0]);
unsigned trailing(0U);
for (std::string::size_type i = 0U; (m_data.size() > i) && ('=' != m_data[i]); ++i)
@ -1923,6 +1945,7 @@ private:
bool m_hasalpha = false; // is there any alpha component present?
// cold state
std::string m_searchpath; // asset search path (for lazy loading)
std::string m_dirname; // directory name of image file (for lazy loading)
std::string m_imagefile; // name of the image file (for lazy loading)
std::string m_alphafile; // name of the alpha file (for lazy loading)
@ -1935,8 +1958,8 @@ class layout_element::rect_component : public component
{
public:
// construction/destruction
rect_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
rect_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
}
@ -1988,8 +2011,8 @@ class layout_element::disk_component : public component
{
public:
// construction/destruction
disk_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
disk_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
}
@ -2054,8 +2077,8 @@ class layout_element::text_component : public component
{
public:
// construction/destruction
text_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
text_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
m_string = env.get_attribute_string(compnode, "string", "");
m_textalign = env.get_attribute_int(compnode, "align", 0);
@ -2081,8 +2104,8 @@ class layout_element::led7seg_component : public component
{
public:
// construction/destruction
led7seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
led7seg_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
}
@ -2143,8 +2166,8 @@ class layout_element::led8seg_gts1_component : public component
{
public:
// construction/destruction
led8seg_gts1_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
led8seg_gts1_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
}
@ -2211,8 +2234,8 @@ class layout_element::led14seg_component : public component
{
public:
// construction/destruction
led14seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
led14seg_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
}
@ -2323,8 +2346,8 @@ class layout_element::led16seg_component : public component
{
public:
// construction/destruction
led16seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
led16seg_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
}
@ -2445,8 +2468,8 @@ class layout_element::led14segsc_component : public component
{
public:
// construction/destruction
led14segsc_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
led14segsc_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
}
@ -2568,8 +2591,8 @@ class layout_element::led16segsc_component : public component
{
public:
// construction/destruction
led16segsc_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
led16segsc_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
}
@ -2700,8 +2723,8 @@ class layout_element::dotmatrix_component : public component
{
public:
// construction/destruction
dotmatrix_component(int dots, environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
dotmatrix_component(int dots, environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
, m_dots(dots)
{
}
@ -2741,8 +2764,8 @@ class layout_element::simplecounter_component : public component
{
public:
// construction/destruction
simplecounter_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
simplecounter_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
, m_digits(env.get_attribute_int(compnode, "digits", 2))
, m_textalign(env.get_attribute_int(compnode, "align", 0))
, m_maxstate(env.get_attribute_int(compnode, "maxstate", 999))
@ -2774,49 +2797,30 @@ class layout_element::reel_component : public component
public:
// construction/destruction
reel_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
: component(env, compnode, dirname)
reel_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
, m_searchpath(env.search_path() ? env.search_path() : "")
, m_dirname(env.directory_name() ? env.directory_name() : "")
{
for (auto & elem : m_hasalpha)
elem = false;
std::string symbollist = env.get_attribute_string(compnode, "symbollist", "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15");
// split out position names from string and figure out our number of symbols
int location;
m_numstops = 0;
location=symbollist.find(',');
while (location!=-1)
for (std::string::size_type location = symbollist.find(','); std::string::npos != location; location = symbollist.find(','))
{
m_stopnames[m_numstops] = symbollist;
m_stopnames[m_numstops] = m_stopnames[m_numstops].substr(0, location);
symbollist = symbollist.substr(location+1, symbollist.length()-(location-1));
m_stopnames[m_numstops] = symbollist.substr(0, location);
symbollist.erase(0, location + 1);
m_numstops++;
location=symbollist.find(',');
}
m_stopnames[m_numstops++] = symbollist;
// careful, dirname is nullptr if we're coming from internal layout, and our string assignment doesn't like that
if (dirname != nullptr)
m_dirname = dirname;
for (int i=0;i<m_numstops;i++)
for (int i = 0; i < m_numstops; i++)
{
location=m_stopnames[i].find(':');
if (location!=-1)
std::string::size_type const location = m_stopnames[i].find(':');
if (location != std::string::npos)
{
m_imagefile[i] = m_stopnames[i];
m_stopnames[i] = m_stopnames[i].substr(0, location);
m_imagefile[i] = m_imagefile[i].substr(location+1, m_imagefile[i].length()-(location-1));
//m_alphafile[i] =
m_file[i] = std::make_unique<emu_file>(env.machine().options().art_path(), OPEN_FLAG_READ);
}
else
{
//m_imagefile[i] = 0;
//m_alphafile[i] = 0;
m_file[i].reset();
m_imagefile[i] = m_stopnames[i].substr(location + 1);
m_stopnames[i].erase(location);
}
}
@ -2829,6 +2833,17 @@ public:
protected:
// overrides
virtual int maxstate() const override { return 65535; }
virtual void preload(running_machine &machine) override
{
for (int i = 0; i < m_numstops; i++)
{
if (!m_imagefile[i].empty() && !m_bitmap[i].valid())
load_reel_bitmap(i);
}
}
virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
if (m_beltreel)
@ -2850,16 +2865,12 @@ protected:
u32 const b = c.b * 255.0f;
u32 const a = c.a * 255.0f;
// get the width of the string
auto font = machine.render().font_alloc("default");
float aspect = 1.0f;
s32 width;
int curry = 0;
int num_shown = m_numsymbolsvisible;
int ourheight = bounds.height();
auto font = machine.render().font_alloc("default");
for (int fruit = 0;fruit<m_numstops;fruit++)
{
int basey;
@ -2884,47 +2895,31 @@ protected:
// only render the symbol / text if it's actually in view because the code is SLOW
if ((endpos >= bounds.top()) && (basey <= bounds.bottom()))
{
while (1)
{
width = font->string_width(ourheight / num_shown, aspect, m_stopnames[fruit].c_str());
if (width < bounds.width())
break;
aspect *= 0.9f;
}
if (!m_imagefile[fruit].empty() && !m_bitmap[fruit].valid())
load_reel_bitmap(fruit);
s32 curx;
curx = bounds.left() + (bounds.width() - width) / 2;
if (m_file[fruit])
if (!m_bitmap[fruit].valid())
load_reel_bitmap(fruit);
if (m_file[fruit]) // render gfx
if (m_bitmap[fruit].valid()) // render gfx
{
bitmap_argb32 tempbitmap2(dest.width(), ourheight/num_shown);
render_resample_argb_bitmap_hq(tempbitmap2, m_bitmap[fruit], c);
if (m_bitmap[fruit].valid())
for (int y = 0; y < ourheight/num_shown; y++)
{
render_resample_argb_bitmap_hq(tempbitmap2, m_bitmap[fruit], c);
int effy = basey + y;
for (int y = 0; y < ourheight/num_shown; y++)
if (effy >= bounds.top() && effy <= bounds.bottom())
{
int effy = basey + y;
if (effy >= bounds.top() && effy <= bounds.bottom())
u32 const *const src = &tempbitmap2.pix(y);
u32 *const d = &dest.pix(effy);
for (int x = 0; x < dest.width(); x++)
{
u32 const *const src = &tempbitmap2.pix(y);
u32 *const d = &dest.pix(effy);
for (int x = 0; x < dest.width(); x++)
int effx = x;
if (effx >= bounds.left() && effx <= bounds.right())
{
int effx = x;
if (effx >= bounds.left() && effx <= bounds.right())
u32 spix = rgb_t(src[x]).a();
if (spix != 0)
{
u32 spix = rgb_t(src[x]).a();
if (spix != 0)
{
d[effx] = src[x];
}
d[effx] = src[x];
}
}
}
@ -2941,6 +2936,20 @@ protected:
const char *s = origs;
char32_t schar;
// get the width of the string
float aspect = 1.0f;
s32 width;
while (1)
{
width = font->string_width(ourheight / num_shown, aspect, m_stopnames[fruit].c_str());
if (width < bounds.width())
break;
aspect *= 0.9f;
}
s32 curx = bounds.left() + (bounds.width() - width) / 2;
// loop over characters
while (*s != 0)
{
@ -3011,15 +3020,12 @@ private:
u32 const b = c.b * 255.0f;
u32 const a = c.a * 255.0f;
// get the width of the string
auto font = machine.render().font_alloc("default");
float aspect = 1.0f;
s32 width;
int currx = 0;
int num_shown = m_numsymbolsvisible;
int ourwidth = bounds.width();
auto font = machine.render().font_alloc("default");
for (int fruit = 0;fruit<m_numstops;fruit++)
{
int basex;
@ -3043,56 +3049,53 @@ private:
// only render the symbol / text if it's actually in view because the code is SLOW
if ((endpos >= bounds.left()) && (basex <= bounds.right()))
{
while (1)
{
width = font->string_width(dest.height(), aspect, m_stopnames[fruit].c_str());
if (width < bounds.width())
break;
aspect *= 0.9f;
}
if (!m_imagefile[fruit].empty() && !m_bitmap[fruit].valid())
load_reel_bitmap(fruit);
s32 curx;
curx = bounds.left();
if (m_file[fruit])
if (!m_bitmap[fruit].valid())
load_reel_bitmap(fruit);
if (m_file[fruit]) // render gfx
if (m_bitmap[fruit].valid()) // render gfx
{
bitmap_argb32 tempbitmap2(ourwidth/num_shown, dest.height());
render_resample_argb_bitmap_hq(tempbitmap2, m_bitmap[fruit], c);
if (m_bitmap[fruit].valid())
for (int y = 0; y < dest.height(); y++)
{
render_resample_argb_bitmap_hq(tempbitmap2, m_bitmap[fruit], c);
int effy = y;
for (int y = 0; y < dest.height(); y++)
if (effy >= bounds.top() && effy <= bounds.bottom())
{
int effy = y;
if (effy >= bounds.top() && effy <= bounds.bottom())
u32 const *const src = &tempbitmap2.pix(y);
u32 *const d = &dest.pix(effy);
for (int x = 0; x < ourwidth/num_shown; x++)
{
u32 const *const src = &tempbitmap2.pix(y);
u32 *const d = &dest.pix(effy);
for (int x = 0; x < ourwidth/num_shown; x++)
int effx = basex + x;
if (effx >= bounds.left() && effx <= bounds.right())
{
int effx = basex + x;
if (effx >= bounds.left() && effx <= bounds.right())
u32 spix = rgb_t(src[x]).a();
if (spix != 0)
{
u32 spix = rgb_t(src[x]).a();
if (spix != 0)
{
d[effx] = src[x];
}
d[effx] = src[x];
}
}
}
}
}
}
else // render text (fallback)
{
// get the width of the string
float aspect = 1.0f;
s32 width;
while (1)
{
width = font->string_width(dest.height(), aspect, m_stopnames[fruit].c_str());
if (width < bounds.width())
break;
aspect *= 0.9f;
}
s32 curx = bounds.left();
// allocate a temporary bitmap
bitmap_argb32 tempbitmap(dest.width(), dest.height());
@ -3157,34 +3160,29 @@ private:
void load_reel_bitmap(int number)
{
// load the basic bitmap
assert(m_file != nullptr);
if (m_file[number]->open(m_dirname + PATH_SEPARATOR + m_imagefile[number]) == osd_file::error::NONE)
{
/*m_hasalpha[number] = */ render_load_png(m_bitmap[number], *m_file[number]);
m_file[number]->close();
}
emu_file file(m_searchpath.empty() ? m_dirname : m_searchpath, OPEN_FLAG_READ);
std::string filename;
if (!m_searchpath.empty())
filename = m_dirname;
if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
filename.append(PATH_SEPARATOR);
filename.append(m_imagefile[number]);
// load the alpha bitmap if specified
//if (m_bitmap[number].valid() && m_alphafile[number])
// render_load_png(m_bitmap[number], *m_file[number], m_dirname, m_alphafile[number], true);
// load the basic bitmap
if (file.open(filename) == osd_file::error::NONE)
render_load_png(m_bitmap[number], file);
// if we can't load the bitmap just use text rendering
if (!m_bitmap[number].valid())
{
// fallback to text rendering
m_file[number].reset();
}
m_imagefile[number].clear();
}
// internal state
bitmap_argb32 m_bitmap[MAX_BITMAPS]; // source bitmap for images
std::string m_searchpath; // asset search path (for lazy loading)
std::string m_dirname; // directory name of image file (for lazy loading)
std::unique_ptr<emu_file> m_file[MAX_BITMAPS]; // file object for reading image/alpha files
std::string m_imagefile[MAX_BITMAPS]; // name of the image file (for lazy loading)
std::string m_alphafile[MAX_BITMAPS]; // name of the alpha file (for lazy loading)
bool m_hasalpha[MAX_BITMAPS]; // is there any alpha component present?
// basically made up of multiple text strings / gfx
int m_numstops;
@ -3201,9 +3199,9 @@ private:
//-------------------------------------------------
template <typename T>
layout_element::component::ptr layout_element::make_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
layout_element::component::ptr layout_element::make_component(environment &env, util::xml::data_node const &compnode)
{
return std::make_unique<T>(env, compnode, dirname);
return std::make_unique<T>(env, compnode);
}
@ -3213,9 +3211,9 @@ layout_element::component::ptr layout_element::make_component(environment &env,
//-------------------------------------------------
template <int D>
layout_element::component::ptr layout_element::make_dotmatrix_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
layout_element::component::ptr layout_element::make_dotmatrix_component(environment &env, util::xml::data_node const &compnode)
{
return std::make_unique<dotmatrix_component>(D, env, compnode, dirname);
return std::make_unique<dotmatrix_component>(D, env, compnode);
}
@ -3276,7 +3274,7 @@ layout_element::texture &layout_element::texture::operator=(texture &&that)
// component - constructor
//-------------------------------------------------
layout_element::component::component(environment &env, util::xml::data_node const &compnode, const char *dirname)
layout_element::component::component(environment &env, util::xml::data_node const &compnode)
: m_statemask(env.get_attribute_int(compnode, "statemask", env.get_attribute_string(compnode, "state", "")[0] ? ~0 : 0))
, m_stateval(env.get_attribute_int(compnode, "state", m_statemask) & m_statemask)
{
@ -4576,13 +4574,17 @@ layout_view::visibility_toggle::visibility_toggle(std::string &&name, u32 mask)
// layout_file - constructor
//-------------------------------------------------
layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode, char const *dirname)
layout_file::layout_file(
device_t &device,
util::xml::data_node const &rootnode,
char const *searchpath,
char const *dirname)
: m_elemmap()
, m_viewlist()
{
try
{
environment env(device);
environment env(device, searchpath, dirname);
// find the layout node
util::xml::data_node const *const mamelayoutnode = rootnode.get_child("mamelayout");
@ -4596,7 +4598,7 @@ layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode,
// parse all the parameters, elements and groups
group_map groupmap;
add_elements(dirname, env, *mamelayoutnode, groupmap, false, true);
add_elements(env, *mamelayoutnode, groupmap, false, true);
// parse all the views
for (util::xml::data_node const *viewnode = mamelayoutnode->get_child("view"); viewnode != nullptr; viewnode = viewnode->get_next_sibling("view"))
@ -4633,7 +4635,6 @@ layout_file::~layout_file()
void layout_file::add_elements(
char const *dirname,
environment &env,
util::xml::data_node const &parentnode,
group_map &groupmap,
@ -4654,7 +4655,7 @@ void layout_file::add_elements(
char const *const name(env.get_attribute_string(*childnode, "name", nullptr));
if (!name)
throw layout_syntax_error("element lacks name attribute");
if (!m_elemmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(env, *childnode, dirname)).second)
if (!m_elemmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(env, *childnode)).second)
throw layout_syntax_error(util::string_format("duplicate element name %s", name));
}
else if (!strcmp(childnode->get_name(), "group"))
@ -4673,7 +4674,7 @@ void layout_file::add_elements(
environment local(env);
for (int i = 0; count > i; ++i)
{
add_elements(dirname, local, *childnode, groupmap, true, !i);
add_elements(local, *childnode, groupmap, true, !i);
local.increment_parameters();
}
}