source: trunk/dll/loadbmp.c@ 793

Last change on this file since 793 was 793, checked in by Gregg Young, 18 years ago

Move #pragma alloc_text to end for OpenWatcom compat

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