source: trunk/dll/loadbmp.c@ 1486

Last change on this file since 1486 was 1486, checked in by Gregg Young, 16 years ago

Initial changes to commands handling. Allows you to reorder commands menu without breaking toolbars and changing hotkeys. Fixes the environment so it is used and so it is deleted if the command is deleted. Allows for user defined bitmaps in toolbars which are named based on the text or the the ID of the command.The new commands.dat will not be usable with earlier versions of FM/2

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