1 /*
2 PLIB - A Suite of Portable Game Libraries
3 Copyright (C) 1998,2002 Steve Baker
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 For further information visit http://plib.sourceforge.net
20
21 $Id: ssgLoadBMP.cxx 2109 2006-12-12 15:29:22Z fayjf $
22 */
23
24
25 #include "ssgLocal.h"
26
27 #ifdef SSG_LOAD_BMP_SUPPORTED
28
29 static FILE *curr_image_fd ;
30 static char curr_image_fname [ 512 ] ;
31 static int isSwapped ;
32
33
swab_short(unsigned short * x)34 static void swab_short ( unsigned short *x )
35 {
36 if ( isSwapped )
37 *x = (( *x >> 8 ) & 0x00FF ) |
38 (( *x << 8 ) & 0xFF00 ) ;
39 }
40
swab_int(unsigned int * x)41 static void swab_int ( unsigned int *x )
42 {
43 if ( isSwapped )
44 *x = (( *x >> 24 ) & 0x000000FF ) |
45 (( *x >> 8 ) & 0x0000FF00 ) |
46 (( *x << 8 ) & 0x00FF0000 ) |
47 (( *x << 24 ) & 0xFF000000 ) ;
48 }
49
50 /*static void swab_int_array ( int *x, int leng )
51 {
52 if ( ! isSwapped )
53 return ;
54
55 for ( int i = 0 ; i < leng ; i++ )
56 {
57 *x = (( *x >> 24 ) & 0x000000FF ) |
58 (( *x >> 8 ) & 0x0000FF00 ) |
59 (( *x << 8 ) & 0x00FF0000 ) |
60 (( *x << 24 ) & 0xFF000000 ) ;
61 x++ ;
62 }
63 }*/
64
65
readByte()66 static unsigned char readByte ()
67 {
68 unsigned char x ;
69 fread ( & x, sizeof(unsigned char), 1, curr_image_fd ) ;
70 return x ;
71 }
72
readShort()73 static unsigned short readShort ()
74 {
75 unsigned short x ;
76 fread ( & x, sizeof(unsigned short), 1, curr_image_fd ) ;
77 swab_short ( & x ) ;
78 return x ;
79 }
80
readInt()81 static unsigned int readInt ()
82 {
83 unsigned int x ;
84 fread ( & x, sizeof(unsigned int), 1, curr_image_fd ) ;
85 swab_int ( & x ) ;
86 return x ;
87 }
88
89
90 /*
91 Original source for BMP loader kindly
92 donated by "Sean L. Palmer" <spalmer@pobox.com>
93 */
94
95
96 struct BMPHeader
97 {
98 unsigned short FileType ;
99 unsigned int FileSize ;
100 unsigned short Reserved1 ;
101 unsigned short Reserved2 ;
102 unsigned int OffBits ;
103 unsigned int Size ;
104 unsigned int Width ;
105 unsigned int Height ;
106 unsigned short Planes ;
107 unsigned short BitCount ;
108 unsigned int Compression ;
109 unsigned int SizeImage ;
110 unsigned int XPelsPerMeter ;
111 unsigned int YPelsPerMeter ;
112 unsigned int ClrUsed ;
113 unsigned int ClrImportant ;
114 } ;
115
116
117 struct RGBA
118 {
119 unsigned char r,g,b,a ;
120 } ;
121
122
ssgLoadBMP(const char * fname,ssgTextureInfo * info)123 bool ssgLoadBMP ( const char *fname, ssgTextureInfo* info )
124 {
125 int w, h, bpp ;
126 int index=0;
127 bool old_format = false;
128 RGBA pal [ 256 ] ;
129
130 BMPHeader bmphdr ;
131
132 /* Open file & get size */
133
134 strcpy ( curr_image_fname, fname ) ;
135
136 if ( ( curr_image_fd = fopen ( curr_image_fname, "rb" ) ) == NULL )
137 {
138 char *p = strrchr(curr_image_fname,'_');
139 if (p != 0) {
140 *p = '\0';
141 p++;
142 index = atoi (p);
143 old_format = true;
144 if ( ( curr_image_fd = fopen(curr_image_fname, "rb")) == NULL) {
145 perror ( "ssgLoadTexture" ) ;
146 ulSetError( UL_WARNING, "ssgLoadTexture: Failed to load '%s' for reading.", curr_image_fname );
147 return false ;
148 }
149 p--;
150 *p = '_';
151 }
152 else {
153 perror ( "ssgLoadTexture" ) ;
154 ulSetError( UL_WARNING, "ssgLoadTexture: Failed to open '%s' for reading.", curr_image_fname );
155 return false ;
156 }
157 }
158
159 /*
160 Load the BMP piecemeal to avoid struct packing issues
161 */
162
163 isSwapped = FALSE ;
164 bmphdr.FileType = readShort () ;
165
166 if ( bmphdr.FileType == ((int)'B' + ((int)'M'<<8)) )
167 isSwapped = FALSE ;
168 else
169 if ( bmphdr.FileType == ((int)'M' + ((int)'B'<<8)) )
170 isSwapped = TRUE ;
171 else
172 {
173 ulSetError ( UL_WARNING, "%s: Unrecognised magic number 0x%04x",
174 curr_image_fname, bmphdr.FileType ) ;
175 return false ;
176 }
177
178 bmphdr.FileSize = readInt () ;
179 bmphdr.Reserved1 = readShort () ;
180 bmphdr.Reserved2 = readShort () ;
181 bmphdr.OffBits = readInt () ;
182 bmphdr.Size = readInt () ;
183 bmphdr.Width = readInt () ;
184 bmphdr.Height = readInt () ;
185 bmphdr.Planes = readShort () ;
186 bmphdr.BitCount = readShort () ;
187 bmphdr.Compression = readInt () ;
188 bmphdr.SizeImage = readInt () ;
189 bmphdr.XPelsPerMeter = readInt () ;
190 bmphdr.YPelsPerMeter = readInt () ;
191 bmphdr.ClrUsed = readInt () ;
192 bmphdr.ClrImportant = readInt () ;
193
194 w = bmphdr.Width ;
195 h = bmphdr.Height ;
196 bpp = bmphdr.Planes * bmphdr.BitCount ;
197
198 bool top_down = false ;
199 if ( h < 0 )
200 {
201 top_down = true ;
202 h = -1 * h ;
203 }
204
205 #ifdef PRINT_BMP_HEADER_DEBUG
206 ulSetError ( UL_DEBUG, "Filetype %04x", bmphdr.FileType ) ;
207 ulSetError ( UL_DEBUG, "Filesize %08x", bmphdr.FileSize ) ;
208 ulSetError ( UL_DEBUG, "R1 %04x", bmphdr.Reserved1 ) ;
209 ulSetError ( UL_DEBUG, "R2 %04x", bmphdr.Reserved2 ) ;
210 ulSetError ( UL_DEBUG, "Offbits %08x", bmphdr.OffBits ) ;
211 ulSetError ( UL_DEBUG, "Size %08x", bmphdr.Size ) ;
212 ulSetError ( UL_DEBUG, "Width %08x", bmphdr.Width ) ;
213 ulSetError ( UL_DEBUG, "Height %08x", bmphdr.Height ) ;
214 ulSetError ( UL_DEBUG, "Planes %04x", bmphdr.Planes ) ;
215 ulSetError ( UL_DEBUG, "Bitcount %04x", bmphdr.BitCount ) ;
216 ulSetError ( UL_DEBUG, "Compression %08x", bmphdr.Compression ) ;
217 ulSetError ( UL_DEBUG, "SizeImage %08x", bmphdr.SizeImage ) ;
218 ulSetError ( UL_DEBUG, "XPelsPerMeter %08x", bmphdr.XPelsPerMeter ) ;
219 ulSetError ( UL_DEBUG, "YPelsPerMeter %08x", bmphdr.YPelsPerMeter ) ;
220 ulSetError ( UL_DEBUG, "ClrUsed %08x", bmphdr.ClrUsed ) ;
221 ulSetError ( UL_DEBUG, "ClrImportant %08x", bmphdr.ClrImportant ) ;
222 #endif
223
224 int isMonochrome = TRUE ;
225 int isOpaque = TRUE ;
226
227 if ( bpp <= 8 )
228 {
229 for ( int i = 0 ; i < 256 ; i++ )
230 {
231 pal[i].b = readByte () ;
232 pal[i].g = readByte () ;
233 pal[i].r = readByte () ;
234
235 /* According to BMP specs, this fourth value is not really alpha value
236 but just a filler byte, so it is ignored for now. */
237 pal[i].a = readByte () ;
238 if (old_format == true) {
239 pal[i].a = (i<index)?0:255;
240
241 }
242
243 if ( pal[i].r != pal[i].g ||
244 pal[i].g != pal[i].b ) isMonochrome = FALSE ;
245 }
246 }
247
248 fseek ( curr_image_fd, bmphdr.OffBits, SEEK_SET ) ;
249
250 bmphdr.SizeImage = w * h * (bpp / 8) ;
251 GLubyte *data = new GLubyte [ bmphdr.SizeImage ] ;
252
253 /* read (and maybe flip) image */
254 {
255 int row_size = w * (bpp / 8) ;
256 for ( int y = h-1 ; y >= 0 ; y-- )
257 {
258 GLubyte *row_ptr ;
259 if ( top_down )
260 {
261 /* store flipped image */
262 row_ptr = &data [ y * row_size ] ;
263 }
264 else
265 {
266 /* store without flipping */
267 row_ptr = &data [ ( h - ( y + 1 ) ) * row_size ] ;
268 }
269 if ( fread ( row_ptr, 1, row_size, curr_image_fd ) != (unsigned)row_size )
270 {
271 ulSetError ( UL_WARNING, "Premature EOF in '%s'", curr_image_fname ) ;
272 return false ;
273 }
274 }
275 }
276
277 fclose ( curr_image_fd ) ;
278
279 GLubyte *image ;
280 int z ;
281
282 if ( bpp == 8 )
283 {
284 int i ;
285
286 // check for diffrent alpha values in the bitmap
287 // assume blending if that's the case
288 for ( i = 1 ; i < w * h ; i++ ) {
289 if (pal[data[i]].a != pal[data[i-1]].a) {
290 isOpaque = FALSE ;
291 break;
292 }
293 }
294
295 if ( isMonochrome )
296 z = isOpaque ? 1 : 2 ;
297 else
298 z = isOpaque ? 3 : 4 ;
299
300 image = new GLubyte [ w * h * z ] ;
301
302 for ( i = 0 ; i < w * h ; i++ )
303 switch ( z )
304 {
305 case 1 : image [ i ] = pal[data[i]].r ; break ;
306 case 2 : image [ i*2 ] = pal[data[i]].r ;
307 image [ i*2 + 1 ] = pal[data[i]].a ; break ;
308 case 3 : image [ i*3 ] = pal[data[i]].r ;
309 image [ i*3 + 1 ] = pal[data[i]].g ;
310 image [ i*3 + 2 ] = pal[data[i]].b ; break ;
311 case 4 : image [ i*4 ] = pal[data[i]].r ;
312 image [ i*4 + 1 ] = pal[data[i]].g ;
313 image [ i*4 + 2 ] = pal[data[i]].b ;
314 image [ i*4 + 3 ] = pal[data[i]].a ; break ;
315 default : break ;
316 }
317
318 delete [] data ;
319 }
320 else
321 if ( bpp == 24 )
322 {
323 z = 3 ;
324 image = data ;
325
326 /* BGR --> RGB */
327
328 for ( int i = 0 ; i < w * h ; i++ )
329 {
330 GLubyte tmp = image [ 3 * i ] ;
331 image [ 3 * i ] = image [ 3 * i + 2 ];
332 image [ 3 * i + 2 ] = tmp ;
333 }
334 }
335 else
336 if ( bpp == 32 )
337 {
338 z = 4 ;
339 image = data ;
340
341 /* BGRA --> RGBA */
342
343 for ( int i = 0 ; i < w * h ; i++ )
344 {
345 GLubyte tmp = image [ 4 * i ] ;
346 image [ 4 * i ] = image [ 4 * i + 2 ];
347 image [ 4 * i + 2 ] = tmp ;
348 }
349 }
350 else
351 {
352 ulSetError ( UL_WARNING, "ssgLoadTexture: Can't load %d bpp BMP textures.", bpp ) ;
353 return false ;
354 }
355
356 if ( info != NULL )
357 {
358 info -> width = w ;
359 info -> height = h ;
360 info -> depth = z ;
361 info -> alpha = ( isOpaque == FALSE ) ;
362 }
363
364 return ssgMakeMipMaps ( image, w, h, z ) ;
365 }
366
367 #else
368
ssgLoadBMP(const char * fname,ssgTextureInfo * info)369 bool ssgLoadBMP ( const char *fname, ssgTextureInfo* info )
370 {
371 ulSetError ( UL_WARNING,
372 "ssgLoadTexture: '%s' - BMP support not configured", fname ) ;
373 return false ;
374 }
375
376 #endif
377