/* テスト */
/* File: readdib.c */

/*
 * This package provides a routine to read a DIB file and set up the
 * device dependent version of the image.
 *
 * This file has been modified for use with "Angband 2.9.2"
 *
 * COPYRIGHT:
 *
 *   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
 *
 *   You have a royalty-free right to use, modify, reproduce and
 *   distribute the Sample Files (and/or any modified version) in
 *   any way you find useful, provided that you agree that
 *   Microsoft has no warranty obligations or liability for any
 *   Sample Application Files which are modified.
 */

#if defined(USE_WIN) || defined(WINDOWS) || defined(WIN32)

#include <windows.h>
extern "C"
{
#include "readdib.hpp"
}

// extern "C" void show_win_error(void);

/*
 * Number of bytes to be read during each read operation
 */
#define MAXREAD  32768

/*
 * Private routine to read more than 64K at a time
 *
 * Reads data in steps of 32k till all the data has been read.
 *
 * Returns number of bytes requested, or zero if something went wrong.
 */
#if 0
static DWORD PASCAL lread(HANDLE hFile, VOID FAR *pv, DWORD ul)
{
	DWORD ulT = ul;
	BYTE *inBuffer = (byte *)pv;
	DWORD nBytesToRead = MAXREAD;
	DWORD nBytesRead;

	while (ul > (DWORD)MAXREAD)
	{
/*		if (_lread(fh, (LPTSTR)hp, (WORD)MAXREAD) != MAXREAD) */
		ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL);
		if (nBytesRead != MAXREAD)
				return 0;
		ul -= MAXREAD;
		inBuffer += MAXREAD;
	}
/*	if (_lread(fh, (LPTSTR)hp, (WORD)ul) != (WORD)ul) */
	ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL);
	if (nBytesRead != (WORD)ul)
		return 0;
	return ulT;
}
#endif

/*
 * Given a BITMAPINFOHEADER, create a palette based on the color table.
 *
 * Returns the handle of a palette, or zero if something went wrong.
 */
static HPALETTE PASCAL NEAR MakeDIBPalette(LPBITMAPINFOHEADER lpInfo)
{
	PLOGPALETTE npPal;
	RGBQUAD FAR *lpRGB;
	HPALETTE hLogPal;
	DWORD i;

	/*
	 * since biClrUsed field was filled during the loading of the DIB,
	 * we know it contains the number of colors in the color table.
	 */
	if (lpInfo->biClrUsed)
	{
		npPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
		                                 (WORD)lpInfo->biClrUsed * sizeof(PALETTEENTRY));
		if (!npPal)
			return (FALSE);

		npPal->palVersion = 0x300;
		npPal->palNumEntries = (WORD)lpInfo->biClrUsed;

		/* get pointer to the color table */
		lpRGB = (RGBQUAD FAR *)((LPTSTR)lpInfo + lpInfo->biSize);

		/* copy colors from the color table to the LogPalette structure */
		for (i = 0; i < lpInfo->biClrUsed; i++, lpRGB++)
		{
			npPal->palPalEntry[i].peRed = lpRGB->rgbRed;
			npPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
			npPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
			npPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
		}

		hLogPal = CreatePalette((LPLOGPALETTE)npPal);
		LocalFree((HANDLE)npPal);
		return (hLogPal);
	}
	/*
	 * 24-bit DIB with no color table.  return default palette.  Another
	 * option would be to create a 256 color "rainbow" palette to provide
	 * some good color choices.
	 */
	else
	{
		return ((HPALETTE)GetStockObject(DEFAULT_PALETTE));
	}
}

/*
 * Given a DIB, create a bitmap and corresponding palette to be used for a
 * device-dependent representation of the image.
 *
 * Returns TRUE on success (phPal and phBitmap are filled with appropriate
 * handles.  Caller is responsible for freeing objects) and FALSE on failure
 * (unable to create objects, both pointer are invalid).
 */
