diff options
Diffstat (limited to 'src/frontend/mame/ui/icorender.h')
-rw-r--r-- | src/frontend/mame/ui/icorender.h | 227 |
1 files changed, 213 insertions, 14 deletions
diff --git a/src/frontend/mame/ui/icorender.h b/src/frontend/mame/ui/icorender.h index bb3f1a083be..17bc5a1d8ea 100644 --- a/src/frontend/mame/ui/icorender.h +++ b/src/frontend/mame/ui/icorender.h @@ -1,13 +1,13 @@ // license:BSD-3-Clause -// copyright-holders:Vas Crabb +// copyright-holders:Maurizio Petrarota, Victor Laskin /*************************************************************************** ui/icorender.h - Windows icon file parser. + ICOns file loader. - File handles passed to these functions must support read and seek - operations. + Original code by Victor Laskin (victor.laskin@gmail.com) + http://vitiy.info/Code/ico.cpp ***************************************************************************/ #ifndef MAME_FRONTEND_MAME_UI_ICORENDER_H @@ -15,20 +15,219 @@ #pragma once -namespace ui { +// These next two structs represent how the icon information is stored +// in an ICO file. +typedef struct +{ + uint8_t bWidth; // Width of the image + uint8_t bHeight; // Height of the image (times 2) + uint8_t bColorCount; // Number of colors in image (0 if >=8bpp) + uint8_t bReserved; // Reserved + uint16_t wPlanes; // Color Planes + uint16_t wBitCount; // Bits per pixel + uint32_t dwBytesInRes; // how many bytes in this resource? + uint32_t dwImageOffset; // where in the file is this image +} ICONDIRENTRY, *LPICONDIRENTRY; -// get number of images in icon file (-1 on error) -int images_in_ico(util::core_file &fp); +typedef struct +{ + uint16_t idReserved; // Reserved + uint16_t idType; // resource type (1 for icons) + uint16_t idCount; // how many images? + //ICONDIRENTRY idEntries[1]; // the entries for each image +} ICONDIR, *LPICONDIR; -// load specified icon from file (zero-based) -void render_load_ico(util::core_file &fp, unsigned index, bitmap_argb32 &bitmap); +// size - 40 bytes +typedef struct { + uint32_t biSize; + uint32_t biWidth; + uint32_t biHeight; // Icon Height (added height of XOR-Bitmap and AND-Bitmap) + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + int32_t biSizeImage; + uint32_t biXPelsPerMeter; + uint32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +} s_BITMAPINFOHEADER, *s_PBITMAPINFOHEADER; -// load first supported icon from file -void render_load_ico_first(util::core_file &fp, bitmap_argb32 &bitmap); +// 46 bytes +typedef struct{ + s_BITMAPINFOHEADER icHeader; // DIB header + uint32_t icColors[1]; // Color table (short 4 bytes) //RGBQUAD + uint8_t icXOR[1]; // DIB bits for XOR mask + uint8_t icAND[1]; // DIB bits for AND mask +} ICONIMAGE, *LPICONIMAGE; -// load highest detail supported icon from file -void render_load_ico_highest_detail(util::core_file &fp, bitmap_argb32 &bitmap); +//------------------------------------------------- +// load an ICO file into a bitmap +//------------------------------------------------- -} // namespace ui +inline void render_load_ico(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename) +{ + int32_t width = 0; + int32_t height = 0; + + // deallocate previous bitmap + bitmap.reset(); + + // define file's full name + std::string fname; + + if (!dirname) + fname = filename; + else + fname.assign(dirname).append(PATH_SEPARATOR).append(filename); + + osd_file::error filerr = file.open(fname.c_str()); + + if (filerr != osd_file::error::NONE) + return; + + // allocates a buffer for the image + uint64_t size = file.size(); + uint8_t *buffer = global_alloc_array(uint8_t, size + 1); + + // read data from the file and set them in the buffer + file.read(buffer, size); + + LPICONDIR icoDir = (LPICONDIR)buffer; + int iconsCount = icoDir->idCount; + + if (icoDir->idReserved != 0 || icoDir->idType != 1 || iconsCount == 0 || iconsCount > 20) + { + file.close(); + global_free_array(buffer); + return; + } + + uint8_t* cursor = buffer; + cursor += 6; + ICONDIRENTRY* dirEntry = (ICONDIRENTRY*)(cursor); + int maxSize = 0; + int offset = 0; + int maxBitCount = 0; + for (int i = 0; i < iconsCount; i++, ++dirEntry) + { + int w = dirEntry->bWidth; + int h = dirEntry->bHeight; + int bitCount = dirEntry->wBitCount; + if (w * h > maxSize || bitCount > maxBitCount) // we choose icon with max resolution + { + width = w; + height = h; + offset = dirEntry->dwImageOffset; + maxSize = w * h; + } + } + + if (offset == 0) return; + + cursor = buffer; + cursor += offset; + ICONIMAGE* icon = (ICONIMAGE*)(cursor); + int realBitsCount = (int)icon->icHeader.biBitCount; + bool hasAndMask = (realBitsCount < 32) && (height != icon->icHeader.biHeight); + + cursor += 40; + bitmap.allocate(width, height); + + // rgba + vertical swap + if (realBitsCount >= 32) + { + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + int shift2 = 4 * (x + (height - y - 1) * width); + bitmap.pix32(y, x) = rgb_t(cursor[shift2 + 3], cursor[shift2 + 2], cursor[shift2 + 1], cursor[shift2]); + } + } + else if (realBitsCount == 24) + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + int shift2 = 3 * (x + (height - y - 1) * width); + bitmap.pix32(y, x) = rgb_t(255, cursor[shift2 + 2], cursor[shift2 + 1], cursor[shift2]); + } + else if (realBitsCount == 8) // 256 colors + { + // 256 color table + uint8_t *colors = cursor; + cursor += 256 * 4; + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + int shift2 = (x + (height - y - 1) * width); + int index = 4 * cursor[shift2]; + bitmap.pix32(y, x) = rgb_t(255, colors[index + 2], colors[index + 1], colors[index]); + } + } + else if (realBitsCount == 4) // 16 colors + { + // 16 color table + uint8_t *colors = cursor; + cursor += 16 * 4; + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + int shift2 = (x + (height - y - 1) * width); + uint8_t index = cursor[shift2 / 2]; + if (shift2 % 2 == 0) + index = (index >> 4) & 0xF; + else + index = index & 0xF; + index *= 4; + bitmap.pix32(y, x) = rgb_t(255, colors[index + 2], colors[index + 1], colors[index]); + } + } + else if (realBitsCount == 1) // 2 colors + { + // 2 color table + uint8_t *colors = cursor; + cursor += 2 * 4; + int boundary = width; // !!! 32 bit boundary (http://www.daubnet.com/en/file-format-ico) + while (boundary % 32 != 0) boundary++; + + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + int shift2 = (x + (height - y - 1) * boundary); + uint8_t index = cursor[shift2 / 8]; + + // select 1 bit only + uint8_t bit = 7 - (x % 8); + index = (index >> bit) & 0x01; + index *= 4; + bitmap.pix32(y, x) = rgb_t(255, colors[index + 2], colors[index + 1], colors[index]); + } + } + + // Read AND mask after base color data - 1 BIT MASK + if (hasAndMask) + { + int boundary = width * realBitsCount; // !!! 32 bit boundary (http://www.daubnet.com/en/file-format-ico) + while (boundary % 32 != 0) boundary++; + cursor += boundary * height / 8; + + boundary = width; + while (boundary % 32 != 0) boundary++; + + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + { + uint8_t bit = 7 - (x % 8); + int shift2 = (x + (height - y - 1) * boundary) / 8; + int mask = (0x01 & ((uint8_t)cursor[shift2] >> bit)); + rgb_t colors = bitmap.pix32(y, x); + uint8_t alpha = colors.a(); + alpha *= 1 - mask; + colors.set_a(alpha); + bitmap.pix32(y, x) = colors; + } + } + file.close(); + global_free_array(buffer); +} #endif // MAME_FRONTEND_MAME_UI_ICORENDER_H |