diff options
author | 2020-10-09 02:52:49 +1100 | |
---|---|---|
committer | 2020-10-09 02:52:49 +1100 | |
commit | 740011e4d1db8a9468f917ef518e1e7a1c95cde1 (patch) | |
tree | cb9d82e642005bbb68e8637cdf24d5dc7bcee25b /src/emu/rendlay.cpp | |
parent | 7fc54760e16341bd1f13fa63663e2cb0a56cb035 (diff) |
Allow layout files to embed image data.
Also improved symmetry of disk components, fixed positioning of
components when fitting to the pixel grid, and fixed inherited color
when item has no color specified.
Removed the dotmatrix components from complay.py - there are more
flexible ways to achieve the same thing.
Diffstat (limited to 'src/emu/rendlay.cpp')
-rw-r--r-- | src/emu/rendlay.cpp | 199 |
1 files changed, 145 insertions, 54 deletions
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index 2f57c7ade1d..25604722212 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -1521,14 +1521,14 @@ void layout_element::element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, c // get the local scaled bounds render_bounds const compbounds(curcomp->bounds(elemtex.m_state)); rectangle bounds( - render_round_nearest(compbounds.x0 * dest.width()), - render_round_nearest(compbounds.x1 * dest.width()), - render_round_nearest(compbounds.y0 * dest.height()), - render_round_nearest(compbounds.y1 * dest.height())); - bounds &= dest.cliprect(); + s32(compbounds.x0 * float(dest.width()) + 0.5F), + s32(floorf(compbounds.x1 * float(dest.width()) - 0.5F)), + s32(compbounds.y0 * float(dest.height()) + 0.5F), + s32(floorf(compbounds.y1 * float(dest.height()) - 0.5F))); // based on the component type, add to the texture - curcomp->draw(elemtex.m_element->machine(), dest, bounds, elemtex.m_state); + if (!bounds.empty()) + curcomp->draw(elemtex.m_element->machine(), dest, bounds, elemtex.m_state); } } } @@ -1684,44 +1684,29 @@ private: void load_image(running_machine &machine) { - // attempt to open the file - LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load image file '%s%s%s'\n", m_dirname, PATH_SEPARATOR, m_imagefile); + // if we have a filename, go with that emu_file file(machine.options().art_path(), OPEN_FLAG_READ); - osd_file::error const imgerr = file.open(m_dirname.empty() ? m_imagefile : (m_dirname + PATH_SEPARATOR + m_imagefile)); - if (osd_file::error::NONE == imgerr) + if (!m_imagefile.empty()) { - ru_imgformat const format = render_detect_image(file); - switch (format) + 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)); + if (osd_file::error::NONE == imgerr) { - case RENDUTIL_IMGFORMAT_ERROR: - LOGMASKED(LOG_IMAGE_LOAD, "Image component error detecting image file format\n"); - break; - - case RENDUTIL_IMGFORMAT_PNG: - LOGMASKED(LOG_IMAGE_LOAD, "Image component detected PNG file format\n"); - m_hasalpha = render_load_png(m_bitmap, file); - break; - - case RENDUTIL_IMGFORMAT_JPEG: - LOGMASKED(LOG_IMAGE_LOAD, "Image component detected JPEG file format\n"); - render_load_jpeg(m_bitmap, file); - break; - - case RENDUTIL_IMGFORMAT_MSDIB: - LOGMASKED(LOG_IMAGE_LOAD, "Image component detected Microsoft DIB file format\n"); - render_load_msdib(m_bitmap, file); - break; - - default: - LOGMASKED(LOG_IMAGE_LOAD, "Image component failed to detect image file format, trying SVG\n"); - load_svg(file); - break; + if (!load_bitmap(file)) + { + LOGMASKED(LOG_IMAGE_LOAD, "Image component will attempt to parse file as SVG\n"); + load_svg(file); + } + file.close(); + } + else + { + LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open image file '%s%s%s'\n", m_dirname, PATH_SEPARATOR, m_imagefile); } - file.close(); } else { - LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open image file '%s%s%s'\n", m_dirname, PATH_SEPARATOR, m_imagefile); + load_image_data(); } // load the alpha bitmap if specified @@ -1775,13 +1760,104 @@ private: m_data.clear(); } - void load_svg(util::core_file &file) + void load_image_data() { - if (!m_rasterizer) + // in-place Base64 decode + static constexpr char base64chars[] = + "\t\n\v\f\r +/0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + static constexpr char base64tail[] = + "\t\n\v\f\r ="; + std::string::size_type const tail(m_data.find_first_not_of(base64chars)); + std::string::size_type const end(m_data.find_first_not_of(base64tail, tail)); + if (std::string::npos == end) { - osd_printf_warning("No SVG rasteriser available, won't attempt to parse component image '%s' as SVG\n", m_imagefile); - return; + LOGMASKED(LOG_IMAGE_LOAD, "Image component decoding Base64 image m_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) + { + u8 sym; + if (('A' <= m_data[i]) && ('Z' >= m_data[i])) + sym = m_data[i] - 'A'; + else if (('a' <= m_data[i]) && ('z' >= m_data[i])) + sym = m_data[i] - 'a' + 26; + else if (('0' <= m_data[i]) && ('9' >= m_data[i])) + sym = m_data[i] - '0' + 52; + else if ('+' == m_data[i]) + sym = 62; + else if ('/' == m_data[i]) + sym = 63; + else + continue; + if (trailing) + *dst |= (sym << 2) >> trailing; + else + *dst = sym << 2; + if (trailing >= 2U) + ++dst; + trailing = (trailing + 6U) & 7U; + if (trailing) + *dst = sym << (8U - trailing); + } + m_data.resize(dst - &m_data[0]); } + + // make a file wrapper for the data and see if it looks like a bitmap + util::core_file::ptr file; + osd_file::error const filerr(util::core_file::open_ram(m_data.c_str(), m_data.size(), OPEN_FLAG_READ, file)); + bool const bitmapdata((osd_file::error::NONE == filerr) && file && load_bitmap(*file)); + file.reset(); + + // if it didn't look like a bitmap, see if it looks like it might be XML and hence SVG + if (!bitmapdata) + { + bool const utf16be((0xfe == u8(m_data[0])) && (0xff == u8(m_data[1]))); + bool const utf16le((0xff == u8(m_data[0])) && (0xfe == u8(m_data[1]))); + bool const utf8((0xef == u8(m_data[0])) && (0xbb == u8(m_data[1])) && (0xbf == u8(m_data[2]))); + std::string::size_type const found(m_data.find_first_not_of("\t\n\v\f\r ")); + bool const xmltag((std::string::npos != found) && ('<' == m_data[found])); + if (utf16be || utf16le || utf8 || xmltag) + { + LOGMASKED(LOG_IMAGE_LOAD, "Image component will attempt to parse data as SVG\n"); + parse_svg(&m_data[0]); + } + } + } + + bool load_bitmap(util::core_file &file) + { + ru_imgformat const format = render_detect_image(file); + switch (format) + { + case RENDUTIL_IMGFORMAT_ERROR: + LOGMASKED(LOG_IMAGE_LOAD, "Image component error detecting image file format\n"); + return false; + + case RENDUTIL_IMGFORMAT_PNG: + LOGMASKED(LOG_IMAGE_LOAD, "Image component detected PNG file format\n"); + m_hasalpha = render_load_png(m_bitmap, file); + return true; + + case RENDUTIL_IMGFORMAT_JPEG: + LOGMASKED(LOG_IMAGE_LOAD, "Image component detected JPEG file format\n"); + render_load_jpeg(m_bitmap, file); + return true; + + case RENDUTIL_IMGFORMAT_MSDIB: + LOGMASKED(LOG_IMAGE_LOAD, "Image component detected Microsoft DIB file format\n"); + render_load_msdib(m_bitmap, file); + return true; + + default: + LOGMASKED(LOG_IMAGE_LOAD, "Image component failed to detect bitmap file format\n"); + return false; + } + } + + void load_svg(util::core_file &file) + { u64 len(file.size()); if ((std::numeric_limits<size_t>::max() - 1) < len) { @@ -1807,8 +1883,17 @@ private: ptr += read; len -= read; } - m_svg.reset(nsvgParse(svgbuf.get(), "px", 72)); - svgbuf.reset(); + parse_svg(svgbuf.get()); + } + + void parse_svg(char *svgdata) + { + if (!m_rasterizer) + { + osd_printf_warning("No SVG rasteriser available, won't attempt to parse component image '%s' as SVG\n", m_imagefile); + return; + } + m_svg.reset(nsvgParse(svgdata, "px", 72)); if (!m_svg) { osd_printf_warning("Failed to parse component image '%s' as SVG\n", m_imagefile); @@ -1922,8 +2007,8 @@ protected: u32 const inva(255 - a); // find the center - float const xcenter = float(bounds.xcenter()); - float const ycenter = float(bounds.ycenter()); + float const xcenter = float(bounds.left() + bounds.right()) * 0.5F; + float const ycenter = float(bounds.top() + bounds.bottom()) * 0.5F; float const xradius = float(bounds.width()) * 0.5F; float const yradius = float(bounds.height()) * 0.5F; float const ooyradius2 = 1.0F / (yradius * yradius); @@ -1932,22 +2017,21 @@ protected: for (u32 y = bounds.top(); y <= bounds.bottom(); ++y) { // compute left/right coordinates - float const ycoord = ycenter - (float(y) + 0.5F); + float const ycoord = ycenter - float(y); float const xval = xradius * sqrtf(1.0F - (ycoord * ycoord) * ooyradius2); - s32 const left = s32(xcenter - xval + 0.5F); - s32 const right = s32(xcenter + xval + 0.5F); + s32 const right = bounds.right() - left + bounds.left(); // draw this scanline if (255 <= a) { // optimise opaque pixels - std::fill_n(&dest.pix(y, left), right - left, f); + std::fill_n(&dest.pix(y, left), right - left + 1, f); } else if (a) { - u32 *dst(&dest.pix(y, bounds.left())); - for (u32 x = left; x < right; ++x, ++dst) + u32 *dst(&dest.pix(y, left)); + for (s32 x = left; x <= right; ++x, ++dst) { // we're translucent, add in the destination pixel contribution rgb_t const dpix(*dst); @@ -4354,9 +4438,16 @@ layout_view::item::color_vector layout_view::item::make_color( itemnode.get_name())); } } - for (emu::render::detail::color_step &step : result) - step.color *= mult; - set_color_deltas(result); + if (result.empty()) + { + result.emplace_back(emu::render::detail::color_step{ 0, mult, { 0.0F, 0.0F, 0.0F, 0.0F } }); + } + else + { + for (emu::render::detail::color_step &step : result) + step.color *= mult; + set_color_deltas(result); + } return result; } |