OSDN Git Service

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