1 /**
2  * \file readdib.c
3  *
4  * This package provides a routine to read a DIB file and set up the
5  * device dependent version of the image.
6  *
7  * This file has been modified for use with "Angband 2.9.2"
8  *
9  * COPYRIGHT:
10  *
11  *   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
12  *
13  *   You have a royalty-free right to use, modify, reproduce and
14  *   distribute the Sample Files (and/or any modified version) in
15  *   any way you find useful, provided that you agree that
16  *   Microsoft has no warranty obligations or liability for any
17  *   Sample Application Files which are modified.
18  */
19 
20 #if defined(USE_WIN) || defined(WINDOWS) || defined(WIN32)
21 
22 #include <windows.h>
23 
24 #include "readdib.h"
25 
26 
27 /**
28  * Needed for lcc-win32
29  */
30 #ifndef SEEK_SET
31 #define SEEK_SET 0
32 #endif
33 
34 
35 /**
36  * Number of bytes to be read during each read operation
37  */
38 #define MAXREAD  32768
39 
40 /**
41  * Private routine to read more than 64K at a time
42  *
43  * Reads data in steps of 32k till all the data has been read.
44  *
45  * Returns number of bytes requested, or zero if something went wrong.
46  */
lread(HFILE fh,VOID FAR * pv,DWORD ul)47 static DWORD PASCAL lread(HFILE fh, VOID FAR *pv, DWORD ul)
48 {
49 	DWORD ulT = ul;
50 	BYTE *hp = pv;
51 
52 	while (ul > (DWORD)MAXREAD)
53 	{
54 		if (_lread(fh, (LPSTR)hp, (WORD)MAXREAD) != MAXREAD)
55 				return 0;
56 		ul -= MAXREAD;
57 		hp += MAXREAD;
58 	}
59 	if (_lread(fh, (LPSTR)hp, (WORD)ul) != (WORD)ul)
60 		return 0;
61 	return ulT;
62 }
63 
64 
65 /**
66  * Given a BITMAPINFOHEADER, create a palette based on the color table.
67  *
68  * Returns the handle of a palette, or zero if something went wrong.
69  */
MakeDIBPalette(LPBITMAPINFOHEADER lpInfo)70 static HPALETTE PASCAL NEAR MakeDIBPalette(LPBITMAPINFOHEADER lpInfo)
71 {
72 	PLOGPALETTE npPal;
73 	RGBQUAD FAR *lpRGB;
74 	HPALETTE hLogPal;
75 	DWORD i;
76 
77 	/*
78 	 * since biClrUsed field was filled during the loading of the DIB,
79 	 * we know it contains the number of colors in the color table.
80 	 */
81 	if (lpInfo->biClrUsed)
82 	{
83 		npPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
84 		                                 (WORD)lpInfo->biClrUsed * sizeof(PALETTEENTRY));
85 		if (!npPal)
86 			return (false);
87 
88 		npPal->palVersion = 0x300;
89 		npPal->palNumEntries = (WORD)lpInfo->biClrUsed;
90 
91 		/* get pointer to the color table */
92 		lpRGB = (RGBQUAD FAR *)((LPSTR)lpInfo + lpInfo->biSize);
93 
94 		/* copy colors from the color table to the LogPalette structure */
95 		for (i = 0; i < lpInfo->biClrUsed; i++, lpRGB++)
96 		{
97 			npPal->palPalEntry[i].peRed = lpRGB->rgbRed;
98 			npPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
99 			npPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
100 			npPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
101 		}
102 
103 		hLogPal = CreatePalette((LPLOGPALETTE)npPal);
104 		LocalFree((HANDLE)npPal);
105 		return (hLogPal);
106 	}
107 
108 	/*
109 	 * 24-bit DIB with no color table.  return default palette.  Another
110 	 * option would be to create a 256 color "rainbow" palette to provide
111 	 * some good color choices.
112 	 */
113 	else
114 	{
115 		return (GetStockObject(DEFAULT_PALETTE));
116 	}
117 }
118 
119 
120 /**
121  * Given a DIB, create a bitmap and corresponding palette to be used for a
122  * device-dependent representation of the image.
123  *
124  * Returns true on success (phPal and phBitmap are filled with appropriate
125  * handles.  Caller is responsible for freeing objects) and false on failure
126  * (unable to create objects, both pointer are invalid).
127  */
MakeBitmapAndPalette(HDC hDC,HANDLE hDIB,HPALETTE * phPal,HBITMAP * phBitmap)128 static bool NEAR PASCAL MakeBitmapAndPalette(HDC hDC, HANDLE hDIB,
129                                              HPALETTE * phPal, HBITMAP * phBitmap)
130 {
131 	LPBITMAPINFOHEADER lpInfo;
132 	bool result = false;
133 	HBITMAP hBitmap;
134 	HPALETTE hPalette, hOldPal;
135 	LPSTR lpBits;
136 
137 	lpInfo = (LPBITMAPINFOHEADER) GlobalLock(hDIB);
138 	if ((hPalette = MakeDIBPalette(lpInfo)) != 0)
139 	{
140 		/* Need to realize palette for converting DIB to bitmap. */
141 		hOldPal = SelectPalette(hDC, hPalette, true);
142 		RealizePalette(hDC);
143 
144 		lpBits = ((LPSTR)lpInfo + (WORD)lpInfo->biSize +
145 		          (WORD)lpInfo->biClrUsed * sizeof(RGBQUAD));
146 		hBitmap = CreateDIBitmap(hDC, lpInfo, CBM_INIT, lpBits,
147 		                         (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);
148 
149 		SelectPalette(hDC, hOldPal, true);
150 		RealizePalette(hDC);
151 
152 		if (!hBitmap)
153 		{
154 			DeleteObject(hPalette);
155 		}
156 		else
157 		{
158 			*phBitmap = hBitmap;
159 			*phPal = hPalette;
160 			result = true;
161 		}
162 	}
163 	return (result);
164 }
165 
166 
167 
168 /**
169  * Reads a DIB from a file, obtains a handle to its BITMAPINFO struct, and
170  * loads the DIB.  Once the DIB is loaded, the function also creates a bitmap
171  * and palette out of the DIB for a device-dependent form.
172  *
173  * Returns true if the DIB is loaded and the bitmap/palette created, in which
174  * case, the DIBINIT structure pointed to by pInfo is filled with the appropriate
175  * handles, and false if something went wrong.
176  */
ReadDIB(HWND hWnd,LPSTR lpFileName,DIBINIT * pInfo)177 bool ReadDIB(HWND hWnd, LPSTR lpFileName, DIBINIT *pInfo)
178 {
179 	HFILE fh;
180 	LPBITMAPINFOHEADER lpbi;
181 	OFSTRUCT of;
182 	BITMAPFILEHEADER bf;
183 	WORD nNumColors;
184 	bool result = false;
185 	DWORD offBits;
186 	HDC hDC;
187 	bool bCoreHead = false;
188 
189 	/* Open the file and get a handle to it's BITMAPINFO */
190 	fh = OpenFile(lpFileName, &of, OF_READ);
191 	if (fh == -1)
192 		return (false);
193 
194 	pInfo->hDIB = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER) +
195 	                          256 * sizeof(RGBQUAD)));
196 
197 	if (!pInfo->hDIB)
198 		return (false);
199 
200 	lpbi = (LPBITMAPINFOHEADER)GlobalLock(pInfo->hDIB);
201 
202 	/* read the BITMAPFILEHEADER */
203 	if (sizeof (bf) != _lread(fh, (LPSTR)&bf, sizeof(bf)))
204 		goto ErrExit;
205 
206 	/* 'BM' */
207 	if (bf.bfType != 0x4d42)
208 		goto ErrExit;
209 
210 	if (sizeof(BITMAPCOREHEADER) != _lread(fh, (LPSTR)lpbi, sizeof(BITMAPCOREHEADER)))
211 		goto ErrExit;
212 
213 	if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
214 	{
215 		lpbi->biSize = sizeof(BITMAPINFOHEADER);
216 		lpbi->biBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
217 		lpbi->biPlanes = ((LPBITMAPCOREHEADER)lpbi)->bcPlanes;
218 		lpbi->biHeight = ((LPBITMAPCOREHEADER)lpbi)->bcHeight;
219 		lpbi->biWidth = ((LPBITMAPCOREHEADER)lpbi)->bcWidth;
220 		bCoreHead = true;
221 	}
222 	else
223 	{
224 		/* get to the start of the header and read INFOHEADER */
225 		_llseek(fh, sizeof(BITMAPFILEHEADER), SEEK_SET);
226 		if (sizeof(BITMAPINFOHEADER) != _lread(fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
227 			goto ErrExit;
228 	}
229 
230 	if ((nNumColors = (WORD)lpbi->biClrUsed) == 0)
231 	{
232 		/* no color table for 24-bit, default size otherwise */
233 		if (lpbi->biBitCount != 24)
234 			nNumColors = 1 << lpbi->biBitCount;
235 	}
236 
237 	/* fill in some default values if they are zero */
238 	if (lpbi->biClrUsed == 0)
239 		lpbi->biClrUsed = nNumColors;
240 
241 	if (lpbi->biSizeImage == 0)
242 	{
243 		lpbi->biSizeImage = (((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
244 		                     * lpbi->biHeight);
245 	}
246 
247 	/* otherwise wouldn't work with 16 color bitmaps -- S.K. */
248 	else if ((nNumColors == 16) && (lpbi->biSizeImage > bf.bfSize))
249 	{
250 		lpbi->biSizeImage /= 2;
251 	}
252 
253 	/* get a proper-sized buffer for header, color table and bits */
254 	GlobalUnlock(pInfo->hDIB);
255 	pInfo->hDIB = GlobalReAlloc(pInfo->hDIB, lpbi->biSize +
256 										nNumColors * sizeof(RGBQUAD) +
257 										lpbi->biSizeImage, 0);
258 
259 	/* can't resize buffer for loading */
260 	if (!pInfo->hDIB)
261 		goto ErrExit2;
262 
263 	lpbi = (LPBITMAPINFOHEADER)GlobalLock(pInfo->hDIB);
264 
265 	/* read the color table */
266 	if (!bCoreHead)
267 	{
268 		_lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
269 	}
270 	else
271 	{
272 		signed int i;
273 		RGBQUAD FAR *pQuad;
274 		RGBTRIPLE FAR *pTriple;
275 
276 		_lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBTRIPLE));
277 
278 		pQuad = (RGBQUAD FAR *)((LPSTR)lpbi + lpbi->biSize);
279 		pTriple = (RGBTRIPLE FAR *) pQuad;
280 		for (i = nNumColors - 1; i >= 0; i--)
281 		{
282 			pQuad[i].rgbRed = pTriple[i].rgbtRed;
283 			pQuad[i].rgbBlue = pTriple[i].rgbtBlue;
284 			pQuad[i].rgbGreen = pTriple[i].rgbtGreen;
285 			pQuad[i].rgbReserved = 0;
286 		}
287 	}
288 
289 	pInfo->ImageWidth = lpbi->biWidth;
290 	pInfo->ImageHeight = lpbi->biHeight;
291 
292 	/* offset to the bits from start of DIB header */
293 	offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
294 
295 	if (bf.bfOffBits != 0L)
296 	{
297 		_llseek(fh,bf.bfOffBits,SEEK_SET);
298 	}
299 
300 	/* Use local version of '_lread()' above */
301 	if (lpbi->biSizeImage == lread(fh, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
302 	{
303 		GlobalUnlock(pInfo->hDIB);
304 
305 		hDC = GetDC(hWnd);
306 		if (!MakeBitmapAndPalette(hDC, pInfo->hDIB, &(pInfo->hPalette),
307 		                          &(pInfo->hBitmap)))
308 		{
309 			ReleaseDC(hWnd,hDC);
310 			goto ErrExit2;
311 		}
312 		else
313 		{
314 			ReleaseDC(hWnd,hDC);
315 			result = true;
316 		}
317 	}
318 	else
319 	{
320 ErrExit:
321 		GlobalUnlock(pInfo->hDIB);
322 ErrExit2:
323 		GlobalFree(pInfo->hDIB);
324 	}
325 
326 	_lclose(fh);
327 	return (result);
328 }
329 
330 
331 /* Free a DIB */
FreeDIB(DIBINIT * dib)332 void FreeDIB(DIBINIT *dib)
333 {
334 	/* Free the bitmap stuff */
335 	if (dib->hPalette) DeleteObject(dib->hPalette);
336 	if (dib->hBitmap) DeleteObject(dib->hBitmap);
337 	if (dib->hDIB) GlobalFree(dib->hDIB);
338 
339 	dib->hPalette = NULL;
340 	dib->hBitmap = NULL;
341 	dib->hDIB = NULL;
342 	dib->ImageWidth = 0;
343 	dib->ImageHeight = 0;
344 }
345 
346 #endif /* USE_WIN || WINDOWS || WIN32 */
347