summaryrefslogblamecommitdiffstatshomepage
path: root/src/frontend/mame/ui/icorender.h
blob: 677ebf001c73f59b421a15d60c3c6df962747e3d (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                       
                                                      

                                                                            
                  





                                                            


                                                                            

                          

















































                                                                                      
                                                                                                             














                                                                              
                                                          
 
                                            


















































































































































                                                                                                                                       
                               
// license:BSD-3-Clause
// copyright-holders:Maurizio Petrarota, Victor Laskin
/***************************************************************************

    ui/icorender.h

    ICOns file loader.

    Original code by Victor Laskin (victor.laskin@gmail.com)
    http://vitiy.info/Code/ico.cpp

***************************************************************************/
#pragma once

#ifndef __UI_ICORENDER_H__
#define __UI_ICORENDER_H__

// These next two structs represent how the icon information is stored
// in an ICO file.
typedef struct
{
	UINT8   bWidth;                // Width of the image
	UINT8   bHeight;               // Height of the image (times 2)
	UINT8   bColorCount;           // Number of colors in image (0 if >=8bpp)
	UINT8   bReserved;             // Reserved
	UINT16  wPlanes;               // Color Planes
	UINT16  wBitCount;             // Bits per pixel
	UINT32  dwBytesInRes;          // how many bytes in this resource?
	UINT32  dwImageOffset;         // where in the file is this image
} ICONDIRENTRY, *LPICONDIRENTRY;

typedef struct
{
	UINT16  idReserved;            // Reserved
	UINT16  idType;                // resource type (1 for icons)
	UINT16  idCount;               // how many images?
	//ICONDIRENTRY  idEntries[1];  // the entries for each image
} ICONDIR, *LPICONDIR;

// size - 40 bytes
typedef struct {
	UINT32  biSize;
	UINT32  biWidth;
	UINT32  biHeight;   // Icon Height (added height of XOR-Bitmap and AND-Bitmap)
	UINT16  biPlanes;
	UINT16  biBitCount;
	UINT32  biCompression;
	INT32   biSizeImage;
	UINT32  biXPelsPerMeter;
	UINT32  biYPelsPerMeter;
	UINT32  biClrUsed;
	UINT32  biClrImportant;
} s_BITMAPINFOHEADER, *s_PBITMAPINFOHEADER;

// 46 bytes
typedef struct{
	s_BITMAPINFOHEADER  icHeader;       // DIB header
	UINT32              icColors[1];    // Color table (short 4 bytes) //RGBQUAD
	UINT8               icXOR[1];       // DIB bits for XOR mask
	UINT8               icAND[1];       // DIB bits for AND mask
} ICONIMAGE, *LPICONIMAGE;

//-------------------------------------------------
//  load an ICO file into a bitmap
//-------------------------------------------------

inline void render_load_ico(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename)
{
	INT32 width = 0;
	INT32 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 size = file.size();
	UINT8 *buffer = global_alloc_array(UINT8, 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* 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 *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 *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 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 *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 index = cursor[shift2 / 8];

				// select 1 bit only
				UINT8 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 bit = 7 - (x % 8);
				int shift2 = (x + (height - y - 1) * boundary) / 8;
				int mask = (0x01 & ((UINT8)cursor[shift2] >> bit));
				rgb_t colors = bitmap.pix32(y, x);
				UINT8 alpha = colors.a();
				alpha *= 1 - mask;
				colors.set_a(alpha);
				bitmap.pix32(y, x) = colors;
			}
	}
	file.close();
	global_free_array(buffer);
}

#endif /* __UI_ICORENDER_H__ */