static BOOL NEAR PASCAL MakeBitmapAndPalette(HDC hDC, HANDLE hDIB,
                                             HPALETTE * phPal, HBITMAP * phBitmap)
{
	LPBITMAPINFOHEADER lpInfo;
	BOOL result = FALSE;
	HBITMAP hBitmap;
	HPALETTE hPalette, hOldPal;
	LPTSTR lpBits;

	lpInfo = (LPBITMAPINFOHEADER) GlobalLock(hDIB);
	if ((hPalette = MakeDIBPalette(lpInfo)) != 0)
	{
		/* Need to realize palette for converting DIB to bitmap. */
		hOldPal = SelectPalette(hDC, hPalette, TRUE);
		RealizePalette(hDC);

		lpBits = ((LPTSTR)lpInfo + (WORD)lpInfo->biSize +
		          (WORD)lpInfo->biClrUsed * sizeof(RGBQUAD));
		hBitmap = CreateDIBitmap(hDC, lpInfo, CBM_INIT, lpBits,
		                         (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);

		SelectPalette(hDC, hOldPal, TRUE);
		RealizePalette(hDC);

		if (!hBitmap)
		{
			DeleteObject(hPalette);
		}
		else
		{
			*phBitmap = hBitmap;
			*phPal = hPalette;
			result = TRUE;
		}
	}
	return (result);
}

/*
 * Reads a DIB from a file, obtains a handle to its BITMAPINFO struct, and
 * loads the DIB.  Once the DIB is loaded, the function also creates a bitmap
 * and palette out of the DIB for a device-dependent form.
 *
 * Returns TRUE if the DIB is loaded and the bitmap/palette created, in which
 * case, the DIBINIT structure pointed to by pInfo is filled with the appropriate
 * handles, and FALSE if something went wrong.
 */


//BOOL ReadDIB(HWND hWnd, LPCWSTR lpFileName, DIBINIT *pInfo)
//{
//	HANDLE hFile;
//	LPBITMAPINFOHEADER lpbi;
//	BITMAPINFOHEADER bmih;
//	BITMAPFILEHEADER bf;
//	WORD nNumColors;
//	BOOL result = FALSE;
//	DWORD offBits;
//	DWORD nBytesToRead;
//	DWORD nBytesRead;
//	HDC hDC;
//	BOOL bCoreHead = FALSE;
//	int ret;
//
//	/* Open the file and get a handle to its BITMAPINFO */ /* TODO Get this to work */
//	hFile = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//	if (hFile == INVALID_HANDLE_VALUE)
//		return (FALSE);
//
//	pInfo->hDIB = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
//		(DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
//
//	if (!pInfo->hDIB)
//		return (FALSE);
//
//	lpbi = (LPBITMAPINFOHEADER) (pInfo->hDIB);
//
//	/* read the BITMAPFILEHEADER */
//	nBytesToRead = sizeof(BITMAPFILEHEADER);
//	ReadFile(hFile, &bf, nBytesToRead, &nBytesRead, NULL);
//	if (nBytesRead != sizeof(bf))
//		goto ErrExit;
//
//	/* 'BM' */
//	if (bf.bfType != 0x4d42)
//		goto ErrExit;
//
//	nBytesToRead = sizeof(BITMAPINFOHEADER);
//	ret = ReadFile(hFile, &bmih, nBytesToRead, &nBytesRead, (LPOVERLAPPED)NULL);
//	if (!ret)
//		goto ErrExit;
//
//	if (nBytesRead != sizeof(BITMAPINFOHEADER)) 
//		goto ErrExit;
//
//	if (bmih.biSize == sizeof(BITMAPCOREHEADER))
//	{
//		lpbi->biSize          = bmih.biSize; 
//		lpbi->biWidth         = bmih.biWidth; 
//		lpbi->biHeight        = bmih.biHeight; 
//		lpbi->biPlanes        = bmih.biPlanes; 
//		lpbi->biBitCount      = bmih.biBitCount; 
//		lpbi->biCompression   = bmih.biCompression; 
//		lpbi->biSizeImage     = bmih.biSizeImage; 
//		lpbi->biXPelsPerMeter = bmih.biXPelsPerMeter; 
//		lpbi->biYPelsPerMeter = bmih.biYPelsPerMeter; 
//		lpbi->biClrUsed       = bmih.biClrUsed; 
//		lpbi->biClrImportant  = bmih.biClrImportant; 
//
//		bCoreHead = TRUE;
//	}
//	else
//	{
//		LONG lDistanceToMove = sizeof(BITMAPFILEHEADER);
//		PLONG lpDistanceToMoveHigh = NULL;
//		/* get to the start of the header and read INFOHEADER */
//		/*_llseek(fh, sizeof(BITMAPFILEHEADER), SEEK_SET); */
//		SetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, FILE_BEGIN); 
//
//		nBytesToRead = sizeof(BITMAPCOREHEADER);
//		ReadFile(hFile, &lpbi, nBytesToRead, &nBytesRead, NULL);
//		if (nBytesRead != sizeof(BITMAPCOREHEADER)) 
//			goto ErrExit;
//	}
//	if ((nNumColors = (WORD)lpbi->biClrUsed) == 0)
//	{
//		/* no color table for 24-bit, default size otherwise */
//		if (lpbi->biBitCount != 24)
//			nNumColors = 1 << lpbi->biBitCount;
//	}
//	/* fill in some default values if they are zero */
//	if (lpbi->biClrUsed == 0)
//		lpbi->biClrUsed = nNumColors;
//
//	if (lpbi->biSizeImage == 0)
//	{
//		lpbi->biSizeImage = (((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
//		                     * lpbi->biHeight);
//	}
//	/* otherwise wouldn't work with 16 color bitmaps -- S.K. */
//	else if ((nNumColors == 16) && (lpbi->biSizeImage > bf.bfSize))
//	{
//		lpbi->biSizeImage /= 2;
//	}
//	/* get a proper-sized buffer for header, color table and bits */
//	pInfo->hDIB = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfo->hDIB, lpbi->biSize +
//										nNumColors * sizeof(RGBQUAD) +
//										lpbi->biSizeImage);
//
//	/* can't resize buffer for loading */
//	if (!pInfo->hDIB)
//		goto ErrExit;
//
//	lpbi = (LPBITMAPINFOHEADER)(pInfo->hDIB);
//
//	/* read the color table */
//	if (!bCoreHead)
//	{
//		nBytesToRead = nNumColors * sizeof(RGBQUAD);
//		ReadFile(hFile, &lpbi + lpbi->biSize, nBytesToRead, &nBytesRead, NULL);
//	}
//	else
//	{
//		signed int i;
//		RGBQUAD FAR *pQuad;
//		RGBTRIPLE FAR *pTriple;
//
//		nBytesToRead = nNumColors * sizeof(RGBTRIPLE);
//		ReadFile(hFile, &lpbi + lpbi->biSize, nBytesToRead, &nBytesRead, NULL);
//
//		pQuad = (RGBQUAD FAR *)((LPTSTR)lpbi + lpbi->biSize);
//		pTriple = (RGBTRIPLE FAR *) pQuad;
//		for (i = nNumColors - 1; i >= 0; i--)
//		{
//			pQuad[i].rgbRed = pTriple[i].rgbtRed;
//			pQuad[i].rgbBlue = pTriple[i].rgbtBlue;
//			pQuad[i].rgbGreen = pTriple[i].rgbtGreen;
//			pQuad[i].rgbReserved = 0;
//		}
//	}
//	/* offset to the bits from start of DIB header */
//	offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
//
//	if (bf.bfOffBits != 0L)
//	{
///*		_llseek(fh,bf.bfOffBits,SEEK_SET); */
//
//		LONG lDistanceToMove = bf.bfOffBits;
//		PLONG lpDistanceToMoveHigh = NULL;
//		SetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, FILE_BEGIN); 
//	}
//	nBytesToRead = lpbi->biSizeImage;
//	ret = ReadFile(hFile, &lpbi + offBits, nBytesToRead, &nBytesRead, NULL);
//	if(!ret)
//		goto ErrExit;
//
//	if(nBytesRead != nBytesToRead)
//	{
//
//		hDC = GetDC(hWnd);
//		if (!MakeBitmapAndPalette(hDC, pInfo->hDIB, &(pInfo->hPalette),
//		                          &(pInfo->hBitmap)))
//		{
//			ReleaseDC(hWnd,hDC);
//			goto ErrExit;
//		}
//		else
//		{
//			ReleaseDC(hWnd,hDC);
//			result = TRUE;
//		}
//	}
//	else
//	{
//ErrExit:
//		extern void show_win_error(void);
//		HeapFree(GetProcessHeap(), 0, pInfo->hDIB);
//	}
//	CloseHandle(hFile); 
//	return (result);
//}

/* Free a DIB */
void FreeDIB(DIBINIT *dib)
{
	/* Free the bitmap stuff */
	if (dib->hPalette) 
		DeleteObject(dib->hPalette);
	if (dib->hBitmap) 
		DeleteObject(dib->hBitmap);
	if (dib->hDIB) 
		HeapFree(GetProcessHeap(), 0, dib->hDIB);

	dib->hPalette = NULL;
	dib->hBitmap = NULL;
	dib->hDIB = NULL;
}

/*
 * LoadBitmapFromBMPFile and ReadDIB (below) use example code 
 * (C) Copyright Microsoft
 * c.f. http://support.microsoft.com/kb/q158898/
 */

BOOL LoadBitmapFromBMPFile( LPCWSTR szFileName, HBITMAP *phBitmap,
		HPALETTE *phPalette )
{

	BITMAP  bm;

	*phBitmap = NULL;
	*phPalette = NULL;

	// Use LoadImage() to get the image loaded into a DIBSection
	*phBitmap = (HBITMAP)LoadImage( NULL, szFileName, IMAGE_BITMAP, 0, 0,
			   LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );
	if( *phBitmap == NULL )
		return FALSE;

	// Get the color depth of the DIBSection
	GetObject(*phBitmap, sizeof(BITMAP), &bm );
	// If the DIBSection is 256 color or less, it has a color table
	if( ( bm.bmBitsPixel * bm.bmPlanes ) <= 8 )
	{
		HDC           hMemDC;
		HBITMAP       hOldBitmap;
		RGBQUAD       rgb[256];
		LPLOGPALETTE  pLogPal;
		WORD          i;

		// Create a memory DC and select the DIBSection into it
		hMemDC = CreateCompatibleDC( NULL );
		hOldBitmap = (HBITMAP)SelectObject( hMemDC, *phBitmap );
		// Get the DIBSection's color table
		GetDIBColorTable( hMemDC, 0, 256, rgb );
		// Create a palette from the color tabl
		pLogPal = (LOGPALETTE *)malloc( sizeof(LOGPALETTE) + (256*sizeof(PALETTEENTRY)) );
		pLogPal->palVersion = 0x300;
		pLogPal->palNumEntries = 256;
		for(i=0;i<256;i++)
		{
			pLogPal->palPalEntry[i].peRed = rgb[i].rgbRed;
			pLogPal->palPalEntry[i].peGreen = rgb[i].rgbGreen;
			pLogPal->palPalEntry[i].peBlue = rgb[i].rgbBlue;
			pLogPal->palPalEntry[i].peFlags = 0;
		}
		*phPalette = CreatePalette( pLogPal );
		// Clean up
		free( pLogPal );
		SelectObject( hMemDC, hOldBitmap );
		DeleteDC( hMemDC );
	}
	else   // It has no color table, so use a halftone palette
	{
		HDC    hRefDC;

		hRefDC = GetDC( NULL );
		*phPalette = CreateHalftonePalette( hRefDC );
		ReleaseDC( NULL, hRefDC );
	}
	return TRUE;
}

BOOL ReadDIB(HWND hWnd, LPCWSTR lpFileName, DIBINIT *pInfo)
{
	if (!(LoadBitmapFromBMPFile(lpFileName, &pInfo->hBitmap, &pInfo->hPalette)))
	{
		extern void show_win_error(void);
		return FALSE;
	}
	return TRUE;
}

#endif /* USE_WIN || WINDOWS || WIN32 */
