source: trunk/dll/loadbmp.c@ 1104

Last change on this file since 1104 was 1104, checked in by Gregg Young, 17 years ago

Replace save_dir2(dir) with strcpy(dir, pFM2SaveDirectory)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1
2/***********************************************************************
3
4 $Id: loadbmp.c 1104 2008-08-02 20:33:03Z gyoung $
5
6 Load bitmaps
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2006, 2008 Steven H. Levine
10
11 22 Jul 06 SHL Check more run time errors
12 16 Jan 07 SHL Check more run time errors
13 16 Jan 07 SHL Sync variable names for sanity
14 16 Jan 07 SHL Open bitmap file binary - no wonder the code does not work
15 16 Jan 07 SHL Beautify with indent -i2
16 18 Apr 08 SHL LoadBitmapFromFile ensure pf initialized if no hPS
17 19 Jul 08 GKY Replace save_dir2(dir) with pFM2SaveDirectory
18
19***********************************************************************/
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <share.h>
25
26#define INCL_DOS
27#define INCL_WIN
28#define INCL_GPI
29#define INCL_LONGLONG // dircnrs.h
30
31#include "errutil.h" // Dos_Error...
32#include "fm3dll.h"
33
34static PSZ pszSrcFile = __FILE__;
35
36HBITMAP LoadBitmapFromFileNum(USHORT id)
37{
38 char s[CCHMAXPATH];
39
40 strcpy(s, pFM2SaveDirectory);
41 sprintf(s + strlen(s), "\\%u.BMP", id);
42 return LoadBitmapFromFile(s);
43}
44
45HBITMAP LoadBitmapFromFile(CHAR * pszFileName)
46{
47 HBITMAP hBmp = (HBITMAP) 0;
48 FILE *pf;
49 ULONG rc;
50 USHORT usType;
51 PBITMAPARRAYFILEHEADER2 pbmafh2 = NULL; // Must init for xfree
52 PBITMAPFILEHEADER2 pbmfh2; // No color table
53 PBITMAPINFOHEADER2 pbmih2; // No color table
54 PBITMAPINFO2 pbmi2; // Includes color table
55 BOOL is2x; // Format 1.x or 2.x
56 ULONG ulColors;
57 ULONG ulRGBOffset;
58 PBYTE pData = NULL; // Must init for xfree
59 ULONG ulDataSize;
60 SIZEL sizel;
61 HPS hPS = WinGetPS(HWND_DESKTOP);
62
63 if (!hPS) {
64 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__, "WinGetPS");
65 pf = NULL;
66 goto ExitLoadBMP;
67 }
68
69 pf = _fsopen(pszFileName, "rb", SH_DENYWR);
70 if (!pf) {
71 // OK for file to not exist - enable following for debug as needed
72 // Runtime_Error(pszSrcFile, __LINE__, "_fsopen %s", pszFileName);
73 goto ExitLoadBMP;
74 }
75
76 // Read image type
77 // fixme to just read type2 header - this is silly and wastes time
78 rc = fread(&usType, 1, sizeof(usType), pf);
79 if (rc != sizeof(usType)) {
80 Runtime_Error(pszSrcFile, __LINE__, "fread");
81 goto ExitLoadBMP;
82 }
83
84 /* Read bitmap info header
85 Allocate enough to hold a complete 2.x bitmap array file header
86 fixme to support > 256 colors?
87 */
88 pbmafh2 =
89 xmalloc(sizeof(*pbmafh2) + 256 * sizeof(RGB2), pszSrcFile, __LINE__);
90 if (!pbmafh2)
91 goto ExitLoadBMP;
92 /* Assign pointers to the file header and bitmap info header etc.
93 Both the 1.x and 2.x structures are assigned to simplify code
94 fixme to clean this up - aliased pointers are evil
95 */
96 pbmfh2 = &pbmafh2->bfh2;
97 pbmih2 = &pbmfh2->bmp2;
98 pbmi2 = (PBITMAPINFO2) pbmih2;
99
100 switch (usType) {
101 case BFT_BMAP:
102 case BFT_ICON:
103 case BFT_POINTER:
104 case BFT_COLORICON:
105 case BFT_COLORPOINTER:
106 {
107 /* Assume image is a 2.0 image and read as a 2.x header
108 OK for 1.x file - read will not fail unless file is corrupted
109 */
110 rc = fseek(pf, 0, SEEK_SET);
111 if (rc) {
112 Runtime_Error(pszSrcFile, __LINE__, "fseek 0");
113 goto ExitLoadBMP;
114 }
115
116 rc = fread(pbmfh2, 1, sizeof(*pbmfh2), pf);
117 if (rc != sizeof(*pbmfh2)) {
118 Runtime_Error(pszSrcFile, __LINE__, "fread");
119 goto ExitLoadBMP;
120 }
121
122 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER); // 1.x or 2.x bitmap
123 /* We will read the color table later
124 Color table follows header but
125 location depends on the type of the bitmap (old vs new)
126 1.x header is fixed size
127 2.x header is variable sized, so offset must be calculated
128 cbFix contains actual size of BITMAPINFOHEADER2 in file
129 */
130 ulRGBOffset = is2x ? sizeof(*pbmfh2) - sizeof(*pbmih2) + pbmih2->cbFix :
131 sizeof(BITMAPFILEHEADER);
132 }
133 break;
134
135 case BFT_BITMAPARRAY:
136 {
137 /* Now we are dealing with a bitmap array which is a collection of bitmaps
138 Each bitmap has its own file header
139 */
140
141 ULONG ulCurOffset;
142 ULONG clScreenWidth;
143 ULONG clScreenHeight;
144 ULONG ulDeviceColors;
145 ULONG ulSizeDiff;
146 ULONG ulOffsetPicked = 0;
147 ULONG ulColorsPicked;
148 ULONG ulSizeDiffPicked;
149 HDC hdc;
150
151 /* Scan the array and chose the bitmap best suited
152 for the current display size and color capacities
153 */
154 hdc = GpiQueryDevice(hPS);
155 if (!hdc) {
156 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__,
157 "GpiQueryDevice");
158 goto ExitLoadBMP;
159 }
160 DevQueryCaps(hdc, CAPS_COLORS, 1, (PLONG) & ulDeviceColors);
161 DevQueryCaps(hdc, CAPS_WIDTH, 1, (PLONG) & clScreenWidth);
162 DevQueryCaps(hdc, CAPS_HEIGHT, 1, (PLONG) & clScreenHeight);
163 pbmafh2->offNext = 0;
164 do {
165 ulCurOffset = pbmafh2->offNext;
166 rc = fseek(pf, pbmafh2->offNext, SEEK_SET);
167 if (rc) {
168 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", pbmafh2->offNext);
169 goto ExitLoadBMP;
170 }
171 rc = fread(pbmafh2, 1, sizeof(*pbmafh2), pf);
172 if (rc != sizeof(*pbmafh2)) {
173 Runtime_Error(pszSrcFile, __LINE__, "fread");
174 goto ExitLoadBMP;
175 }
176 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER);
177 if (is2x) {
178 ulColors = 1 << (pbmafh2->bfh2.bmp2.cBitCount *
179 pbmafh2->bfh2.bmp2.cPlanes);
180 }
181 else {
182 ulColors =
183 1 << (((PBITMAPARRAYFILEHEADER) pbmafh2)->bfh.bmp.cBitCount *
184 ((PBITMAPARRAYFILEHEADER) pbmafh2)->bfh.bmp.cPlanes);
185 }
186 if (pbmafh2->cxDisplay == 0 && pbmafh2->cyDisplay == 0) {
187 // This is a device independant bitmap - process it as a VGA
188 pbmafh2->cxDisplay = 640;
189 pbmafh2->cyDisplay = 480;
190 }
191 ulSizeDiff = abs(pbmafh2->cxDisplay - clScreenWidth) +
192 abs(pbmafh2->cyDisplay - clScreenHeight);
193 if (ulDeviceColors == ulColors && ulSizeDiff == 0) {
194 // We found the perfect match
195 ulOffsetPicked = ulCurOffset;
196 break; // Stop scan
197 }
198 if (ulOffsetPicked == 0 || // First time thru
199 ulSizeDiff < ulSizeDiffPicked || // Better fit than any previous
200 (ulColors > ulColorsPicked && ulColors < ulDeviceColors) || // More colors than prev & less than device
201 (ulColors < ulColorsPicked && ulColors > ulDeviceColors)) {
202 ulOffsetPicked = ulCurOffset; // Make this our current pick
203 ulColorsPicked = ulColors;
204 ulSizeDiffPicked = ulSizeDiff;
205 }
206 } while (pbmafh2->offNext != 0);
207
208 // Retrieve the selected bitmap
209 rc = fseek(pf, ulOffsetPicked, SEEK_SET);
210 if (rc) {
211 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", ulOffsetPicked);
212 goto ExitLoadBMP;
213 }
214 rc = fread(pbmafh2, 1, sizeof(*pbmafh2), pf);
215 if (rc != sizeof(*pbmafh2)) {
216 Runtime_Error(pszSrcFile, __LINE__, "fread");
217 goto ExitLoadBMP;
218 }
219
220 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER);
221 /* As before, we calculate offset in file stream to color table
222 This code must match single bitmap logic
223 */
224 ulRGBOffset = ulOffsetPicked;
225 ulRGBOffset +=
226 is2x ? sizeof(*pbmafh2) - sizeof(*pbmih2) +
227 pbmih2->cbFix : sizeof(BITMAPARRAYFILEHEADER);
228 }
229 break;
230
231 default:
232 Runtime_Error(pszSrcFile, __LINE__, "Bad type %u", usType);
233 goto ExitLoadBMP;
234 } // endswitch
235
236 // Position to color table
237 rc = fseek(pf, ulRGBOffset, SEEK_SET);
238 if (rc) {
239 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", ulRGBOffset);
240 goto ExitLoadBMP;
241 }
242
243 // Read color table
244 if (is2x) {
245 /* For a 2.0 bitmap, read the color table as is
246 The bitmap info structure is header + color table
247 If we have 24 bits per pel, there is usually no color table, unless
248 pbmih2->cclrUsed or pbmih2->cclrImportant are non zero
249 fixme to test this
250 */
251 if (pbmih2->cBitCount < 24) {
252 ULONG ulRGBBytes;
253
254 ulColors = 1L << pbmih2->cBitCount;
255
256 if (ulColors > 256) {
257 Runtime_Error(pszSrcFile, __LINE__, "RGB exceeds 256 colors: %lu",
258 ulColors);
259 goto ExitLoadBMP;
260 }
261 ulRGBBytes = ulColors * sizeof(RGB2);
262 rc = fread(&pbmi2->argbColor[0], 1, ulRGBBytes, pf);
263 if (rc != ulRGBBytes) {
264 Runtime_Error(pszSrcFile, __LINE__, "fread");
265 goto ExitLoadBMP;
266 }
267 } // endif
268 // Get pointer to bitmap info (header and color table)
269 pbmi2 = (PBITMAPINFO2) pbmih2;
270 }
271 else {
272 /* This is a 1.x format bitmap
273 Since the current standard format is the 2.0
274 convert the header and color table to 2.x format
275 */
276 ULONG ul;
277 RGB rgb;
278 PBITMAPINFOHEADER pbmih = &((PBITMAPARRAYFILEHEADER) pbmafh2)->bfh.bmp;
279
280 if (pbmih->cBitCount < 24) {
281 ulColors = 1 << pbmih->cBitCount;
282 if (ulColors > 256) {
283 Runtime_Error(pszSrcFile, __LINE__, "RGB exceeds 256 colors: %lu",
284 ulColors);
285 goto ExitLoadBMP;
286 }
287 // Read in 1.x color table and reformat for 2.x
288 for (ul = 0; ul < ulColors; ul++) {
289 fread(&rgb, 1, sizeof(rgb), pf);
290 pbmi2->argbColor[ul].bRed = rgb.bRed;
291 pbmi2->argbColor[ul].bGreen = rgb.bGreen;
292 pbmi2->argbColor[ul].bBlue = rgb.bBlue;
293 pbmi2->argbColor[ul].fcOptions = 0; // initialize 2.x extra byte to 0
294 } // for
295 }
296
297 // Convert the old style to the new header format
298 pbmi2->cbFix = sizeof(BITMAPINFOHEADER2);
299 pbmi2->cBitCount = pbmih->cBitCount;
300 pbmi2->cPlanes = pbmih->cPlanes;
301 pbmi2->cy = pbmih->cy;
302 pbmi2->cx = pbmih->cx;
303 // set rest to zero
304 memset((PCHAR) pbmi2 + 16, 0, sizeof(BITMAPINFOHEADER2) - 16);
305 } // if 1.x
306
307 /* The 2.0 bitmap info structure set up
308 Position to start of the bitmap data
309 */
310 rc = fseek(pf, pbmfh2->offBits, SEEK_SET);
311 if (rc) {
312 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", pbmfh2->offBits);
313 goto ExitLoadBMP;
314 }
315
316 /* Read the bitmap data
317 The read size is derived using the magic formula
318 Each bitmap scan line is aligned on a doubleword boundary
319 The size of the scan line is the number of pels times the bpp
320 After aligning it, we divide by 4 to get the number of bytes, and
321 multiply by the number of scan lines and the number of pel planes
322 */
323 if (pbmi2->ulCompression)
324 ulDataSize = pbmi2->cbImage;
325 else
326 ulDataSize = (((pbmi2->cBitCount * pbmi2->cx) + 31) / 32) * 4 *
327 pbmi2->cy * pbmi2->cPlanes;
328 pData = xmalloc(ulDataSize, pszSrcFile, __LINE__);
329 if (!pData)
330 goto ExitLoadBMP;
331 rc = fread(pData, 1, ulDataSize, pf);
332 if (rc != ulDataSize) {
333 Runtime_Error(pszSrcFile, __LINE__, "fread");
334 goto ExitLoadBMP;
335 }
336
337 // Create the GPI bitmap image
338 sizel.cx = pbmi2->cx;
339 sizel.cy = pbmi2->cy;
340
341 hBmp = GpiCreateBitmap(hPS, (PBITMAPINFOHEADER2) pbmi2, CBM_INIT,
342 pData, pbmi2);
343 if (!hBmp)
344 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__,
345 "GpiCreateBitmap");
346
347ExitLoadBMP:
348
349 xfree(pData, pszSrcFile, __LINE__);
350 xfree(pbmafh2, pszSrcFile, __LINE__);
351 if (pf)
352 fclose(pf);
353 if (hPS)
354 WinReleasePS(hPS);
355 return hBmp;
356}
357
358#pragma alloc_text(LOADBITMAP,LoadBitmapFromFile,LoadBitmapFromFileNum)
Note: See TracBrowser for help on using the repository browser.