IMG_lbm.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 23 Sep 2001 23:33:06 +0000
changeset 45 45736a3044c0
child 50 754bff7e03aa
permissions -rw-r--r--
Daniel Morais - Sun Sep 23 16:32:13 PDT 2001
* Added support for the IFF (LBM) image format
slouken@45
     1
/*
slouken@45
     2
    IMGLIB:  An example image loading library for use with SDL
slouken@45
     3
    Copyright (C) 1999  Sam Lantinga
slouken@45
     4
slouken@45
     5
    This library is free software; you can redistribute it and/or
slouken@45
     6
    modify it under the terms of the GNU Library General Public
slouken@45
     7
    License as published by the Free Software Foundation; either
slouken@45
     8
    version 2 of the License, or (at your option) any later version.
slouken@45
     9
slouken@45
    10
    This library is distributed in the hope that it will be useful,
slouken@45
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@45
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@45
    13
    Library General Public License for more details.
slouken@45
    14
slouken@45
    15
    You should have received a copy of the GNU Library General Public
slouken@45
    16
    License along with this library; if not, write to the Free
slouken@45
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@45
    18
slouken@45
    19
    Sam Lantinga
slouken@45
    20
    5635-34 Springhouse Dr.
slouken@45
    21
    Pleasanton, CA 94588 (USA)
slouken@45
    22
    slouken@devolution.com
slouken@45
    23
*/
slouken@45
    24
 
slouken@45
    25
/* This is a ILBM image file loading framework
slouken@45
    26
   Load IFF pictures, PBM & ILBM packing methods, with or without stencil
slouken@45
    27
   Written by Daniel Morais ( Daniel@Morais.com ) in September 2001
slouken@45
    28
*/
slouken@45
    29
slouken@45
    30
#include <stdio.h>
slouken@45
    31
#include <stdlib.h>
slouken@45
    32
slouken@45
    33
#include "SDL_endian.h"
slouken@45
    34
#include "SDL_image.h"
slouken@45
    35
slouken@45
    36
#ifdef LOAD_LBM
slouken@45
    37
slouken@45
    38
slouken@45
    39
//===========================================================================
slouken@45
    40
// DEFINES
slouken@45
    41
//===========================================================================
slouken@45
    42
slouken@45
    43
#define MAXCOLORS 256
slouken@45
    44
slouken@45
    45
//===========================================================================
slouken@45
    46
// STRUCTURES
slouken@45
    47
//===========================================================================
slouken@45
    48
slouken@45
    49
// Structure for an IFF picture ( BMHD = Bitmap Header )
slouken@45
    50
slouken@45
    51
typedef struct
slouken@45
    52
{
slouken@45
    53
   Uint16 w, h;		// width & height of the bitmap in pixels
slouken@45
    54
   Sint16 x, y;      // screen coordinates of the bitmap
slouken@45
    55
   Uint8 planes;     // number of planes of the bitmap
slouken@45
    56
   Uint8 mask;       // mask type ( 0 => no mask )
slouken@45
    57
   Uint8 tcomp;      // compression type
slouken@45
    58
   Uint8 pad1;       // dummy value, for padding
slouken@45
    59
   Uint16 tcolor;    // transparent color
slouken@45
    60
   Uint8 xAspect,    // pixel aspect ratio
slouken@45
    61
         yAspect;
slouken@45
    62
   Sint16  Lpage;		// width of the screen in pixels
slouken@45
    63
   Sint16  Hpage;		// height of the screen in pixels
slouken@45
    64
slouken@45
    65
} BMHD;
slouken@45
    66
slouken@45
    67
//===========================================================================
slouken@45
    68
// See if an image is contained in a data source
slouken@45
    69
slouken@45
    70
int IMG_isLBM( SDL_RWops *src )
slouken@45
    71
{
slouken@45
    72
	int   is_LBM;
slouken@45
    73
	Uint8 magic[4+4+4];
slouken@45
    74
slouken@45
    75
	is_LBM = 0;
slouken@45
    76
	if ( SDL_RWread( src, magic, 4+4+4, 1 ) ) 
slouken@45
    77
	{
slouken@45
    78
		if ( !memcmp( magic, "FORM", 4 ) && 
slouken@45
    79
			( !memcmp( magic + 8, "PBM ", 4 ) || 
slouken@45
    80
			  !memcmp( magic + 8, "ILBM", 4 ) ) ) 
slouken@45
    81
		{
slouken@45
    82
			is_LBM = 1;
slouken@45
    83
		}
slouken@45
    84
	}
slouken@45
    85
	return( is_LBM );
slouken@45
    86
}
slouken@45
    87
