OSDN Git Service

#37287 #37353 (2.2.0.89) 型の置換を継続中。 / Ongoing type replacement.
[hengband/hengband.git] / src / readdib.c
1 /*!
2  * @file readdib.c
3  * @brief Windows用ビットマップファイル読み込み処理パッケージ /
4  * This package provides a routine to read a DIB file and set up the device dependent version of the image.
5  * @date 2014/08/08
6  * @author
7  * This file has been modified for use with "Angband 2.8.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  * @details
19  * mind.cとあるが実際には超能力者、練気術師、狂戦士、鏡使い、忍者までの
20  * 特殊技能を揃えて実装している。
21  */
22
23 #include <windows.h>
24
25 #include "readdib.h"
26
27
28 /*
29  * Extract the "WIN32" flag from the compiler
30  */
31 #if defined(__WIN32__) || defined(__WINNT__) || defined(__NT__)
32 # ifndef WIN32
33 #  define WIN32
34 # endif
35 #endif
36
37 /*
38  * Make sure "huge" is legal XXX XXX XXX
39  */
40 #undef huge
41 #ifdef WIN32
42 # define huge /* oops */
43 #endif
44
45
46 /*
47  * Needed for lcc-win32
48  */
49 #ifndef SEEK_SET
50 #define SEEK_SET 0
51 #endif
52
53
54 /*!
55  * 一度にファイルから読み込むデータ量 / Number of bytes to be read during each read operation
56  */
57 #define MAXREAD  32768
58
59 /*!
60  * @brief 32KBのデータ読み取りを繰り返すことで、64KB以上のデータを一度に読み取るサブルーチン
61  * Private routine to read more than 64K at a time Reads data in steps of 32k till all the data has been read.
62  * @param fh ファイルヘッダ
63  * @param pv 読み取りポインタ
64  * @param ul 読み込むバイト数
65  * @return
66  * 取得できたデータ量をバイトで返す。0ならば何らかのエラー。
67  * Returns number of bytes requested, or zero if something went wrong.
68  */
69 static DWORD PASCAL lread(int fh, VOID FAR *pv, DWORD ul)
70 {
71         DWORD ulT = ul;
72         BYTE huge *hp = pv;
73
74         while (ul > (DWORD)MAXREAD)
75         {
76                 if (_lread(fh, (LPSTR)hp, (WORD)MAXREAD) != MAXREAD)
77                                 return 0;
78                 ul -= MAXREAD;
79                 hp += MAXREAD;
80         }
81         if (_lread(fh, (LPSTR)hp, (WORD)ul) != ul)
82                 return 0;
83         return ulT;
84 }
85
86 /*!
87  * @brief BITMAPINFOHEADERを取得してカラーテーブルを基本としたパレットを作成する。
88  * Given a BITMAPINFOHEADER, create a palette based on the color table.
89  * @param lpInfo BITMAPINFOHEADERのポインタ
90  * @return
91  * パレットの参照を返す。NULLならばエラー。
92  * Returns the handle of a palette, or zero if something went wrong.
93  */
94 static HPALETTE PASCAL NEAR MakeDIBPalette(LPBITMAPINFOHEADER lpInfo)
95 {
96         PLOGPALETTE npPal;
97         RGBQUAD FAR *lpRGB;
98         HPALETTE hLogPal;
99         WORD i;
100
101         /*
102          * since biClrUsed field was filled during the loading of the DIB,
103          * we know it contains the number of colors in the color table.
104          */
105         if (lpInfo->biClrUsed)
106         {
107                 npPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
108                                                  (WORD)lpInfo->biClrUsed * sizeof(PALETTEENTRY));
109                 if (!npPal)
110                         return(FALSE);
111
112                 npPal->palVersion = 0x300;
113                 npPal->palNumEntries = (WORD)lpInfo->biClrUsed;
114
115                 /* get pointer to the color table */
116                 lpRGB = (RGBQUAD FAR *)((LPSTR)lpInfo + lpInfo->biSize);
117
118                 /* copy colors from the color table to the LogPalette structure */
119                 for (i = 0; i < (WORD)lpInfo->biClrUsed; i++, lpRGB++)
120                 {
121                         npPal->palPalEntry[i].peRed = lpRGB->rgbRed;
122                         npPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
123                         npPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
124                         npPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
125                 }
126
127                 hLogPal = CreatePalette((LPLOGPALETTE)npPal);
128                 LocalFree((HANDLE)npPal);
129                 return(hLogPal);
130         }
131
132         /*
133          * 24-bit DIB with no color table.  return default palette.  Another
134          * option would be to create a 256 color "rainbow" palette to provide
135          * some good color choices.
136          */
137         else
138         {
139                 return(GetStockObject(DEFAULT_PALETTE));
140         }
141 }
142
143
144 /*!
145  * @brief
146  * ビットマップファイルを受け取り、画像のデバイス依存の描画のために使われる共通パレットとビットマップを作成する
147  * Given a DIB, create a bitmap and corresponding palette to be used for a
148  * device-dependent representation of the image.
149  * @param hDC デバイスコンテキストハンドル
150  * @param hDIB ビットマップ画像ハンドル
151  * @param phPal パレット取得ハンドル
152  * @param phBitmap ビットマップ取得ハンドル
153  * @return
154  * 成功したならばTRUEを返す。失敗の場合FALSE。
155  * Returns TRUE on success (phPal and phBitmap are filled with appropriate
156  * handles.  Caller is responsible for freeing objects) and FALSE on failure
157  * (unable to create objects, both pointer are invalid).
158  */
159 static BOOL NEAR PASCAL MakeBitmapAndPalette(HDC hDC, HANDLE hDIB,
160                                              HPALETTE * phPal, HBITMAP * phBitmap)
161 {
162         LPBITMAPINFOHEADER lpInfo;
163         BOOL result = FALSE;
164         HBITMAP hBitmap;
165         HPALETTE hPalette, hOldPal;
166         LPSTR lpBits;
167
168         lpInfo = (LPBITMAPINFOHEADER) GlobalLock(hDIB);
169         if ((hPalette = MakeDIBPalette(lpInfo)) != 0)
170         {
171                 /* Need to realize palette for converting DIB to bitmap. */
172                 hOldPal = SelectPalette(hDC, hPalette, TRUE);
173                 RealizePalette(hDC);
174
175                 lpBits = ((LPSTR)lpInfo + (WORD)lpInfo->biSize +
176                           (WORD)lpInfo->biClrUsed * sizeof(RGBQUAD));
177                 hBitmap = CreateDIBitmap(hDC, lpInfo, CBM_INIT, lpBits,
178                                          (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);
179
180                 SelectPalette(hDC, hOldPal, TRUE);
181                 RealizePalette(hDC);
182
183                 if (!hBitmap)
184                 {
185                         DeleteObject(hPalette);
186                 }
187                 else
188                 {
189                         *phBitmap = hBitmap;
190                         *phPal = hPalette;
191                         result = TRUE;
192                 }
193         }
194         return(result);
195 }
196
197
198
199 /*!
200  * @brief
201  * ビットマップファイルを読み込み、BITMAPINFO構造体にハンドルを取得する。
202  * Reads a DIB from a file, obtains a handle to its BITMAPINFO struct, and
203  * loads the DIB.  Once the DIB is loaded, the function also creates a bitmap
204  * and palette out of the DIB for a device-dependent form.
205  * device-dependent representation of the image.
206  * @param hWnd ウィンドウハンドル
207  * @param lpFileName 読み込むビットマップファイル
208  * @param pInfo 取得情報を補完するビットマップ情報構造体ポインタ
209  * @return
210  * Returns TRUE if the DIB is loaded and the bitmap/palette created, in which
211  * case, the DIBINIT structure pointed to by pInfo is filled with the appropriate
212  * handles, and FALSE if something went wrong.
213  * @details
214  * Reads a DIB from a file, obtains a handle to its BITMAPINFO struct, and
215  * loads the DIB.  Once the DIB is loaded, the function also creates a bitmap
216  * and palette out of the DIB for a device-dependent form.
217  */
218 BOOL ReadDIB(HWND hWnd, LPSTR lpFileName, DIBINIT *pInfo)
219 {
220         unsigned fh;
221         LPBITMAPINFOHEADER lpbi;
222         OFSTRUCT of;
223         BITMAPFILEHEADER bf;
224         WORD nNumColors;
225         BOOL result = FALSE;
226         char str[128];
227         WORD offBits;
228         HDC hDC;
229         BOOL bCoreHead = FALSE;
230
231         /* Open the file and get a handle to it's BITMAPINFO */
232         fh = OpenFile(lpFileName, &of, OF_READ);
233         if (fh == -1)
234         {
235                 wsprintf(str, "Can't open file '%s'", (LPSTR)lpFileName);
236                 MessageBox(NULL, str, "Error", MB_ICONSTOP | MB_OK);
237                 return (FALSE);
238         }
239
240         pInfo->hDIB = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER) +
241                                   256 * sizeof(RGBQUAD)));
242
243         if (!pInfo->hDIB)
244                 return (FALSE);
245
246         lpbi = (LPBITMAPINFOHEADER)GlobalLock(pInfo->hDIB);
247
248         /* read the BITMAPFILEHEADER */
249         if (sizeof (bf) != _lread(fh, (LPSTR)&bf, sizeof(bf)))
250                 goto ErrExit;
251
252         /* 'BM' */
253         if (bf.bfType != 0x4d42)
254                 goto ErrExit;
255
256         if (sizeof(BITMAPCOREHEADER) != _lread(fh, (LPSTR)lpbi, sizeof(BITMAPCOREHEADER)))
257                 goto ErrExit;
258
259         if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
260         {
261                 lpbi->biSize = sizeof(BITMAPINFOHEADER);
262                 lpbi->biBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
263                 lpbi->biPlanes = ((LPBITMAPCOREHEADER)lpbi)->bcPlanes;
264                 lpbi->biHeight = ((LPBITMAPCOREHEADER)lpbi)->bcHeight;
265                 lpbi->biWidth = ((LPBITMAPCOREHEADER)lpbi)->bcWidth;
266                 bCoreHead = TRUE;
267         }
268         else
269         {
270                 /* get to the start of the header and read INFOHEADER */
271                 _llseek(fh, sizeof(BITMAPFILEHEADER), SEEK_SET);
272                 if (sizeof(BITMAPINFOHEADER) != _lread(fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
273                         goto ErrExit;
274         }
275
276         if (!(nNumColors = (WORD)lpbi->biClrUsed))
277         {
278                 /* no color table for 24-bit, default size otherwise */
279                 if (lpbi->biBitCount != 24)
280                         nNumColors = 1 << lpbi->biBitCount;
281         }
282
283         /* fill in some default values if they are zero */
284         if (lpbi->biClrUsed == 0)
285                 lpbi->biClrUsed = nNumColors;
286
287         if (lpbi->biSizeImage == 0)
288         {
289                 lpbi->biSizeImage = (((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
290                                      * lpbi->biHeight);
291         }
292
293         /* otherwise wouldn't work with 16 color bitmaps -- S.K. */
294         else if ((nNumColors == 16) && (lpbi->biSizeImage > bf.bfSize))
295         {
296                 lpbi->biSizeImage /= 2;
297         }
298
299         /* get a proper-sized buffer for header, color table and bits */
300         GlobalUnlock(pInfo->hDIB);
301         pInfo->hDIB = GlobalReAlloc(pInfo->hDIB, lpbi->biSize +
302                                                                                 nNumColors * sizeof(RGBQUAD) +
303                                                                                 lpbi->biSizeImage, 0);
304
305         /* can't resize buffer for loading */
306         if (!pInfo->hDIB)
307                 goto ErrExit2;
308
309         lpbi = (LPBITMAPINFOHEADER)GlobalLock(pInfo->hDIB);
310
311         /* read the color table */
312         if (!bCoreHead)
313         {
314                 _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
315         }
316         else
317         {
318                 signed int i;
319                 RGBQUAD FAR *pQuad;
320                 RGBTRIPLE FAR *pTriple;
321
322                 _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBTRIPLE));
323
324                 pQuad = (RGBQUAD FAR *)((LPSTR)lpbi + lpbi->biSize);
325                 pTriple = (RGBTRIPLE FAR *) pQuad;
326                 for (i = nNumColors - 1; i >= 0; i--)
327                 {
328                         pQuad[i].rgbRed = pTriple[i].rgbtRed;
329                         pQuad[i].rgbBlue = pTriple[i].rgbtBlue;
330                         pQuad[i].rgbGreen = pTriple[i].rgbtGreen;
331                         pQuad[i].rgbReserved = 0;
332                 }
333         }
334
335         /* offset to the bits from start of DIB header */
336         offBits = (WORD)lpbi->biSize + nNumColors * sizeof(RGBQUAD);
337
338         if (bf.bfOffBits != 0L)
339         {
340                 _llseek(fh,bf.bfOffBits,SEEK_SET);
341         }
342
343         /* Use local version of '_lread()' above */
344         if (lpbi->biSizeImage == lread(fh, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
345         {
346                 GlobalUnlock(pInfo->hDIB);
347
348                 hDC = GetDC(hWnd);
349                 if (!MakeBitmapAndPalette(hDC, pInfo->hDIB, &((HPALETTE)pInfo->hPalette),
350                                           &((HBITMAP)pInfo->hBitmap)))
351                 {
352                         ReleaseDC(hWnd,hDC);
353                         goto ErrExit2;
354                 }
355                 else
356                 {
357                         ReleaseDC(hWnd,hDC);
358                         result = TRUE;
359                 }
360         }
361         else
362         {
363 ErrExit:
364                 GlobalUnlock(pInfo->hDIB);
365 ErrExit2:
366                 GlobalFree(pInfo->hDIB);
367         }
368
369         _lclose(fh);
370         return(result);
371 }
372