/***************************************************************************

	bmp.c

	PSP windows bitmap file I/O functions.

***************************************************************************/

#ifdef SUPPORT_BMP

#include "psp.h"


/***************************************************************************
	Windows bitmap structures
 **************************************************************************/

#define BFH_SIZE	(2+4+2+2+4)
#define BIH_SIZE	(4+4+4+2+2+4+4+4+4+4+4)

typedef unsigned char BYTE;
typedef unsigned DWORD;
typedef int LONG;
typedef unsigned short WORD;

typedef struct tagRGBQUAD
{
	BYTE rgbBlue;
	BYTE rgbGreen;
	BYTE rgbRed;
	BYTE rgbReserved;
} RGBQUAD;

typedef struct tagBITMAPFILEHEADER
{
	WORD  bfType;
	DWORD bfSize;
	WORD  bfReserved1;
	WORD  bfReserved2;
	DWORD bfOffBits;
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER
{
	DWORD biSize;
	LONG  biWidth;
	LONG  biHeight;
	WORD  biPlanes;
	WORD  biBitCount;
	DWORD biCompression;
	DWORD biSizeImage;
	LONG  biXPelsPerMeter;
	LONG  biYPelsPerMeter;
	DWORD biClrUsed;
	DWORD biClrImportant;
} BITMAPINFOHEADER;


/*--------------------------------------------------------
	Load BMP
 -------------------------------------------------------*/

int load_bmp(const char *name)
{
	BITMAPFILEHEADER bf;
	BITMAPINFOHEADER bi;
	RGBQUAD rgb[256];
	int x, y, y2, sx, sy, width, height, pitch;
	u16 *vptr, *dst;
	FILE *fp;

	if ((fp = fopen(name, "rb")) == NULL)
		return 0;

	// BITMAPFILEHEADER
	fread(&bf.bfType,      1, 2, fp);
	fread(&bf.bfSize,      1, 4, fp);
	fread(&bf.bfReserved1, 1, 2, fp);
	fread(&bf.bfReserved2, 1, 2, fp);
	fread(&bf.bfOffBits,   1, 4, fp);

	// BITMAPINFOHEADER
	fread(&bi.biSize,          1, 4, fp);
	fread(&bi.biWidth,         1, 4, fp);
	fread(&bi.biHeight,        1, 4, fp);
	fread(&bi.biPlanes,        1, 2, fp);
	fread(&bi.biBitCount,      1, 2, fp);
	fread(&bi.biCompression,   1, 4, fp);
	fread(&bi.biSizeImage,     1, 4, fp);
	fread(&bi.biXPelsPerMeter, 1, 4, fp);
	fread(&bi.biYPelsPerMeter, 1, 4, fp);
	fread(&bi.biClrUsed,       1, 4, fp);
	fread(&bi.biClrImportant,  1, 4, fp);

	if (bf.bfType != 0x4d42 || bi.biCompression || (bi.biBitCount < 4 || bi.biBitCount > 24))
	{
		fclose(fp);
		return 0;
	}

	video_clear_vram(2);

	width = (bi.biWidth  > 480) ? 480 : bi.biWidth;
	height = (bi.biHeight > 272) ? 272 : bi.biHeight;

	sx = (SCR_WIDTH - width) >> 1;
	sy = (SCR_HEIGHT - height) >> 1;
	vptr = video_vram_addr(sx, sy + (2 * SCR_HEIGHT));

	switch (bi.biBitCount)
	{
	case 4:
		fread(rgb, 1, sizeof(RGBQUAD) * 16, fp);
		pitch = ((bi.biWidth / 2) + 3) & ~3;
		for (y = 0; y < bi.biHeight; y++)
		{
			y2 = (bi.biHeight - 1) - y;

			if (y2 < height)
			{
				dst = &vptr[y2 * BUF_WIDTH];

				for (x = 0; x < pitch; x++)
				{
					int c = fgetc(fp);

					if ((x << 1) < width)
					{
						int c1 = c & 0x0f;
						int c2 = c >> 4;

						dst[x * 2 + 0] = MAKECOL15(rgb[c1].rgbRed, rgb[c1].rgbGreen, rgb[c1].rgbBlue);
						dst[x * 2 + 1] = MAKECOL15(rgb[c2].rgbRed, rgb[c2].rgbGreen, rgb[c2].rgbBlue);
					}
				}
			}
			else fseek(fp, pitch, SEEK_CUR);
		}
		break;

	case 8:
		fread(rgb, 1, sizeof(RGBQUAD) * 256, fp);
		pitch = (bi.biWidth + 3) & ~3;
		for (y = 0; y < bi.biHeight; y++)
		{
			y2 = (bi.biHeight - 1) - y;

			if (y2 < height)
			{
				dst = &vptr[y2 * BUF_WIDTH];

				for (x = 0; x < pitch; x++)
				{
					int c = fgetc(fp);

					if (x < width)
						dst[x] = MAKECOL15(rgb[c].rgbRed, rgb[c].rgbGreen, rgb[c].rgbBlue);
				}
			}
			else fseek(fp, pitch, SEEK_CUR);
		}
		break;

	case 24:
		pitch = ((bi.biWidth * 3) + 3) & ~3;
		for (y = 0; y < bi.biHeight; y++)
		{
			y2 = (bi.biHeight - 1) - y;
			dst = &vptr[y2 * BUF_WIDTH];

			if (y2 < height)
			{
				for (x = 0; x < pitch / 3; x++)
				{
					int b = fgetc(fp);
					int g = fgetc(fp);
					int r = fgetc(fp);

					if (y2 < height && x < width)
						dst[x] = MAKECOL15(r, g, b);
				}

				if (pitch % 3)
					fseek(fp, pitch % 3, SEEK_CUR);
			}
			else fseek(fp, pitch, SEEK_CUR);
		}
		break;
	}

	fclose(fp);

	return 1;
}


/*--------------------------------------------------------
	Save BMP
 -------------------------------------------------------*/

int save_bmp(const char *name)
{
	BITMAPFILEHEADER bf;
	BITMAPINFOHEADER bi;
	int x, y, y2;
	u16 *vptr, *src;
	FILE *fp;

	if ((fp = fopen(name, "wb")) == NULL)
		return 0;

	bf.bfType          = 0x4d42;
	bf.bfReserved1     = 0;
	bf.bfReserved2     = 0;
	bf.bfOffBits       = BFH_SIZE + BIH_SIZE;

	bi.biSize          = BIH_SIZE;
	bi.biWidth         = SCR_WIDTH;
	bi.biHeight        = SCR_HEIGHT;
	bi.biPlanes        = 1;
	bi.biBitCount      = 24;
	bi.biCompression   = 0;
	bi.biSizeImage     = bi.biWidth * bi.biHeight * 3;
	bi.biXPelsPerMeter = 3780;
	bi.biYPelsPerMeter = 3780;
	bi.biClrUsed       = 0;
	bi.biClrImportant  = 0;

	bf.bfSize          = bf.bfOffBits + bi.biSizeImage;

	// BITMAPFILEHEADER
	fwrite(&bf.bfType,      1, 2, fp);
	fwrite(&bf.bfSize,      1, 4, fp);
	fwrite(&bf.bfReserved1, 1, 2, fp);
	fwrite(&bf.bfReserved2, 1, 2, fp);
	fwrite(&bf.bfOffBits,   1, 4, fp);

	// BITMAPINFOHEADER
	fwrite(&bi.biSize,          1, 4, fp);
	fwrite(&bi.biWidth,         1, 4, fp);
	fwrite(&bi.biHeight,        1, 4, fp);
	fwrite(&bi.biPlanes,        1, 2, fp);
	fwrite(&bi.biBitCount,      1, 2, fp);
	fwrite(&bi.biCompression,   1, 4, fp);
	fwrite(&bi.biSizeImage,     1, 4, fp);
	fwrite(&bi.biXPelsPerMeter, 1, 4, fp);
	fwrite(&bi.biYPelsPerMeter, 1, 4, fp);
	fwrite(&bi.biClrUsed,       1, 4, fp);
	fwrite(&bi.biClrImportant,  1, 4, fp);

	vptr = video_vram_addr(0, draw_frame * SCR_HEIGHT);

	for (y = 0; y < SCR_HEIGHT; y++)
	{
		y2 = (SCR_HEIGHT - 1) - y;

		src = &vptr[y2 * BUF_WIDTH];

		for (x = 0; x < SCR_WIDTH; x++)
		{
			u16 color = src[x];
			int r = GETR15(color);
			int g = GETG15(color);
			int b = GETB15(color);

			fputc(b, fp);
			fputc(g, fp);
			fputc(r, fp);
		}
	}

	fclose(fp);

	return 1;
}

#endif
