[email protected]
http://www.multimania.com/mavati
http://www.multimania.com/mavati
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_endian.h"
#include "SDL_image.h"
#ifdef LOAD_LBM
#define MAXCOLORS 256
typedef struct
{
    Uint16 w, h;		
    Sint16 x, y;		
    Uint8 planes;		
    Uint8 mask;			
    Uint8 tcomp;		
    Uint8 pad1;			
    Uint16 tcolor;		
    Uint8 xAspect,		
         yAspect;
    Sint16  Lpage;		
    Sint16  Hpage;		
} BMHD;
int IMG_isLBM( SDL_RWops *src )
{
	int   is_LBM;
	Uint8 magic[4+4+4];
	is_LBM = 0;
	if ( SDL_RWread( src, magic, 4+4+4, 1 ) )
	{
		if ( !memcmp( magic, "FORM", 4 ) &&
			( !memcmp( magic + 8, "PBM ", 4 ) ||
			  !memcmp( magic + 8, "ILBM", 4 ) ) )
		{
			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;
	Uint32      size, bytesloaded, nbcolors;
	Uint32      i, j, bytesperline, nbplanes, plane, h;
	Uint32      remainingbytes;
	Uint32      width;
	BMHD	      bmhd;
	char        *error;
	Uint8       flagHAM,flagEHB;
	Image   = NULL;
	error   = NULL;
	MiniBuf = NULL;
	if ( !src ) {
		
		return NULL;
	}
	if ( !SDL_RWread( src, id, 4, 1 ) )
	{
		error="error reading IFF chunk";
		goto done;
	}
	
	if ( !SDL_RWread( src, &size, 4, 1 ) )
	{
		error="error reading IFF chunk size";
		goto done;
	}
	
	if ( memcmp( id, "FORM", 4 ) != 0 )
	{
		error="not a IFF file";
		goto done;
	}
	if ( !SDL_RWread( src, id, 4, 1 ) )
	{
		error="error reading IFF chunk";
		goto done;
	}
	pbm = 0;
	
	if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
	else if ( memcmp( id, "ILBM", 4 ) )
	{
		error="not a IFF picture";
		goto done;
	}
	nbcolors = 0;
	memset( &bmhd, 0, sizeof( BMHD ) );
	flagHAM = 0;
	flagEHB = 0;
	while ( memcmp( id, "BODY", 4 ) != 0 )
	{
		if ( !SDL_RWread( src, id, 4, 1 ) ) 
		{
			error="error reading IFF chunk";
			goto done;
		}
		if ( !SDL_RWread( src, &size, 4, 1 ) )
		{
			error="error reading IFF chunk size";
			goto done;
		}
		bytesloaded = 0;
		size = SDL_SwapBE32( size );
		if ( !memcmp( id, "BMHD", 4 ) ) 
		{
			if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
			{
				error="error reading BMHD chunk";
				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 );
		}
		if ( !memcmp( id, "CMAP", 4 ) ) 
		{
			if ( !SDL_RWread( src, &colormap, size, 1 ) )
			{
				error="error reading CMAP chunk";
				goto done;
			}
			bytesloaded = size;
			nbcolors = size / 3;
		}
		if ( !memcmp( id, "CAMG", 4 ) ) 
		{
			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;
		}
		if ( memcmp( id, "BODY", 4 ) )
		{
			if ( size & 1 )	++size;  	
			size -= bytesloaded;
			
			if ( size )	SDL_RWseek( src, size, SEEK_CUR );
		}
	}
	
	width = ( bmhd.w + 15 ) & 0xFFFFFFF0;  
	bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
	nbplanes = bmhd.planes;
	if ( pbm )                         
	{
		bytesperline *= 8;
		nbplanes = 1;
	}
	if ( bmhd.mask & 1 ) ++nbplanes;   
	
	if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
	{
		error="no enough memory for temporary buffer";
		goto done;
	}
	if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, (bmhd.planes==24 || flagHAM==1)?24:8, 0, 0, 0, 0 ) ) == NULL )
	   goto done;
	if ( bmhd.mask & 2 )               
		SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
	
	
	if ( nbcolors>0 && flagHAM==0 )
	{
		int nbrcolorsfinal = 1 << nbplanes;
		ptr = &colormap[0];
		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++;
		}
		
		
		
		
		
		if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
		{
			nbcolors = 64;
			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;
			}
		}
		
		
		if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
			nbrcolorsfinal = (1<<bmhd.planes);
		}
		for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
		{
			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;
		}
		Image->format->palette->ncolors = nbrcolorsfinal;
	}
	
	for ( h=0; h < bmhd.h; h++ )
	{
		
		for ( plane=0; plane < nbplanes; plane++ )
		{
			ptr = MiniBuf + ( plane * bytesperline );
			remainingbytes = bytesperline;
			if ( bmhd.tcomp == 1 )	    
			{
				do
				{
					if ( !SDL_RWread( src, &count, 1, 1 ) )
					{
						error="error reading BODY chunk";
						goto done;
					}
					if ( count & 0x80 )
					{
						count ^= 0xFF;
						count += 2; 
						if ( !SDL_RWread( src, &color, 1, 1 ) )
						{
						   error="error reading BODY chunk";
							goto done;
						}
						memset( ptr, color, count );
					}
					else
					{
						++count;
						if ( !SDL_RWread( src, ptr, count, 1 ) )
						{
						   error="error reading BODY chunk";
							goto done;
						}
					}
					ptr += count;
					remainingbytes -= count;
				} while ( remainingbytes > 0 );
			}
			else
			{
				if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
				{
					error="error reading BODY chunk";
					goto done;
				}
			}
		}
		
		ptr = Image->pixels;
		if ( nbplanes==24 || flagHAM==1 )
			ptr += h * width * 3;
		else
			ptr += h * width;
		if ( pbm )                 
		{
		   memcpy( ptr, MiniBuf, width );
		}
		else		
		{
			if ( nbplanes!=24 && flagHAM==0 )
			{
				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
			{
				Uint32 finalcolor = 0;
				size = ( width + 7 ) / 8;
				
				
				for ( i=0; i<width; i=i+8 )
				{
					Uint8 maskBit = 0x80;
					for ( j=0; j<8; j++ )
					{
						Uint32 pixelcolor = 0;
						Uint32 maskColor = 1;
						Uint8 dataBody;
						for ( plane=0; plane < nbplanes; plane++ )
						{
							dataBody = MiniBuf[ plane*size+i/8 ];
							if ( dataBody&maskBit )
								pixelcolor = pixelcolor | maskColor;
							maskColor = maskColor<<1;
						}
						
						
						if ( flagHAM )
						{
							switch( pixelcolor>>(nbplanes-2) )
							{
								case 0: 
									finalcolor = colormap[ pixelcolor*3 ] + (colormap[ pixelcolor*3+1 ]<<8) + (colormap[ pixelcolor*3+2 ]<<16);
									break;
								case 1: 
									finalcolor = finalcolor&0x00FFFF;
									finalcolor = finalcolor | (pixelcolor<<(16+(10-nbplanes)));
									break;
								case 2: 
									finalcolor = finalcolor&0xFFFF00;
									finalcolor = finalcolor | pixelcolor<<(10-nbplanes);
									break;
								case 3: 
									finalcolor = finalcolor&0xFF00FF;
									finalcolor = finalcolor | (pixelcolor<<(8+(10-nbplanes)));
									break;
							}
						}
						else
						{
							finalcolor = pixelcolor;
						}
						if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
						{
							*ptr++ = finalcolor>>16;
							*ptr++ = finalcolor>>8;
							*ptr++ = finalcolor;
						}
						else
						{
							*ptr++ = finalcolor;
							*ptr++ = finalcolor>>8;
							*ptr++ = finalcolor>>16;
						}
						maskBit = maskBit>>1;
					}
				}
			}
		}
	}
done:
	if ( MiniBuf ) free( MiniBuf );
	if ( error )
	{
		IMG_SetError( error );
		SDL_FreeSurface( Image );
		Image = NULL;
	}
	return( Image );
}
#else 
int IMG_isLBM(SDL_RWops *src)
{
	return(0);
}
SDL_Surface *IMG_LoadLBM_RW(SDL_RWops *src)
{
	return(NULL);
}
#endif