Date: Wed, 2 Apr 2003 19:13:31 +0200 From: David Raulo To: sdl@libsdl.org Subject: Re: [SDL] SDL_Image patch for ILBM Amiga images diff -BNaur sdl-image1.2-1.2.3/IMG_lbm.c sdl-image1.2-1.2.3.david/IMG_lbm.c --- sdl-image1.2-1.2.3/IMG_lbm.c 2003-02-26 17:57:45.000000000 +0100 +++ sdl-image1.2-1.2.3.david/IMG_lbm.c 2003-04-02 18:48:42.000000000 +0200 @@ -84,7 +84,10 @@ Uint32 i, j, bytesperline, nbplanes, plane, h; Uint32 remainingbytes; Uint32 width; - BMHD bmhd; + BMHD bmhd; + Uint32 camg; + Uint8 is_ham, is_ehb, red, green, blue; + Uint8 colors[8], ham_shift1, ham_shift2, ham_mask1, ham_mask2; char *error; Image = NULL; @@ -131,9 +134,10 @@ } nbcolors = 0; - + camg = 0; + memset( &bmhd, 0, sizeof( BMHD ) ); - + while ( memcmp( id, "BODY", 4 ) != 0 ) { if ( !SDL_RWread( src, id, 4, 1 ) ) @@ -183,6 +187,18 @@ nbcolors = size / 3; } + if ( !memcmp( id, "CAMG", 4 ) ) /* Commodore AMiGa */ + { + if ( !SDL_RWread( src, &camg, 4, 1 ) ) + { + error="error reading CAMG chunk"; + goto done; + } + + bytesloaded = 4; + camg = SDL_SwapBE32( camg ); + } + if ( memcmp( id, "BODY", 4 ) ) { if ( size & 1 ) ++size; /* padding ! */ @@ -206,7 +222,25 @@ nbplanes = 1; } - if ( bmhd.mask ) ++nbplanes; /* There is a mask ( 'stencil' ) */ + if ( bmhd.mask & 0x01 ) ++nbplanes; /* There is a mask ( 'stencil' ) */ + + /* Amiga HAM and EHB modes */ + + is_ham = 0; /* Hold And Modify */ + is_ehb = 0; /* Extra Half-Brite */ + if ( camg & 0x0800 ) + is_ham = 1; + else if ( ( camg & 0x0080 ) || + ( ( nbplanes == 6 ) && ( nbcolors == 32 ) ) ) + is_ehb = 1; + + if ( is_ham ) /* compute usefull values for decoding Amiga HAM images */ + { + ham_shift1 = nbplanes - 2; + ham_shift2 = 10 - nbplanes; + ham_mask1 = ( 1 << ham_shift1 ) - 1; + ham_mask2 = ( 1 << ham_shift2 ) - 1; + } /* Allocate memory for a temporary buffer ( used for decompression/deinterleaving ) */ @@ -217,13 +251,27 @@ goto done; } - if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, bmhd.planes==24?24:8, 0, 0, 0, 0 ) ) == NULL ) - goto done; + /* Allocate a new SDL_surface */ + + if ( (bmhd.planes==24) || is_ham ) /* 24bits, RGB format */ + Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, 24, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x0000FF, 0x00FF00, 0xFF0000, +#else + 0xFF0000, 0x00FF00, 0x0000FF, +#endif + 0 ); + else + Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, + 8, 0, 0, 0, 0 ); + if ( Image == NULL ) + goto done; /* Update palette informations */ - /* There is no palette in 24 bits ILBM file */ - if ( nbcolors>0 ) + /* There is no palette in 24 bits ILBM file, and Amiga HAM images are + converted to 24 bits */ + if ( nbcolors>0 && ! is_ham ) { Image->format->palette->ncolors = nbcolors; @@ -235,6 +283,22 @@ Image->format->palette->colors[i].g = *ptr++; Image->format->palette->colors[i].b = *ptr++; } + + /* In Amiga "Extra Half-Brite" mode, the second half of the colormap + is computed from the first half, with components divided by 2 */ + if ( is_ehb ) + { + Image->format->palette->ncolors = 64; + + ptr = &colormap[0]; + + for ( i=0; i<32; i++ ) + { + Image->format->palette->colors[i+32].r = *ptr++ >> 1; + Image->format->palette->colors[i+32].g = *ptr++ >> 1; + Image->format->palette->colors[i+32].b = *ptr++ >> 1; + } + } } /* Get the bitmap */ @@ -300,7 +364,7 @@ /* One line has been read, store it ! */ ptr = Image->pixels; - if ( nbplanes==24 ) + if ( nbplanes==24 || is_ham ) ptr += h * width * 3; else ptr += h * width; @@ -313,11 +377,18 @@ { if ( nbplanes!=24 ) { + if ( is_ham ) + { + red = colormap[0]; + green = colormap[1]; + blue = colormap[2]; + } + size = ( width + 7 ) / 8; for ( i=0; i < size; i++ ) { - memset( ptr, 0, 8 ); + memset( colors, 0, 8 ); for ( plane=0; plane < nbplanes; plane++ ) { @@ -326,13 +397,45 @@ 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 ); + if ( ( plane + j ) <= 7 ) colors[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j ); + else colors[j] |= (Uint8)( color & msk ) << ( plane + j - 7 ); msk >>= 1; } } - ptr += 8; + + if ( is_ham ) + { + for ( j=0; j<8; j++ ) + { + color = colors[j] & ham_mask1; + switch ( colors[j] >> ham_shift1 ) + { + case 0x00: + red = colormap[3*color]; + green = colormap[3*color+1]; + blue = colormap[3*color+2]; + break; + case 0x01: + blue = ( blue & ham_mask2 ) | ( color << ham_shift2 ); + break; + case 0x02: + red = ( red & ham_mask2 ) | ( color << ham_shift2 ); + break; + case 0x03: + green = ( green & ham_mask2 ) | ( color << ham_shift2 ); + break; + } + *ptr++ = red; + *ptr++ = green; + *ptr++ = blue; + } + } + else + { + memcpy( ptr, colors, 8 ); + ptr += 8; + } } } else @@ -354,19 +457,9 @@ color24 = color24 | maskColor24; maskColor24 = maskColor24<<1; } - if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) - { - *ptr++ = color24>>16; - *ptr++ = color24>>8; - *ptr++ = color24; - } - else - { - *ptr++ = color24; - *ptr++ = color24>>8; - *ptr++ = color24>>16; - } - + *ptr++ = color24; + *ptr++ = color24>>8; + *ptr++ = color24>>16; maskBit = maskBit>>1; } }