OSDN Git Service

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