Skip to content

Latest commit

 

History

History
491 lines (412 loc) · 11.8 KB

IMG_lbm.c

File metadata and controls

491 lines (412 loc) · 11.8 KB
 
Dec 14, 2001
Dec 14, 2001
2
SDL_image: An example image loading library for use with SDL
Jan 4, 2004
Jan 4, 2004
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
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Dec 14, 2001
Dec 14, 2001
22
23
/* $Id$ */
Jan 20, 2003
Jan 20, 2003
24
25
26
/* This is a ILBM image file loading framework
Load IFF pictures, PBM & ILBM packing methods, with or without stencil
Sep 15, 2004
Sep 15, 2004
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.
Jan 4, 2004
Jan 4, 2004
30
EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
Sep 15, 2004
Sep 15, 2004
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>
Dec 17, 2001
Dec 17, 2001
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
Nov 20, 2001
Nov 20, 2001
47
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
48
49
50
typedef struct
{
Nov 20, 2001
Nov 20, 2001
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;
Nov 20, 2001
Nov 20, 2001
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;
Jan 20, 2003
Jan 20, 2003
70
if ( SDL_RWread( src, magic, 4+4+4, 1 ) )
Jan 20, 2003
Jan 20, 2003
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;
Jan 20, 2003
Jan 20, 2003
86
Uint32 size, bytesloaded, nbcolors;
87
88
Uint32 i, j, bytesperline, nbplanes, plane, h;
Uint32 remainingbytes;
Feb 26, 2003
Feb 26, 2003
89
Uint32 width;
90
91
BMHD bmhd;
char *error;
Jan 4, 2004
Jan 4, 2004
92
Uint8 flagHAM,flagEHB;
93
94
95
96
97
Image = NULL;
error = NULL;
MiniBuf = NULL;
Jan 4, 2004
Jan 4, 2004
98
99
100
101
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
Jan 4, 2004
Jan 4, 2004
102
if ( !SDL_RWread( src, id, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
104
error="error reading IFF chunk";
105
106
107
goto done;
}
Nov 20, 2001
Nov 20, 2001
108
109
/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
if ( !SDL_RWread( src, &size, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
111
error="error reading IFF chunk size";
112
113
114
goto done;
}
Nov 20, 2001
Nov 20, 2001
115
/* As size is not used here, no need to swap it */
Jan 20, 2003
Jan 20, 2003
116
117
if ( memcmp( id, "FORM", 4 ) != 0 )
Jan 20, 2003
Jan 20, 2003
119
error="not a IFF file";
120
121
122
goto done;
}
Jan 20, 2003
Jan 20, 2003
123
if ( !SDL_RWread( src, id, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
125
error="error reading IFF chunk";
126
127
128
129
130
goto done;
}
pbm = 0;
Nov 20, 2001
Nov 20, 2001
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 ) )
{
Jan 20, 2003
Jan 20, 2003
135
error="not a IFF picture";
136
137
138
139
140
141
goto done;
}
nbcolors = 0;
memset( &bmhd, 0, sizeof( BMHD ) );
Jan 4, 2004
Jan 4, 2004
142
143
flagHAM = 0;
flagEHB = 0;
Jan 20, 2003
Jan 20, 2003
145
while ( memcmp( id, "BODY", 4 ) != 0 )
146
147
148
{
if ( !SDL_RWread( src, id, 4, 1 ) )
{
Jan 20, 2003
Jan 20, 2003
149
error="error reading IFF chunk";
150
151
152
goto done;
}
Jan 20, 2003
Jan 20, 2003
153
if ( !SDL_RWread( src, &size, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
155
error="error reading IFF chunk size";
156
157
158
159
160
161
goto done;
}
bytesloaded = 0;
size = SDL_SwapBE32( size );
Jan 20, 2003
Jan 20, 2003
162
Nov 20, 2001
Nov 20, 2001
163
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
164
165
166
{
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
{
Jan 20, 2003
Jan 20, 2003
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 );
}
Nov 20, 2001
Nov 20, 2001
182
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
183
184
185
{
if ( !SDL_RWread( src, &colormap, size, 1 ) )
{
Jan 20, 2003
Jan 20, 2003
186
error="error reading CMAP chunk";
187
188
189
190
191
192
193
goto done;
}
bytesloaded = size;
nbcolors = size / 3;
}
Jan 4, 2004
Jan 4, 2004
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 ) )
{
Jan 20, 2003
Jan 20, 2003
213
if ( size & 1 ) ++size; /* padding ! */
214
size -= bytesloaded;
Nov 20, 2001
Nov 20, 2001
215
216
/* skip the remaining bytes of this chunk */
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
217
218
219
}
}
Nov 20, 2001
Nov 20, 2001
220
/* compute some usefull values, based on the bitmap header */
Nov 20, 2001
Nov 20, 2001
222
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
Nov 20, 2001
Nov 20, 2001
224
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
Nov 20, 2001
Nov 20, 2001
226
nbplanes = bmhd.planes;
Nov 20, 2001
Nov 20, 2001
228
if ( pbm ) /* File format : 'Packed Bitmap' */
Jan 20, 2003
Jan 20, 2003
230
bytesperline *= 8;
231
232
233
nbplanes = 1;
}
Feb 9, 2004
Feb 9, 2004
234
if ( bmhd.mask & 1 ) ++nbplanes; /* There is a mask ( 'stencil' ) */
Nov 20, 2001
Nov 20, 2001
236
237
/* Allocate memory for a temporary buffer ( used for
decompression/deinterleaving ) */
238
239
240
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
{
Jan 20, 2003
Jan 20, 2003
241
error="no enough memory for temporary buffer";
242
243
244
goto done;
}
Jan 4, 2004
Jan 4, 2004
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;
Feb 9, 2004
Feb 9, 2004
248
249
250
if ( bmhd.mask & 2 ) /* There is a transparent color */
SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
Nov 20, 2001
Nov 20, 2001
251
/* Update palette informations */
Jan 20, 2003
Jan 20, 2003
253
/* There is no palette in 24 bits ILBM file */
Jan 4, 2004
Jan 4, 2004
254
if ( nbcolors>0 && flagHAM==0 )
Jan 20, 2003
Jan 20, 2003
255
{
Sep 15, 2004
Sep 15, 2004
256
int nbrcolorsfinal = 1 << nbplanes;
Jan 20, 2003
Jan 20, 2003
257
ptr = &colormap[0];
Jan 20, 2003
Jan 20, 2003
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++;
}
Jan 4, 2004
Jan 4, 2004
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 */
Feb 9, 2004
Feb 9, 2004
269
/* Some Amiga pictures save 64 colors with 32 last wrong colors, */
Jan 4, 2004
Jan 4, 2004
270
271
272
/* they shouldn't !, and here we overwrite these 32 bad colors. */
if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
{
Feb 9, 2004
Feb 9, 2004
273
nbcolors = 64;
Jan 4, 2004
Jan 4, 2004
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;
}
}
Feb 9, 2004
Feb 9, 2004
282
283
284
/* If nbcolors < 2^nbplanes, repeat the colormap */
/* This happens when pictures have a stencil mask */
Sep 15, 2004
Sep 15, 2004
285
286
287
if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
nbrcolorsfinal = (1<<bmhd.planes);
}
Nov 15, 2004
Nov 15, 2004
288
for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
Feb 9, 2004
Feb 9, 2004
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;
}
Sep 15, 2004
Sep 15, 2004
294
Image->format->palette->ncolors = nbrcolorsfinal;
295
296
}
Nov 20, 2001
Nov 20, 2001
297
/* Get the bitmap */
298
299
300
for ( h=0; h < bmhd.h; h++ )
{
Jan 20, 2003
Jan 20, 2003
301
302
303
/* uncompress the datas of each planes */
for ( plane=0; plane < nbplanes; plane++ )
Jan 20, 2003
Jan 20, 2003
305
306
ptr = MiniBuf + ( plane * bytesperline );
307
remainingbytes = bytesperline;
Jan 20, 2003
Jan 20, 2003
308
Nov 20, 2001
Nov 20, 2001
309
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
Jan 20, 2003
Jan 20, 2003
311
do
Jan 20, 2003
Jan 20, 2003
313
if ( !SDL_RWread( src, &count, 1, 1 ) )
Jan 20, 2003
Jan 20, 2003
315
error="error reading BODY chunk";
316
317
goto done;
}
Jan 20, 2003
Jan 20, 2003
318
319
320
if ( count & 0x80 )
{
Jan 20, 2003
Jan 20, 2003
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
{
Jan 20, 2003
Jan 20, 2003
333
++count;
334
335
336
337
338
339
340
if ( !SDL_RWread( src, ptr, count, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
}
Jan 20, 2003
Jan 20, 2003
341
342
343
ptr += count;
remainingbytes -= count;
Jan 20, 2003
Jan 20, 2003
344
345
346
} while ( remainingbytes > 0 );
}
Jan 20, 2003
Jan 20, 2003
347
else
Jan 20, 2003
Jan 20, 2003
349
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
Jan 20, 2003
Jan 20, 2003
351
error="error reading BODY chunk";
352
353
354
355
goto done;
}
}
}
Jan 20, 2003
Jan 20, 2003
356
357
/* One line has been read, store it ! */
358
359
ptr = Image->pixels;
Jan 4, 2004
Jan 4, 2004
360
if ( nbplanes==24 || flagHAM==1 )
Jan 20, 2003
Jan 20, 2003
361
362
363
364
ptr += h * width * 3;
else
ptr += h * width;
Nov 20, 2001
Nov 20, 2001
365
if ( pbm ) /* File format : 'Packed Bitmap' */
366
367
368
{
memcpy( ptr, MiniBuf, width );
}
Nov 20, 2001
Nov 20, 2001
369
else /* We have to un-interlace the bits ! */
Jan 4, 2004
Jan 4, 2004
371
if ( nbplanes!=24 && flagHAM==0 )
Jan 20, 2003
Jan 20, 2003
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
Jan 4, 2004
Jan 4, 2004
397
Uint32 finalcolor = 0;
Jan 20, 2003
Jan 20, 2003
398
399
size = ( width + 7 ) / 8;
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
Jan 4, 2004
Jan 4, 2004
400
/* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
Jan 20, 2003
Jan 20, 2003
401
for ( i=0; i<width; i=i+8 )
Jan 20, 2003
Jan 20, 2003
403
Uint8 maskBit = 0x80;
404
405
for ( j=0; j<8; j++ )
{
Jan 4, 2004
Jan 4, 2004
406
407
Uint32 pixelcolor = 0;
Uint32 maskColor = 1;
Jan 20, 2003
Jan 20, 2003
408
409
410
411
412
Uint8 dataBody;
for ( plane=0; plane < nbplanes; plane++ )
{
dataBody = MiniBuf[ plane*size+i/8 ];
if ( dataBody&maskBit )
Jan 4, 2004
Jan 4, 2004
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;
Jan 20, 2003
Jan 20, 2003
442
443
444
}
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
{
Jan 4, 2004
Jan 4, 2004
445
446
447
*ptr++ = finalcolor>>16;
*ptr++ = finalcolor>>8;
*ptr++ = finalcolor;
Jan 20, 2003
Jan 20, 2003
448
449
450
}
else
{
Jan 4, 2004
Jan 4, 2004
451
452
453
*ptr++ = finalcolor;
*ptr++ = finalcolor>>8;
*ptr++ = finalcolor>>16;
Jan 20, 2003
Jan 20, 2003
454
455
456
}
maskBit = maskBit>>1;
457
458
459
460
461
462
463
464
465
466
}
}
}
}
}
done:
if ( MiniBuf ) free( MiniBuf );
Jan 20, 2003
Jan 20, 2003
467
if ( error )
468
469
{
IMG_SetError( error );
Jan 20, 2003
Jan 20, 2003
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 */