slouken@45
    88
//===========================================================================
slouken@45
    89
// Load a IFF type image from an SDL datasource
slouken@45
    90
slouken@45
    91
SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
slouken@45
    92
{
slouken@45
    93
	SDL_Surface *Image;
slouken@45
    94
	Uint8       id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
slouken@45
    95
   Uint32      size, bytesloaded, nbcolors;
slouken@45
    96
	Uint32      i, j, bytesperline, nbplanes, plane, h;
slouken@45
    97
	Uint32      remainingbytes;
slouken@45
    98
	int         width;
slouken@45
    99
	BMHD	      bmhd;
slouken@45
   100
	char        *error;
slouken@45
   101
slouken@45
   102
	Image   = NULL;
slouken@45
   103
	error   = NULL;
slouken@45
   104
	MiniBuf = NULL;
slouken@45
   105
slouken@45
   106
	if ( src == NULL ) goto done;
slouken@45
   107
slouken@45
   108
	if ( !SDL_RWread( src, id, 4, 1 ) ) 
slouken@45
   109
	{
slouken@45
   110
	   error="error reading IFF chunk";
slouken@45
   111
		goto done;
slouken@45
   112
	}
slouken@45
   113
slouken@45
   114
	if ( !SDL_RWread( src, &size, 4, 1 ) ) // Should be the size of the file minus 4+4 ( 'FORM'+size )
slouken@45
   115
	{
slouken@45
   116
	   error="error reading IFF chunk size";
slouken@45
   117
		goto done;
slouken@45
   118
	}
slouken@45
   119
slouken@45
   120
	// As size is not used here, no need to swap it
slouken@45
   121
	
slouken@45
   122
	if ( memcmp( id, "FORM", 4 ) != 0 ) 
slouken@45
   123
	{
slouken@45
   124
	   error="not a IFF file";
slouken@45
   125
		goto done;
slouken@45
   126
	}
slouken@45
   127
slouken@45
   128
	if ( !SDL_RWread( src, id, 4, 1 ) ) 
slouken@45
   129
	{
slouken@45
   130
	   error="error reading IFF chunk";
slouken@45
   131
		goto done;
slouken@45
   132
	}
slouken@45
   133
slouken@45
   134
	pbm = 0;
slouken@45
   135
slouken@45
   136
	if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1; // File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap
slouken@45
   137
	else if ( memcmp( id, "ILBM", 4 ) )
slouken@45
   138
	{
slouken@45
   139
	   error="not a IFF picture";
slouken@45
   140
		goto done;
slouken@45
   141
	}
slouken@45
   142
slouken@45
   143
	nbcolors = 0;
slouken@45
   144
slouken@45
   145
	memset( &bmhd, 0, sizeof( BMHD ) );
slouken@45
   146
slouken@45
   147
	while ( memcmp( id, "BODY", 4 ) != 0 ) 
slouken@45
   148
	{
slouken@45
   149
		if ( !SDL_RWread( src, id, 4, 1 ) ) 
slouken@45
   150
		{
slouken@45
   151
	      error="error reading IFF chunk";
slouken@45
   152
			goto done;
slouken@45
   153
		}
slouken@45
   154
slouken@45
   155
		if ( !SDL_RWread( src, &size, 4, 1 ) ) 
slouken@45
   156
		{
slouken@45
   157
	      error="error reading IFF chunk size";
slouken@45
   158
			goto done;
slouken@45
   159
		}
slouken@45
   160
slouken@45
   161
		bytesloaded = 0;
slouken@45
   162
slouken@45
   163
		size = SDL_SwapBE32( size );
slouken@45
   164
		
slouken@45
   165
		if ( !memcmp( id, "BMHD", 4 ) ) // Bitmap header
slouken@45
   166
		{
slouken@45
   167
			if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
slouken@45
   168
			{
slouken@45
   169
			   error="error reading BMHD chunk";
slouken@45
   170
				goto done;
slouken@45
   171
			}
slouken@45
   172
slouken@45
   173
			bytesloaded = sizeof( BMHD );
slouken@45
   174
slouken@45
   175
			bmhd.w 		= SDL_SwapBE16( bmhd.w );
slouken@45
   176
			bmhd.h 		= SDL_SwapBE16( bmhd.h );
slouken@45
   177
			bmhd.x 		= SDL_SwapBE16( bmhd.x );
slouken@45
   178
			bmhd.y 		= SDL_SwapBE16( bmhd.y );
slouken@45
   179
			bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor );
slouken@45
   180
			bmhd.Lpage 	= SDL_SwapBE16( bmhd.Lpage );
slouken@45
   181
			bmhd.Hpage 	= SDL_SwapBE16( bmhd.Hpage );
slouken@45
   182
		}
slouken@45
   183
slouken@45
   184
		if ( !memcmp( id, "CMAP", 4 ) ) // palette ( Color Map )
slouken@45
   185
		{
slouken@45
   186
			if ( !SDL_RWread( src, &colormap, size, 1 ) )
slouken@45
   187
			{
slouken@45
   188
			   error="error reading CMAP chunk";
slouken@45
   189
				goto done;
slouken@45
   190
			}
slouken@45
   191
slouken@45
   192
			bytesloaded = size;
slouken@45
   193
			nbcolors = size / 3;
slouken@45
   194
		}
slouken@45
   195
slouken@45
   196
		if ( memcmp( id, "BODY", 4 ) )
slouken@45
   197
		{
slouken@45
   198
		   if ( size & 1 )	++size;  	// padding !
slouken@45
   199
			size -= bytesloaded;
slouken@45
   200
			if ( size )	SDL_RWseek( src, size, SEEK_CUR ); // skip the remaining bytes of this chunk
slouken@45
   201
		}
slouken@45
   202
	}
