diff options
| author | 2017-08-12 02:43:53 +1000 | |
|---|---|---|
| committer | 2017-08-12 02:43:53 +1000 | |
| commit | a7b15fc928ea5713bd19b68d9992de6c3b93be51 (patch) | |
| tree | 2b0a124cfb367c6a0d2bdb3fae12df8934362a21 /src/emu/rendutil.cpp | |
| parent | ac6762603cb1f482eeeb425b2bf6f29dcadbbd86 (diff) | |
add minimal support for reading Adam7 interlaced PNG
(nw) This is the path of least resistance, and I plan to fix it up
later, I just wanted to get it to actually work first. Decompression
and unfiltering is fully supported, at least for all the pixel formats
that previously worked. Expanding 1/2/4bpp to 8bpp should work
properly, too. Bitmap mapping for Adam7 is only implemented in
rendutil.cpp which is whate everything in MAME uses. The function in
png.cpp (used by pngcmp) has not been updated. At some point I'll unify
at least one of the functions in rendutil.cpp with the one in png.cpp
and we can go from three functions that need to do the mapping down to
two at the most.
Diffstat (limited to 'src/emu/rendutil.cpp')
| -rw-r--r-- | src/emu/rendutil.cpp | 242 |
1 files changed, 146 insertions, 96 deletions
diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp index 015a08e4e11..f35332436fb 100644 --- a/src/emu/rendutil.cpp +++ b/src/emu/rendutil.cpp @@ -655,7 +655,7 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, png_free(&png); return false; } - if (png.interlace_method != 0) + if (png.interlace_method != 0 && png.interlace_method != 1) { osd_printf_error("%s: Interlace unsupported\n", filename); png_free(&png); @@ -696,59 +696,86 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, static bool copy_png_to_bitmap(bitmap_argb32 &bitmap, const 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; - u8 *src; - int x, y; - /* handle 8bpp palettized case */ - if (png->color_type == 3) - { - /* loop over width/height */ - src = png->image; - for (y = 0; y < png->height; y++) - for (x = 0; x < png->width; x++, src++) - { - /* determine alpha and expand to 32bpp */ - u8 alpha = (*src < png->num_trans) ? png->trans[*src] : 0xff; - accumalpha &= alpha; - bitmap.pix32(y, x) = rgb_t(alpha, png->palette[*src * 3], png->palette[*src * 3 + 1], png->palette[*src * 3 + 2]); - } - } + // colour format table + static constexpr unsigned samples[] = { 1, 0, 3, 1, 2, 0, 4 }; - /* handle 8bpp grayscale case */ - else if (png->color_type == 0) - { - /* loop over width/height */ - src = png->image; - for (y = 0; y < png->height; y++) - for (x = 0; x < png->width; x++, src++) - bitmap.pix32(y, x) = rgb_t(0xff, *src, *src, *src); - } - - /* handle 32bpp non-alpha case */ - else if (png->color_type == 2) - { - /* loop over width/height */ - src = png->image; - for (y = 0; y < png->height; y++) - for (x = 0; x < png->width; x++, src += 3) - bitmap.pix32(y, x) = rgb_t(0xff, src[0], src[1], src[2]); - } + // adam7 interlace tables + static constexpr unsigned x_bias[7] = { 7, 3, 3, 1, 1, 0, 0 }; + static constexpr unsigned y_bias[7] = { 7, 7, 3, 3, 1, 1, 0 }; + static constexpr unsigned x_shift[7] = { 3, 3, 2, 2, 1, 1, 0 }; + static constexpr unsigned y_shift[7] = { 3, 3, 3, 2, 2, 1, 1 }; - /* handle 32bpp alpha case */ - else + unsigned const pass_count(png->interlace_method ? 7 : 1); + u32 pass_offset[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + for (unsigned pass = 0; pass_count > pass; ++pass) { - /* loop over width/height */ - src = png->image; - for (y = 0; y < png->height; y++) - for (x = 0; x < png->width; x++, src += 4) + // calculate offset for next interlace pass + u32 const width(png->interlace_method ? ((png->width + x_bias[pass]) >> x_shift[pass]) : png->width); + u32 const height(png->interlace_method ? ((png->height + y_bias[pass]) >> y_shift[pass]) : png->height); + u32 const rowbytes(((width * samples[png->color_type] * png->bit_depth) + 7) >> 3); + pass_offset[pass + 1] = pass_offset[pass] + (height * (rowbytes + 1)); + u8 const *src(png->image + pass_offset[pass]); + auto const x_trans = [offs = (1 << x_shift[pass]) - x_bias[pass] - 1, shift = x_shift[pass]] (u32 x) { return (x << shift) + offs; }; + auto const y_trans = [offs = (1 << y_shift[pass]) - y_bias[pass] - 1, shift = y_shift[pass]] (u32 y) { return (y << shift) + offs; }; + + if (png->color_type == 3) + { + // handle 8bpp palettized case + for (u32 y = 0; height > y; ++y) { - accumalpha &= src[3]; - bitmap.pix32(y, x) = rgb_t(src[3], src[0], src[1], src[2]); + for (u32 x = 0; width > x; ++x, ++src) + { + // determine alpha and expand to 32bpp + u8 alpha = (*src < png->num_trans) ? png->trans[*src] : 0xff; + accumalpha &= alpha; + rgb_t const pix(alpha, png->palette[*src * 3], png->palette[*src * 3 + 1], png->palette[*src * 3 + 2]); + (png->interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x)) = pix; + } + } + } + else if (png->color_type == 0) + { + // handle 8bpp grayscale case + for (u32 y = 0; height > y; ++y) + { + for (u32 x = 0; width > x; ++x, ++src) + { + rgb_t const pix(0xff, *src, *src, *src); + (png->interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x)) = pix; + } + } + } + else if (png->color_type == 2) + { + // handle 32bpp non-alpha case + for (u32 y = 0; height > y; ++y) + { + for (u32 x = 0; width > x; ++x, src += 3) + { + rgb_t const pix(0xff, src[0], src[1], src[2]); + (png->interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x)) = pix; + } + } + } + else + { + // handle 32bpp alpha case + for (u32 y = 0; height > y; ++y) + { + for (u32 x = 0; width > x; ++x, src += 4) + { + accumalpha &= src[3]; + rgb_t const pix(src[3], src[0], src[1], src[2]); + (png->interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x)) = pix; + } } + } } - /* set the hasalpha flag */ + // set the hasalpha flag return (accumalpha != 0xff); } @@ -760,69 +787,92 @@ static bool copy_png_to_bitmap(bitmap_argb32 &bitmap, const png_info *png) static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const 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; - u8 *src; - int x, y; - /* handle 8bpp palettized case */ - if (png->color_type == 3) + // colour format table + static constexpr unsigned samples[] = { 1, 0, 3, 1, 2, 0, 4 }; + + // adam7 interlace tables + static constexpr unsigned x_bias[7] = { 7, 3, 3, 1, 1, 0, 0 }; + static constexpr unsigned y_bias[7] = { 7, 7, 3, 3, 1, 1, 0 }; + static constexpr unsigned x_shift[7] = { 3, 3, 2, 2, 1, 1, 0 }; + static constexpr unsigned y_shift[7] = { 3, 3, 3, 2, 2, 1, 1 }; + + unsigned const pass_count(png->interlace_method ? 7 : 1); + u32 pass_offset[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + for (unsigned pass = 0; pass_count > pass; ++pass) { - /* loop over width/height */ - src = png->image; - for (y = 0; y < png->height; y++) - for (x = 0; x < png->width; x++, src++) + // calculate offset for next interlace pass + u32 const width(png->interlace_method ? ((png->width + x_bias[pass]) >> x_shift[pass]) : png->width); + u32 const height(png->interlace_method ? ((png->height + y_bias[pass]) >> y_shift[pass]) : png->height); + u32 const rowbytes(((width * samples[png->color_type] * png->bit_depth) + 7) >> 3); + pass_offset[pass + 1] = pass_offset[pass] + (height * (rowbytes + 1)); + u8 const *src(png->image + pass_offset[pass]); + auto const x_trans = [offs = (1 << x_shift[pass]) - x_bias[pass] - 1, shift = x_shift[pass]] (u32 x) { return (x << shift) + offs; }; + auto const y_trans = [offs = (1 << y_shift[pass]) - y_bias[pass] - 1, shift = y_shift[pass]] (u32 y) { return (y << shift) + offs; }; + + if (png->color_type == 3) + { + // handle 8bpp palettized case + for (u32 y = 0; height > y; ++y) { - rgb_t pixel = bitmap.pix32(y, x); - u8 alpha = rgb_t(png->palette[*src * 3], png->palette[*src * 3 + 1], png->palette[*src * 3 + 2]).brightness(); - accumalpha &= alpha; - bitmap.pix32(y, x) = rgb_t(alpha, pixel.r(), pixel.g(), pixel.b()); + for (u32 x = 0; width > x; ++x, ++src) + { + bitmap_argb32::pixel_t &dest(png->interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x)); + rgb_t const pixel(dest); + u8 const alpha(rgb_t(png->palette[*src * 3], png->palette[*src * 3 + 1], png->palette[*src * 3 + 2]).brightness()); + accumalpha &= alpha; + dest = rgb_t(alpha, pixel.r(), pixel.g(), pixel.b()); + } } - } - - /* handle 8bpp grayscale case */ - else if (png->color_type == 0) - { - /* loop over width/height */ - src = png->image; - for (y = 0; y < png->height; y++) - for (x = 0; x < png->width; x++, src++) + } + else if (png->color_type == 0) + { + // handle 8bpp grayscale case + for (u32 y = 0; height > y; ++y) { - rgb_t pixel = bitmap.pix32(y, x); - accumalpha &= *src; - bitmap.pix32(y, x) = rgb_t(*src, pixel.r(), pixel.g(), pixel.b()); + for (u32 x = 0; width > x; ++x, ++src) + { + bitmap_argb32::pixel_t &dest(png->interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x)); + rgb_t const pixel(dest); + accumalpha &= *src; + dest = rgb_t(*src, pixel.r(), pixel.g(), pixel.b()); + } } - } - - /* handle 32bpp non-alpha case */ - else if (png->color_type == 2) - { - /* loop over width/height */ - src = png->image; - for (y = 0; y < png->height; y++) - for (x = 0; x < png->width; x++, src += 3) + } + else if (png->color_type == 2) + { + // handle 32bpp non-alpha case + for (u32 y = 0; height > y; ++y) { - rgb_t pixel = bitmap.pix32(y, x); - u8 alpha = rgb_t(src[0], src[1], src[2]).brightness(); - accumalpha &= alpha; - bitmap.pix32(y, x) = rgb_t(alpha, pixel.r(), pixel.g(), pixel.b()); + for (u32 x = 0; width > x; ++x, src += 3) + { + bitmap_argb32::pixel_t &dest(png->interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x)); + rgb_t const pixel(dest); + u8 const alpha(rgb_t(src[0], src[1], src[2]).brightness()); + accumalpha &= alpha; + dest = rgb_t(alpha, pixel.r(), pixel.g(), pixel.b()); + } } - } - - /* handle 32bpp alpha case */ - else - { - /* loop over width/height */ - src = png->image; - for (y = 0; y < png->height; y++) - for (x = 0; x < png->width; x++, src += 4) + } + else + { + // handle 32bpp alpha case + for (u32 y = 0; height > y; ++y) { - rgb_t pixel = bitmap.pix32(y, x); - u8 alpha = rgb_t(src[0], src[1], src[2]).brightness(); - accumalpha &= alpha; - bitmap.pix32(y, x) = rgb_t(alpha, pixel.r(), pixel.g(), pixel.b()); + for (u32 x = 0; width > x; ++x, src += 4) + { + bitmap_argb32::pixel_t &dest(png->interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x)); + rgb_t const pixel(dest); + u8 const alpha(rgb_t(src[0], src[1], src[2]).brightness()); + accumalpha &= alpha; + dest = rgb_t(alpha, pixel.r(), pixel.g(), pixel.b()); + } } + } } - /* set the hasalpha flag */ + // set the hasalpha flag return (accumalpha != 0xff); } |
