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