/
IMG_lbm.c
491 lines (412 loc) · 11.8 KB
1
/*
2
SDL_image: An example image loading library for use with SDL
3
Copyright (C) 1999-2004 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
23
/* $Id$ */
24
25
26
/* This is a ILBM image file loading framework
Load IFF pictures, PBM & ILBM packing methods, with or without stencil
27
28
29
Written by Daniel Morais ( Daniel AT Morais DOT com ) in September 2001.
24 bits ILBM files support added by Marc Le Douarain (http://www.multimania.com/mavati)
in December 2002.
30
EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
31
32
(http://www.multimania.com/mavati) in December 2003.
Stencil and colorkey fixes by David Raulo (david.raulo AT free DOT fr) in February 2004.
33
34
35
36
*/
#include <stdio.h>
#include <stdlib.h>
37
#include <string.h>
38
39
40
41
42
43
44
45
46
#include "SDL_endian.h"
#include "SDL_image.h"
#ifdef LOAD_LBM
#define MAXCOLORS 256
47
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
48
49
50
typedef struct
{
51
52
53
54
55
56
57
58
Uint16 w, h; /* width & height of the bitmap in pixels */
Sint16 x, y; /* screen coordinates of the bitmap */
Uint8 planes; /* number of planes of the bitmap */
Uint8 mask; /* mask type ( 0 => no mask ) */
Uint8 tcomp; /* compression type */
Uint8 pad1; /* dummy value, for padding */
Uint16 tcolor; /* transparent color */
Uint8 xAspect, /* pixel aspect ratio */
59
yAspect;
60
61
Sint16 Lpage; /* width of the screen in pixels */
Sint16 Hpage; /* height of the screen in pixels */
62
63
64
65
66
67
68
69
} BMHD;
int IMG_isLBM( SDL_RWops *src )
{
int is_LBM;
Uint8 magic[4+4+4];
is_LBM = 0;
70
if ( SDL_RWread( src, magic, 4+4+4, 1 ) )
71
{
72
73
74
if ( !memcmp( magic, "FORM", 4 ) &&
( !memcmp( magic + 8, "PBM ", 4 ) ||
!memcmp( magic + 8, "ILBM", 4 ) ) )
75
76
77
78
79
80
81
82
83
84
85
{
is_LBM = 1;
}
}
return( is_LBM );
}
SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
{
SDL_Surface *Image;
Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
86
Uint32 size, bytesloaded, nbcolors;
87
88
Uint32 i, j, bytesperline, nbplanes, plane, h;
Uint32 remainingbytes;
89
Uint32 width;
90
91
BMHD bmhd;
char *error;
92
Uint8 flagHAM,flagEHB;
93
94
95
96
97
Image = NULL;
error = NULL;
MiniBuf = NULL;
98
99
100
101
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
102
if ( !SDL_RWread( src, id, 4, 1 ) )
103
{
104
error="error reading IFF chunk";
105
106
107
goto done;
}
108
109
/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
if ( !SDL_RWread( src, &size, 4, 1 ) )
110
{
111
error="error reading IFF chunk size";
112
113
114
goto done;
}
115
/* As size is not used here, no need to swap it */
116
117
if ( memcmp( id, "FORM", 4 ) != 0 )
118
{
119
error="not a IFF file";
120
121
122
goto done;
}
123
if ( !SDL_RWread( src, id, 4, 1 ) )
124
{
125
error="error reading IFF chunk";
126
127
128
129
130
goto done;
}
pbm = 0;
131
132
/* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
133
134
else if ( memcmp( id, "ILBM", 4 ) )
{
135
error="not a IFF picture";
136
137
138
139
140
141
goto done;
}
nbcolors = 0;
memset( &bmhd, 0, sizeof( BMHD ) );
142
143
flagHAM = 0;
flagEHB = 0;
144
145
while ( memcmp( id, "BODY", 4 ) != 0 )
146
147
148
{
if ( !SDL_RWread( src, id, 4, 1 ) )
{
149
error="error reading IFF chunk";
150
151
152
goto done;
}
153
if ( !SDL_RWread( src, &size, 4, 1 ) )
154
{
155
error="error reading IFF chunk size";
156
157
158
159
160
161
goto done;
}
bytesloaded = 0;
size = SDL_SwapBE32( size );
162
163
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
164
165
166
{
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
{
167
error="error reading BMHD chunk";
168
169
170
171
172
173
174
175
176
177
178
179
180
181
goto done;
}
bytesloaded = sizeof( BMHD );
bmhd.w = SDL_SwapBE16( bmhd.w );
bmhd.h = SDL_SwapBE16( bmhd.h );
bmhd.x = SDL_SwapBE16( bmhd.x );
bmhd.y = SDL_SwapBE16( bmhd.y );
bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor );
bmhd.Lpage = SDL_SwapBE16( bmhd.Lpage );
bmhd.Hpage = SDL_SwapBE16( bmhd.Hpage );
}
182
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
183
184
185
{
if ( !SDL_RWread( src, &colormap, size, 1 ) )
{
186
error="error reading CMAP chunk";
187
188
189
190
191
192
193
goto done;
}
bytesloaded = size;
nbcolors = size / 3;
}
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
if ( !memcmp( id, "CAMG", 4 ) ) /* Amiga ViewMode */
{
Uint32 viewmodes;
if ( !SDL_RWread( src, &viewmodes, sizeof(viewmodes), 1 ) )
{
error="error reading CAMG chunk";
goto done;
}
bytesloaded = size;
viewmodes = SDL_SwapBE32( viewmodes );
if ( viewmodes & 0x0800 )
flagHAM = 1;
if ( viewmodes & 0x0080 )
flagEHB = 1;
}
211
212
if ( memcmp( id, "BODY", 4 ) )
{
213
if ( size & 1 ) ++size; /* padding ! */
214
size -= bytesloaded;
215
216
/* skip the remaining bytes of this chunk */
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
217
218
219
}
}
220
/* compute some usefull values, based on the bitmap header */
221
222
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
223
224
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
225
226
nbplanes = bmhd.planes;
227
228
if ( pbm ) /* File format : 'Packed Bitmap' */
229
{
230
bytesperline *= 8;
231
232
233
nbplanes = 1;
}
234
if ( bmhd.mask & 1 ) ++nbplanes; /* There is a mask ( 'stencil' ) */
235
236
237
/* Allocate memory for a temporary buffer ( used for
decompression/deinterleaving ) */
238
239
240
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
{
241
error="no enough memory for temporary buffer";
242
243
244
goto done;
}
245
if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, (bmhd.planes==24 || flagHAM==1)?24:8, 0, 0, 0, 0 ) ) == NULL )
246
247
goto done;
248
249
250
if ( bmhd.mask & 2 ) /* There is a transparent color */
SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
251
/* Update palette informations */
252
253
/* There is no palette in 24 bits ILBM file */
254
if ( nbcolors>0 && flagHAM==0 )
255
{
256
int nbrcolorsfinal = 1 << nbplanes;
257
ptr = &colormap[0];
258
259
260
261
262
263
264
for ( i=0; i<nbcolors; i++ )
{
Image->format->palette->colors[i].r = *ptr++;
Image->format->palette->colors[i].g = *ptr++;
Image->format->palette->colors[i].b = *ptr++;
}
265
266
267
268
/* Amiga EHB mode (Extra-Half-Bright) */
/* 6 bitplanes mode with a 32 colors palette */
/* The 32 last colors are the same but divided by 2 */
269
/* Some Amiga pictures save 64 colors with 32 last wrong colors, */
270
271
272
/* they shouldn't !, and here we overwrite these 32 bad colors. */
if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
{
273
nbcolors = 64;
274
275
276
277
278
279
280
281
ptr = &colormap[0];
for ( i=32; i<64; i++ )
{
Image->format->palette->colors[i].r = (*ptr++)/2;
Image->format->palette->colors[i].g = (*ptr++)/2;
Image->format->palette->colors[i].b = (*ptr++)/2;
}
}
282
283
284
/* If nbcolors < 2^nbplanes, repeat the colormap */
/* This happens when pictures have a stencil mask */
285
286
287
if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
nbrcolorsfinal = (1<<bmhd.planes);
}
288
for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
289
290
291
292
293
{
Image->format->palette->colors[i].r = Image->format->palette->colors[i%nbcolors].r;
Image->format->palette->colors[i].g = Image->format->palette->colors[i%nbcolors].g;
Image->format->palette->colors[i].b = Image->format->palette->colors[i%nbcolors].b;
}
294
Image->format->palette->ncolors = nbrcolorsfinal;
295
296
}
297
/* Get the bitmap */
298
299
300
for ( h=0; h < bmhd.h; h++ )
{
301
302
303
/* uncompress the datas of each planes */
for ( plane=0; plane < nbplanes; plane++ )
304
{
305
306
ptr = MiniBuf + ( plane * bytesperline );
307
remainingbytes = bytesperline;
308
309
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
310
{
311
do
312
{
313
if ( !SDL_RWread( src, &count, 1, 1 ) )
314
{
315
error="error reading BODY chunk";
316
317
goto done;
}
318
319
320
if ( count & 0x80 )
{
321
322
323
count ^= 0xFF;
count += 2; /* now it */
324
325
326
327
328
329
330
331
332
if ( !SDL_RWread( src, &color, 1, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
memset( ptr, color, count );
}
else
{
333
++count;
334
335
336
337
338
339
340
if ( !SDL_RWread( src, ptr, count, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
}
341
342
343
ptr += count;
remainingbytes -= count;
344
345
346
} while ( remainingbytes > 0 );
}
347
else
348
{
349
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
350
{
351
error="error reading BODY chunk";
352
353
354
355
goto done;
}
}
}
356
357
/* One line has been read, store it ! */
358
359
ptr = Image->pixels;
360
if ( nbplanes==24 || flagHAM==1 )
361
362
363
364
ptr += h * width * 3;
else
ptr += h * width;
365
if ( pbm ) /* File format : 'Packed Bitmap' */
366
367
368
{
memcpy( ptr, MiniBuf, width );
}
369
else /* We have to un-interlace the bits ! */
370
{
371
if ( nbplanes!=24 && flagHAM==0 )
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
{
size = ( width + 7 ) / 8;
for ( i=0; i < size; i++ )
{
memset( ptr, 0, 8 );
for ( plane=0; plane < nbplanes; plane++ )
{
color = *( MiniBuf + i + ( plane * bytesperline ) );
msk = 0x80;
for ( j=0; j<8; j++ )
{
if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j );
else ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 );
msk >>= 1;
}
}
ptr += 8;
}
}
else
396
{
397
Uint32 finalcolor = 0;
398
399
size = ( width + 7 ) / 8;
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
400
/* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
401
for ( i=0; i<width; i=i+8 )
402
{
403
Uint8 maskBit = 0x80;
404
405
for ( j=0; j<8; j++ )
{
406
407
Uint32 pixelcolor = 0;
Uint32 maskColor = 1;
408
409
410
411
412
Uint8 dataBody;
for ( plane=0; plane < nbplanes; plane++ )
{
dataBody = MiniBuf[ plane*size+i/8 ];
if ( dataBody&maskBit )
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
pixelcolor = pixelcolor | maskColor;
maskColor = maskColor<<1;
}
/* HAM : 12 bits RGB image (4 bits per color component) */
/* HAM8 : 18 bits RGB image (6 bits per color component) */
if ( flagHAM )
{
switch( pixelcolor>>(nbplanes-2) )
{
case 0: /* take direct color from palette */
finalcolor = colormap[ pixelcolor*3 ] + (colormap[ pixelcolor*3+1 ]<<8) + (colormap[ pixelcolor*3+2 ]<<16);
break;
case 1: /* modify only blue component */
finalcolor = finalcolor&0x00FFFF;
finalcolor = finalcolor | (pixelcolor<<(16+(10-nbplanes)));
break;
case 2: /* modify only red component */
finalcolor = finalcolor&0xFFFF00;
finalcolor = finalcolor | pixelcolor<<(10-nbplanes);
break;
case 3: /* modify only green component */
finalcolor = finalcolor&0xFF00FF;
finalcolor = finalcolor | (pixelcolor<<(8+(10-nbplanes)));
break;
}
}
else
{
finalcolor = pixelcolor;
442
443
444
}
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
{
445
446
447
*ptr++ = finalcolor>>16;
*ptr++ = finalcolor>>8;
*ptr++ = finalcolor;
448
449
450
}
else
{
451
452
453
*ptr++ = finalcolor;
*ptr++ = finalcolor>>8;
*ptr++ = finalcolor>>16;
454
455
456
}
maskBit = maskBit>>1;
457
458
459
460
461
462
463
464
465
466
}
}
}
}
}
done:
if ( MiniBuf ) free( MiniBuf );
467
if ( error )
468
469
{
IMG_SetError( error );
470
SDL_FreeSurface( Image );
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
Image = NULL;
}
return( Image );
}
#else /* LOAD_LBM */
/* See if an image is contained in a data source */
int IMG_isLBM(SDL_RWops *src)
{
return(0);
}
/* Load an IFF type image from an SDL datasource */
SDL_Surface *IMG_LoadLBM_RW(SDL_RWops *src)
{
return(NULL);
}
#endif /* LOAD_LBM */