summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/imagedev/picture.cpp26
-rw-r--r--src/devices/video/fixfreq.cpp5
-rw-r--r--src/devices/video/vector.cpp5
-rw-r--r--src/emu/crsshair.cpp36
-rw-r--r--src/emu/recording.cpp16
-rw-r--r--src/emu/render.cpp26
-rw-r--r--src/emu/render.h80
-rw-r--r--src/emu/rendertypes.h153
-rw-r--r--src/emu/rendlay.cpp448
-rw-r--r--src/emu/rendutil.cpp319
-rw-r--r--src/emu/rendutil.h81
-rw-r--r--src/emu/screen.cpp37
-rw-r--r--src/emu/video.cpp8
-rw-r--r--src/frontend/mame/ui/icorender.cpp508
-rw-r--r--src/frontend/mame/ui/menu.cpp13
-rw-r--r--src/frontend/mame/ui/selmenu.cpp135
-rw-r--r--src/lib/util/msdib.cpp642
-rw-r--r--src/lib/util/msdib.h46
-rw-r--r--src/lib/util/nanosvg.h33
-rw-r--r--src/lib/util/png.cpp253
-rw-r--r--src/lib/util/png.h42
-rw-r--r--src/mame/drivers/alg.cpp1
-rw-r--r--src/mame/drivers/by17.cpp5
-rw-r--r--src/mame/drivers/by35.cpp5
-rw-r--r--src/mame/drivers/cliffhgr.cpp1
-rw-r--r--src/mame/drivers/decwritr.cpp2
-rw-r--r--src/mame/drivers/dlair.cpp1
-rw-r--r--src/mame/drivers/istellar.cpp1
-rw-r--r--src/mame/drivers/lgp.cpp1
-rw-r--r--src/mame/layout/unkeinv.lay52
-rw-r--r--src/mame/video/midtunit.cpp2
-rw-r--r--src/mame/video/ssv.cpp1
-rw-r--r--src/mame/video/st0020.cpp4
-rw-r--r--src/mame/video/tx1.cpp4
-rw-r--r--src/osd/modules/render/bgfx/texturemanager.cpp6
-rw-r--r--src/osd/modules/render/d3d/d3dhlsl.cpp26
-rw-r--r--src/tools/pngcmp.cpp20
-rw-r--r--src/tools/regrep.cpp12
38 files changed, 1862 insertions, 1194 deletions
diff --git a/src/devices/imagedev/picture.cpp b/src/devices/imagedev/picture.cpp
index e50f2c0d4c6..e6736fb10c9 100644
--- a/src/devices/imagedev/picture.cpp
+++ b/src/devices/imagedev/picture.cpp
@@ -10,7 +10,7 @@
#include "emu.h"
#include "picture.h"
-#include "png.h"
+#include "rendutil.h"
/***************************************************************************
TYPE DEFINITIONS
@@ -44,15 +44,25 @@ void picture_image_device::device_start()
image_init_result picture_image_device::call_load()
{
- if (png_read_bitmap(image_core_file(), m_picture) != PNGERR_NONE)
- {
- m_picture.reset();
-
- // todo: try JPEG here.
- return image_init_result::FAIL;
+ switch (render_detect_image(image_core_file()))
+ {
+ case RENDUTIL_IMGFORMAT_PNG:
+ render_load_png(m_picture, image_core_file());
+ break;
+
+ case RENDUTIL_IMGFORMAT_JPEG:
+ render_load_jpeg(m_picture, image_core_file());
+ break;
+
+ case RENDUTIL_IMGFORMAT_MSDIB:
+ render_load_msdib(m_picture, image_core_file());
+ break;
+
+ default:
+ m_picture.reset();
}
- return image_init_result::PASS;
+ return m_picture.valid() ? image_init_result::PASS : image_init_result::FAIL;
}
void picture_image_device::call_unload()
diff --git a/src/devices/video/fixfreq.cpp b/src/devices/video/fixfreq.cpp
index 3810dc76a76..5de27dc0b08 100644
--- a/src/devices/video/fixfreq.cpp
+++ b/src/devices/video/fixfreq.cpp
@@ -14,10 +14,11 @@
***************************************************************************/
#include "emu.h"
-#include "ui/uimain.h"
-#include "rendutil.h"
#include "fixfreq.h"
+#include "render.h"
+#include "ui/uimain.h"
+
// for quick and dirty debugging
#define VERBOSE 0
#define LOG_OUTPUT_STREAM std::cerr
diff --git a/src/devices/video/vector.cpp b/src/devices/video/vector.cpp
index 4e44603c136..46a21b535be 100644
--- a/src/devices/video/vector.cpp
+++ b/src/devices/video/vector.cpp
@@ -42,10 +42,11 @@
**************************************************************************** */
#include "emu.h"
-#include "emuopts.h"
-#include "rendutil.h"
#include "vector.h"
+#include "emuopts.h"
+#include "render.h"
+
#define VECTOR_WIDTH_DENOM 512
diff --git a/src/emu/crsshair.cpp b/src/emu/crsshair.cpp
index dd75ba119f1..027d8828e32 100644
--- a/src/emu/crsshair.cpp
+++ b/src/emu/crsshair.cpp
@@ -9,11 +9,15 @@
***************************************************************************/
#include "emu.h"
+#include "crsshair.h"
+
+#include "config.h"
#include "emuopts.h"
+#include "render.h"
#include "rendutil.h"
-#include "config.h"
+#include "screen.h"
+
#include "xmlfile.h"
-#include "crsshair.h"
@@ -171,28 +175,42 @@ void render_crosshair::create_bitmap()
rgb_t color = m_player < ARRAY_LENGTH(crosshair_colors) ? crosshair_colors[m_player] : rgb_t::white();
// if we have a bitmap and texture for this player, kill it
- if (m_bitmap == nullptr)
+ if (!m_bitmap)
{
m_bitmap = std::make_unique<bitmap_argb32>();
m_texture = m_machine.render().texture_alloc(render_texture::hq_scale);
}
+ else
+ {
+ m_bitmap->reset();
+ }
emu_file crossfile(m_machine.options().crosshair_path(), OPEN_FLAG_READ);
if (!m_name.empty())
{
// look for user specified file
- std::string filename = m_name + ".png";
- render_load_png(*m_bitmap, crossfile, nullptr, filename.c_str());
+ if (crossfile.open(m_name + ".png") == osd_file::error::NONE)
+ {
+ render_load_png(*m_bitmap, crossfile);
+ crossfile.close();
+ }
}
else
{
// look for default cross?.png in crsshair/game dir
- std::string filename = string_format("cross%d.png", m_player + 1);
- render_load_png(*m_bitmap, crossfile, m_machine.system().name, filename.c_str());
+ std::string const filename = string_format("cross%d.png", m_player + 1);
+ if (crossfile.open(m_machine.system().name + (PATH_SEPARATOR + filename)) == osd_file::error::NONE)
+ {
+ render_load_png(*m_bitmap, crossfile);
+ crossfile.close();
+ }
// look for default cross?.png in crsshair dir
- if (!m_bitmap->valid())
- render_load_png(*m_bitmap, crossfile, nullptr, filename.c_str());
+ if (!m_bitmap->valid() && (crossfile.open(filename) == osd_file::error::NONE))
+ {
+ render_load_png(*m_bitmap, crossfile);
+ crossfile.close();
+ }
}
/* if that didn't work, use the built-in one */
diff --git a/src/emu/recording.cpp b/src/emu/recording.cpp
index 2e134f03f4a..dd75c27d62f 100644
--- a/src/emu/recording.cpp
+++ b/src/emu/recording.cpp
@@ -248,7 +248,7 @@ mng_movie_recording::mng_movie_recording(screen_device *screen, std::map<std::st
mng_movie_recording::~mng_movie_recording()
{
if (m_mng_file)
- mng_capture_stop(*m_mng_file);
+ util::mng_capture_stop(*m_mng_file);
}
@@ -264,10 +264,10 @@ bool mng_movie_recording::initialize(std::unique_ptr<emu_file> &&file, bitmap_t
set_frame_period(attotime::from_hz(rate));
m_mng_file = std::move(file);
- png_error pngerr = mng_capture_start(*m_mng_file, snap_bitmap, rate);
- if (pngerr != PNGERR_NONE)
- osd_printf_error("Error capturing MNG, png_error=%d\n", pngerr);
- return pngerr == PNGERR_NONE;
+ util::png_error pngerr = util::mng_capture_start(*m_mng_file, snap_bitmap, rate);
+ if (pngerr != util::png_error::NONE)
+ osd_printf_error("Error capturing MNG, png_error=%d\n", std::underlying_type_t<util::png_error>(pngerr));
+ return pngerr == util::png_error::NONE;
}
@@ -278,15 +278,15 @@ bool mng_movie_recording::initialize(std::unique_ptr<emu_file> &&file, bitmap_t
bool mng_movie_recording::append_single_video_frame(bitmap_rgb32 &bitmap, const rgb_t *palette, int palette_entries)
{
// set up the text fields in the movie info
- png_info pnginfo;
+ util::png_info pnginfo;
if (current_frame() == 0)
{
for (auto &ent : m_info_fields)
pnginfo.add_text(ent.first.c_str(), ent.second.c_str());
}
- png_error error = mng_capture_frame(*m_mng_file, pnginfo, bitmap, palette_entries, palette);
- return error == png_error::PNGERR_NONE;
+ util::png_error error = util::mng_capture_frame(*m_mng_file, pnginfo, bitmap, palette_entries, palette);
+ return error == util::png_error::NONE;
}
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 531e327c978..b1518d87dd4 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -1371,9 +1371,9 @@ render_primitive_list &render_target::get_primitives()
{
// if we are not in the running stage, draw an outer box
render_primitive *prim = list.alloc(render_primitive::QUAD);
- set_render_bounds_xy(prim->bounds, 0.0f, 0.0f, (float)m_width, (float)m_height);
+ prim->bounds.set_xy(0.0f, 0.0f, (float)m_width, (float)m_height);
prim->full_bounds = prim->bounds;
- set_render_color(&prim->color, 1.0f, 0.1f, 0.1f, 0.1f);
+ prim->color.set(1.0f, 0.1f, 0.1f, 0.1f);
prim->texture.base = nullptr;
prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
list.append(*prim);
@@ -1381,9 +1381,9 @@ render_primitive_list &render_target::get_primitives()
if (m_width > 1 && m_height > 1)
{
prim = list.alloc(render_primitive::QUAD);
- set_render_bounds_xy(prim->bounds, 1.0f, 1.0f, (float)(m_width - 1), (float)(m_height - 1));
+ prim->bounds.set_xy(1.0f, 1.0f, float(m_width - 1), float(m_height - 1));
prim->full_bounds = prim->bounds;
- set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim->color.set(1.0f, 0.0f, 0.0f, 0.0f);
prim->texture.base = nullptr;
prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
list.append(*prim);
@@ -1535,7 +1535,7 @@ bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&in
if (item.has_input())
{
// point successfully mapped
- input_port = item.input_tag_and_mask(input_mask);
+ std::tie(input_port, input_mask) = item.input_tag_and_mask();
input_x = (target_f.first - bounds.x0) / bounds.width();
input_y = (target_f.second - bounds.y0) / bounds.height();
return true;
@@ -2237,7 +2237,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
cliprect.y0 = xform.yoffs;
cliprect.x1 = xform.xoffs + xform.xscale;
cliprect.y1 = xform.yoffs + xform.yscale;
- sect_render_bounds(cliprect, m_bounds);
+ cliprect &= m_bounds;
float root_xoffs = root_xform.xoffs + fabsf(root_xform.xscale - xform.xscale) * 0.5f;
float root_yoffs = root_xform.yoffs + fabsf(root_xform.yscale - xform.yscale) * 0.5f;
@@ -2247,7 +2247,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
root_cliprect.y0 = root_yoffs;
root_cliprect.x1 = root_xoffs + root_xform.xscale;
root_cliprect.y1 = root_yoffs + root_xform.yscale;
- sect_render_bounds(root_cliprect, m_bounds);
+ root_cliprect &= m_bounds;
// compute the container transform
object_transform container_xform;
@@ -2477,7 +2477,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
// allocate a primitive
render_primitive *prim = list.alloc(render_primitive::QUAD);
- set_render_bounds_wh(prim->bounds, xform.xoffs, xform.yoffs, xform.xscale, xform.yscale);
+ prim->bounds.set_wh(xform.xoffs, xform.yoffs, xform.xscale, xform.yscale);
prim->full_bounds = prim->bounds;
prim->color = container_xform.color;
width = render_round_nearest(prim->bounds.x1) - render_round_nearest(prim->bounds.x0);
@@ -2525,7 +2525,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob
// compute the bounds
s32 width = render_round_nearest(xform.xscale);
s32 height = render_round_nearest(xform.yscale);
- set_render_bounds_wh(prim->bounds, render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), (float) width, (float) height);
+ prim->bounds.set_wh(render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), float(width), float(height));
prim->full_bounds = prim->bounds;
if (xform.orientation & ORIENTATION_SWAP_XY)
std::swap(width, height);
@@ -2542,7 +2542,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob
cliprect.y0 = render_round_nearest(xform.yoffs);
cliprect.x1 = render_round_nearest(xform.xoffs + xform.xscale);
cliprect.y1 = render_round_nearest(xform.yoffs + xform.yscale);
- sect_render_bounds(cliprect, m_bounds);
+ cliprect &= m_bounds;
// determine UV coordinates and apply clipping
prim->texcoords = oriented_texcoords[xform.orientation];
@@ -2956,9 +2956,9 @@ void render_target::add_clear_extents(render_primitive_list &list)
if (x1 - x0 > 0)
{
render_primitive *prim = list.alloc(render_primitive::QUAD);
- set_render_bounds_xy(prim->bounds, (float)x0, (float)y0, (float)x1, (float)y1);
+ prim->bounds.set_xy(float(x0), float(y0), float(x1), float(y1));
prim->full_bounds = prim->bounds;
- set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim->color.set(1.0f, 0.0f, 0.0f, 0.0f);
prim->texture.base = nullptr;
prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
clearlist.append(*prim);
@@ -3012,7 +3012,7 @@ void render_target::add_clear_and_optimize_primitive_list(render_primitive_list
if (PRIMFLAG_GET_BLENDMODE(prim.flags) == BLENDMODE_RGB_MULTIPLY)
{
// RGB multiply will multiply against 0, leaving nothing
- set_render_color(&prim.color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim.color.set(1.0f, 0.0f, 0.0f, 0.0f);
prim.texture.base = nullptr;
prim.flags = (prim.flags & ~PRIMFLAG_BLENDMODE_MASK) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE);
}
diff --git a/src/emu/render.h b/src/emu/render.h
index 6a76e23eda4..c78fa8fb7d2 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -46,6 +46,7 @@
#ifndef MAME_EMU_RENDER_H
#define MAME_EMU_RENDER_H
+#include "rendertypes.h"
#include "screen.h"
#include <array>
@@ -65,17 +66,6 @@
// CONSTANTS
//**************************************************************************
-// blending modes
-enum
-{
- BLENDMODE_NONE = 0, // no blending
- BLENDMODE_ALPHA, // standard alpha blend
- BLENDMODE_RGB_MULTIPLY, // apply source alpha to source pix, then multiply RGB values
- BLENDMODE_ADD, // apply source alpha to source pix, then add to destination
-
- BLENDMODE_COUNT
-};
-
// render creation flags
constexpr u8 RENDER_CREATE_NO_ART = 0x01; // ignore any views that have art in them
@@ -166,62 +156,6 @@ constexpr u32 PRIMFLAG_GET_VECTORBUF(u32 x) { return (x & PRIMFLAG_VECTORBUF_MAS
// texture scaling callback
typedef void (*texture_scaler_func)(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param);
-// render_bounds - floating point bounding rectangle
-struct render_bounds
-{
- float x0; // leftmost X coordinate
- float y0; // topmost Y coordinate
- float x1; // rightmost X coordinate
- float y1; // bottommost Y coordinate
-
- constexpr float width() const { return x1 - x0; }
- constexpr float height() const { return y1 - y0; }
- constexpr float aspect() const { return width() / height(); }
- constexpr bool includes(float x, float y) const { return (x >= x0) && (x <= x1) && (y >= y0) && (y <= y1); }
-};
-
-
-// render_color - floating point set of ARGB values
-struct render_color
-{
- float a; // alpha component (0.0 = transparent, 1.0 = opaque)
- float r; // red component (0.0 = none, 1.0 = max)
- float g; // green component (0.0 = none, 1.0 = max)
- float b; // blue component (0.0 = none, 1.0 = max)
-
- constexpr render_color operator*(render_color const &c) const
- {
- return render_color{ a * c.a, r * c.r, g * c.g, b * c.b };
- }
-
- render_color &operator*=(render_color const &c)
- {
- a *= c.a;
- r *= c.r;
- g *= c.g;
- b *= c.b;
- return *this;
- }
-};
-
-
-// render_texuv - floating point set of UV texture coordinates
-struct render_texuv
-{
- float u; // U coordinate (0.0-1.0)
- float v; // V coordinate (0.0-1.0)
-};
-
-
-// render_quad_texuv - floating point set of UV texture coordinates
-struct render_quad_texuv
-{
- render_texuv tl; // top-left UV coordinate
- render_texuv tr; // top-right UV coordinate
- render_texuv bl; // bottom-left UV coordinate
- render_texuv br; // bottom-right UV coordinate
-};
-
// render_texinfo - texture information
struct render_texinfo
@@ -818,7 +752,7 @@ public:
// interactivity
bool has_input() const { return bool(m_input_port); }
- ioport_port *input_tag_and_mask(ioport_value &mask) const { mask = m_input_mask; return m_input_port; };
+ std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
bool clickthrough() const { return m_clickthrough; }
// fetch state based on configured source
@@ -831,13 +765,17 @@ public:
using bounds_vector = emu::render::detail::bounds_vector;
using color_vector = emu::render::detail::color_vector;
+ int animation_state() const;
+
static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
static bounds_vector make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
static color_vector make_color(view_environment &env, util::xml::data_node const &itemnode, render_color const &mult);
static std::string make_animoutput_tag(view_environment &env, util::xml::data_node const &itemnode);
+ static std::string make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode);
+ static ioport_value make_animmask(view_environment &env, util::xml::data_node const &itemnode);
static std::string make_input_tag(view_environment &env, util::xml::data_node const &itemnode);
static int get_blend_mode(view_environment &env, util::xml::data_node const &itemnode);
- static unsigned get_input_shift(ioport_value mask);
+ static unsigned get_state_shift(ioport_value mask);
// internal state
layout_element *const m_element; // pointer to the associated element (non-screens only)
@@ -845,6 +783,9 @@ public:
output_finder<> m_animoutput; // associated output for animation if different
bool const m_have_output; // whether we actually have an output
bool const m_have_animoutput; // whether we actually have an output for animation
+ ioport_port * m_animinput_port; // input port used for animation
+ ioport_value const m_animmask; // mask for animation state
+ u8 const m_animshift; // shift for animation state
ioport_port * m_input_port; // input port of this item
ioport_field const * m_input_field; // input port field of this item
ioport_value const m_input_mask; // input mask of this item
@@ -860,6 +801,7 @@ public:
// cold items
std::string const m_input_tag; // input tag of this item
+ std::string const m_animinput_tag; // tag of input port for animation state
bounds_vector const m_rawbounds; // raw (original) bounds of the item
bool const m_has_clickthrough; // whether clickthrough was explicitly configured
};
diff --git a/src/emu/rendertypes.h b/src/emu/rendertypes.h
new file mode 100644
index 00000000000..0fa698cc931
--- /dev/null
+++ b/src/emu/rendertypes.h
@@ -0,0 +1,153 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, Vas Crabb
+/***************************************************************************
+
+ render.h
+
+ Core renderer constants and structures for MAME.
+
+***************************************************************************/
+#ifndef MAME_EMU_RENDERTYPES_H
+#define MAME_EMU_RENDERTYPES_H
+
+#pragma once
+
+#include <algorithm>
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+
+// blending modes
+enum
+{
+ BLENDMODE_NONE = 0, // no blending
+ BLENDMODE_ALPHA, // standard alpha blend
+ BLENDMODE_RGB_MULTIPLY, // apply source alpha to source pix, then multiply RGB values
+ BLENDMODE_ADD, // apply source alpha to source pix, then add to destination
+
+ BLENDMODE_COUNT
+};
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// render_bounds - floating point bounding rectangle
+struct render_bounds
+{
+ float x0; // leftmost X coordinate
+ float y0; // topmost Y coordinate
+ float x1; // rightmost X coordinate
+ float y1; // bottommost Y coordinate
+
+ constexpr float width() const { return x1 - x0; }
+ constexpr float height() const { return y1 - y0; }
+ constexpr float aspect() const { return width() / height(); }
+ constexpr bool includes(float x, float y) const { return (x >= x0) && (x <= x1) && (y >= y0) && (y <= y1); }
+
+ // intersection
+ constexpr render_bounds operator&(render_bounds const &b) const
+ {
+ return render_bounds{ (std::max)(x0, b.x0), (std::max)(y0, b.y0), (std::min)(x1, b.x1), (std::min)(y1, b.y1) };
+ }
+
+ render_bounds &operator&=(render_bounds const &b)
+ {
+ x0 = (std::max)(x0, b.x0);
+ y0 = (std::max)(y0, b.y0);
+ x1 = (std::min)(x1, b.x1);
+ y1 = (std::min)(y1, b.y1);
+ return *this;
+ }
+
+ // union
+ constexpr render_bounds operator|(render_bounds const &b) const
+ {
+ return render_bounds{ (std::min)(x0, b.x0), (std::min)(y0, b.y0), (std::max)(x1, b.x1), (std::max)(y1, b.y1) };
+ }
+
+ render_bounds &operator|=(render_bounds const &b)
+ {
+ x0 = (std::min)(x0, b.x0);
+ y0 = (std::min)(y0, b.y0);
+ x1 = (std::max)(x1, b.x1);
+ y1 = (std::max)(y1, b.y1);
+ return *this;
+ }
+
+ render_bounds &set_xy(float left, float top, float right, float bottom)
+ {
+ x0 = left;
+ y0 = top;
+ x1 = right;
+ y1 = bottom;
+ return *this;
+ }
+
+ render_bounds &set_wh(float left, float top, float width, float height)
+ {
+ x0 = left;
+ y0 = top;
+ x1 = left + width;
+ y1 = top + height;
+ return *this;
+ }
+};
+
+
+// render_color - floating point set of ARGB values
+struct render_color
+{
+ float a; // alpha component (0.0 = transparent, 1.0 = opaque)
+ float r; // red component (0.0 = none, 1.0 = max)
+ float g; // green component (0.0 = none, 1.0 = max)
+ float b; // blue component (0.0 = none, 1.0 = max)
+
+ constexpr render_color operator*(render_color const &c) const
+ {
+ return render_color{ a * c.a, r * c.r, g * c.g, b * c.b };
+ }
+
+ render_color &operator*=(render_color const &c)
+ {
+ a *= c.a;
+ r *= c.r;
+ g *= c.g;
+ b *= c.b;
+ return *this;
+ }
+
+ render_color &set(float alpha, float red, float green, float blue)
+ {
+ a = alpha;
+ r = red;
+ g = green;
+ b = blue;
+ return *this;
+ }
+};
+
+
+// render_texuv - floating point set of UV texture coordinates
+struct render_texuv
+{
+ float u; // U coordinate (0.0-1.0)
+ float v; // V coordinate (0.0-1.0)
+};
+
+
+// render_quad_texuv - floating point set of UV texture coordinates
+struct render_quad_texuv
+{
+ render_texuv tl; // top-left UV coordinate
+ render_texuv tr; // top-right UV coordinate
+ render_texuv bl; // bottom-left UV coordinate
+ render_texuv br; // bottom-right UV coordinate
+};
+
+#endif // MAME_EMU_RENDERTYPES_H
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index 940923ae0e1..2f57c7ade1d 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -17,6 +17,7 @@
#include "rendutil.h"
#include "video/rgbutil.h"
+#include "nanosvg.h"
#include "vecstream.h"
#include "xmlfile.h"
@@ -27,6 +28,7 @@
#include <cstdio>
#include <cstring>
#include <iomanip>
+#include <limits>
#include <locale>
#include <sstream>
#include <stdexcept>
@@ -578,25 +580,29 @@ private:
entry_vector m_entries;
util::ovectorstream m_buffer;
+ std::shared_ptr<NSVGrasterizer> const m_svg_rasterizer;
device_t &m_device;
layout_environment *const m_next = nullptr;
bool m_cached = false;
public:
explicit layout_environment(device_t &device)
- : m_device(device)
+ : m_svg_rasterizer(nsvgCreateRasterizer(), util::nsvg_deleter())
+ , m_device(device)
{
}
explicit layout_environment(layout_environment &next)
- : m_device(next.m_device)
+ : m_svg_rasterizer(next.m_svg_rasterizer)
+ , m_device(next.m_device)
, m_next(&next)
{
}
layout_environment(layout_environment const &) = delete;
- device_t &device() { return m_device; }
- running_machine &machine() { return device().machine(); }
- bool is_root_device() { return &device() == &machine().root_device(); }
+ device_t &device() const { return m_device; }
+ running_machine &machine() const { return device().machine(); }
+ bool is_root_device() const { return &device() == &machine().root_device(); }
+ std::shared_ptr<NSVGrasterizer> const &svg_rasterizer() const { return m_svg_rasterizer; }
void set_parameter(std::string &&name, std::string &&value)
{
@@ -785,34 +791,44 @@ public:
void parse_bounds(util::xml::data_node const *node, render_bounds &result)
{
- // default to unit rectangle
if (!node)
{
+ // default to unit rectangle
result.x0 = result.y0 = 0.0F;
result.x1 = result.y1 = 1.0F;
}
else
{
- // parse attributes
+ // horizontal position/size
if (node->has_attribute("left"))
{
- // left/right/top/bottom format
result.x0 = get_attribute_float(*node, "left", 0.0F);
result.x1 = get_attribute_float(*node, "right", 1.0F);
- result.y0 = get_attribute_float(*node, "top", 0.0F);
- result.y1 = get_attribute_float(*node, "bottom", 1.0F);
}
- else if (node->has_attribute("x"))
+ else
{
- // x/y/width/height format
- result.x0 = get_attribute_float(*node, "x", 0.0F);
- result.x1 = result.x0 + get_attribute_float(*node, "width", 1.0F);
- result.y0 = get_attribute_float(*node, "y", 0.0F);
- result.y1 = result.y0 + get_attribute_float(*node, "height", 1.0F);
+ float const width = get_attribute_float(*node, "width", 1.0F);
+ if (node->has_attribute("xc"))
+ result.x0 = get_attribute_float(*node, "xc", 0.0F) - (width / 2.0F);
+ else
+ result.x0 = get_attribute_float(*node, "x", 0.0F);
+ result.x1 = result.x0 + width;
+ }
+
+ // vertical position/size
+ if (node->has_attribute("top"))
+ {
+ result.y0 = get_attribute_float(*node, "top", 0.0F);
+ result.y1 = get_attribute_float(*node, "bottom", 1.0F);
}
else
{
- throw layout_syntax_error("bounds element requires either left or x attribute");
+ float const height = get_attribute_float(*node, "height", 1.0F);
+ if (node->has_attribute("yc"))
+ result.y0 = get_attribute_float(*node, "yc", 0.0F) - (height / 2.0F);
+ else
+ result.y0 = get_attribute_float(*node, "y", 0.0F);
+ result.y1 = result.y0 + height;
}
// check for errors
@@ -978,7 +994,7 @@ render_bounds accumulate_bounds(emu::render::detail::bounds_vector const &steps)
auto i(steps.begin());
render_bounds result(i->bounds);
while (steps.end() != ++i)
- union_render_bounds(result, i->bounds);
+ result |= i->bounds;
return result;
}
@@ -1123,7 +1139,7 @@ layout_element::layout_element(environment &env, util::xml::data_node const &ele
if (first)
bounds = newcomp.overall_bounds();
else
- union_render_bounds(bounds, newcomp.overall_bounds());
+ bounds |= newcomp.overall_bounds();
first = false;
// determine the maximum state
@@ -1286,7 +1302,7 @@ void layout_group::resolve_bounds(environment &env, group_map &groupmap, std::ve
seen.push_back(this);
if (!m_bounds_resolved)
{
- set_render_bounds_xy(m_bounds, 0.0F, 0.0F, 1.0F, 1.0F);
+ m_bounds.set_xy(0.0F, 0.0F, 1.0F, 1.0F);
environment local(env);
bool empty(true);
resolve_bounds(local, m_groupnode, groupmap, seen, empty, false, false, true);
@@ -1349,13 +1365,13 @@ void layout_group::resolve_bounds(
{
render_bounds b;
env.parse_bounds(boundsnode, b);
- union_render_bounds(itembounds, b);
+ itembounds |= b;
}
}
if (empty)
m_bounds = itembounds;
else
- union_render_bounds(m_bounds, itembounds);
+ m_bounds |= itembounds;
empty = false;
LOGMASKED(LOG_GROUP_BOUNDS_RESOLUTION, "Accumulate item bounds (%s %s %s %s) -> (%s %s %s %s)\n",
itembounds.x0, itembounds.y0, itembounds.x1, itembounds.y1,
@@ -1371,7 +1387,7 @@ void layout_group::resolve_bounds(
if (empty)
m_bounds = itembounds;
else
- union_render_bounds(m_bounds, itembounds);
+ m_bounds |= itembounds;
empty = false;
LOGMASKED(LOG_GROUP_BOUNDS_RESOLUTION, "Accumulate group '%s' reference explicit bounds (%s %s %s %s) -> (%s %s %s %s)\n",
itemnode->get_attribute_string("ref", ""),
@@ -1399,7 +1415,7 @@ void layout_group::resolve_bounds(
if (empty)
m_bounds = itembounds;
else
- union_render_bounds(m_bounds, itembounds);
+ m_bounds |= itembounds;
empty = false;
unresolved = false;
LOGMASKED(LOG_GROUP_BOUNDS_RESOLUTION, "Accumulate group '%s' reference computed bounds (%s %s %s %s) -> (%s %s %s %s)\n",
@@ -1523,11 +1539,13 @@ class layout_element::image_component : public component
{
public:
// construction/destruction
- image_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
+ image_component(environment &env, util::xml::data_node const &compnode, char const *dirname)
: component(env, compnode, dirname)
+ , m_rasterizer(env.svg_rasterizer())
, m_dirname(dirname ? dirname : "")
, m_imagefile(env.get_attribute_string(compnode, "file", ""))
, m_alphafile(env.get_attribute_string(compnode, "alphafile", ""))
+ , m_data(get_data(compnode))
{
}
@@ -1535,97 +1553,204 @@ public:
virtual void preload(running_machine &machine) override
{
if (!m_bitmap.valid())
- load_bitmap(machine);
+ load_image(machine);
}
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw(running_machine &machine, bitmap_argb32 &dest, rectangle const &bounds, int state) override
{
- if (!m_bitmap.valid())
- load_bitmap(machine);
+ if (!m_bitmap.valid() && !m_svg)
+ load_image(machine);
+
+ if (m_bitmap.valid())
+ draw_bitmap(dest, bounds, state);
+ else if (m_svg)
+ draw_svg(dest, bounds, state);
+ }
+private:
+ // internal helpers
+ void draw_bitmap(bitmap_argb32 &dest, rectangle const &bounds, int state)
+ {
render_color const c(color(state));
if (m_hasalpha || (1.0F > c.a))
{
bitmap_argb32 tempbitmap(dest.width(), dest.height());
render_resample_argb_bitmap_hq(tempbitmap, m_bitmap, c);
- for (s32 y0 = 0, y1 = bounds.top(); bounds.bottom() >= y1; ++y0, ++y1)
+ alpha_blend(tempbitmap, dest, bounds);
+ }
+ else
+ {
+ bitmap_argb32 destsub(dest, bounds);
+ render_resample_argb_bitmap_hq(destsub, m_bitmap, c);
+ }
+ }
+
+ void draw_svg(bitmap_argb32 &dest, rectangle const &bounds, int state)
+ {
+ // rasterise into a temporary bitmap
+ float const xscale(bounds.width() / m_svg->width);
+ float const yscale(bounds.height() / m_svg->height);
+ float const drawscale((std::max)(xscale, yscale));
+ bitmap_argb32 tempbitmap(int(m_svg->width * drawscale), int(m_svg->height * drawscale));
+ nsvgRasterize(
+ m_rasterizer.get(),
+ m_svg.get(),
+ 0, 0, drawscale,
+ reinterpret_cast<unsigned char *>(&tempbitmap.pix(0)),
+ tempbitmap.width(), tempbitmap.height(),
+ tempbitmap.rowbytes());
+
+ // correct colour format and multiply by state colour
+ bool havealpha(false);
+ render_color const c(color(state));
+ for (s32 y = 0; tempbitmap.height() > y; ++y)
+ {
+ u32 *dst(&tempbitmap.pix(y));
+ for (s32 x = 0; tempbitmap.width() > x; ++x, ++dst)
+ {
+ u8 const *const src(reinterpret_cast<u8 const *>(dst));
+ rgb_t const d(
+ u8((float(src[3]) * c.a) + 0.5),
+ u8((float(src[0]) * c.r) + 0.5),
+ u8((float(src[1]) * c.g) + 0.5),
+ u8((float(src[2]) * c.b) + 0.5));
+ *dst = d;
+ havealpha = havealpha || (d.a() < 255U);
+ }
+ }
+
+ // find most efficient way to insert it in the target bitmap
+ if (!havealpha)
+ {
+ if ((tempbitmap.width() == bounds.width()) && (tempbitmap.height() == bounds.height()))
+ {
+ for (s32 y = 0; tempbitmap.height() > y; ++y)
+ std::copy_n(&tempbitmap.pix(y), bounds.width(), &dest.pix(y + bounds.top(), bounds.left()));
+ }
+ else
{
- u32 const *src(&tempbitmap.pix(y0, 0));
- u32 *dst(&dest.pix(y1, bounds.left()));
- for (s32 x1 = bounds.left(); bounds.right() >= x1; ++x1, ++src, ++dst)
+ bitmap_argb32 destsub(dest, bounds);
+ render_resample_argb_bitmap_hq(destsub, tempbitmap, render_color{ 1.0F, 1.0F, 1.0F, 1.0F });
+ }
+ }
+ else if ((tempbitmap.width() == bounds.width()) && (tempbitmap.height() == bounds.height()))
+ {
+ alpha_blend(tempbitmap, dest, bounds);
+ }
+ else
+ {
+ bitmap_argb32 scaled(bounds.width(), bounds.height());
+ render_resample_argb_bitmap_hq(scaled, tempbitmap, render_color{ 1.0F, 1.0F, 1.0F, 1.0F });
+ tempbitmap.reset();
+ alpha_blend(scaled, dest, bounds);
+ }
+ }
+
+ void alpha_blend(bitmap_argb32 const &srcbitmap, bitmap_argb32 &dstbitmap, rectangle const &bounds)
+ {
+ for (s32 y0 = 0, y1 = bounds.top(); bounds.bottom() >= y1; ++y0, ++y1)
+ {
+ u32 const *src(&srcbitmap.pix(y0, 0));
+ u32 *dst(&dstbitmap.pix(y1, bounds.left()));
+ for (s32 x1 = bounds.left(); bounds.right() >= x1; ++x1, ++src, ++dst)
+ {
+ rgb_t const a(*src);
+ u32 const aa(a.a());
+ if (255 == aa)
+ {
+ *dst = *src;
+ }
+ else if (aa)
{
- rgb_t const a(*src);
- u32 const aa(a.a());
- if (255 == aa)
+ rgb_t const b(*dst);
+ u32 const ba(b.a());
+ if (ba)
{
- *dst = *src;
+ u32 const ca((aa * 255) + (ba * (255 - aa)));
+ *dst = rgb_t(
+ u8(ca / 255),
+ u8(((a.r() * aa * 255) + (b.r() * ba * (255 - aa))) / ca),
+ u8(((a.g() * aa * 255) + (b.g() * ba * (255 - aa))) / ca),
+ u8(((a.b() * aa * 255) + (b.b() * ba * (255 - aa))) / ca));
}
- else if (aa)
+ else
{
- rgb_t const b(*dst);
- u32 const ba(b.a());
- if (ba)
- {
- u32 const ca((aa * 255) + (ba * (255 - aa)));
- *dst = rgb_t(
- u8(ca / 255),
- u8(((a.r() * aa * 255) + (b.r() * ba * (255 - aa))) / ca),
- u8(((a.g() * aa * 255) + (b.g() * ba * (255 - aa))) / ca),
- u8(((a.b() * aa * 255) + (b.b() * ba * (255 - aa))) / ca));
- }
- else
- {
- *dst = *src;
- }
+ *dst = *src;
}
}
}
}
- else
- {
- bitmap_argb32 destsub(dest, bounds);
- render_resample_argb_bitmap_hq(destsub, m_bitmap, c);
- }
}
-private:
- // internal helpers
- void load_bitmap(running_machine &machine)
+ void load_image(running_machine &machine)
{
- LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load image file '%s/%s'\n", m_dirname, m_imagefile);
+ // 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);
emu_file file(machine.options().art_path(), OPEN_FLAG_READ);
-
- ru_imgformat const format = render_detect_image(file, m_dirname.c_str(), m_imagefile.c_str());
- switch (format)
+ 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:
- // load the basic bitmap
- LOGMASKED(LOG_IMAGE_LOAD, "Image component detected PNG file format\n");
- m_hasalpha = render_load_png(m_bitmap, file, m_dirname.c_str(), m_imagefile.c_str());
- break;
-
- default:
- // try JPG
- LOGMASKED(LOG_IMAGE_LOAD, "Image component failed to detect image file format, trying JPEG\n");
- render_load_jpeg(m_bitmap, file, m_dirname.c_str(), m_imagefile.c_str());
- break;
+ 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");
+ 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;
+ }
+ 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 the alpha bitmap if specified
- if (m_bitmap.valid() && !m_alphafile.empty())
+ if (!m_alphafile.empty())
{
- // TODO: no way to detect corner case where we had alpha from the image but the alpha PNG makes it entirely opaque
- LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load alpha channel from file '%s/%s'\n", m_dirname, m_alphafile);
- if (render_load_png(m_bitmap, file, m_dirname.c_str(), m_alphafile.c_str(), true))
- m_hasalpha = true;
+ 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));
+ 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
+ if (render_load_png(m_bitmap, file, true))
+ m_hasalpha = true;
+ file.close();
+ }
+ else
+ {
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open alpha channel file '%s%s%s'\n", m_dirname, PATH_SEPARATOR, m_alphafile);
+ }
+ }
+ else if (m_svg)
+ {
+ osd_printf_warning("Component alpha channel file '%s' ignored for SVG image '%s'\n", m_alphafile, m_imagefile);
+ }
}
- // if we can't load the bitmap, allocate a dummy one and report an error
- if (!m_bitmap.valid())
+ // if we can't load an image, allocate a dummy one and report an error
+ if (!m_bitmap.valid() && !m_svg)
{
// draw some stripes in the bitmap
m_bitmap.allocate(100, 100);
@@ -1636,18 +1761,87 @@ private:
// log an error
if (m_alphafile.empty())
- osd_printf_warning("Unable to load component bitmap '%s'\n", m_imagefile);
+ osd_printf_warning("Unable to load component image '%s'\n", m_imagefile);
else
- osd_printf_warning("Unable to load component bitmap '%s'/'%s'\n", m_imagefile, m_alphafile);
+ osd_printf_warning("Unable to load component image '%s'/'%s'\n", m_imagefile, m_alphafile);
+ }
+
+ // clear out this stuff in case it's large
+ if (!m_svg)
+ m_rasterizer.reset();
+ m_dirname.clear();
+ m_imagefile.clear();
+ m_alphafile.clear();
+ m_data.clear();
+ }
+
+ void load_svg(util::core_file &file)
+ {
+ if (!m_rasterizer)
+ {
+ osd_printf_warning("No SVG rasteriser available, won't attempt to parse component image '%s' as SVG\n", m_imagefile);
+ return;
+ }
+ u64 len(file.size());
+ if ((std::numeric_limits<size_t>::max() - 1) < len)
+ {
+ osd_printf_warning("Component image '%s' is too large to read into memory\n", m_imagefile);
+ return;
+ }
+ std::unique_ptr<char []> svgbuf(new (std::nothrow) char [size_t(len) + 1]);
+ if (!svgbuf)
+ {
+ osd_printf_warning("Error allocating memory to read component image '%s'\n", m_imagefile);
+ return;
+ }
+ svgbuf[len] = '\0';
+ for (char *ptr = svgbuf.get(); len; )
+ {
+ u32 const block(u32(std::min<u64>(std::numeric_limits<u32>::max(), len)));
+ u32 const read(file.read(ptr, block));
+ if (!read)
+ {
+ osd_printf_warning("Error reading component image '%s'\n", m_imagefile);
+ return;
+ }
+ ptr += read;
+ len -= read;
+ }
+ m_svg.reset(nsvgParse(svgbuf.get(), "px", 72));
+ svgbuf.reset();
+ if (!m_svg)
+ {
+ osd_printf_warning("Failed to parse component image '%s' as SVG\n", m_imagefile);
+ return;
+ }
+ if ((0.0F >= m_svg->width) || (0.0F >= m_svg->height))
+ {
+ osd_printf_warning("Parsing component image '%s' as SVG produced empty image\n", m_imagefile);
+ m_svg.reset();
+ return;
}
}
+ static std::string get_data(util::xml::data_node const &compnode)
+ {
+ util::xml::data_node const *datanode(compnode.get_child("data"));
+ if (datanode && datanode->get_value())
+ return datanode->get_value();
+ else
+ return "";
+ }
+
// internal state
- bitmap_argb32 m_bitmap; // source bitmap for images
- std::string const m_dirname; // directory name of image file (for lazy loading)
- std::string const m_imagefile; // name of the image file (for lazy loading)
- std::string const m_alphafile; // name of the alpha file (for lazy loading)
- bool m_hasalpha = false; // is there any alpha component present?
+ util::nsvg_image_ptr m_svg; // parsed SVG image
+ std::shared_ptr<NSVGrasterizer> m_rasterizer; // SVG rasteriser
+ bitmap_argb32 m_bitmap; // source bitmap for images
+ bool m_hasalpha = false; // is there any alpha component present?
+
+ // cold state
+ 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)
+ std::string m_data; // embedded image data
};
@@ -2881,7 +3075,11 @@ private:
{
// load the basic bitmap
assert(m_file != nullptr);
- /*m_hasalpha[number] = */ render_load_png(m_bitmap[number], *m_file[number], m_dirname.c_str(), m_imagefile[number].c_str());
+ 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();
+ }
// load the alpha bitmap if specified
//if (m_bitmap[number].valid() && m_alphafile[number])
@@ -3593,7 +3791,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
if (first)
m_bounds = rawbounds;
else
- union_render_bounds(m_bounds, rawbounds);
+ m_bounds |= rawbounds;
first = false;
// accumulate visible screens and their bounds bounds
@@ -3602,7 +3800,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
if (scrfirst)
scrbounds = rawbounds;
else
- union_render_bounds(scrbounds, rawbounds);
+ scrbounds |= rawbounds;
scrfirst = false;
// accumulate active screens
@@ -3912,10 +4110,13 @@ layout_view::item::item(
, m_animoutput(env.device(), make_animoutput_tag(env, itemnode))
, m_have_output(env.get_attribute_string(itemnode, "name", "")[0])
, m_have_animoutput(!make_animoutput_tag(env, itemnode).empty())
+ , m_animinput_port(nullptr)
+ , m_animmask(make_animmask(env, itemnode))
+ , m_animshift(get_state_shift(m_animmask))
, m_input_port(nullptr)
, m_input_field(nullptr)
, m_input_mask(env.get_attribute_int(itemnode, "inputmask", 0))
- , m_input_shift(get_input_shift(m_input_mask))
+ , m_input_shift(get_state_shift(m_input_mask))
, m_input_raw(env.get_attribute_bool(itemnode, "inputraw", 0))
, m_clickthrough(env.get_attribute_bool(itemnode, "clickthrough", "yes"))
, m_screen(nullptr)
@@ -3924,6 +4125,7 @@ layout_view::item::item(
, m_blend_mode(get_blend_mode(env, itemnode))
, m_visibility_mask(env.visibility_mask())
, m_input_tag(make_input_tag(env, itemnode))
+ , m_animinput_tag(make_animinput_tag(env, itemnode))
, m_rawbounds(make_bounds(env, itemnode, trans))
, m_has_clickthrough(env.get_attribute_string(itemnode, "clickthrough", "")[0])
{
@@ -3972,7 +4174,7 @@ render_bounds layout_view::item::bounds() const
if (m_bounds.size() == 1U)
return m_bounds.front().bounds;
else
- return interpolate_bounds(m_bounds, m_have_animoutput ? s32(m_animoutput) : state());
+ return interpolate_bounds(m_bounds, animation_state());
}
@@ -3985,7 +4187,7 @@ render_color layout_view::item::color() const
if (m_color.size() == 1U)
return m_color.front().color;
else
- return interpolate_color(m_color, m_have_animoutput ? s32(m_animoutput) : state());
+ return interpolate_color(m_color, animation_state());
}
@@ -4038,6 +4240,9 @@ void layout_view::item::resolve_tags()
if (m_have_animoutput)
m_animoutput.resolve();
+ if (!m_animinput_tag.empty())
+ m_animinput_port = m_element->machine().root_device().ioport(m_animinput_tag);
+
if (!m_input_tag.empty())
{
m_input_port = m_element->machine().root_device().ioport(m_input_tag);
@@ -4066,6 +4271,21 @@ void layout_view::item::resolve_tags()
// find_element - find element definition
//---------------------------------------------
+inline int layout_view::item::animation_state() const
+{
+ if (m_have_animoutput)
+ return (s32(m_animoutput) & m_animmask) >> m_animshift;
+ else if (m_animinput_port)
+ return (m_animinput_port->read() & m_animmask) >> m_animshift;
+ else
+ return state();
+}
+
+
+//---------------------------------------------
+// find_element - find element definition
+//---------------------------------------------
+
layout_element *layout_view::item::find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
{
char const *const name(env.get_attribute_string(itemnode, !strcmp(itemnode.get_name(), "element") ? "ref" : "element", nullptr));
@@ -4157,6 +4377,30 @@ std::string layout_view::item::make_animoutput_tag(view_environment &env, util::
//---------------------------------------------
+// make_animmask - get animation state mask
+//---------------------------------------------
+
+ioport_value layout_view::item::make_animmask(view_environment &env, util::xml::data_node const &itemnode)
+{
+ util::xml::data_node const *const animate(itemnode.get_child("animate"));
+ return animate ? env.get_attribute_int(*animate, "mask", ~ioport_value(0)) : ~ioport_value(0);
+}
+
+
+//---------------------------------------------
+// make_animinput_tag - get absolute tag for
+// animation input
+//---------------------------------------------
+
+std::string layout_view::item::make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode)
+{
+ util::xml::data_node const *const animate(itemnode.get_child("animate"));
+ char const *tag(animate ? env.get_attribute_string(*animate, "inputtag", nullptr) : nullptr);
+ return tag ? env.device().subtag(tag) : std::string();
+}
+
+
+//---------------------------------------------
// make_input_tag - get absolute input tag
//---------------------------------------------
@@ -4200,10 +4444,10 @@ int layout_view::item::get_blend_mode(view_environment &env, util::xml::data_nod
//---------------------------------------------
-// get_input_shift - shift to right-align LSB
+// get_state_shift - shift to right-align LSB
//---------------------------------------------
-unsigned layout_view::item::get_input_shift(ioport_value mask)
+unsigned layout_view::item::get_state_shift(ioport_value mask)
{
unsigned result(0U);
while (mask && !BIT(mask, 0))
diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp
index 18755ffb340..c66492a8895 100644
--- a/src/emu/rendutil.cpp
+++ b/src/emu/rendutil.cpp
@@ -11,9 +11,109 @@
#include "emu.h"
#include "rendutil.h"
+#include "msdib.h"
#include "png.h"
#include "jpeglib.h"
+#include "jerror.h"
+
+
+namespace {
+
+struct jpeg_corefile_source : public jpeg_source_mgr
+{
+ static void source(j_decompress_ptr cinfo, util::core_file &file);
+
+private:
+ static constexpr unsigned INPUT_BUF_SIZE = 4096;
+
+ static void do_init(j_decompress_ptr cinfo)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+ src.start_of_file = true;
+ }
+
+ static boolean do_fill(j_decompress_ptr cinfo)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+
+ size_t nbytes = src.infile->read(src.buffer, INPUT_BUF_SIZE);
+
+ if (0 >= nbytes)
+ {
+ if (src.start_of_file)
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ src.buffer[0] = JOCTET(0xff);
+ src.buffer[1] = JOCTET(JPEG_EOI);
+ nbytes = 2;
+ }
+
+ src.next_input_byte = src.buffer;
+ src.bytes_in_buffer = nbytes;
+ src.start_of_file = false;
+
+ return TRUE;
+ }
+
+ static void do_skip(j_decompress_ptr cinfo, long num_bytes)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+
+ if (0 < num_bytes)
+ {
+ while (long(src.bytes_in_buffer) < num_bytes)
+ {
+ num_bytes -= long(src.bytes_in_buffer);
+ (void)(*src.fill_input_buffer)(cinfo);
+ }
+ src.next_input_byte += size_t(num_bytes);
+ src.bytes_in_buffer -= size_t(num_bytes);
+ }
+ }
+
+ static void do_term(j_decompress_ptr cinfo)
+ {
+ }
+
+ util::core_file *infile;
+ JOCTET *buffer;
+ bool start_of_file;
+};
+
+void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::core_file &file)
+{
+ jpeg_corefile_source *src;
+ if (!cinfo->src)
+ {
+ src = reinterpret_cast<jpeg_corefile_source *>(
+ (*cinfo->mem->alloc_small)(
+ reinterpret_cast<j_common_ptr>(cinfo),
+ JPOOL_PERMANENT,
+ sizeof(jpeg_corefile_source)));
+ cinfo->src = src;
+ src->buffer = reinterpret_cast<JOCTET *>(
+ (*cinfo->mem->alloc_small)(
+ reinterpret_cast<j_common_ptr>(cinfo),
+ JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * sizeof(JOCTET)));
+ }
+ else
+ {
+ src = static_cast<jpeg_corefile_source *>(cinfo->src);
+ }
+
+ src->init_source = &jpeg_corefile_source::do_init;
+ src->fill_input_buffer = &jpeg_corefile_source::do_fill;
+ src->skip_input_data = &jpeg_corefile_source::do_skip;
+ src->resync_to_restart = jpeg_resync_to_restart;
+ src->term_source = &jpeg_corefile_source::do_term;
+ src->infile = &file;
+ src->bytes_in_buffer = 0;
+ src->next_input_byte = nullptr;
+}
+
+} // anonymous namespace
/***************************************************************************
@@ -23,7 +123,7 @@
/* utilities */
static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy);
static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy);
-static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png);
+static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png);
@@ -543,81 +643,103 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_
/*-------------------------------------------------
- render_load_jpeg - load a JPG file into a
- bitmap
+ render_load_msdib - load a Microsoft DIB file
+ into a bitmap
-------------------------------------------------*/
-void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename)
+void render_load_msdib(bitmap_argb32 &bitmap, util::core_file &file)
{
// deallocate previous bitmap
bitmap.reset();
- // define file's full name
- std::string fname;
+ // read the DIB data
+ util::msdib_error const result = util::msdib_read_bitmap(file, bitmap);
+ if (result != util::msdib_error::NONE)
+ {
+ osd_printf_error("Error reading Microsoft DIB file\n");
+ bitmap.reset();
+ }
+}
- if (dirname == nullptr)
- fname = filename;
- else
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- if (file.open(fname) != osd_file::error::NONE)
- return;
+/*-------------------------------------------------
+ render_load_jpeg - load a JPEG file into a
+ bitmap
+-------------------------------------------------*/
+
+void render_load_jpeg(bitmap_argb32 &bitmap, util::core_file &file)
+{
+ // deallocate previous bitmap
+ bitmap.reset();
- // define standard JPEG structures
+ // create a JPEG source for the file
jpeg_decompress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);
-
- // allocates a buffer for the image
- u32 jpg_size = file.size();
- std::unique_ptr<unsigned char[]> jpg_buffer = std::make_unique<unsigned char[]>(jpg_size);
-
- // read data from the file and set them in the buffer
- file.read(jpg_buffer.get(), jpg_size);
- jpeg_mem_src(&cinfo, jpg_buffer.get(), jpg_size);
-
- // read JPEG header and start decompression
- jpeg_read_header(&cinfo, TRUE);
- jpeg_start_decompress(&cinfo);
-
- // allocates the destination bitmap
- int w = cinfo.output_width;
- int h = cinfo.output_height;
- int s = cinfo.output_components;
- bitmap.allocate(w, h);
-
- // allocates a buffer to receive the information and copy them into the bitmap
- int row_stride = cinfo.output_width * cinfo.output_components;
- JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
- buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);
-
- while ( cinfo.output_scanline < cinfo.output_height )
+ jerr.error_exit = [] (j_common_ptr cinfo) { throw cinfo->err; };
+ JSAMPARRAY buffer = nullptr;
+ try
{
- int j = cinfo.output_scanline;
- jpeg_read_scanlines(&cinfo, buffer, 1);
+ jpeg_create_decompress(&cinfo);
+ cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
+ jpeg_corefile_source::source(&cinfo, file);
+
+ // read JPEG header and start decompression
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ // allocates the destination bitmap
+ int w = cinfo.output_width;
+ int h = cinfo.output_height;
+ int s = cinfo.output_components;
+ bitmap.allocate(w, h);
+
+ // allocates a buffer to receive the information and copy them into the bitmap
+ int row_stride = cinfo.output_width * cinfo.output_components;
+ JSAMPARRAY buffer = reinterpret_cast<JSAMPARRAY>(malloc(sizeof(JSAMPROW)));
+ buffer[0] = reinterpret_cast<JSAMPROW>(malloc(sizeof(JSAMPLE) * row_stride));
+
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ int j = cinfo.output_scanline;
+ jpeg_read_scanlines(&cinfo, buffer, 1);
- if (s == 1)
- for (int i = 0; i < w; ++i)
- bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
+ if (s == 1)
+ {
+ for (int i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
- else if (s == 3)
- for (int i = 0; i < w; ++i)
- bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
- else
- {
- osd_printf_error("Cannot read JPEG data from %s file.\n", fname);
- bitmap.reset();
- break;
+ }
+ else if (s == 3)
+ {
+ for (int i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
+ }
+ else
+ {
+ osd_printf_error("Cannot read JPEG data from file.\n");
+ bitmap.reset();
+ break;
+ }
}
- }
- // finish decompression and frees the memory
- jpeg_finish_decompress(&cinfo);
+ // finish decompression and frees the memory
+ jpeg_finish_decompress(&cinfo);
+ }
+ catch (jpeg_error_mgr *err)
+ {
+ char msg[1024];
+ (cinfo.err->format_message)(reinterpret_cast<j_common_ptr>(&cinfo), msg);
+ osd_printf_error("JPEG error reading data from file: %s\n", msg);
+ bitmap.reset();
+ }
jpeg_destroy_decompress(&cinfo);
- file.close();
- free(buffer[0]);
- free(buffer);
+ if (buffer)
+ {
+ if (buffer[0])
+ free(buffer[0]);
+ free(buffer);
+ }
}
@@ -626,36 +748,25 @@ void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname
bitmap
-------------------------------------------------*/
-bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename, bool load_as_alpha_to_existing)
+bool render_load_png(bitmap_argb32 &bitmap, util::core_file &file, bool load_as_alpha_to_existing)
{
// deallocate if we're not overlaying alpha
if (!load_as_alpha_to_existing)
bitmap.reset();
- // open the file
- std::string fname;
- if (dirname)
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- else
- fname.assign(filename);
- osd_file::error const filerr = file.open(fname);
- if (filerr != osd_file::error::NONE)
- return false;
-
// read the PNG data
- png_info png;
- png_error const result = png.read_file(file);
- file.close();
- if (result != PNGERR_NONE)
+ util::png_info png;
+ util::png_error const result = png.read_file(file);
+ if (result != util::png_error::NONE)
{
- osd_printf_error("%s: Error reading PNG file\n", filename);
+ osd_printf_error("Error reading PNG file\n");
return false;
}
// if less than 8 bits, upsample
- if (PNGERR_NONE != png.expand_buffer_8bit())
+ if (util::png_error::NONE != png.expand_buffer_8bit())
{
- osd_printf_error("%s: Error upsampling PNG bitmap\n", filename);
+ osd_printf_error("Error upsampling PNG bitmap\n");
return false;
}
@@ -663,9 +774,9 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
if (!load_as_alpha_to_existing)
{
// non-alpha case
- if (PNGERR_NONE != png.copy_to_bitmap(bitmap, hasalpha))
+ if (util::png_error::NONE != png.copy_to_bitmap(bitmap, hasalpha))
{
- osd_printf_error("%s: Error copying PNG bitmap to MAME bitmap\n", filename);
+ osd_printf_error("Error copying PNG bitmap to MAME bitmap\n");
return false;
}
}
@@ -674,7 +785,7 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
// verify we can handle this PNG
if (png.bit_depth > 8)
{
- osd_printf_error("%s: Unsupported bit depth %d (8 bit max)\n", filename, png.bit_depth);
+ osd_printf_error("Unsupported bit depth %d (8 bit max)\n", png.bit_depth);
return false;
}
@@ -692,7 +803,7 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
to the alpha channel of a bitmap
-------------------------------------------------*/
-static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
+static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png)
{
// FIXME: this function is basically copy/pasted from the PNG code in util, and should be unified with it
u8 accumalpha = 0xff;
@@ -803,29 +914,41 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
render_detect_image - detect image format
-------------------------------------------------*/
-ru_imgformat render_detect_image(emu_file &file, const char *dirname, const char *filename)
+ru_imgformat render_detect_image(util::core_file &file)
{
- // open the file
- std::string fname;
- if (dirname)
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- else
- fname.assign(filename);
- osd_file::error const filerr = file.open(fname);
- if (filerr != osd_file::error::NONE)
- return RENDUTIL_IMGFORMAT_ERROR;
-
// PNG: check for valid header
- png_error const result = png_info::verify_header(file);
- if (result == PNGERR_NONE)
- {
- file.close();
+ util::png_error const png = util::png_info::verify_header(file);
+ file.seek(0, SEEK_SET);
+ if (util::png_error::NONE == png)
return RENDUTIL_IMGFORMAT_PNG;
- }
+ // JPEG: attempt to read header with libjpeg
+ jpeg_decompress_struct cinfo;
+ jpeg_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr);
+ jerr.error_exit = [] (j_common_ptr cinfo) { throw cinfo->err; };
+ try
+ {
+ jpeg_create_decompress(&cinfo);
+ cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
+ jpeg_corefile_source::source(&cinfo, file);
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_destroy_decompress(&cinfo);
+ file.seek(0, SEEK_SET);
+ return RENDUTIL_IMGFORMAT_JPEG;
+ }
+ catch (jpeg_error_mgr *err)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ file.seek(0, SEEK_SET);
+ }
+
+ // Microsoft DIB: check for valid header
+ util::msdib_error const msdib = util::msdib_verify_header(file);
file.seek(0, SEEK_SET);
- // TODO: add more when needed
+ if (util::msdib_error::NONE == msdib)
+ return RENDUTIL_IMGFORMAT_MSDIB;
- file.close();
+ // TODO: add more as necessary
return RENDUTIL_IMGFORMAT_UNKNOWN;
}
diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h
index b5c06d6d0fc..c5cdd7d2c4c 100644
--- a/src/emu/rendutil.h
+++ b/src/emu/rendutil.h
@@ -13,7 +13,7 @@
#pragma once
-#include "render.h"
+#include "rendertypes.h"
#include <cmath>
@@ -23,6 +23,8 @@
enum ru_imgformat
{
RENDUTIL_IMGFORMAT_PNG,
+ RENDUTIL_IMGFORMAT_JPEG,
+ RENDUTIL_IMGFORMAT_MSDIB,
RENDUTIL_IMGFORMAT_UNKNOWN,
RENDUTIL_IMGFORMAT_ERROR
@@ -40,9 +42,10 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source,
bool render_clip_line(render_bounds *bounds, const render_bounds *clip);
bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords);
void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1);
-void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename);
-bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename, bool load_as_alpha_to_existing = false);
-ru_imgformat render_detect_image(emu_file &file, const char *dirname, const char *filename);
+void render_load_msdib(bitmap_argb32 &bitmap, util::core_file &file);
+void render_load_jpeg(bitmap_argb32 &bitmap, util::core_file &file);
+bool render_load_png(bitmap_argb32 &bitmap, util::core_file &file, bool load_as_alpha_to_existing = false);
+ru_imgformat render_detect_image(util::core_file &file);
@@ -62,75 +65,6 @@ static inline float render_round_nearest(float f)
/*-------------------------------------------------
- set_render_bounds_xy - cleaner way to set the
- bounds
--------------------------------------------------*/
-
-static inline void set_render_bounds_xy(render_bounds &bounds, float x0, float y0, float x1, float y1)
-{
- bounds.x0 = x0;
- bounds.y0 = y0;
- bounds.x1 = x1;
- bounds.y1 = y1;
-}
-
-
-/*-------------------------------------------------
- set_render_bounds_wh - cleaner way to set the
- bounds
--------------------------------------------------*/
-
-static inline void set_render_bounds_wh(render_bounds &bounds, float x0, float y0, float width, float height)
-{
- bounds.x0 = x0;
- bounds.y0 = y0;
- bounds.x1 = x0 + width;
- bounds.y1 = y0 + height;
-}
-
-
-/*-------------------------------------------------
- sect_render_bounds - compute the intersection
- of two render_bounds
--------------------------------------------------*/
-
-static inline void sect_render_bounds(render_bounds &dest, const render_bounds &src)
-{
- dest.x0 = (std::max)(dest.x0, src.x0);
- dest.x1 = (std::min)(dest.x1, src.x1);
- dest.y0 = (std::max)(dest.y0, src.y0);
- dest.y1 = (std::min)(dest.y1, src.y1);
-}
-
-
-/*-------------------------------------------------
- union_render_bounds - compute the union of two
- render_bounds
--------------------------------------------------*/
-
-static inline void union_render_bounds(render_bounds &dest, const render_bounds &src)
-{
- dest.x0 = (std::min)(dest.x0, src.x0);
- dest.x1 = (std::max)(dest.x1, src.x1);
- dest.y0 = (std::min)(dest.y0, src.y0);
- dest.y1 = (std::max)(dest.y1, src.y1);
-}
-
-
-/*-------------------------------------------------
- set_render_color - cleaner way to set a color
--------------------------------------------------*/
-
-static inline void set_render_color(render_color *color, float a, float r, float g, float b)
-{
- color->a = a;
- color->r = r;
- color->g = g;
- color->b = b;
-}
-
-
-/*-------------------------------------------------
orientation_swap_flips - swap the X and Y
flip flags
-------------------------------------------------*/
@@ -213,5 +147,4 @@ static inline u8 apply_brightness_contrast_gamma(u8 src, float brightness, float
return u8(result * 255.0f);
}
-
#endif // MAME_EMU_RENDUTIL_H
diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp
index c1e575819db..c265b14e31b 100644
--- a/src/emu/screen.cpp
+++ b/src/emu/screen.cpp
@@ -9,14 +9,15 @@
***************************************************************************/
#include "emu.h"
+#include "screen.h"
+
#include "emuopts.h"
-#include "png.h"
+#include "render.h"
#include "rendutil.h"
-#include <nanosvg/src/nanosvg.h>
-#include <nanosvg/src/nanosvgrast.h>
+#include "nanosvg.h"
+#include "png.h"
-#include <clocale>
#include <set>
@@ -43,7 +44,6 @@ u32 screen_device::m_id_counter = 0;
class screen_device::svg_renderer {
public:
svg_renderer(memory_region *region);
- ~svg_renderer();
int width() const;
int height() const;
@@ -69,8 +69,8 @@ private:
int x0, y0, x1, y1;
};
- NSVGimage *m_image;
- NSVGrasterizer *m_rasterizer;
+ util::nsvg_image_ptr m_image;
+ util::nsvg_rasterizer_ptr m_rasterizer;
std::vector<bool> m_key_state;
std::vector<std::vector<NSVGshape *>> m_keyed_shapes;
std::unordered_map<std::string, int> m_key_ids;
@@ -97,8 +97,8 @@ screen_device::svg_renderer::svg_renderer(memory_region *region)
const std::unique_ptr<char []> s(new char[region->bytes() + 1]);
memcpy(s.get(), region->base(), region->bytes());
s[region->bytes()] = 0;
- m_image = nsvgParse(s.get(), "px", 72);
- m_rasterizer = nsvgCreateRasterizer();
+ m_image.reset(nsvgParse(s.get(), "px", 72));
+ m_rasterizer.reset(nsvgCreateRasterizer());
m_key_count = 0;
@@ -123,12 +123,6 @@ screen_device::svg_renderer::svg_renderer(memory_region *region)
osd_printf_verbose("Parsed SVG '%s', aspect ratio %f\n", region->name(), (m_image->height == 0.0f) ? 0 : m_image->width / m_image->height);
}
-screen_device::svg_renderer::~svg_renderer()
-{
- nsvgDeleteRasterizer(m_rasterizer);
- nsvgDelete(m_image);
-}
-
int screen_device::svg_renderer::width() const
{
return int(m_image->width + 0.5);
@@ -150,7 +144,7 @@ void screen_device::svg_renderer::render_state(std::vector<u32> &dest, const std
s->flags &= ~NSVG_FLAGS_VISIBLE;
}
- nsvgRasterize(m_rasterizer, m_image, 0, 0, m_scale, (unsigned char *)&dest[0], m_sx, m_sy, m_sx*4);
+ nsvgRasterize(m_rasterizer.get(), m_image.get(), 0, 0, m_scale, (unsigned char *)&dest[0], m_sx, m_sy, m_sx*4);
// Nanosvg generates non-premultiplied alpha, so remultiply by
// alpha to "blend" against a black background. Plus align the
@@ -1921,14 +1915,14 @@ void screen_device::finalize_burnin()
osd_file::error filerr = file.open(util::string_format("%s" PATH_SEPARATOR "burnin-%s.png", machine().basename(), tag() + 1));
if (filerr == osd_file::error::NONE)
{
- png_info pnginfo;
+ util::png_info pnginfo;
// add two text entries describing the image
pnginfo.add_text("Software", util::string_format("%s %s", emulator_info::get_appname(), emulator_info::get_build_version()).c_str());
pnginfo.add_text("System", util::string_format("%s %s", machine().system().manufacturer, machine().system().type.fullname()).c_str());
// now do the actual work
- png_write_bitmap(file, &pnginfo, finalmap, 0, nullptr);
+ util::png_write_bitmap(file, &pnginfo, finalmap, 0, nullptr);
}
}
@@ -1947,8 +1941,13 @@ void screen_device::load_effect_overlay(const char *filename)
fullname.append(".png");
// load the file
+ m_screen_overlay_bitmap.reset();
emu_file file(machine().options().art_path(), OPEN_FLAG_READ);
- render_load_png(m_screen_overlay_bitmap, file, nullptr, fullname.c_str());
+ if (file.open(fullname) == osd_file::error::NONE)
+ {
+ render_load_png(m_screen_overlay_bitmap, file);
+ file.close();
+ }
if (m_screen_overlay_bitmap.valid())
m_container->set_overlay(&m_screen_overlay_bitmap);
else
diff --git a/src/emu/video.cpp b/src/emu/video.cpp
index 6f88d9ae03d..56d60ba1661 100644
--- a/src/emu/video.cpp
+++ b/src/emu/video.cpp
@@ -329,16 +329,16 @@ void video_manager::save_snapshot(screen_device *screen, emu_file &file)
// add two text entries describing the image
std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version());
std::string text2 = std::string(machine().system().manufacturer).append(" ").append(machine().system().type.fullname());
- png_info pnginfo;
+ util::png_info pnginfo;
pnginfo.add_text("Software", text1.c_str());
pnginfo.add_text("System", text2.c_str());
// now do the actual work
const rgb_t *palette = (screen != nullptr && screen->has_palette()) ? screen->palette().palette()->entry_list_adjusted() : nullptr;
int entries = (screen != nullptr && screen->has_palette()) ? screen->palette().entries() : 0;
- png_error error = png_write_bitmap(file, &pnginfo, m_snap_bitmap, entries, palette);
- if (error != PNGERR_NONE)
- osd_printf_error("Error generating PNG for snapshot: png_error = %d\n", error);
+ util::png_error error = util::png_write_bitmap(file, &pnginfo, m_snap_bitmap, entries, palette);
+ if (error != util::png_error::NONE)
+ osd_printf_error("Error generating PNG for snapshot: png_error = %d\n", std::underlying_type_t<util::png_error>(error));
}
diff --git a/src/frontend/mame/ui/icorender.cpp b/src/frontend/mame/ui/icorender.cpp
index bea85f9dd60..5bda0836838 100644
--- a/src/frontend/mame/ui/icorender.cpp
+++ b/src/frontend/mame/ui/icorender.cpp
@@ -19,6 +19,7 @@
#include "emu.h"
#include "icorender.h"
+#include "util/msdib.h"
#include "util/png.h"
#include <algorithm>
@@ -26,11 +27,10 @@
#include <cstdint>
#include <cstring>
-// need to set LOG_OUTPUT_STREAM because there's no logerror outside devices
-#define LOG_OUTPUT_STREAM std::cerr
+// need to set LOG_OUTPUT_FUNC or LOG_OUTPUT_STREAM because there's no logerror outside devices
+#define LOG_OUTPUT_FUNC osd_printf_verbose
#define LOG_GENERAL (1U << 0)
-#define LOG_DIB (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_DIB)
@@ -41,16 +41,6 @@ namespace ui {
namespace {
-// DIB compression schemes
-enum : uint32_t
-{
- DIB_COMP_NONE = 0,
- DIB_COMP_RLE8 = 1,
- DIB_COMP_RLE4 = 2,
- DIB_COMP_BITFIELDS = 3
-};
-
-
// ICO file header
struct icon_dir_t
{
@@ -83,67 +73,6 @@ struct icon_dir_entry_t
uint32_t offset; // offset to image data from start of file
};
-// old-style DIB header
-struct bitmap_core_header_t
-{
- uint32_t size; // size of the header (12, 16 or 64)
- int16_t width; // width of bitmap in pixels
- int16_t height; // height of the image in pixels
- uint16_t planes; // number of colour planes (must be 1)
- uint16_t bpp; // bits per pixel
-};
-
-// new-style DIB header
-struct bitmap_info_header_t
-{
- uint32_t size; // size of the header
- int32_t width; // width of bitmap in pixels
- int32_t height; // height of bitmap in pixels
- uint16_t planes; // number of colour planes (must be 1)
- uint16_t bpp; // bits per pixel
- uint32_t comp; // compression method
- uint32_t rawsize; // size of bitmap data after decompression or 0 if uncompressed
- int32_t hres; // horizontal resolution in pixels/metre
- int32_t vres; // horizontal resolution in pixels/metre
- uint32_t colors; // number of colours or 0 for 1 << bpp
- uint32_t important; // number of important colours or 0 if all important
- uint32_t red; // red field mask - must be contiguous
- uint32_t green; // green field mask - must be contiguous
- uint32_t blue; // blue field mask - must be contiguous
- uint32_t alpha; // alpha field mask - must be contiguous
-};
-
-
-bool dib_parse_mask(uint32_t mask, unsigned &shift, unsigned &bits)
-{
- shift = count_leading_zeros(mask);
- mask <<= shift;
- bits = count_leading_ones(mask);
- mask <<= shift;
- shift = 32 - shift - bits;
- return !mask;
-}
-
-
-void dib_truncate_channel(unsigned &shift, unsigned &bits)
-{
- if (8U < bits)
- {
- unsigned const excess(bits - 8);
- shift += excess;
- bits -= excess;
- }
-}
-
-
-uint8_t dib_splat_sample(uint8_t val, unsigned bits)
-{
- assert(8U >= bits);
- for (val <<= (8U - bits); bits && (8U > bits); bits <<= 1)
- val |= val >> bits;
- return val;
-}
-
bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb32 &bitmap)
{
@@ -151,10 +80,10 @@ bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb3
if (9U >= dir.size)
return false;
fp.seek(dir.offset, SEEK_SET);
- png_error const err(png_read_bitmap(fp, bitmap));
+ util::png_error const err(util::png_read_bitmap(fp, bitmap));
switch (err)
{
- case PNGERR_NONE:
+ case util::png_error::NONE:
// found valid PNG image
assert(bitmap.valid());
if ((dir.get_width() == bitmap.width()) && ((dir.get_height() == bitmap.height())))
@@ -172,7 +101,7 @@ bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb3
}
return true;
- case PNGERR_BAD_SIGNATURE:
+ case util::png_error::BAD_SIGNATURE:
// doesn't look like PNG data - just fall back to DIB without the file header
return false;
@@ -190,426 +119,37 @@ bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb3
bool load_ico_dib(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb32 &bitmap)
{
- // check that these things haven't been padded somehow
- static_assert(sizeof(bitmap_core_header_t) == 12U, "compiler has applied padding to bitmap_core_header_t");
- static_assert(sizeof(bitmap_info_header_t) == 56U, "compiler has applied padding to bitmap_info_header_t");
-
- // ensure the header fits in the space for the image data
- union { bitmap_core_header_t core; bitmap_info_header_t info; } header;
- assert(&header.core.size == &header.info.size);
- if (sizeof(header.core) > dir.size)
- return false;
- std::memset(&header, 0, sizeof(header));
fp.seek(dir.offset, SEEK_SET);
- if (fp.read(&header.core.size, sizeof(header.core.size)) != sizeof(header.core.size))
- {
- LOG(
- "Error reading DIB header size from ICO file at offset %u (directory size %u)\n",
- dir.offset,
- dir.size);
- return false;
- }
- header.core.size = little_endianize_int32(header.core.size);
- if (dir.size < header.core.size)
- {
- LOG(
- "ICO file image data at %u (%u bytes) is too small for DIB header (%u bytes)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
- }
-
- // identify and read the header - convert OS/2 headers to Windows 3 format
- unsigned palette_bytes(4U);
- switch (header.core.size)
+ util::msdib_error const err(util::msdib_read_bitmap_data(fp, bitmap, dir.size, dir.get_height()));
+ switch (err)
{
- case 16U:
- case 64U:
- // extended OS/2 bitmap header with support for compression
- LOG(
- "ICO image data at %u (%u bytes) uses unsupported OS/2 DIB header (size %u)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
-
- case 12U:
- // introduced in OS/2 and Windows 2.0
+ case util::msdib_error::NONE:
+ // found valid DIB image
+ assert(bitmap.valid());
+ if ((dir.get_width() == bitmap.width()) && ((dir.get_height() == bitmap.height())))
{
- palette_bytes = 3U;
- uint32_t const header_read(std::min<uint32_t>(header.core.size, sizeof(header.core)) - sizeof(header.core.size));
- if (fp.read(&header.core.width, header_read) != header_read)
- {
- LOG("Error reading DIB core header from ICO file image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- fp.seek(header.core.size - sizeof(header.core.size) - header_read, SEEK_CUR);
- header.core.width = little_endianize_int16(header.core.width);
- header.core.height = little_endianize_int16(header.core.height);
- header.core.planes = little_endianize_int16(header.core.planes);
- header.core.bpp = little_endianize_int16(header.core.bpp);
- LOGMASKED(
- LOG_DIB,
- "Read DIB core header from ICO file image data at %u: %d*%d, %u planes, %u bpp\n",
- dir.offset,
- header.core.width,
- header.core.height,
- header.core.planes,
- header.core.bpp);
-
- // this works because the core header only aliases the width/height of the info header
- header.info.bpp = header.core.bpp;
- header.info.planes = header.core.planes;
- header.info.height = header.core.height;
- header.info.width = header.core.width;
- header.info.size = 40U;
+ LOG("Loaded %d*%d pixel DIB image from ICO file\n", bitmap.width(), bitmap.height());
}
- break;
-
- default:
- // the next version will be longer
- if (124U >= header.core.size)
+ else
{
LOG(
- "ICO image data at %u (%u bytes) uses unsupported DIB header format (size %u)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
- }
- // fall through
- case 40U:
- case 52U:
- case 56U:
- case 108U:
- case 124U:
- // the Windows 3 bitmap header with optional extensions
- {
- palette_bytes = 4U;
- uint32_t const header_read(std::min<uint32_t>(header.info.size, sizeof(header.info)) - sizeof(header.info.size));
- if (fp.read(&header.info.width, header_read) != header_read)
- {
- LOG("Error reading DIB info header from ICO file image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- fp.seek(header.info.size - sizeof(header.info.size) - header_read, SEEK_CUR);
- header.info.width = little_endianize_int32(header.info.width);
- header.info.height = little_endianize_int32(header.info.height);
- header.info.planes = little_endianize_int16(header.info.planes);
- header.info.bpp = little_endianize_int16(header.info.bpp);
- header.info.comp = little_endianize_int32(header.info.comp);
- header.info.rawsize = little_endianize_int32(header.info.rawsize);
- header.info.hres = little_endianize_int32(header.info.hres);
- header.info.vres = little_endianize_int32(header.info.vres);
- header.info.colors = little_endianize_int32(header.info.colors);
- header.info.important = little_endianize_int32(header.info.important);
- header.info.red = little_endianize_int32(header.info.red);
- header.info.green = little_endianize_int32(header.info.green);
- header.info.blue = little_endianize_int32(header.info.blue);
- header.info.alpha = little_endianize_int32(header.info.alpha);
- LOGMASKED(
- LOG_DIB,
- "Read DIB info header from ICO file image data at %u: %d*%d (%d*%d ppm), %u planes, %u bpp %u/%s%u colors\n",
- dir.offset,
- header.info.width,
- header.info.height,
- header.info.hres,
- header.info.vres,
- header.info.planes,
- header.info.bpp,
- header.info.important,
- header.info.colors ? "" : "2^",
- header.info.colors ? header.info.colors : header.info.bpp);
- }
- break;
- }
-
- // check for unsupported planes/bit depth
- if ((1U != header.info.planes) || !header.info.bpp || (32U < header.info.bpp) || ((8U < header.info.bpp) ? (header.info.bpp % 8) : (8 % header.info.bpp)))
- {
- LOG(
- "ICO file DIB image data at %u uses unsupported planes/bits per pixel %u*%u\n",
- dir.offset,
- header.info.planes,
- header.info.bpp);
- return false;
- }
-
- // check dimensions
- if ((0 >= header.info.width) || (0 == header.info.height))
- {
- LOG(
- "ICO file DIB image data at %u has invalid dimensions %u*%u\n",
- dir.offset,
- header.info.width,
- header.info.height);
- return false;
- }
- bool const top_down(0 > header.info.height);
- if (top_down)
- header.info.height = -header.info.height;
- bool have_and_mask((2 * dir.get_height()) == header.info.height);
- if (!have_and_mask && (dir.get_height() != header.info.height))
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu height %ld doesn't match directory height %u with or without AND mask\n",
- (unsigned long)dir.offset,
- (long)header.info.height,
- dir.get_height());
- return false;
- }
- if (have_and_mask)
- header.info.height >>= 1;
-
- // ensure compression scheme is supported
- bool indexed(true), no_palette(false);
- switch (header.info.comp)
- {
- case DIB_COMP_NONE:
- // uncompressed - direct colour with implied bitfields if more than eight bits/pixel
- indexed = 8U >= header.info.bpp;
- if (indexed)
- {
- if ((1U << header.info.bpp) < header.info.colors)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu has oversized palette with %lu entries for %u bits per pixel\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.colors,
- (unsigned)header.info.bpp);
- }
- }
- if (!indexed)
- {
- no_palette = true;
- switch(header.info.bpp)
- {
- case 16U:
- header.info.red = 0x00007c00;
- header.info.green = 0x000003e0;
- header.info.blue = 0x0000001f;
- header.info.alpha = 0x00000000;
- break;
- case 24U:
- case 32U:
- header.info.red = 0x00ff0000;
- header.info.green = 0x0000ff00;
- header.info.blue = 0x000000ff;
- header.info.alpha = 0x00000000;
- break;
- }
- }
- break;
-
- case DIB_COMP_BITFIELDS:
- // uncompressed direct colour with explicitly-specified bitfields
- indexed = false;
- if (offsetof(bitmap_info_header_t, alpha) > header.info.size)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu specifies bit masks but is too small (size %lu)\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.size);
- return false;
+ "Loaded %d*%d pixel DIB image from ICO file (directory indicated %u*%u)\n",
+ bitmap.width(),
+ bitmap.height(),
+ dir.get_width(),
+ dir.get_height());
}
- break;
+ return true;
default:
- LOG("ICO file DIB image data at %u uses unsupported compression scheme %u\n", header.info.comp);
- return false;
- }
-
- // we can now calculate the size of the palette and row data
- size_t const palette_entries(
- indexed
- ? ((1U == header.info.bpp) ? 2U : header.info.colors ? header.info.colors : (1U << header.info.bpp))
- : (no_palette ? 0U : header.info.colors));
- size_t const palette_size(palette_bytes * palette_entries);
- size_t const row_bytes(((31 + (header.info.width * header.info.bpp)) >> 5) << 2);
- size_t const mask_row_bytes(((31 + header.info.width) >> 5) << 2);
- size_t const required_size(
- header.info.size +
- palette_size +
- ((row_bytes + (have_and_mask ? mask_row_bytes : 0U)) * header.info.height));
- if (required_size > dir.size)
- {
+ // invalid DIB data or I/O error
LOG(
- "ICO file image data at %u (%u bytes) smaller than calculated DIB data size (%u bytes)\n",
+ "Error %u reading DIB image data from ICO file at offset %u (directory size %u)\n",
+ unsigned(err),
dir.offset,
- dir.size,
- required_size);
+ dir.size);
return false;
}
-
- // load the palette for indexed colour formats or the shifts for direct colour formats
- unsigned red_shift(0), green_shift(0), blue_shift(0), alpha_shift(0);
- unsigned red_bits(0), green_bits(0), blue_bits(0), alpha_bits(0);
- std::unique_ptr<rgb_t []> palette;
- if (indexed)
- {
- // read palette and convert
- std::unique_ptr<uint8_t []> palette_data(new uint8_t [palette_size]);
- if (fp.read(palette_data.get(), palette_size) != palette_size)
- {
- LOG("Error reading palette from ICO file DIB image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- size_t const palette_usable(std::min<size_t>(palette_entries, size_t(1) << header.info.bpp));
- palette.reset(new rgb_t [palette_usable]);
- uint8_t const *ptr(palette_data.get());
- for (size_t i = 0; palette_usable > i; ++i, ptr += palette_bytes)
- palette[i] = rgb_t(ptr[2], ptr[1], ptr[0]);
- }
- else
- {
- // skip over the palette if necessary
- if (palette_entries)
- fp.seek(palette_bytes * palette_entries, SEEK_CUR);
-
- // convert masks to shifts
- bool const masks_contiguous(
- dib_parse_mask(header.info.red, red_shift, red_bits) &&
- dib_parse_mask(header.info.green, green_shift, green_bits) &&
- dib_parse_mask(header.info.blue, blue_shift, blue_bits) &&
- dib_parse_mask(header.info.alpha, alpha_shift, alpha_bits));
- if (!masks_contiguous)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu specifies non-contiguous channel masks 0x%lx | 0x%lx | 0x%lx | 0x%lx\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.red,
- (unsigned long)header.info.green,
- (unsigned long)header.info.blue,
- (unsigned long)header.info.alpha);
- }
- if ((32U != header.info.bpp) && ((header.info.red | header.info.green | header.info.blue | header.info.alpha) >> header.info.bpp))
- {
- LOG(
- "ICO file DIB image data at %lu specifies channel masks 0x%x | 0x%x | 0x%x | 0x%x that exceed %u bits per pixel\n",
- dir.offset,
- header.info.red,
- header.info.green,
- header.info.blue,
- header.info.alpha,
- header.info.bpp);
- return false;
- }
- LOGMASKED(
- LOG_DIB,
- "DIB from ICO file image data at %1$u using channels: R((x >> %3$u) & 0x%4$0*2$x) G((x >> %5$u) & 0x%6$0*2$x) B((x >> %7$u) & 0x%8$0*2$x) A((x >> %9$u) & 0x%10$0*2$x)\n",
- dir.offset,
- (header.info.bpp + 3) >> 2,
- red_shift,
- (uint32_t(1) << red_bits) - 1,
- green_shift,
- (uint32_t(1) << green_bits) - 1,
- blue_shift,
- (uint32_t(1) << blue_bits) - 1,
- alpha_shift,
- (uint32_t(1) << alpha_bits) - 1);
-
- // the MAME bitmap only supports 8 bits/sample maximum
- dib_truncate_channel(red_shift, red_bits);
- dib_truncate_channel(green_shift, green_bits);
- dib_truncate_channel(blue_shift, blue_bits);
- dib_truncate_channel(alpha_shift, alpha_bits);
- }
-
- // allocate the bitmap and process row data
- std::unique_ptr<uint8_t []> row_data(new uint8_t [row_bytes]);
- bitmap.allocate(header.info.width, header.info.height);
- int const y_inc(top_down ? 1 : -1);
- for (int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
- {
- if (fp.read(row_data.get(), row_bytes) != row_bytes)
- {
- LOG("Error reading DIB row %d data from ICO image data at %u\n", i, dir.offset);
- return false;
- }
- uint8_t *src(row_data.get());
- uint32_t *dest(&bitmap.pix(y));
- unsigned shift(0U);
- for (int32_t x = 0; header.info.width > x; ++x, ++dest)
- {
- // extract or compose a pixel
- uint32_t pix(0U);
- if (8U >= header.info.bpp)
- {
- assert(8U > shift);
- pix = *src >> (8U - header.info.bpp);
- *src <<= header.info.bpp;
- shift += header.info.bpp;
- if (8U <= shift)
- {
- shift = 0U;
- ++src;
- }
- }
- else for (shift = 0; header.info.bpp > shift; shift += 8U, ++src)
- {
- pix |= uint32_t(*src) << shift;
- }
-
- // convert to RGB
- if (indexed)
- {
- if (palette_entries > pix)
- {
- *dest = palette[pix];
- }
- else
- {
- *dest = rgb_t::transparent();
- osd_printf_verbose(
- "ICO file DIB image data at %lu has out-of-range color %lu at (%ld, %ld) with %lu palette entries\n",
- (unsigned long)dir.offset,
- (unsigned long)pix,
- (long)x,
- (long)y,
- (unsigned long)palette_entries);
- }
- }
- else
- {
- uint8_t r(dib_splat_sample((pix >> red_shift) & ((uint32_t(1) << red_bits) - 1), red_bits));
- uint8_t g(dib_splat_sample((pix >> green_shift) & ((uint32_t(1) << green_bits) - 1), green_bits));
- uint8_t b(dib_splat_sample((pix >> blue_shift) & ((uint32_t(1) << blue_bits) - 1), blue_bits));
- uint8_t a(dib_splat_sample((pix >> alpha_shift) & ((uint32_t(1) << alpha_bits) - 1), alpha_bits));
- *dest = rgb_t(alpha_bits ? a : 255, r, g, b);
- }
- }
- }
-
- // process the AND mask if present
- if (have_and_mask)
- {
- for (int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
- {
- if (fp.read(row_data.get(), mask_row_bytes) != mask_row_bytes)
- {
- LOG("Error reading DIB mask row %d data from ICO image data at %u\n", i, dir.offset);
- return false;
- }
- uint8_t *src(row_data.get());
- uint32_t *dest(&bitmap.pix(y));
- unsigned shift(0U);
- for (int32_t x = 0; header.info.width > x; ++x, ++dest)
- {
- assert(8U > shift);
- rgb_t pix(*dest);
- *dest = pix.set_a(BIT(*src, 7U - shift) ? 0U : pix.a());
- if (8U <= ++shift)
- {
- shift = 0U;
- ++src;
- }
- }
- }
- }
-
- // we're done!
- return true;
}
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index b1bcbb908b7..aa7d90f0ea3 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -92,10 +92,17 @@ menu::global_state::global_state(running_machine &machine, ui_options const &opt
{
m_bgrnd_bitmap = std::make_unique<bitmap_argb32>(0, 0);
emu_file backgroundfile(".", OPEN_FLAG_READ);
- render_load_jpeg(*m_bgrnd_bitmap, backgroundfile, nullptr, "background.jpg");
+ if (backgroundfile.open("background.jpg") == osd_file::error::NONE)
+ {
+ render_load_jpeg(*m_bgrnd_bitmap, backgroundfile);
+ backgroundfile.close();
+ }
- if (!m_bgrnd_bitmap->valid())
- render_load_png(*m_bgrnd_bitmap, backgroundfile, nullptr, "background.png");
+ if (!m_bgrnd_bitmap->valid() && (backgroundfile.open("background.png") == osd_file::error::NONE))
+ {
+ render_load_png(*m_bgrnd_bitmap, backgroundfile);
+ backgroundfile.close();
+ }
if (m_bgrnd_bitmap->valid())
m_bgrnd_texture->set_bitmap(*m_bgrnd_bitmap, m_bgrnd_bitmap->cliprect(), TEXFORMAT_ARGB32);
diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp
index b05991b02e9..7a652c1b6bf 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -95,6 +95,62 @@ char const *const hover_msg[] = {
__("Show DATs view"),
};
+
+void load_image(bitmap_argb32 &bitmap, emu_file &file, std::string const &base)
+{
+ if (file.open(base + ".png") == osd_file::error::NONE)
+ {
+ render_load_png(bitmap, file);
+ file.close();
+ }
+
+ if (!bitmap.valid() && (file.open(base + ".jpg") == osd_file::error::NONE))
+ {
+ render_load_jpeg(bitmap, file);
+ file.close();
+ }
+
+ if (!bitmap.valid() && (file.open(base + ".bmp") == osd_file::error::NONE))
+ {
+ render_load_msdib(bitmap, file);
+ file.close();
+ }
+}
+
+
+void load_driver_image(bitmap_argb32 &bitmap, emu_file &file, game_driver const &driver)
+{
+ // try to load snapshot first from saved "0000.png" file
+ std::string fullname = driver.name;
+ load_image(bitmap, file, fullname + PATH_SEPARATOR + "0000");
+
+ // if fail, attempt to load from standard file
+ if (!bitmap.valid())
+ load_image(bitmap, file, fullname);
+
+ // if fail again, attempt to load from parent file
+ if (!bitmap.valid())
+ {
+ // ignore BIOS sets
+ bool isclone = strcmp(driver.parent, "0") != 0;
+ if (isclone)
+ {
+ int const cx = driver_list::find(driver.parent);
+ if ((0 <= cx) && (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT))
+ isclone = false;
+ }
+
+ if (isclone)
+ {
+ fullname = driver.parent;
+ load_image(bitmap, file, fullname + PATH_SEPARATOR + "0000");
+
+ if (!bitmap.valid())
+ load_image(bitmap, file, fullname);
+ }
+ }
+}
+
} // anonymous namespace
constexpr std::size_t menu_select_launch::MAX_VISIBLE_SEARCH; // stupid non-inline semantics
@@ -2226,41 +2282,16 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
if (software->startempty == 1)
{
// Load driver snapshot
- std::string fullname = std::string(software->driver->name) + ".png";
- render_load_png(tmp_bitmap, snapfile, nullptr, fullname.c_str());
-
- if (!tmp_bitmap.valid())
- {
- fullname.assign(software->driver->name).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, nullptr, fullname.c_str());
- }
+ load_driver_image(tmp_bitmap, snapfile, *software->driver);
}
else
{
// First attempt from name list
- std::string pathname = software->listname;
- std::string fullname = software->shortname + ".png";
- render_load_png(tmp_bitmap, snapfile, pathname.c_str(), fullname.c_str());
+ load_image(tmp_bitmap, snapfile, software->listname + PATH_SEPARATOR + software->shortname);
+ // Second attempt from driver name + part name
if (!tmp_bitmap.valid())
- {
- fullname.assign(software->shortname).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, pathname.c_str(), fullname.c_str());
- }
-
- if (!tmp_bitmap.valid())
- {
- // Second attempt from driver name + part name
- pathname.assign(software->driver->name).append(software->part);
- fullname.assign(software->shortname).append(".png");
- render_load_png(tmp_bitmap, snapfile, pathname.c_str(), fullname.c_str());
-
- if (!tmp_bitmap.valid())
- {
- fullname.assign(software->shortname).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, pathname.c_str(), fullname.c_str());
- }
- }
+ load_image(tmp_bitmap, snapfile, software->driver->name + software->part + PATH_SEPARATOR + software->shortname);
}
m_cache->set_snapx_software(software);
@@ -2285,51 +2316,7 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
{
emu_file snapfile(searchstr, OPEN_FLAG_READ);
bitmap_argb32 tmp_bitmap;
-
- // try to load snapshot first from saved "0000.png" file
- std::string fullname(driver->name);
- render_load_png(tmp_bitmap, snapfile, fullname.c_str(), "0000.png");
-
- if (!tmp_bitmap.valid())
- render_load_jpeg(tmp_bitmap, snapfile, fullname.c_str(), "0000.jpg");
-
- // if fail, attemp to load from standard file
- if (!tmp_bitmap.valid())
- {
- fullname.assign(driver->name).append(".png");
- render_load_png(tmp_bitmap, snapfile, nullptr, fullname.c_str());
-
- if (!tmp_bitmap.valid())
- {
- fullname.assign(driver->name).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, nullptr, fullname.c_str());
- }
- }
-
- // if fail again, attemp to load from parent file
- if (!tmp_bitmap.valid())
- {
- // set clone status
- bool cloneof = strcmp(driver->parent, "0");
- if (cloneof)
- {
- int cx = driver_list::find(driver->parent);
- if ((cx >= 0) && (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT))
- cloneof = false;
- }
-
- if (cloneof)
- {
- fullname.assign(driver->parent).append(".png");
- render_load_png(tmp_bitmap, snapfile, nullptr, fullname.c_str());
-
- if (!tmp_bitmap.valid())
- {
- fullname.assign(driver->parent).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, nullptr, fullname.c_str());
- }
- }
- }
+ load_driver_image(tmp_bitmap, snapfile, *driver);
m_cache->set_snapx_driver(driver);
m_switch_image = false;
diff --git a/src/lib/util/msdib.cpp b/src/lib/util/msdib.cpp
new file mode 100644
index 00000000000..a1ae5eaddf0
--- /dev/null
+++ b/src/lib/util/msdib.cpp
@@ -0,0 +1,642 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ msdib.h
+
+ Microsoft Device-Independent Bitmap file loading.
+
+***************************************************************************/
+
+#include "msdib.h"
+
+#include "eminline.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+
+
+#define LOG_GENERAL (1U << 0)
+#define LOG_DIB (1U << 1)
+
+//#define VERBOSE (LOG_GENERAL | LOG_DIB)
+
+#define LOG_OUTPUT_FUNC osd_printf_verbose
+
+#ifndef VERBOSE
+#define VERBOSE 0
+#endif
+
+#define LOGMASKED(mask, ...) do { if (VERBOSE & (mask)) (LOG_OUTPUT_FUNC)(__VA_ARGS__); } while (false)
+
+#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__)
+
+
+namespace util {
+
+namespace {
+
+// DIB compression schemes
+enum : std::uint32_t
+{
+ DIB_COMP_NONE = 0,
+ DIB_COMP_RLE8 = 1,
+ DIB_COMP_RLE4 = 2,
+ DIB_COMP_BITFIELDS = 3
+};
+
+
+// file header doesn't use natural alignment
+using bitmap_file_header = std::uint8_t [14];
+
+
+// old-style DIB header
+struct bitmap_core_header
+{
+ std::uint32_t size; // size of the header (12, 16 or 64)
+ std::int16_t width; // width of bitmap in pixels
+ std::int16_t height; // height of the image in pixels
+ std::uint16_t planes; // number of colour planes (must be 1)
+ std::uint16_t bpp; // bits per pixel
+};
+
+// new-style DIB header
+struct bitmap_info_header
+{
+ std::uint32_t size; // size of the header
+ std::int32_t width; // width of bitmap in pixels
+ std::int32_t height; // height of bitmap in pixels
+ std::uint16_t planes; // number of colour planes (must be 1)
+ std::uint16_t bpp; // bits per pixel
+ std::uint32_t comp; // compression method
+ std::uint32_t rawsize; // size of bitmap data after decompression or 0 if uncompressed
+ std::int32_t hres; // horizontal resolution in pixels/metre
+ std::int32_t vres; // horizontal resolution in pixels/metre
+ std::uint32_t colors; // number of colours or 0 for 1 << bpp
+ std::uint32_t important; // number of important colours or 0 if all important
+ std::uint32_t red; // red field mask - must be contiguous
+ std::uint32_t green; // green field mask - must be contiguous
+ std::uint32_t blue; // blue field mask - must be contiguous
+ std::uint32_t alpha; // alpha field mask - must be contiguous
+};
+
+
+union bitmap_headers
+{
+ bitmap_core_header core;
+ bitmap_info_header info;
+};
+
+
+bool dib_parse_mask(uint32_t mask, unsigned &shift, unsigned &bits)
+{
+ shift = count_leading_zeros(mask);
+ mask <<= shift;
+ bits = count_leading_ones(mask);
+ mask <<= shift;
+ shift = 32 - shift - bits;
+ return !mask;
+}
+
+
+void dib_truncate_channel(unsigned &shift, unsigned &bits)
+{
+ if (8U < bits)
+ {
+ unsigned const excess(bits - 8);
+ shift += excess;
+ bits -= excess;
+ }
+}
+
+
+uint8_t dib_splat_sample(uint8_t val, unsigned bits)
+{
+ assert(8U >= bits);
+ for (val <<= (8U - bits); bits && (8U > bits); bits <<= 1)
+ val |= val >> bits;
+ return val;
+}
+
+
+msdib_error dib_read_file_header(core_file &fp, std::uint32_t &filelen)
+{
+ // the bitmap file header doesn't use natural alignment
+ bitmap_file_header file_header;
+ if (fp.read(file_header, sizeof(file_header)) != sizeof(file_header))
+ {
+ LOG("Error reading DIB file header\n");
+ return msdib_error::FILE_TRUNCATED;
+ }
+
+ // only support Windows bitmaps for now
+ if ((0x42 != file_header[0]) || (0x4d != file_header[1]))
+ return msdib_error::BAD_SIGNATURE;
+
+ // do a very basic check on the file length
+ std::uint32_t const file_length(
+ (std::uint32_t(file_header[2]) << 0) |
+ (std::uint32_t(file_header[3]) << 8) |
+ (std::uint32_t(file_header[4]) << 16) |
+ (std::uint32_t(file_header[5]) << 24));
+ if ((sizeof(file_header) + sizeof(bitmap_core_header)) > file_length)
+ return msdib_error::FILE_CORRUPT;
+
+ // check that the offset to the pixel data looks half sane
+ std::uint32_t const pixel_offset(
+ (std::uint32_t(file_header[10]) << 0) |
+ (std::uint32_t(file_header[11]) << 8) |
+ (std::uint32_t(file_header[12]) << 16) |
+ (std::uint32_t(file_header[13]) << 24));
+ if (((sizeof(file_header) + sizeof(bitmap_core_header)) > pixel_offset) || (file_length < pixel_offset))
+ return msdib_error::FILE_CORRUPT;
+
+ // looks OK enough
+ filelen = file_length;
+ return msdib_error::NONE;
+}
+
+
+msdib_error dib_read_bitmap_header(
+ core_file &fp,
+ bitmap_headers &header,
+ unsigned &palette_bytes,
+ bool &indexed,
+ std::size_t &palette_entries,
+ std::size_t &palette_size,
+ std::size_t &row_bytes,
+ std::uint32_t length)
+{
+ // check that these things haven't been padded somehow
+ static_assert(sizeof(bitmap_core_header) == 12U, "compiler has applied padding to bitmap_core_header");
+ static_assert(sizeof(bitmap_info_header) == 56U, "compiler has applied padding to bitmap_info_header");
+
+ // ensure the header fits in the space for the image data
+ assert(&header.core.size == &header.info.size);
+ if (sizeof(header.core) > length)
+ return msdib_error::FILE_TRUNCATED;
+ std::memset(&header, 0, sizeof(header));
+ if (fp.read(&header.core.size, sizeof(header.core.size)) != sizeof(header.core.size))
+ {
+ LOG("Error reading DIB header size (length %u)\n", length);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ header.core.size = little_endianize_int32(header.core.size);
+ if (length < header.core.size)
+ {
+ LOG("DIB image data (%u bytes) is too small for DIB header (%u bytes)\n", length, header.core.size);
+ return msdib_error::FILE_CORRUPT;
+ }
+
+ // identify and read the header - convert OS/2 headers to Windows 3 format
+ palette_bytes = 4U;
+ switch (header.core.size)
+ {
+ case 16U:
+ case 64U:
+ // extended OS/2 bitmap header with support for compression
+ LOG(
+ "DIB image data (%u bytes) uses unsupported OS/2 DIB header (size %u)\n",
+ length,
+ header.core.size);
+ return msdib_error::UNSUPPORTED_FORMAT;
+
+ case 12U:
+ // introduced in OS/2 and Windows 2.0
+ {
+ palette_bytes = 3U;
+ std::uint32_t const header_read(std::min<std::uint32_t>(header.core.size, sizeof(header.core)) - sizeof(header.core.size));
+ if (fp.read(&header.core.width, header_read) != header_read)
+ {
+ LOG("Error reading DIB core header from image data (%u bytes)\n", length);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ fp.seek(header.core.size - sizeof(header.core.size) - header_read, SEEK_CUR);
+ header.core.width = little_endianize_int16(header.core.width);
+ header.core.height = little_endianize_int16(header.core.height);
+ header.core.planes = little_endianize_int16(header.core.planes);
+ header.core.bpp = little_endianize_int16(header.core.bpp);
+ LOGMASKED(
+ LOG_DIB,
+ "Read DIB core header from image data : %d*%d, %u planes, %u bpp\n",
+ header.core.width,
+ header.core.height,
+ header.core.planes,
+ header.core.bpp);
+
+ // this works because the core header only aliases the width/height of the info header
+ header.info.bpp = header.core.bpp;
+ header.info.planes = header.core.planes;
+ header.info.height = header.core.height;
+ header.info.width = header.core.width;
+ header.info.size = 40U;
+ }
+ break;
+
+ default:
+ // the next version will be longer
+ if (124U >= header.core.size)
+ {
+ LOG(
+ "DIB image data (%u bytes) uses unsupported DIB header format (size %u)\n",
+ length,
+ header.core.size);
+ return msdib_error::UNSUPPORTED_FORMAT;
+ }
+ // fall through
+ case 40U:
+ case 52U:
+ case 56U:
+ case 108U:
+ case 124U:
+ // the Windows 3 bitmap header with optional extensions
+ {
+ palette_bytes = 4U;
+ std::uint32_t const header_read(std::min<std::uint32_t>(header.info.size, sizeof(header.info)) - sizeof(header.info.size));
+ if (fp.read(&header.info.width, header_read) != header_read)
+ {
+ LOG("Error reading DIB info header from image data (%u bytes)\n", length);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ fp.seek(header.info.size - sizeof(header.info.size) - header_read, SEEK_CUR);
+ header.info.width = little_endianize_int32(header.info.width);
+ header.info.height = little_endianize_int32(header.info.height);
+ header.info.planes = little_endianize_int16(header.info.planes);
+ header.info.bpp = little_endianize_int16(header.info.bpp);
+ header.info.comp = little_endianize_int32(header.info.comp);
+ header.info.rawsize = little_endianize_int32(header.info.rawsize);
+ header.info.hres = little_endianize_int32(header.info.hres);
+ header.info.vres = little_endianize_int32(header.info.vres);
+ header.info.colors = little_endianize_int32(header.info.colors);
+ header.info.important = little_endianize_int32(header.info.important);
+ header.info.red = little_endianize_int32(header.info.red);
+ header.info.green = little_endianize_int32(header.info.green);
+ header.info.blue = little_endianize_int32(header.info.blue);
+ header.info.alpha = little_endianize_int32(header.info.alpha);
+ LOGMASKED(
+ LOG_DIB,
+ "Read DIB info header from image data: %d*%d (%d*%d ppm), %u planes, %u bpp %u/%s%u colors\n",
+ header.info.width,
+ header.info.height,
+ header.info.hres,
+ header.info.vres,
+ header.info.planes,
+ header.info.bpp,
+ header.info.important,
+ header.info.colors ? "" : "2^",
+ header.info.colors ? header.info.colors : header.info.bpp);
+ }
+ break;
+ }
+
+ // check for unsupported planes/bit depth
+ if ((1U != header.info.planes) || !header.info.bpp || (32U < header.info.bpp) || ((8U < header.info.bpp) ? (header.info.bpp % 8) : (8 % header.info.bpp)))
+ {
+ LOG("DIB image data uses unsupported planes/bits per pixel %u*%u\n", header.info.planes, header.info.bpp);
+ return msdib_error::UNSUPPORTED_FORMAT;
+ }
+
+ // check dimensions
+ if ((0 >= header.info.width) || (0 == header.info.height))
+ {
+ LOG("DIB image data has invalid dimensions %u*%u\n", header.info.width, header.info.height);
+ return msdib_error::FILE_CORRUPT;
+ }
+
+ // ensure compression scheme is supported
+ bool no_palette(false);
+ indexed = true;
+ switch (header.info.comp)
+ {
+ case DIB_COMP_NONE:
+ // uncompressed - direct colour with implied bitfields if more than eight bits/pixel
+ indexed = 8U >= header.info.bpp;
+ if (indexed)
+ {
+ if ((1U << header.info.bpp) < header.info.colors)
+ {
+ osd_printf_verbose(
+ "DIB image data has oversized palette with %u entries for %u bits per pixel\n",
+ header.info.colors,
+ header.info.bpp);
+ }
+ }
+ if (!indexed)
+ {
+ no_palette = true;
+ switch(header.info.bpp)
+ {
+ case 16U:
+ header.info.red = 0x00007c00;
+ header.info.green = 0x000003e0;
+ header.info.blue = 0x0000001f;
+ header.info.alpha = 0x00000000;
+ break;
+ case 24U:
+ case 32U:
+ header.info.red = 0x00ff0000;
+ header.info.green = 0x0000ff00;
+ header.info.blue = 0x000000ff;
+ header.info.alpha = 0x00000000;
+ break;
+ }
+ }
+ break;
+
+ case DIB_COMP_BITFIELDS:
+ // uncompressed direct colour with explicitly-specified bitfields
+ indexed = false;
+ if (offsetof(bitmap_info_header, alpha) > header.info.size)
+ {
+ osd_printf_verbose(
+ "DIB image data specifies bit masks but is too small (size %u)\n",
+ header.info.size);
+ return msdib_error::FILE_CORRUPT;
+ }
+ break;
+
+ default:
+ LOG("DIB image data uses unsupported compression scheme %u\n", header.info.comp);
+ return msdib_error::UNSUPPORTED_FORMAT;
+ }
+
+ // we can now calculate the size of the palette and row data
+ palette_entries =
+ indexed
+ ? ((1U == header.info.bpp) ? 2U : header.info.colors ? header.info.colors : (1U << header.info.bpp))
+ : (no_palette ? 0U : header.info.colors);
+ palette_size = palette_bytes * palette_entries;
+ row_bytes = ((31 + (header.info.width * header.info.bpp)) >> 5) << 2;
+
+ // header looks OK
+ return msdib_error::NONE;
+}
+
+} // anonymous namespace
+
+
+
+msdib_error msdib_verify_header(core_file &fp)
+{
+ msdib_error err;
+
+ // file header
+ std::uint32_t file_length;
+ err = dib_read_file_header(fp, file_length);
+ if (msdib_error::NONE != err)
+ return err;
+
+ // bitmap header
+ bitmap_headers header;
+ unsigned palette_bytes;
+ bool indexed;
+ std::size_t palette_entries, palette_size, row_bytes;
+ err = dib_read_bitmap_header(
+ fp,
+ header,
+ palette_bytes,
+ indexed,
+ palette_entries,
+ palette_size,
+ row_bytes,
+ file_length - sizeof(bitmap_file_header));
+ if (msdib_error::NONE != err)
+ return err;
+
+ // check length
+ std::size_t const required_size(
+ sizeof(bitmap_file_header) +
+ header.info.size +
+ palette_size +
+ (row_bytes * std::abs(header.info.height)));
+ if (required_size > file_length)
+ return msdib_error::FILE_TRUNCATED;
+
+ // good chance this file is supported
+ return msdib_error::NONE;
+}
+
+
+msdib_error msdib_read_bitmap(core_file &fp, bitmap_argb32 &bitmap)
+{
+ std::uint32_t file_length;
+ msdib_error const headerr(dib_read_file_header(fp, file_length));
+ if (msdib_error::NONE != headerr)
+ return headerr;
+
+ return msdib_read_bitmap_data(fp, bitmap, file_length - sizeof(bitmap_file_header), 0U);
+}
+
+
+msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::uint32_t length, std::uint32_t dirheight)
+{
+ // read the bitmap header
+ bitmap_headers header;
+ unsigned palette_bytes;
+ bool indexed;
+ std::size_t palette_entries, palette_size, row_bytes;
+ msdib_error const head_error(dib_read_bitmap_header(fp, header, palette_bytes, indexed, palette_entries, palette_size, row_bytes, length));
+ if (msdib_error::NONE != head_error)
+ return head_error;
+
+ // check dimensions
+ bool const top_down(0 > header.info.height);
+ if (top_down)
+ header.info.height = -header.info.height;
+ bool have_and_mask((2 * dirheight) == header.info.height);
+ if (!have_and_mask && (0 < dirheight) && (dirheight != header.info.height))
+ {
+ osd_printf_verbose(
+ "DIB image data height %d doesn't match directory height %u with or without AND mask\n",
+ header.info.height,
+ dirheight);
+ return msdib_error::UNSUPPORTED_FORMAT;
+ }
+ if (have_and_mask)
+ header.info.height >>= 1;
+
+ // we can now calculate the size of the image data
+ std::size_t const mask_row_bytes(((31 + header.info.width) >> 5) << 2);
+ std::size_t const required_size(
+ header.info.size +
+ palette_size +
+ ((row_bytes + (have_and_mask ? mask_row_bytes : 0U)) * header.info.height));
+ if (required_size > length)
+ {
+ LOG("DIB image data (%u bytes) smaller than calculated DIB data size (%u bytes)\n", length, required_size);
+ return msdib_error::FILE_TRUNCATED;
+ }
+
+ // load the palette for indexed colour formats or the shifts for direct colour formats
+ unsigned red_shift(0), green_shift(0), blue_shift(0), alpha_shift(0);
+ unsigned red_bits(0), green_bits(0), blue_bits(0), alpha_bits(0);
+ std::unique_ptr<rgb_t []> palette;
+ if (indexed)
+ {
+ // read palette and convert
+ std::unique_ptr<std::uint8_t []> palette_data;
+ try { palette_data.reset(new std::uint8_t [palette_size]); }
+ catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; }
+ if (fp.read(palette_data.get(), palette_size) != palette_size)
+ {
+ LOG("Error reading palette from DIB image data (%u bytes)\n", length);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ std::size_t const palette_usable(std::min<std::size_t>(palette_entries, std::size_t(1) << header.info.bpp));
+ try { palette.reset(new rgb_t [palette_usable]); }
+ catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; }
+ std::uint8_t const *ptr(palette_data.get());
+ for (std::size_t i = 0; palette_usable > i; ++i, ptr += palette_bytes)
+ palette[i] = rgb_t(ptr[2], ptr[1], ptr[0]);
+ }
+ else
+ {
+ // skip over the palette if necessary
+ if (palette_entries)
+ fp.seek(palette_bytes * palette_entries, SEEK_CUR);
+
+ // convert masks to shifts
+ bool const masks_contiguous(
+ dib_parse_mask(header.info.red, red_shift, red_bits) &&
+ dib_parse_mask(header.info.green, green_shift, green_bits) &&
+ dib_parse_mask(header.info.blue, blue_shift, blue_bits) &&
+ dib_parse_mask(header.info.alpha, alpha_shift, alpha_bits));
+ if (!masks_contiguous)
+ {
+ osd_printf_verbose(
+ "DIB image data specifies non-contiguous channel masks 0x%x | 0x%x | 0x%x | 0x%x\n",
+ header.info.red,
+ header.info.green,
+ header.info.blue,
+ header.info.alpha);
+ }
+ if ((32U != header.info.bpp) && ((header.info.red | header.info.green | header.info.blue | header.info.alpha) >> header.info.bpp))
+ {
+ LOG(
+ "DIB image data specifies channel masks 0x%x | 0x%x | 0x%x | 0x%x that exceed %u bits per pixel\n",
+ header.info.red,
+ header.info.green,
+ header.info.blue,
+ header.info.alpha,
+ header.info.bpp);
+ return msdib_error::FILE_CORRUPT;
+ }
+ LOGMASKED(
+ LOG_DIB,
+ "DIB image data using channels: R((x >> %2$u) & 0x%3$0*1$x) G((x >> %4$u) & 0x%5$0*1$x) B((x >> %6$u) & 0x%7$0*1$x) A((x >> %8$u) & 0x%9$0*1$x)\n",
+ (header.info.bpp + 3) >> 2,
+ red_shift,
+ (std::uint32_t(1) << red_bits) - 1,
+ green_shift,
+ (std::uint32_t(1) << green_bits) - 1,
+ blue_shift,
+ (std::uint32_t(1) << blue_bits) - 1,
+ alpha_shift,
+ (std::uint32_t(1) << alpha_bits) - 1);
+
+ // the MAME bitmap only supports 8 bits/sample maximum
+ dib_truncate_channel(red_shift, red_bits);
+ dib_truncate_channel(green_shift, green_bits);
+ dib_truncate_channel(blue_shift, blue_bits);
+ dib_truncate_channel(alpha_shift, alpha_bits);
+ }
+
+ // allocate the bitmap and process row data
+ std::unique_ptr<std::uint8_t []> row_data;
+ try {row_data.reset(new std::uint8_t [row_bytes]); }
+ catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; }
+ bitmap.allocate(header.info.width, header.info.height);
+ int const y_inc(top_down ? 1 : -1);
+ for (std::int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
+ {
+ if (fp.read(row_data.get(), row_bytes) != row_bytes)
+ {
+ LOG("Error reading DIB row %d data from image data\n", i);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ std::uint8_t *src(row_data.get());
+ std::uint32_t *dest(&bitmap.pix(y));
+ unsigned shift(0U);
+ for (std::int32_t x = 0; header.info.width > x; ++x, ++dest)
+ {
+ // extract or compose a pixel
+ std::uint32_t pix(0U);
+ if (8U >= header.info.bpp)
+ {
+ assert(8U > shift);
+ pix = *src >> (8U - header.info.bpp);
+ *src <<= header.info.bpp;
+ shift += header.info.bpp;
+ if (8U <= shift)
+ {
+ shift = 0U;
+ ++src;
+ }
+ }
+ else for (shift = 0; header.info.bpp > shift; shift += 8U, ++src)
+ {
+ pix |= std::uint32_t(*src) << shift;
+ }
+
+ // convert to RGB
+ if (indexed)
+ {
+ if (palette_entries > pix)
+ {
+ *dest = palette[pix];
+ }
+ else
+ {
+ *dest = rgb_t::transparent();
+ osd_printf_verbose(
+ "DIB image data has out-of-range color %u at (%d, %d) with %u palette entries\n",
+ pix,
+ x,
+ y,
+ palette_entries);
+ }
+ }
+ else
+ {
+ std::uint8_t r(dib_splat_sample((pix >> red_shift) & ((std::uint32_t(1) << red_bits) - 1), red_bits));
+ std::uint8_t g(dib_splat_sample((pix >> green_shift) & ((std::uint32_t(1) << green_bits) - 1), green_bits));
+ std::uint8_t b(dib_splat_sample((pix >> blue_shift) & ((std::uint32_t(1) << blue_bits) - 1), blue_bits));
+ std::uint8_t a(dib_splat_sample((pix >> alpha_shift) & ((std::uint32_t(1) << alpha_bits) - 1), alpha_bits));
+ *dest = rgb_t(alpha_bits ? a : 255, r, g, b);
+ }
+ }
+ }
+
+ // process the AND mask if present
+ if (have_and_mask)
+ {
+ for (std::int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
+ {
+ if (fp.read(row_data.get(), mask_row_bytes) != mask_row_bytes)
+ {
+ LOG("Error reading DIB mask row %d data from image data\n", i);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ std::uint8_t *src(row_data.get());
+ std::uint32_t *dest(&bitmap.pix(y));
+ unsigned shift(0U);
+ for (std::int32_t x = 0; header.info.width > x; ++x, ++dest)
+ {
+ assert(8U > shift);
+ rgb_t pix(*dest);
+ *dest = pix.set_a(BIT(*src, 7U - shift) ? 0U : pix.a());
+ if (8U <= ++shift)
+ {
+ shift = 0U;
+ ++src;
+ }
+ }
+ }
+ }
+
+ // we're done!
+ return msdib_error::NONE;
+}
+
+} // namespace util
diff --git a/src/lib/util/msdib.h b/src/lib/util/msdib.h
new file mode 100644
index 00000000000..54767e216fb
--- /dev/null
+++ b/src/lib/util/msdib.h
@@ -0,0 +1,46 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ msdib.h
+
+ Microsoft Device-Independent Bitmap file loading.
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_MSDIB_H
+#define MAME_LIB_UTIL_MSDIB_H
+
+#pragma once
+
+#include "bitmap.h"
+#include "corefile.h"
+#include "osdcore.h"
+
+#include <cstdint>
+
+
+namespace util {
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+// Error types
+enum class msdib_error
+{
+ NONE,
+ OUT_OF_MEMORY,
+ FILE_ERROR,
+ BAD_SIGNATURE,
+ FILE_TRUNCATED,
+ FILE_CORRUPT,
+ UNSUPPORTED_FORMAT
+};
+
+msdib_error msdib_verify_header(core_file &fp);
+msdib_error msdib_read_bitmap(core_file &fp, bitmap_argb32 &bitmap);
+msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::uint32_t length, std::uint32_t dirheight = 0U);
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_MSDIB_H
diff --git a/src/lib/util/nanosvg.h b/src/lib/util/nanosvg.h
new file mode 100644
index 00000000000..6be55cdae32
--- /dev/null
+++ b/src/lib/util/nanosvg.h
@@ -0,0 +1,33 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ nanosvg.h
+
+ NanoSVG helpers.
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_NANOSVG_H
+#define MAME_LIB_UTIL_NANOSVG_H
+
+#include <nanosvg/src/nanosvg.h>
+#include <nanosvg/src/nanosvgrast.h>
+
+#include <memory>
+
+
+namespace util {
+
+struct nsvg_deleter
+{
+ void operator()(NSVGimage *ptr) { nsvgDelete(ptr); }
+ void operator()(NSVGrasterizer *ptr) { nsvgDeleteRasterizer(ptr); }
+};
+
+
+using nsvg_image_ptr = std::unique_ptr<NSVGimage, nsvg_deleter>;
+using nsvg_rasterizer_ptr = std::unique_ptr<NSVGrasterizer, nsvg_deleter>;
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_NANOSVG_H
diff --git a/src/lib/util/png.cpp b/src/lib/util/png.cpp
index 69835e54051..50aeb28c5fe 100644
--- a/src/lib/util/png.cpp
+++ b/src/lib/util/png.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
/*********************************************************************
- png.c
+ png.cpp
PNG reading functions.
@@ -16,34 +16,13 @@
#include <algorithm>
#include <cassert>
-#include <cstdint>
-#include <cstring>
-#include <cmath>
-#include <new>
-
#include <cmath>
#include <cstdlib>
+#include <cstring>
+#include <new>
-
-/***************************************************************************
- GLOBAL VARIABLES
-***************************************************************************/
-
-static const int samples[] = { 1, 0, 3, 1, 2, 0, 4 };
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-static inline int compute_rowbytes(const png_info &pnginfo)
-{
- return (pnginfo.width * samples[pnginfo.color_type] * pnginfo.bit_depth + 7) / 8;
-}
-
-
+namespace util {
/***************************************************************************
GENERAL FUNCTIONS
@@ -66,6 +45,12 @@ void png_info::free_data()
namespace {
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+constexpr int samples[] = { 1, 0, 3, 1, 2, 0, 4 };
+
constexpr std::uint8_t PNG_SIGNATURE[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
#define MNG_Signature "\x8A\x4D\x4E\x47\x0D\x0A\x1A\x0A"
@@ -101,6 +86,12 @@ constexpr std::uint8_t PNG_PF_Average = 3;
constexpr std::uint8_t PNG_PF_Paeth = 4;
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+inline int compute_rowbytes(const png_info &pnginfo) { return (pnginfo.width * samples[pnginfo.color_type] * pnginfo.bit_depth + 7) / 8; }
+
inline uint8_t fetch_8bit(uint8_t const *v) { return *v; }
inline uint16_t fetch_16bit(uint8_t const *v) { return big_endianize_int16(*reinterpret_cast<uint16_t const *>(v)); }
inline uint32_t fetch_32bit(uint8_t const *v) { return big_endianize_int32(*reinterpret_cast<uint32_t const *>(v)); }
@@ -132,11 +123,11 @@ private:
{
// do some basic checks for unsupported images
if (!pnginfo.bit_depth || (ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
- return PNGERR_UNSUPPORTED_FORMAT; // unknown colour format
+ return png_error::UNSUPPORTED_FORMAT; // unknown colour format
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
if ((3 == pnginfo.color_type) && (!pnginfo.num_palette || !pnginfo.palette))
- return PNGERR_FILE_CORRUPT; // indexed colour with no palette
+ return png_error::FILE_CORRUPT; // indexed colour with no palette
// calculate the offset for each pass of the interlace
unsigned const pass_count(get_pass_count());
@@ -146,13 +137,13 @@ private:
// allocate memory for the filtered image
try { pnginfo.image.reset(new std::uint8_t [pass_offset[pass_count]]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
// decompress image data
- png_error error = PNGERR_NONE;
+ png_error error = png_error::NONE;
error = decompress(idata, pass_offset[pass_count]);
std::uint32_t const bpp(get_bytes_per_pixel());
- for (unsigned pass = 0; (pass_count > pass) && (PNGERR_NONE == error); ++pass)
+ for (unsigned pass = 0; (pass_count > pass) && (png_error::NONE == error); ++pass)
{
// compute some basic parameters
std::pair<std::uint32_t, std::uint32_t> const dimensions(get_pass_dimensions(pass));
@@ -161,7 +152,7 @@ private:
// we de-filter in place, stripping the filter bytes off the rows
uint8_t *dst(&pnginfo.image[pass_offset[pass]]);
uint8_t const *src(dst);
- for (std::uint32_t y = 0; (dimensions.second > y) && (PNGERR_NONE == error); ++y)
+ for (std::uint32_t y = 0; (dimensions.second > y) && (png_error::NONE == error); ++y)
{
// first byte of each row is the filter type
uint8_t const filter(*src++);
@@ -172,7 +163,7 @@ private:
}
// if we errored, free the image data
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
pnginfo.image.reset();
return error;
@@ -182,7 +173,7 @@ private:
{
// only deflate is permitted
if (0 != pnginfo.compression_method)
- return PNGERR_DECOMPRESS_ERROR;
+ return png_error::DECOMPRESS_ERROR;
// allocate zlib stream
z_stream stream;
@@ -195,7 +186,7 @@ private:
stream.next_in = Z_NULL;
zerr = inflateInit(&stream);
if (Z_OK != zerr)
- return PNGERR_DECOMPRESS_ERROR;
+ return png_error::DECOMPRESS_ERROR;
// decompress IDAT blocks
stream.next_out = pnginfo.image.get();
@@ -217,28 +208,28 @@ private:
// it's all good if we got end-of-stream or we have with no data remaining
if ((Z_OK == inflateEnd(&stream)) && ((Z_STREAM_END == zerr) || ((Z_OK == zerr) && (idata.end() == it) && !stream.avail_in)))
- return PNGERR_NONE;
+ return png_error::NONE;
else
- return PNGERR_DECOMPRESS_ERROR;
+ return png_error::DECOMPRESS_ERROR;
}
png_error unfilter_row(std::uint8_t type, uint8_t const *src, uint8_t *dst, uint8_t const *dstprev, int bpp, std::uint32_t rowbytes)
{
if (0 != pnginfo.filter_method)
- return PNGERR_UNKNOWN_FILTER;
+ return png_error::UNKNOWN_FILTER;
switch (type)
{
case PNG_PF_None: // no filter, just copy
std::copy_n(src, rowbytes, dst);
- return PNGERR_NONE;
+ return png_error::NONE;
case PNG_PF_Sub: // SUB = previous pixel
dst = std::copy_n(src, bpp, dst);
src += bpp;
for (std::uint32_t x = bpp; rowbytes > x; ++x, ++src, ++dst)
*dst = *src + dst[-bpp];
- return PNGERR_NONE;
+ return png_error::NONE;
case PNG_PF_Up: // UP = pixel above
if (dstprev)
@@ -250,7 +241,7 @@ private:
{
std::copy_n(src, rowbytes, dst);
}
- return PNGERR_NONE;
+ return png_error::NONE;
case PNG_PF_Average: // AVERAGE = average of pixel above and previous pixel
if (dstprev)
@@ -267,7 +258,7 @@ private:
for (std::uint32_t x = bpp; rowbytes > x; ++x, ++src, ++dst)
*dst = *src + (dst[-bpp] >> 1);
}
- return PNGERR_NONE;
+ return png_error::NONE;
case PNG_PF_Paeth: // PAETH = special filter
for (std::uint32_t x = 0; rowbytes > x; ++x, ++src, ++dst)
@@ -281,10 +272,10 @@ private:
int32_t const dc(std::abs(prediction - pc));
*dst = ((da <= db) && (da <= dc)) ? (*src + pa) : (db <= dc) ? (*src + pb) : (*src + pc);
}
- return PNGERR_NONE;
+ return png_error::NONE;
default: // unknown filter type
- return PNGERR_UNKNOWN_FILTER;
+ return png_error::UNKNOWN_FILTER;
}
}
@@ -294,7 +285,7 @@ private:
{
case PNG_CN_IHDR: // image header
if (13 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.width = fetch_32bit(&data[0]);
pnginfo.height = fetch_32bit(&data[4]);
pnginfo.bit_depth = fetch_8bit(&data[8]);
@@ -307,31 +298,31 @@ private:
case PNG_CN_PLTE: // palette
pnginfo.num_palette = length / 3;
if ((length % 3) || ((3 == pnginfo.color_type) && ((1 << pnginfo.bit_depth) < pnginfo.num_palette)))
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.palette = std::move(data);
break;
case PNG_CN_tRNS: // transparency information
if (((0 == pnginfo.color_type) && (2 > length)) || ((2 == pnginfo.color_type) && (6 > length)))
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.num_trans = length;
pnginfo.trans = std::move(data);
break;
case PNG_CN_IDAT: // image data
try { idata.emplace_back(length, std::move(data)); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
break;
case PNG_CN_gAMA: // gamma
if (4 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.source_gamma = fetch_32bit(data.get()) / 100000.0;
break;
case PNG_CN_pHYs: // physical information
if (9 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.xres = fetch_32bit(&data[0]);
pnginfo.yres = fetch_32bit(&data[4]);
pnginfo.resolution_unit = fetch_8bit(&data[8]);
@@ -361,17 +352,17 @@ private:
}
catch (std::bad_alloc const &)
{
- return PNGERR_OUT_OF_MEMORY;
+ return png_error::OUT_OF_MEMORY;
}
break;
/* anything else */
default:
if ((type & 0x20000000) == 0)
- return PNGERR_UNKNOWN_CHUNK;
+ return png_error::UNKNOWN_CHUNK;
break;
}
- return PNGERR_NONE;
+ return png_error::NONE;
}
unsigned get_pass_count() const
@@ -413,23 +404,23 @@ private:
return ((samples[pnginfo.color_type] * pnginfo.bit_depth) + 7) >> 3;
}
- static png_error read_chunk(util::core_file &fp, std::unique_ptr<std::uint8_t []> &data, std::uint32_t &type, std::uint32_t &length)
+ static png_error read_chunk(core_file &fp, std::unique_ptr<std::uint8_t []> &data, std::uint32_t &type, std::uint32_t &length)
{
std::uint8_t tempbuff[4];
/* fetch the length of this chunk */
if (fp.read(tempbuff, 4) != 4)
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
length = fetch_32bit(tempbuff);
/* fetch the type of this chunk */
if (fp.read(tempbuff, 4) != 4)
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
type = fetch_32bit(tempbuff);
/* stop when we hit an IEND chunk */
if (type == PNG_CN_IEND)
- return PNGERR_NONE;
+ return png_error::NONE;
/* start the CRC with the chunk type (but not the length) */
std::uint32_t crc = crc32(0, tempbuff, 4);
@@ -439,13 +430,13 @@ private:
{
/* allocate memory for this chunk */
try { data.reset(new std::uint8_t [length]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
/* read the data from the file */
if (fp.read(data.get(), length) != length)
{
data.reset();
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
}
/* update the CRC */
@@ -456,7 +447,7 @@ private:
if (fp.read(tempbuff, 4) != 4)
{
data.reset();
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
}
std::uint32_t const chunk_crc = fetch_32bit(tempbuff);
@@ -464,10 +455,10 @@ private:
if (crc != chunk_crc)
{
data.reset();
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
}
- return PNGERR_NONE;
+ return png_error::NONE;
}
png_info & pnginfo;
@@ -481,13 +472,13 @@ public:
{
// do some basic checks for unsupported images
if ((8 > pnginfo.bit_depth) || (pnginfo.bit_depth % 8))
- return PNGERR_UNSUPPORTED_FORMAT; // only do multiples of 8bps here - expand lower bit depth first
+ return png_error::UNSUPPORTED_FORMAT; // only do multiples of 8bps here - expand lower bit depth first
if ((ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
- return PNGERR_UNSUPPORTED_FORMAT; // unknown colour sample format
+ return png_error::UNSUPPORTED_FORMAT; // unknown colour sample format
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
if ((3 == pnginfo.color_type) && (8 != pnginfo.bit_depth))
- return PNGERR_UNSUPPORTED_FORMAT; // indexed colour must be exactly 8bpp
+ return png_error::UNSUPPORTED_FORMAT; // indexed colour must be exactly 8bpp
// everything looks sane, allocate the bitmap and deinterlace into it
bitmap.allocate(pnginfo.width, pnginfo.height);
@@ -603,22 +594,22 @@ public:
// set hasalpha flag and return
hasalpha = 0xffU != accumalpha;
- return PNGERR_NONE;
+ return png_error::NONE;
}
png_error expand_buffer_8bit()
{
// nothing to do if we're at 8 or greater already
if (pnginfo.bit_depth >= 8)
- return PNGERR_NONE;
+ return png_error::NONE;
// do some basic checks for unsupported images
if (!pnginfo.bit_depth || (8 % pnginfo.bit_depth))
- return PNGERR_UNSUPPORTED_FORMAT; // bit depth must be a factor of eight
+ return png_error::UNSUPPORTED_FORMAT; // bit depth must be a factor of eight
if ((0 != pnginfo.color_type) && (3 != pnginfo.color_type))
- return PNGERR_UNSUPPORTED_FORMAT; // only upsample monochrome and indexed colour
+ return png_error::UNSUPPORTED_FORMAT; // only upsample monochrome and indexed colour
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
// calculate the offset for each pass of the interlace on the input and output
unsigned const pass_count(get_pass_count());
@@ -633,7 +624,7 @@ public:
// allocate a new buffer at 8-bit
std::unique_ptr<std::uint8_t []> outbuf;
try { outbuf.reset(new std::uint8_t [outp_offset[pass_count]]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
// upsample bitmap
std::uint8_t const bytesamples(8 / pnginfo.bit_depth);
@@ -687,13 +678,13 @@ public:
pnginfo.image = std::move(outbuf);
pnginfo.bit_depth = 8;
- return PNGERR_NONE;
+ return png_error::NONE;
}
- png_error read_file(util::core_file &fp)
+ png_error read_file(core_file &fp)
{
// initialize the data structures
- png_error error = PNGERR_NONE;
+ png_error error = png_error::NONE;
pnginfo.reset();
std::list<image_data_chunk> idata;
@@ -701,13 +692,13 @@ public:
error = verify_header(fp);
// loop until we hit an IEND chunk
- while (PNGERR_NONE == error)
+ while (png_error::NONE == error)
{
// read a chunk
std::unique_ptr<std::uint8_t []> chunk_data;
std::uint32_t chunk_type = 0, chunk_length;
error = read_chunk(fp, chunk_data, chunk_type, chunk_length);
- if (PNGERR_NONE == error)
+ if (png_error::NONE == error)
{
if (chunk_type == PNG_CN_IEND)
break; // stop when we hit an IEND chunk
@@ -717,29 +708,29 @@ public:
}
// finish processing the image
- if (PNGERR_NONE == error)
+ if (png_error::NONE == error)
error = process(idata);
// if we have an error, free all the output data
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
pnginfo.reset();
return error;
}
- static png_error verify_header(util::core_file &fp)
+ static png_error verify_header(core_file &fp)
{
EQUIVALENT_ARRAY(PNG_SIGNATURE, std::uint8_t) signature;
// read 8 bytes
if (fp.read(signature, sizeof(signature)) != sizeof(signature))
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
// return an error if we don't match
if (std::memcmp(signature, PNG_SIGNATURE, sizeof(PNG_SIGNATURE)))
- return PNGERR_BAD_SIGNATURE;
+ return png_error::BAD_SIGNATURE;
- return PNGERR_NONE;
+ return png_error::NONE;
}
};
@@ -760,7 +751,7 @@ constexpr unsigned png_private::ADAM7_Y_OFFS[7];
core stream
-------------------------------------------------*/
-png_error png_info::verify_header(util::core_file &fp)
+png_error png_info::verify_header(core_file &fp)
{
return png_private::verify_header(fp);
}
@@ -770,7 +761,7 @@ png_error png_info::verify_header(util::core_file &fp)
read_file - read a PNG from a core stream
-------------------------------------------------*/
-png_error png_info::read_file(util::core_file &fp)
+png_error png_info::read_file(core_file &fp)
{
return png_private(*this).read_file(fp);
}
@@ -781,7 +772,7 @@ png_error png_info::read_file(util::core_file &fp)
bitmap
-------------------------------------------------*/
-png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap)
+png_error png_read_bitmap(core_file &fp, bitmap_argb32 &bitmap)
{
png_error result;
png_info pnginfo;
@@ -789,12 +780,12 @@ png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap)
// read the PNG data
result = png.read_file(fp);
- if (PNGERR_NONE != result)
+ if (png_error::NONE != result)
return result;
// resample to 8bpp if necessary
result = png.expand_buffer_8bit();
- if (PNGERR_NONE != result)
+ if (png_error::NONE != result)
{
pnginfo.free_data();
return result;
@@ -848,13 +839,13 @@ png_error png_info::add_text(const char *keyword, const char *text)
char32_t ch;
int const len(uchar_from_utf8(&ch, ptr, kwend - ptr));
if ((0 >= len) || (32 > ch) || (255 < ch) || ((126 < ch) && (161 > ch)) || (((32 == prev) || (keyword == ptr)) && (32 == ch)))
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
prev = ch;
++cnt;
ptr += len;
}
if ((32 == prev) || (1 > cnt) || (79 < cnt))
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
// apply rules to text
char const *const textend(text + std::strlen(text));
@@ -863,14 +854,14 @@ png_error png_info::add_text(const char *keyword, const char *text)
char32_t ch;
int const len(uchar_from_utf8(&ch, ptr, textend - ptr));
if ((0 >= len) || (1 > ch) || (255 < ch))
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
ptr += len;
}
// allocate a new text element
try { textlist.emplace_back(std::piecewise_construct, std::forward_as_tuple(keyword, kwend), std::forward_as_tuple(text, textend)); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
- return PNGERR_NONE;
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
+ return png_error::NONE;
}
@@ -879,7 +870,7 @@ png_error png_info::add_text(const char *keyword, const char *text)
the given file
-------------------------------------------------*/
-static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t type, uint32_t length)
+static png_error write_chunk(core_file &fp, const uint8_t *data, uint32_t type, uint32_t length)
{
uint8_t tempbuff[8];
uint32_t crc;
@@ -891,22 +882,22 @@ static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t
/* write that data */
if (fp.write(tempbuff, 8) != 8)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* append the actual data */
if (length > 0)
{
if (fp.write(data, length) != length)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
crc = crc32(crc, data, length);
}
/* write the CRC */
put_32bit(tempbuff, crc);
if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
- return PNGERR_NONE;
+ return png_error::NONE;
}
@@ -915,7 +906,7 @@ static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t
chunk to the given file by deflating it
-------------------------------------------------*/
-static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32_t type, uint32_t length)
+static png_error write_deflated_chunk(core_file &fp, uint8_t *data, uint32_t type, uint32_t length)
{
uint64_t lengthpos = fp.tell();
uint8_t tempbuff[8192];
@@ -931,7 +922,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
/* write that data */
if (fp.write(tempbuff, 8) != 8)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* initialize the stream */
memset(&stream, 0, sizeof(stream));
@@ -939,7 +930,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
stream.avail_in = length;
zerr = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
if (zerr != Z_OK)
- return PNGERR_COMPRESS_ERROR;
+ return png_error::COMPRESS_ERROR;
/* now loop until we run out of data */
for ( ; ; )
@@ -956,7 +947,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
if (fp.write(tempbuff, bytes) != bytes)
{
deflateEnd(&stream);
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
}
crc = crc32(crc, tempbuff, bytes);
zlength += bytes;
@@ -970,29 +961,29 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
if (zerr != Z_OK)
{
deflateEnd(&stream);
- return PNGERR_COMPRESS_ERROR;
+ return png_error::COMPRESS_ERROR;
}
}
/* clean up deflater(maus) */
zerr = deflateEnd(&stream);
if (zerr != Z_OK)
- return PNGERR_COMPRESS_ERROR;
+ return png_error::COMPRESS_ERROR;
/* write the CRC */
put_32bit(tempbuff, crc);
if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* seek back and update the length */
fp.seek(lengthpos, SEEK_SET);
put_32bit(tempbuff + 0, zlength);
if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* return to the end */
fp.seek(lengthpos + 8 + zlength + 4, SEEK_SET);
- return PNGERR_NONE;
+ return png_error::NONE;
}
@@ -1016,7 +1007,7 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap
/* allocate memory for the palette */
try { pnginfo.palette.reset(new std::uint8_t [3 * 256]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
/* build the palette */
std::fill_n(pnginfo.palette.get(), 3 * 256, 0);
@@ -1036,7 +1027,7 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap
catch (std::bad_alloc const &)
{
pnginfo.palette.reset();
- return PNGERR_OUT_OF_MEMORY;
+ return png_error::OUT_OF_MEMORY;
}
/* copy in the pixels, specifying a nullptr filter */
@@ -1051,7 +1042,7 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap
*dst++ = *src++;
}
- return PNGERR_NONE;
+ return png_error::NONE;
}
@@ -1075,7 +1066,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
/* allocate memory for the image */
try { pnginfo.image.reset(new std::uint8_t [pnginfo.height * (rowbytes + 1)]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
/* copy in the pixels, specifying a nullptr filter */
for (y = 0; y < pnginfo.height; y++)
@@ -1127,10 +1118,10 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
/* unsupported format */
else
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
}
- return PNGERR_NONE;
+ return png_error::NONE;
}
@@ -1139,7 +1130,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
chunks to the given file
-------------------------------------------------*/
-static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+static png_error write_png_stream(core_file &fp, png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
{
uint8_t tempbuff[16];
png_error error;
@@ -1149,7 +1140,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
error = convert_bitmap_to_image_palette(pnginfo, bitmap, palette_length, palette);
else
error = convert_bitmap_to_image_rgb(pnginfo, bitmap, palette_length, palette);
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
// if we wanted to get clever and do filtering, we would do it here
@@ -1163,18 +1154,18 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
put_8bit(tempbuff + 11, pnginfo.filter_method);
put_8bit(tempbuff + 12, pnginfo.interlace_method);
error = write_chunk(fp, tempbuff, PNG_CN_IHDR, 13);
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
// write the PLTE chunk
if (pnginfo.num_palette > 0)
error = write_chunk(fp, pnginfo.palette.get(), PNG_CN_PLTE, pnginfo.num_palette * 3);
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
- // write a single IDAT chunk */
+ // write a single IDAT chunk
error = write_deflated_chunk(fp, pnginfo.image.get(), PNG_CN_IDAT, pnginfo.height * (compute_rowbytes(pnginfo) + 1));
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
// write TEXT chunks
@@ -1182,7 +1173,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
for (png_info::png_text const &text : pnginfo.textlist)
{
try { textbuf.resize(text.first.length() + 1 + text.second.length()); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
std::uint8_t *dst(&textbuf[0]);
// convert keyword to ISO-8859-1
@@ -1213,7 +1204,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
}
error = write_chunk(fp, &textbuf[0], PNG_CN_tEXt, dst - &textbuf[0]);
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
}
@@ -1222,7 +1213,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
}
-png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
+png_error png_write_bitmap(core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
{
// use a dummy pnginfo if none passed to us
png_info pnginfo;
@@ -1231,7 +1222,7 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &
// write the PNG signature
if (fp.write(PNG_SIGNATURE, sizeof(PNG_SIGNATURE)) != sizeof(PNG_SIGNATURE))
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* write the rest of the PNG data */
return write_png_stream(fp, *info, bitmap, palette_length, palette);
@@ -1246,7 +1237,7 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &
********************************************************************************/
/**
- * @fn png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate)
+ * @fn png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate)
*
* @brief Mng capture start.
*
@@ -1257,12 +1248,12 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &
* @return A png_error.
*/
-png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate)
+png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate)
{
uint8_t mhdr[28];
if (fp.write(MNG_Signature, 8) != 8)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
memset(mhdr, 0, 28);
put_32bit(mhdr + 0, bitmap.width());
@@ -1273,7 +1264,7 @@ png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate
}
/**
- * @fn png_error mng_capture_frame(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+ * @fn png_error mng_capture_frame(core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
*
* @brief Mng capture frame.
*
@@ -1286,13 +1277,13 @@ png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate
* @return A png_error.
*/
-png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
+png_error mng_capture_frame(core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
{
return write_png_stream(fp, info, bitmap, palette_length, palette);
}
/**
- * @fn png_error mng_capture_stop(util::core_file &fp)
+ * @fn png_error mng_capture_stop(core_file &fp)
*
* @brief Mng capture stop.
*
@@ -1301,7 +1292,9 @@ png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const
* @return A png_error.
*/
-png_error mng_capture_stop(util::core_file &fp)
+png_error mng_capture_stop(core_file &fp)
{
return write_chunk(fp, nullptr, MNG_CN_MEND, 0);
}
+
+} // namespace util
diff --git a/src/lib/util/png.h b/src/lib/util/png.h
index 5f852fd8c16..784c92646e6 100644
--- a/src/lib/util/png.h
+++ b/src/lib/util/png.h
@@ -17,31 +17,33 @@
#include "corefile.h"
#include "osdcore.h"
+#include <cstdint>
#include <list>
#include <memory>
#include <string>
#include <utility>
+namespace util {
/***************************************************************************
CONSTANTS
***************************************************************************/
/* Error types */
-enum png_error
+enum class png_error
{
- PNGERR_NONE,
- PNGERR_OUT_OF_MEMORY,
- PNGERR_UNKNOWN_FILTER,
- PNGERR_FILE_ERROR,
- PNGERR_BAD_SIGNATURE,
- PNGERR_DECOMPRESS_ERROR,
- PNGERR_FILE_TRUNCATED,
- PNGERR_FILE_CORRUPT,
- PNGERR_UNKNOWN_CHUNK,
- PNGERR_COMPRESS_ERROR,
- PNGERR_UNSUPPORTED_FORMAT
+ NONE,
+ OUT_OF_MEMORY,
+ UNKNOWN_FILTER,
+ FILE_ERROR,
+ BAD_SIGNATURE,
+ DECOMPRESS_ERROR,
+ FILE_TRUNCATED,
+ FILE_CORRUPT,
+ UNKNOWN_CHUNK,
+ COMPRESS_ERROR,
+ UNSUPPORTED_FORMAT
};
@@ -57,7 +59,7 @@ public:
~png_info() { free_data(); }
- png_error read_file(util::core_file &fp);
+ png_error read_file(core_file &fp);
png_error copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha);
png_error expand_buffer_8bit();
@@ -66,7 +68,7 @@ public:
void free_data();
void reset() { free_data(); operator=(png_info()); }
- static png_error verify_header(util::core_file &fp);
+ static png_error verify_header(core_file &fp);
std::unique_ptr<std::uint8_t []> image;
std::uint32_t width, height;
@@ -99,12 +101,14 @@ private:
FUNCTION PROTOTYPES
***************************************************************************/
-png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap);
+png_error png_read_bitmap(core_file &fp, bitmap_argb32 &bitmap);
-png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette);
+png_error png_write_bitmap(core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette);
-png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate);
-png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette);
-png_error mng_capture_stop(util::core_file &fp);
+png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate);
+png_error mng_capture_frame(core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette);
+png_error mng_capture_stop(core_file &fp);
+
+} // namespace util
#endif // MAME_LIB_UTIL_PNG_H
diff --git a/src/mame/drivers/alg.cpp b/src/mame/drivers/alg.cpp
index 73189abc79e..9e42a1ce7e5 100644
--- a/src/mame/drivers/alg.cpp
+++ b/src/mame/drivers/alg.cpp
@@ -30,7 +30,6 @@
#include "machine/ldp1450.h"
#include "machine/nvram.h"
#include "machine/amigafdc.h"
-#include "render.h"
#include "speaker.h"
diff --git a/src/mame/drivers/by17.cpp b/src/mame/drivers/by17.cpp
index b8832806c8d..33074d0e79b 100644
--- a/src/mame/drivers/by17.cpp
+++ b/src/mame/drivers/by17.cpp
@@ -26,7 +26,6 @@ ToDo:
#include "by17.lh"
#include "by17_pwerplay.lh"
#include "by17_matahari.lh"
-#include "render.h"
class by17_state : public genpin_class
{
@@ -980,10 +979,6 @@ void by17_state::machine_reset()
{
genpin_class::machine_reset();
- render_target *target = machine().render().first_target();
-
- target->set_view(0);
-
m_u10a = 0;
m_u10b = 0;
m_u11a = 0;
diff --git a/src/mame/drivers/by35.cpp b/src/mame/drivers/by35.cpp
index e4f3aab38a6..70d15834ce1 100644
--- a/src/mame/drivers/by35.cpp
+++ b/src/mame/drivers/by35.cpp
@@ -73,7 +73,6 @@ ToDo:
#include "machine/6821pia.h"
#include "machine/timer.h"
#include "audio/bally.h"
-#include "render.h"
#include "speaker.h"
//#define VERBOSE 1
@@ -1441,10 +1440,6 @@ void by35_state::machine_reset()
{
genpin_class::machine_reset();
- render_target *target = machine().render().first_target();
-
- target->set_view(0);
-
m_u10a = 0;
m_u10b = 0;
m_u11a = 0;
diff --git a/src/mame/drivers/cliffhgr.cpp b/src/mame/drivers/cliffhgr.cpp
index 3761c0548b7..339866ab13c 100644
--- a/src/mame/drivers/cliffhgr.cpp
+++ b/src/mame/drivers/cliffhgr.cpp
@@ -83,7 +83,6 @@ Side 2 = 0x8F7DDD (or 0x880000 | ( 0x77 << 12 ) | 0x0DDD)
#include "video/tms9928a.h"
#include "machine/nvram.h"
-#include "render.h"
#include "speaker.h"
diff --git a/src/mame/drivers/decwritr.cpp b/src/mame/drivers/decwritr.cpp
index b5b32b2ee71..84133c2e05c 100644
--- a/src/mame/drivers/decwritr.cpp
+++ b/src/mame/drivers/decwritr.cpp
@@ -19,7 +19,7 @@
#include "machine/i8251.h"
#include "machine/input_merger.h"
#include "sound/beep.h"
-#include "render.h"
+#include "screen.h"
#include "speaker.h"
diff --git a/src/mame/drivers/dlair.cpp b/src/mame/drivers/dlair.cpp
index b914c58b35c..496ad516322 100644
--- a/src/mame/drivers/dlair.cpp
+++ b/src/mame/drivers/dlair.cpp
@@ -46,7 +46,6 @@
#include "sound/ay8910.h"
#include "sound/spkrdev.h"
#include "emupal.h"
-#include "render.h"
#include "speaker.h"
#include "dlair.lh"
diff --git a/src/mame/drivers/istellar.cpp b/src/mame/drivers/istellar.cpp
index 687be6f0e79..1f546d3be55 100644
--- a/src/mame/drivers/istellar.cpp
+++ b/src/mame/drivers/istellar.cpp
@@ -26,7 +26,6 @@ Todo:
#include "machine/gen_latch.h"
#include "machine/ldv1000.h"
#include "emupal.h"
-#include "render.h"
#include "speaker.h"
diff --git a/src/mame/drivers/lgp.cpp b/src/mame/drivers/lgp.cpp
index 67bc14514f8..9b76c5469de 100644
--- a/src/mame/drivers/lgp.cpp
+++ b/src/mame/drivers/lgp.cpp
@@ -69,7 +69,6 @@ Dumping Notes:
#include "cpu/z80/z80.h"
#include "machine/ldv1000.h"
#include "emupal.h"
-#include "render.h"
#include "speaker.h"
diff --git a/src/mame/layout/unkeinv.lay b/src/mame/layout/unkeinv.lay
index 12b42eef798..b5fde8e2ac8 100644
--- a/src/mame/layout/unkeinv.lay
+++ b/src/mame/layout/unkeinv.lay
@@ -6,24 +6,6 @@ license:CC0
<!-- define elements -->
- <element name="black"><rect><color red="0" green="0" blue="0" /></rect></element>
-
- <element name="wandl">
- <rect>
- <bounds x="0" y="0" width="18" height="1" />
- <color red="0" green="0" blue="0" />
- </rect>
- <disk>
- <bounds state="0" x="0" y="0" width="1" height="1" />
- <bounds state="11" x="16.5" y="0" width="1" height="1" />
- <color red="1.0" green="0.2" blue="0.23" />
- </disk>
- </element>
- <element name="wandm" defstate="0">
- <rect state="0"><color red="0.1" green="0.1" blue="0.1" /></rect>
- <rect state="1"><color red="1.0" green="1.0" blue="1.0" /></rect>
- </element>
-
<element name="ledy" defstate="0">
<disk state="0"><color red="0.07" green="0.06" blue="0.02" /></disk>
<disk state="1"><color red="1.0" green="0.95" blue="0.2" /></disk>
@@ -32,6 +14,11 @@ license:CC0
<disk state="0"><color red="0.023" green="0.1" blue="0.02" /></disk>
<disk state="1"><color red="0.23" green="1.0" blue="0.2" /></disk>
</element>
+ <element name="ledr" defstate="0">
+ <disk state="0"><color red="0.1" green="0.02" blue="0.023" /></disk>
+ <disk state="1"><color red="1.0" green="0.2" blue="0.23" /></disk>
+ </element>
+
<!-- build screen -->
@@ -41,21 +28,24 @@ license:CC0
<!-- wand -->
- <repeat count="9">
+ <repeat count="4">
<param name="y" start="1" increment="3" />
- <element ref="black" inputtag="IN.1" inputmask="0x00" inputraw="yes"><bounds x="0" y="~y~" width="18" height="1" /></element>
- <element ref="wandl" inputtag="IN.1" inputmask="0x0f" inputraw="yes"><bounds x="0" y="~y~" width="18" height="1" /></element>
+ <param name="n" start="0" increment="1" />
+ <element ref="ledr" name="~n~.7">
+ <animate inputtag="IN.1" mask="0x0f" />
+ <bounds state="0" x="0" y="~y~" width="1" height="1" />
+ <bounds state="11" x="16.5" y="~y~" width="1" height="1" />
+ </element>
+ </repeat>
+ <repeat count="5">
+ <param name="y" start="13" increment="3" />
+ <param name="n" start="0" increment="1" />
+ <element ref="ledr" name="~n~.6">
+ <animate inputtag="IN.1" mask="0x0f" />
+ <bounds state="0" x="0" y="~y~" width="1" height="1" />
+ <bounds state="11" x="16.5" y="~y~" width="1" height="1" />
+ </element>
</repeat>
-
- <element name="0.7" ref="wandm" blend="multiply"><bounds x="-0.5" y="0.5" width="19" height="2" /></element>
- <element name="1.7" ref="wandm" blend="multiply"><bounds x="-0.5" y="3.5" width="19" height="2" /></element>
- <element name="2.7" ref="wandm" blend="multiply"><bounds x="-0.5" y="6.5" width="19" height="2" /></element>
- <element name="3.7" ref="wandm" blend="multiply"><bounds x="-0.5" y="9.5" width="19" height="2" /></element>
- <element name="0.6" ref="wandm" blend="multiply"><bounds x="-0.5" y="12.5" width="19" height="2" /></element>
- <element name="1.6" ref="wandm" blend="multiply"><bounds x="-0.5" y="15.5" width="19" height="2" /></element>
- <element name="2.6" ref="wandm" blend="multiply"><bounds x="-0.5" y="18.5" width="19" height="2" /></element>
- <element name="3.6" ref="wandm" blend="multiply"><bounds x="-0.5" y="21.5" width="19" height="2" /></element>
- <element name="4.6" ref="wandm" blend="multiply"><bounds x="-0.5" y="24.5" width="19" height="2" /></element>
<!-- invaders -->
diff --git a/src/mame/video/midtunit.cpp b/src/mame/video/midtunit.cpp
index 94594884e38..4a74af2b188 100644
--- a/src/mame/video/midtunit.cpp
+++ b/src/mame/video/midtunit.cpp
@@ -1018,7 +1018,7 @@ void midtunit_video_device::log_bitmap(int command, int bpp, bool Skip)
}
}
- png_write_bitmap(file, nullptr, m_log_bitmap, 0, nullptr);
+ util::png_write_bitmap(file, nullptr, m_log_bitmap, 0, nullptr);
if (m_log_json)
{
diff --git a/src/mame/video/ssv.cpp b/src/mame/video/ssv.cpp
index 47f9f031654..c8629284845 100644
--- a/src/mame/video/ssv.cpp
+++ b/src/mame/video/ssv.cpp
@@ -135,7 +135,6 @@
#include "emu.h"
#include "includes/ssv.h"
-#include "render.h"
void ssv_state::drawgfx_line(bitmap_ind16 &bitmap, const rectangle &cliprect, int gfx, uint32_t code, uint32_t color, int flipx, int flipy, int base_sx, int base_sy, int shadow, int realline, int line)
diff --git a/src/mame/video/st0020.cpp b/src/mame/video/st0020.cpp
index 6702174635a..f378dbbc302 100644
--- a/src/mame/video/st0020.cpp
+++ b/src/mame/video/st0020.cpp
@@ -16,7 +16,9 @@
#include "emu.h"
#include "st0020.h"
-#include "render.h"
+
+#include "screen.h"
+
DEFINE_DEVICE_TYPE(ST0020_SPRITES, st0020_device, "st0020", "Seta ST0020 Sprites")
diff --git a/src/mame/video/tx1.cpp b/src/mame/video/tx1.cpp
index 306da618218..08b74e80462 100644
--- a/src/mame/video/tx1.cpp
+++ b/src/mame/video/tx1.cpp
@@ -7,10 +7,10 @@
****************************************************************************/
#include "emu.h"
-#include "render.h"
+#include "includes/tx1.h"
+
#include "video/resnet.h"
#include "cpu/i86/i86.h"
-#include "includes/tx1.h"
#define OBJ_FRAC 16
diff --git a/src/osd/modules/render/bgfx/texturemanager.cpp b/src/osd/modules/render/bgfx/texturemanager.cpp
index a03a6b46125..d539d1aae46 100644
--- a/src/osd/modules/render/bgfx/texturemanager.cpp
+++ b/src/osd/modules/render/bgfx/texturemanager.cpp
@@ -59,7 +59,11 @@ bgfx_texture* texture_manager::create_png_texture(std::string path, std::string
{
bitmap_argb32 bitmap;
emu_file file(path.c_str(), OPEN_FLAG_READ);
- render_load_png(bitmap, file, nullptr, file_name.c_str());
+ if (file.open(file_name) == osd_file::error::NONE)
+ {
+ render_load_png(bitmap, file);
+ file.close();
+ }
if (bitmap.width() == 0 || bitmap.height() == 0)
{
diff --git a/src/osd/modules/render/d3d/d3dhlsl.cpp b/src/osd/modules/render/d3d/d3dhlsl.cpp
index e19f8882232..57ab4943adb 100644
--- a/src/osd/modules/render/d3d/d3dhlsl.cpp
+++ b/src/osd/modules/render/d3d/d3dhlsl.cpp
@@ -359,14 +359,14 @@ void shaders::render_snapshot(IDirect3DSurface9 *surface)
// add two text entries describing the image
std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version());
std::string text2 = std::string(machine->system().manufacturer).append(" ").append(machine->system().type.fullname());
- png_info pnginfo;
+ util::png_info pnginfo;
pnginfo.add_text("Software", text1.c_str());
pnginfo.add_text("System", text2.c_str());
// now do the actual work
- png_error error = png_write_bitmap(file, &pnginfo, snapshot, 1 << 24, nullptr);
- if (error != PNGERR_NONE)
- osd_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", error);
+ util::png_error error = util::png_write_bitmap(file, &pnginfo, snapshot, 1 << 24, nullptr);
+ if (error != util::png_error::NONE)
+ osd_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", std::underlying_type_t<util::png_error>(error));
result = snap_copy_target->UnlockRect();
if (FAILED(result))
@@ -721,7 +721,11 @@ int shaders::create_resources()
osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call\n", result);
emu_file file(machine->options().art_path(), OPEN_FLAG_READ);
- render_load_png(shadow_bitmap, file, nullptr, options->shadow_mask_texture);
+ if (file.open(options->shadow_mask_texture) == osd_file::error::NONE)
+ {
+ render_load_png(shadow_bitmap, file);
+ file.close();
+ }
// experimental: if we have a shadow bitmap, create a texture for it
if (shadow_bitmap.valid())
@@ -742,7 +746,11 @@ int shaders::create_resources()
d3d->get_texture_manager()->m_texture_list.push_back(std::move(tex));
}
- render_load_png(lut_bitmap, file, nullptr, options->lut_texture);
+ if (file.open(options->lut_texture) == osd_file::error::NONE)
+ {
+ render_load_png(lut_bitmap, file);
+ file.close();
+ }
if (lut_bitmap.valid())
{
render_texinfo texture;
@@ -761,7 +769,11 @@ int shaders::create_resources()
d3d->get_texture_manager()->m_texture_list.push_back(std::move(tex));
}
- render_load_png(ui_lut_bitmap, file, nullptr, options->ui_lut_texture);
+ if (file.open(options->ui_lut_texture) == osd_file::error::NONE)
+ {
+ render_load_png(ui_lut_bitmap, file);
+ file.close();
+ }
if (ui_lut_bitmap.valid())
{
render_texinfo texture;
diff --git a/src/tools/pngcmp.cpp b/src/tools/pngcmp.cpp
index e490d1c6811..714700a3824 100644
--- a/src/tools/pngcmp.cpp
+++ b/src/tools/pngcmp.cpp
@@ -74,7 +74,7 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img
int width, height, maxwidth;
util::core_file::ptr file;
osd_file::error filerr;
- png_error pngerr;
+ util::png_error pngerr;
int error = 100;
/* open the source image */
@@ -86,11 +86,11 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img
}
/* load the source image */
- pngerr = png_read_bitmap(*file, bitmap1);
+ pngerr = util::png_read_bitmap(*file, bitmap1);
file.reset();
- if (pngerr != PNGERR_NONE)
+ if (pngerr != util::png_error::NONE)
{
- printf("Could not read %s (%d)\n", imgfile1.c_str(), pngerr);
+ printf("Could not read %s (%d)\n", imgfile1.c_str(), int(pngerr));
goto error;
}
@@ -103,11 +103,11 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img
}
/* load the source image */
- pngerr = png_read_bitmap(*file, bitmap2);
+ pngerr = util::png_read_bitmap(*file, bitmap2);
file.reset();
- if (pngerr != PNGERR_NONE)
+ if (pngerr != util::png_error::NONE)
{
- printf("Could not read %s (%d)\n", imgfile2.c_str(), pngerr);
+ printf("Could not read %s (%d)\n", imgfile2.c_str(), int(pngerr));
goto error;
}
@@ -176,11 +176,11 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img
printf("Could not open %s (%d)\n", outfilename.c_str(), int(filerr));
goto error;
}
- pngerr = png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr);
+ pngerr = util::png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr);
file.reset();
- if (pngerr != PNGERR_NONE)
+ if (pngerr != util::png_error::NONE)
{
- printf("Could not write %s (%d)\n", outfilename.c_str(), pngerr);
+ printf("Could not write %s (%d)\n", outfilename.c_str(), int(pngerr));
goto error;
}
}
diff --git a/src/tools/regrep.cpp b/src/tools/regrep.cpp
index 5bebc733197..49637c2eb16 100644
--- a/src/tools/regrep.cpp
+++ b/src/tools/regrep.cpp
@@ -748,7 +748,7 @@ static int compare_screenshots(summary_file *curfile)
/* if that worked, load the file */
if (filerr == osd_file::error::NONE)
{
- png_read_bitmap(*file, bitmaps[listnum]);
+ util::png_read_bitmap(*file, bitmaps[listnum]);
file.reset();
}
}
@@ -835,7 +835,7 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir,
int bitmapcount = 0;
util::core_file::ptr file;
osd_file::error filerr;
- png_error pngerr;
+ util::png_error pngerr;
int error = -1;
int starty;
@@ -855,9 +855,9 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir,
goto error;
/* load the source image */
- pngerr = png_read_bitmap(*file, bitmaps[bitmapcount++]);
+ pngerr = util::png_read_bitmap(*file, bitmaps[bitmapcount++]);
file.reset();
- if (pngerr != PNGERR_NONE)
+ if (pngerr != util::png_error::NONE)
goto error;
}
@@ -924,9 +924,9 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir,
filerr = util::core_file::open(dstfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
if (filerr != osd_file::error::NONE)
goto error;
- pngerr = png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr);
+ pngerr = util::png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr);
file.reset();
- if (pngerr != PNGERR_NONE)
+ if (pngerr != util::png_error::NONE)
goto error;
/* if we get here, we are error free */