OSDN Git Service

v3.0.0 Alpha5 OSDN最終版
[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 
39  */
40 #undef huge
41 #ifdef WIN32
42 #define huge
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         nNumColors = (WORD)lpbi->biClrUsed;
277         if (!nNumColors)
278         {
279                 /* no color table for 24-bit, default size otherwise */
280                 if (lpbi->biBitCount != 24)
281                         nNumColors = 1 << lpbi->biBitCount;
282         }
283
284         /* fill in some default values if they are zero */
285         if (lpbi->biClrUsed == 0)
286                 lpbi->biClrUsed = nNumColors;
287
288         if (lpbi->biSizeImage == 0)
289         {
290                 lpbi->biSizeImage = (((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
291                                      * lpbi->biHeight);
292         }
293
294         /* otherwise wouldn't work with 16 color bitmaps -- S.K. */
295         else if ((nNumColors == 16) && (lpbi->biSizeImage > bf.bfSize))
296         {
297                 lpbi->biSizeImage /= 2;
298         }
299
300         /* get a proper-sized buffer for header, color table and bits */
301         GlobalUnlock(pInfo->hDIB);
302         pInfo->hDIB = GlobalReAlloc(pInfo->hDIB, lpbi->biSize +
303                                                                                 nNumColors * sizeof(RGBQUAD) +
304                                                                                 lpbi->biSizeImage, 0);
305
306         /* can't resize buffer for loading */
307         if (!pInfo->hDIB)
308                 goto ErrExit2;
309
310         lpbi = (LPBITMAPINFOHEADER)GlobalLock(pInfo->hDIB);
311
312         /* read the color table */
313         if (!bCoreHead)
314         {
315                 _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
316         }
317         else
318         {
319                 signed int i;
320                 RGBQUAD FAR *pQuad;
321                 RGBTRIPLE FAR *pTriple;
322
323                 _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBTRIPLE));
324
325                 pQuad = (RGBQUAD FAR *)((LPSTR)lpbi + lpbi->biSize);
326                 pTriple = (RGBTRIPLE FAR *) pQuad;
327                 for (i = nNumColors - 1; i >= 0; i--)
328                 {
329                         pQuad[i].rgbRed = pTriple[i].rgbtRed;
330                         pQuad[i].rgbBlue = pTriple[i].rgbtBlue;
331                         pQuad[i].rgbGreen = pTriple[i].rgbtGreen;
332                         pQuad[i].rgbReserved = 0;
333                 }
334         }
335
336         /* offset to the bits from start of DIB header */
337         offBits = (WORD)lpbi->biSize + nNumColors * sizeof(RGBQUAD);
338
339         if (bf.bfOffBits != 0L)
340         {
341                 _llseek(fh,bf.bfOffBits,SEEK_SET);
342         }
343
344         /* Use local version of '_lread()' above */
345         if (lpbi->biSizeImage == lread(fh, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
346         {
347                 GlobalUnlock(pInfo->hDIB);
348
349                 hDC = GetDC(hWnd);
350                 if (!MakeBitmapAndPalette(hDC, pInfo->hDIB, &((HPALETTE)pInfo->hPalette),
351                                           &((HBITMAP)pInfo->hBitmap)))
352                 {
353                         ReleaseDC(hWnd,hDC);
354                         goto ErrExit2;
355                 }
356                 else
357                 {
358                         ReleaseDC(hWnd,hDC);
359                         result = TRUE;
360                 }
361         }
362         else
363         {
364 ErrExit:
365                 GlobalUnlock(pInfo->hDIB);
366 ErrExit2:
367                 GlobalFree(pInfo->hDIB);
368         }
369
370         _lclose(fh);
371         return(result);
372 }
373