slouken@45
   203
slouken@45
   204
	// compute some usefull values, based on the bitmap header
slouken@45
   205
slouken@45
   206
	width = ( bmhd.w + 15 ) & 0xFFFFFFF0;        // Width in pixels modulo 16
slouken@45
   207
slouken@45
   208
	bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;	// Number of bytes per line
slouken@45
   209
slouken@45
   210
	nbplanes = bmhd.planes;                      // Number of planes
slouken@45
   211
slouken@45
   212
	if ( pbm )                                   // File format : 'Packed Bitmap'
slouken@45
   213
	{
slouken@45
   214
	   bytesperline *= 8;
slouken@45
   215
		nbplanes = 1;
slouken@45
   216
	}
slouken@45
   217
slouken@45
   218
	if ( bmhd.mask ) ++nbplanes;                 // There is a mask ( 'stencil' )
slouken@45
   219
slouken@45
   220
	// Allocate memory for a temporary buffer ( used for decompression/deinterleaving )
slouken@45
   221
slouken@45
   222
	if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
slouken@45
   223
	{
slouken@45
   224
	   error="no enough memory for temporary buffer";
slouken@45
   225
		goto done;
slouken@45
   226
	}
slouken@45
   227
slouken@45
   228
	// Create the surface
slouken@45
   229
slouken@45
   230
	if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, 8, 0, 0, 0, 0 ) ) == NULL )
slouken@45
   231
	   goto done;
slouken@45
   232
slouken@45
   233
	// Update palette informations
slouken@45
   234
slouken@45
   235
	Image->format->palette->ncolors = nbcolors;
slouken@45
   236
slouken@45
   237
	ptr = &colormap[0];
slouken@45
   238
slouken@45
   239
	for ( i=0; i<nbcolors; i++ )
slouken@45
   240
	{
slouken@45
   241
	   Image->format->palette->colors[i].r = *ptr++;
slouken@45
   242
	   Image->format->palette->colors[i].g = *ptr++;
slouken@45
   243
	   Image->format->palette->colors[i].b = *ptr++;
slouken@45
   244
	}
slouken@45
   245
slouken@45
   246
	// Get the bitmap
slouken@45
   247
slouken@45
   248
	for ( h=0; h < bmhd.h; h++ )
