diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index acc25e9ab8f..9b33eac7b45 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -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; } diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index a8f93e598f3..500310bd459 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -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 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, ¶ms[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"; diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index 38d1bc4f367..2d811523650 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -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; + }; diff --git a/src/emu/render.cpp b/src/emu/render.cpp index b1518d87dd4..5ade8c54af4 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -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(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 &) { diff --git a/src/emu/render.h b/src/emu/render.h index c78fa8fb7d2..6dab6fde519 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -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 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 make_component_map; // internal helpers static void element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param); - template static component::ptr make_component(environment &env, util::xml::data_node const &compnode, const char *dirname); - template static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode, const char *dirname); + template static component::ptr make_component(environment &env, util::xml::data_node const &compnode); + template 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; // 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 map_point_internal(s32 target_x, s32 target_y); diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index 25604722212..79401b19306 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -582,18 +582,24 @@ private: util::ovectorstream m_buffer; std::shared_ptr 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 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(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= 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= 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 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 -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(env, compnode, dirname); + return std::make_unique(env, compnode); } @@ -3213,9 +3211,9 @@ layout_element::component::ptr layout_element::make_component(environment &env, //------------------------------------------------- template -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(D, env, compnode, dirname); + return std::make_unique(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(); } }