slouken@45
   249
	{
slouken@45
   250
		// uncompress the datas of each planes
slouken@45
   251
			  
slouken@45
   252
	   for ( plane=0; plane < nbplanes; plane++ )
slouken@45
   253
		{
slouken@45
   254
		   ptr = MiniBuf + ( plane * bytesperline );
slouken@45
   255
	
slouken@45
   256
			remainingbytes = bytesperline;
slouken@45
   257
	
slouken@45
   258
			if ( bmhd.tcomp == 1 )			// Datas are compressed
slouken@45
   259
			{
slouken@45
   260
			   do
slouken@45
   261
				{
slouken@45
   262
				   if ( !SDL_RWread( src, &count, 1, 1 ) )
slouken@45
   263
					{
slouken@45
   264
					   error="error reading BODY chunk";
slouken@45
   265
						goto done;
slouken@45
   266
					}
slouken@45
   267
	
slouken@45
   268
					if ( count & 0x80 )
slouken@45
   269
					{
slouken@45
   270
					   count ^= 0xFF;
slouken@45
   271
						count += 2; // now it
slouken@45
   272
						
slouken@45
   273
						if ( !SDL_RWread( src, &color, 1, 1 ) )
slouken@45
   274
						{
slouken@45
   275
						   error="error reading BODY chunk";
slouken@45
   276
							goto done;
slouken@45
   277
						}
slouken@45
   278
						memset( ptr, color, count );
slouken@45
   279
					}
slouken@45
   280
					else
slouken@45
   281
					{
slouken@45
   282
					   ++count;
slouken@45
   283
slouken@45
   284
						if ( !SDL_RWread( src, ptr, count, 1 ) )
slouken@45
   285
						{
slouken@45
   286
						   error="error reading BODY chunk";
slouken@45
   287
							goto done;
slouken@45
   288
						}
slouken@45
   289
					}
slouken@45
   290
	
slouken@45
   291
					ptr += count;
slouken@45
   292
					remainingbytes -= count;
slouken@45
   293
	
slouken@45
   294
				} while ( remainingbytes > 0 );
slouken@45
   295
			}
slouken@45
   296
			else	
slouken@45
   297
			{
slouken@45
   298
			   if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
slouken@45
   299
				{
slouken@45
   300
				   error="error reading BODY chunk";
slouken@45
   301
					goto done;
slouken@45
   302
				}
slouken@45
   303
			}
slouken@45
   304
		}
slouken@45
   305
	
slouken@45
   306
		// One line has been read, store it !
slouken@45
   307
slouken@45
   308
		ptr = Image->pixels;
slouken@45
   309
		ptr += h * width;
slouken@45
   310
	
slouken@45
   311
		if ( pbm )                 // File format : 'Packed Bitmap'
slouken@45
   312
		{
slouken@45
   313
		   memcpy( ptr, MiniBuf, width );
slouken@45
   314
		}
slouken@45
   315
		else							   // We have to un-interlace the bits !
slouken@45
   316
		{
slouken@45
   317
		   size = ( width + 7 ) / 8;
slouken@45
   318
	
slouken@45
   319
			for ( i=0; i < size; i++ )
slouken@45
   320
			{
slouken@45
   321
			   memset( ptr, 0, 8 );
slouken@45
   322
	
slouken@45
   323
				for ( plane=0; plane < nbplanes; plane++ )
slouken@45
   324
				{
slouken@45
   325
				   color = *( MiniBuf + i + ( plane * bytesperline ) );
slouken@45
   326
					msk = 0x80;
slouken@45
   327
	
slouken@45
   328
					for ( j=0; j<8; j++ )
slouken@45
   329
					{
slouken@45
   330
					   if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j );
slouken@45
   331
						else 	                    ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 );
slouken@45
   332
	
slouken@45
   333
						msk >>= 1;
slouken@45
   334
					}
slouken@45
   335
				}
slouken@45
   336
				ptr += 8;
slouken@45
   337
			}
slouken@45
   338
		}
slouken@45
   339
	}
slouken@45
   340
slouken@45
   341
done:
slouken@45
   342
slouken@45
   343
	if ( MiniBuf ) free( MiniBuf );
slouken@45
   344
slouken@45
   345
	if ( error ) 
slouken@45
   346
	{
slouken@45
   347
		IMG_SetError( error );
slouken@45
   348
	   SDL_FreeSurface( Image );
slouken@45
   349
		Image = NULL;
slouken@45
   350
	}
slouken@45
   351
slouken@45
   352
	return( Image );
slouken@45
   353
}
slouken@45
   354
slouken@45
   355
#else /* LOAD_LBM */
slouken@45
   356
slouken@45
   357
/* See if an image is contained in a data source */
slouken@45
   358
int IMG_isLBM(SDL_RWops *src)
slouken@45
   359
{
slouken@45
   360
	return(0);
slouken@45
   361
}
slouken@45
   362
slouken@45
   363
/* Load an IFF type image from an SDL datasource */
slouken@45
   364
SDL_Surface *IMG_LoadLBM_RW(SDL_RWops *src)
slouken@45
   365
{
slouken@45
   366
	return(NULL);
slouken@45
   367
}
slouken@45
   368
slouken@45
   369
#endif /* LOAD_LBM */