DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

SWF_Image.cpp (19213B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 #pragma hdrstop
     29 #include "../idlib/precompiled.h"
     30 #include "../renderer/Image.h"
     31 //#include "../../renderer/ImageTools/ImageProcess.h"
     32 #include "../renderer/jpeg-6/jpeglib.h"
     33 
     34 /*
     35 ========================
     36 idSWF::idDecompressJPEG
     37 These are the static callback functions the jpeg library calls
     38 ========================
     39 */
     40 void swf_jpeg_error_exit( jpeg_common_struct * cinfo ) {
     41 	char buffer[JMSG_LENGTH_MAX] = {0};
     42 	(*cinfo->err->format_message)( cinfo, buffer );
     43 	throw idException( buffer );
     44 }
     45 void swf_jpeg_output_message( jpeg_common_struct * cinfo ) {
     46 	char buffer[JMSG_LENGTH_MAX] = {0};
     47 	(*cinfo->err->format_message)( cinfo, buffer );
     48 	idLib::Printf( "%s\n", buffer );
     49 }
     50 void swf_jpeg_init_source( jpeg_decompress_struct * cinfo ) {
     51 }
     52 boolean swf_jpeg_fill_input_buffer( jpeg_decompress_struct * cinfo ) {
     53 	return TRUE;
     54 }
     55 void swf_jpeg_skip_input_data( jpeg_decompress_struct * cinfo, long num_bytes ) {
     56 	cinfo->src->next_input_byte += num_bytes;
     57 	cinfo->src->bytes_in_buffer -= num_bytes;
     58 }
     59 void swf_jpeg_term_source( jpeg_decompress_struct * cinfo ) {
     60 }
     61 
     62 /*
     63 ========================
     64 idSWF::idDecompressJPEG::idDecompressJPEG
     65 ========================
     66 */
     67 idSWF::idDecompressJPEG::idDecompressJPEG() {
     68 	jpeg_decompress_struct * cinfo = new (TAG_SWF) jpeg_decompress_struct;
     69 	memset( cinfo, 0, sizeof( *cinfo ) );
     70 
     71 	cinfo->err = new (TAG_SWF) jpeg_error_mgr;
     72 	memset( cinfo->err, 0, sizeof( jpeg_error_mgr ) );
     73 	jpeg_std_error( cinfo->err );
     74 	cinfo->err->error_exit = swf_jpeg_error_exit;
     75 	cinfo->err->output_message = swf_jpeg_output_message;
     76 
     77 	jpeg_create_decompress( cinfo );
     78 
     79 	vinfo = cinfo;
     80 }
     81 
     82 /*
     83 ========================
     84 idSWF::idDecompressJPEG::~idDecompressJPEG
     85 ========================
     86 */
     87 idSWF::idDecompressJPEG::~idDecompressJPEG() {
     88 	jpeg_decompress_struct * cinfo = (jpeg_decompress_struct *)vinfo;
     89 
     90 	jpeg_destroy_decompress( cinfo );
     91 	delete cinfo->err;
     92 	delete cinfo;
     93 }
     94 
     95 /*
     96 ========================
     97 idSWF::idDecompressJPEG::Load
     98 ========================
     99 */
    100 byte * idSWF::idDecompressJPEG::Load( const byte * input, int inputSize, int & width, int & height ) {
    101 	jpeg_decompress_struct * cinfo = (jpeg_decompress_struct *)vinfo;
    102 
    103 	try {
    104 
    105 		width = 0;
    106 		height = 0;
    107 
    108 		jpeg_source_mgr src;
    109 		memset( &src, 0, sizeof( src ) );
    110 		src.next_input_byte = (JOCTET *)input;
    111 		src.bytes_in_buffer = inputSize;
    112 		src.init_source = swf_jpeg_init_source;
    113 		src.fill_input_buffer = swf_jpeg_fill_input_buffer;
    114 		src.skip_input_data = swf_jpeg_skip_input_data;
    115 		src.resync_to_restart = jpeg_resync_to_restart;
    116 		src.term_source = swf_jpeg_term_source;
    117 		cinfo->src = &src;
    118 
    119 		int result = 0;
    120 		do {
    121 			result = jpeg_read_header( cinfo, FALSE );
    122 		} while ( result == JPEG_HEADER_TABLES_ONLY );
    123 
    124 		if ( result == JPEG_SUSPENDED ) {
    125 			return NULL;
    126 		}
    127 
    128 		jpeg_start_decompress( cinfo );
    129 		if ( cinfo->output_components != 4 ) {
    130 			// This shouldn't really be possible, unless the source image is some kind of strange grayscale format or something
    131 			idLib::Warning( "JPEG output is not 4 components" );
    132 			jpeg_abort_decompress( cinfo );
    133 			cinfo->src = NULL;	// value goes out of scope
    134 			return NULL;
    135 		}
    136 		int outputSize = cinfo->output_width * cinfo->output_height * cinfo->output_components;
    137 		byte * output = (byte *)Mem_Alloc( outputSize, TAG_SWF );
    138 		memset( output, 255, outputSize );
    139 		while ( cinfo->output_scanline < cinfo->output_height ) {
    140 			JSAMPROW scanlines = output + cinfo->output_scanline * cinfo->output_width * cinfo->output_components;
    141 			jpeg_read_scanlines( cinfo, &scanlines, 1 );
    142 		}
    143 		jpeg_finish_decompress( cinfo );
    144 
    145 		width = cinfo->output_width;
    146 		height = cinfo->output_height;
    147 
    148 		cinfo->src = NULL;	// value goes out of scope
    149 		return output;
    150 
    151 	} catch ( idException & ) {
    152 		swf_jpeg_output_message( (jpeg_common_struct *)cinfo );
    153 		return NULL;
    154 	}
    155 }
    156 
    157 
    158 /*
    159 ========================
    160 idSWF::WriteSwfImageAtlas
    161 
    162 Now that all images have been found, allocate them in an atlas
    163 and write it out.
    164 ========================
    165 */
    166 void RectAllocator( const idList<idVec2i> &inputSizes, idList<idVec2i> &outputPositions, idVec2i &totalSize );
    167 float RectPackingFraction( const idList<idVec2i> &inputSizes, const idVec2i totalSize );
    168 
    169 void idSWF::WriteSwfImageAtlas( const char *filename ) {
    170 	idList<idVec2i>	inputSizes;
    171 	inputSizes.SetNum( packImages.Num() );
    172 	for ( int i = 0 ; i < packImages.Num() ; i++ ) {
    173 		// these are in DXT blocks, not pixels
    174 		inputSizes[i] = packImages[i].allocSize;
    175 	}
    176 
    177 	idList<idVec2i>	outputPositions;
    178 	idVec2i	totalSize;
    179 	// smart allocator
    180 	RectAllocator( inputSizes, outputPositions, totalSize );
    181 
    182 	float frac = RectPackingFraction( inputSizes, totalSize );
    183 	idLib::Printf( "%5.2f packing fraction in %ix%i image\n", frac, totalSize.x*4, totalSize.y*4 );
    184 
    185 	int atlasWidth =  Max( 4, totalSize.x * 4 ) ;
    186 	int atlasHeight =  Max( 4, totalSize.y * 4 ) ;
    187 
    188 	// we require multiple-of-128 widths to use the image data directly
    189 	// without re-packing on the 360 and PS3.  The growth checks in RectAllocator()
    190 	// will always align, but a single image won't necessarily be.
    191 	atlasWidth = ( atlasWidth + 127 ) & ~127;
    192 	
    193 	idTempArray<byte> swfAtlas( atlasWidth * atlasHeight * 4 );
    194 
    195 	// fill everything with solid red
    196 	for ( int i = 0; i < atlasWidth * atlasHeight; i++ ) {
    197 		swfAtlas[i*4+0] = 255;
    198 		swfAtlas[i*4+1] = 0;
    199 		swfAtlas[i*4+2] = 0;
    200 		swfAtlas[i*4+3] = 255;
    201 	}
    202 
    203 	// allocate the blocks and copy the texels
    204 	for ( int i = 0 ; i < packImages.Num() ; i++ ) {
    205 		imageToPack_t & pack = packImages[i];
    206 		assert( pack.imageData != NULL );
    207 
    208 		int	blockWidth = pack.allocSize.x;
    209 		int	blockHeight = pack.allocSize.y;
    210 
    211 		int x = outputPositions[i].x;
    212 		int y = outputPositions[i].y;
    213 
    214 		// get the range for each channel so we can maximize it
    215 		// for better compression
    216 		int	minV[4] = { 255, 255, 255, 255 };
    217 		int	maxV[4] = { 0, 0, 0, 0 };
    218 		for ( int j = 0 ; j < pack.trueSize.x * pack.trueSize.y * 4 ; j++ ) {
    219 			int	v = pack.imageData[ j ];
    220 			int	x = j & 3;
    221 			if ( v < minV[x] ) {
    222 				minV[x] = v;
    223 			}
    224 			if ( v > maxV[x] ) {
    225 				maxV[x] = v;
    226 			}
    227 		}
    228 //		idLib::Printf( "Color normalize: %3i:%3i  %3i:%3i  %3i:%3i  %3i:%3i\n",
    229 //			minV[0], maxV[0], minV[1], maxV[1], minV[2], maxV[2], minV[3], maxV[3] );
    230 
    231 		// don't divide by zero
    232 		for ( int x = 0 ; x < 4 ; x++ ) {
    233 			if ( maxV[x] == 0 ) {
    234 				maxV[x] = 1;
    235 			}
    236 		}
    237 		// rescale the image
    238 		//
    239 		// Note that this must be done in RGBA space, before YCoCg conversion,
    240 		// or the scale factors couldn't be combined with the normal swf coloring.
    241 		//
    242 		// If we create an idMaterial for each atlas element, we could add
    243 		// a bias as well as a scale to enable us to take advantage of the
    244 		// min values as well as the max, but very few gui images don't go to black,
    245 		// and just doing a scale avoids changing more code.
    246 		for ( int j = 0; j < pack.trueSize.x * pack.trueSize.y * 4; j++ ) {
    247 			int	v = pack.imageData[ j ];
    248 			int	x = j & 3;
    249 			v = v * 255 / maxV[x];
    250 			pack.imageData[ j ] = v;
    251 		}
    252 
    253 		assert( ( x + blockWidth )* 4 <= atlasWidth );
    254 		assert( ( y + blockHeight )* 4 <= atlasHeight );
    255 		// Extend the pixels with clamp-to-edge to the edge of the allocation block.
    256 		// The GPU hardware addressing should completely ignore texels outside the true block
    257 		// size, but the compressor works on complete blocks, regardless of the true rect size.
    258 		x <<= 2;
    259 		y <<= 2;
    260 		for ( int dstY = 0; dstY < blockHeight<<2; dstY++ ) {
    261 			int	srcY = dstY-1;
    262 			if ( srcY < 0 ) {
    263 				srcY = 0;
    264 			}
    265 			if ( srcY >= pack.trueSize.y ) {
    266 				srcY = pack.trueSize.y - 1;
    267 			}
    268 			for ( int dstX = 0 ; dstX < blockWidth<<2 ; dstX++ ) {
    269 				int srcX = dstX-1;
    270 				if ( srcX < 0 ) {
    271 					srcX = 0;
    272 				}
    273 				if ( srcX >= pack.trueSize.x ) {
    274 					srcX = pack.trueSize.x - 1;
    275 				}
    276 				((int *)swfAtlas.Ptr())[ (y+dstY) * atlasWidth + (x+dstX) ] = 
    277 					((int *)pack.imageData)[ srcY * pack.trueSize.x + srcX ];
    278 			}
    279 		}
    280 
    281 		// save the information in the SWF dictionary
    282 		idSWFDictionaryEntry * entry = FindDictionaryEntry( pack.characterID );
    283 		assert( entry->material == NULL );
    284 		entry->imageSize.x = pack.trueSize.x;
    285 		entry->imageSize.y = pack.trueSize.y;
    286 		entry->imageAtlasOffset.x = x + 1;
    287 		entry->imageAtlasOffset.y = y + 1;
    288 		for ( int i = 0; i < 4; i++ ) {
    289 			entry->channelScale[i] = maxV[i] / 255.0f;
    290 		}
    291 
    292 		Mem_Free( pack.imageData );
    293 		pack.imageData = NULL;
    294 	}
    295 
    296 	// the TGA is only for examination during development
    297 	R_WriteTGA( filename, swfAtlas.Ptr(), atlasWidth, atlasHeight, false, "fs_basepath" );
    298 }
    299 
    300 /*
    301 ========================
    302 idSWF::LoadImage
    303 Loads RGBA data into an image at the specificied character id in the dictionary
    304 ========================
    305 */
    306 void idSWF::LoadImage( int characterID, const byte * imageData, int width, int height ) {
    307 	idSWFDictionaryEntry * entry = AddDictionaryEntry( characterID, SWF_DICT_IMAGE );
    308 	if ( entry == NULL ) {
    309 		return;
    310 	}
    311 
    312 	// save the data off so we can do the image atlas allocation after we have collected
    313 	// all the images that are used by the entire swf
    314 	imageToPack_t	pack;
    315 	pack.characterID = characterID;
    316 	pack.imageData = (byte *)Mem_Alloc( width*height*4, TAG_SWF );
    317 	memcpy( pack.imageData, imageData, width*height*4 );
    318 	pack.trueSize.x = width;
    319 	pack.trueSize.y = height;
    320 	for ( int i = 0 ; i < 2 ; i++ ) {
    321 		int	v = pack.trueSize[i];
    322 		// Swf images are usually completely random in size, but perform all allocations in
    323 		// DXT blocks of 4.  If we choose to DCT / HDP encode the image block, we should probably
    324 		// increae the block size to 8 or 16 to prevent neighbor effects.
    325 		v = ( v + 3 ) >> 2;
    326 
    327 		// Allways allocate a single pixel border around the images so there won't be any edge
    328 		// bleeds.  This can often be hidden in in the round-up to DXT size.
    329 		if ( ( v << 2 ) - pack.trueSize[i] < 2 ) {
    330 			v++;
    331 		}
    332 		pack.allocSize[i] = v;
    333 	}
    334 	packImages.Append( pack );
    335 
    336 	entry->material = NULL;
    337 }
    338 
    339 /*
    340 ========================
    341 idSWF::JPEGTables
    342 Reads jpeg table data, there can only be one of these in the file, and it has to come before any DefineBits tags
    343 We don't have to worry about clearing the jpeg object because jpeglib will automagically overwrite any tables that are already set (I think?)
    344 ========================
    345 */
    346 void idSWF::JPEGTables( idSWFBitStream & bitstream ) {
    347 	if ( bitstream.Length() == 0 ) {
    348 		// no clue why this happens
    349 		return;
    350 	}
    351 	int width, height;
    352 	jpeg.Load( bitstream.ReadData( bitstream.Length() ), bitstream.Length(), width, height );
    353 }
    354 
    355 /*
    356 ========================
    357 idSWF::DefineBits
    358 Reads a partial jpeg image, using the tables set by the JPEGTables tag
    359 ========================
    360 */
    361 void idSWF::DefineBits( idSWFBitStream & bitstream ) {
    362 	uint16 characterID = bitstream.ReadU16();
    363 
    364 	int jpegSize = bitstream.Length() - sizeof( uint16 );
    365 
    366 	int width, height;
    367 	byte * imageData = jpeg.Load( bitstream.ReadData( jpegSize ), jpegSize, width, height );
    368 	if ( imageData == NULL ) {
    369 		return;
    370 	}
    371 
    372 	LoadImage( characterID, imageData, width, height );
    373 
    374 	Mem_Free( imageData );
    375 }
    376 
    377 /*
    378 ========================
    379 idSWF::DefineBitsJPEG2
    380 Identical to DefineBits, except it uses a local JPEG table (not the one defined by JPEGTables)
    381 ========================
    382 */
    383 void idSWF::DefineBitsJPEG2( idSWFBitStream & bitstream ) {
    384 	uint16 characterID = bitstream.ReadU16();
    385 
    386 	idDecompressJPEG jpeg;
    387 
    388 	int jpegSize = bitstream.Length() - sizeof( uint16 );
    389 
    390 	int width, height;
    391 	byte * imageData = jpeg.Load( bitstream.ReadData( jpegSize ), jpegSize, width, height );
    392 	if ( imageData == NULL ) {
    393 		return;
    394 	}
    395 
    396 	LoadImage( characterID, imageData, width, height );
    397 
    398 	Mem_Free( imageData );
    399 }
    400 
    401 /*
    402 ========================
    403 idSWF::DefineBitsJPEG3
    404 Mostly identical to DefineBitsJPEG2, except it has an additional zlib compressed alpha map
    405 ========================
    406 */
    407 void idSWF::DefineBitsJPEG3( idSWFBitStream & bitstream ) {
    408 	uint16 characterID = bitstream.ReadU16();
    409 	uint32 jpegSize = bitstream.ReadU32();
    410 
    411 	idDecompressJPEG jpeg;
    412 
    413 	int width, height;
    414 	byte * imageData = jpeg.Load( bitstream.ReadData( jpegSize ), jpegSize, width, height );
    415 	if ( imageData == NULL ) {
    416 		return;
    417 	}
    418 
    419 	{
    420 		idTempArray<byte> alphaMap( width * height );
    421 
    422 		int alphaSize = bitstream.Length() - jpegSize - sizeof( characterID ) - sizeof( jpegSize );
    423 		if ( !Inflate( bitstream.ReadData( alphaSize ), alphaSize, alphaMap.Ptr(), (int)alphaMap.Size() ) ) {
    424 			idLib::Warning( "DefineBitsJPEG3: Failed to inflate alpha data" );
    425 			Mem_Free( imageData );
    426 			return;
    427 		}
    428 		for ( int i = 0; i < width * height; i++ ) {
    429 			imageData[i*4+3] = alphaMap[i];
    430 		}
    431 	}
    432 
    433 	LoadImage( characterID, imageData, width, height );
    434 
    435 	Mem_Free( imageData );
    436 }
    437 
    438 /*
    439 ========================
    440 idSWF::DefineBitsLossless
    441 ========================
    442 */
    443 void idSWF::DefineBitsLossless( idSWFBitStream & bitstream ) {
    444 	uint16 characterID = bitstream.ReadU16();
    445 	uint8 format = bitstream.ReadU8();
    446 	uint16 width = bitstream.ReadU16();
    447 	uint16 height = bitstream.ReadU16();
    448 
    449 	idTempArray< byte > buf( width * height * 4 );
    450 	byte * imageData = buf.Ptr();
    451 
    452 	if ( format == 3 ) {
    453 		uint32 paddedWidth = ( width + 3 ) & ~3;
    454 		uint32 colorTableSize = ( bitstream.ReadU8() + 1 ) * 3;
    455 		idTempArray<byte> colorMapData( colorTableSize + ( paddedWidth * height ) );
    456 		uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
    457 		if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, colorMapData.Ptr(), (int)colorMapData.Size() ) ) {
    458 			idLib::Warning( "DefineBitsLossless: Failed to inflate color map data" );
    459 			return;
    460 		}
    461 		byte * indices = colorMapData.Ptr() + colorTableSize;
    462 		for ( int h = 0; h < height; h++ ) {
    463 			for ( int w = 0; w < width; w++ ) {
    464 				byte index = indices[w + (h*paddedWidth)];
    465 				byte * pixel = &imageData[(w + (h*width)) * 4];
    466 				pixel[0] = colorMapData[index * 3 + 0];
    467 				pixel[1] = colorMapData[index * 3 + 1];
    468 				pixel[2] = colorMapData[index * 3 + 2];
    469 				pixel[3] = 0xFF;
    470 			}
    471 		}
    472 	} else if ( format == 4 ) {
    473 		uint32 paddedWidth = ( width + 1 ) & 1;
    474 		idTempArray<uint16> bitmapData( paddedWidth * height * 2 );
    475 		uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
    476 		if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, (byte *)bitmapData.Ptr(), (int)bitmapData.Size() ) ) {
    477 			idLib::Warning( "DefineBitsLossless: Failed to inflate bitmap data" );
    478 			return;
    479 		}
    480 		for ( int h = 0; h < height; h++ ) {
    481 			for ( int w = 0; w < width; w++ ) {
    482 				uint16 pix15 = bitmapData[w + (h*paddedWidth)];
    483 				idSwap::Big( pix15 );
    484 				byte * pixel = &imageData[(w + (h*width)) * 4];
    485 				pixel[0] = ( pix15 >> 10 ) & 0x1F;
    486 				pixel[1] = ( pix15 >> 5  ) & 0x1F;
    487 				pixel[2] = ( pix15 >> 0  ) & 0x1F;
    488 				pixel[3] = 0xFF;
    489 			}
    490 		}
    491 	} else if ( format == 5 ) {
    492 		idTempArray<uint32> bitmapData( width * height );
    493 		uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
    494 		if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, (byte *)bitmapData.Ptr(), (int)bitmapData.Size() ) ) {
    495 			idLib::Warning( "DefineBitsLossless: Failed to inflate bitmap data" );
    496 			return;
    497 		}
    498 		for ( int h = 0; h < height; h++ ) {
    499 			for ( int w = 0; w < width; w++ ) {
    500 				uint32 pix24 = bitmapData[w + (h*width)];
    501 				idSwap::Big( pix24 );
    502 				byte * pixel = &imageData[(w + (h*width)) * 4];
    503 				pixel[0] = ( pix24 >> 16 ) & 0xFF;
    504 				pixel[1] = ( pix24 >> 8  ) & 0xFF;
    505 				pixel[2] = ( pix24 >> 0  ) & 0xFF;
    506 				pixel[3] = 0xFF;
    507 			}
    508 		}
    509 	} else {
    510 		idLib::Warning( "DefineBitsLossless: Unknown image format %d", format );
    511 		memset( imageData, 0xFF, width * height * 4 );
    512 	}
    513 
    514 	LoadImage( characterID, imageData, width, height );
    515 }
    516 
    517 /*
    518 ========================
    519 idSWF::DefineBitsLossless2
    520 ========================
    521 */
    522 void idSWF::DefineBitsLossless2( idSWFBitStream & bitstream ) {
    523 	uint16 characterID = bitstream.ReadU16();
    524 	uint8 format = bitstream.ReadU8();
    525 	uint16 width = bitstream.ReadU16();
    526 	uint16 height = bitstream.ReadU16();
    527 
    528 	idTempArray< byte > buf( width * height * 4 );
    529 	byte * imageData = buf.Ptr();
    530 
    531 	if ( format == 3 ) {
    532 		uint32 paddedWidth = ( width + 3 ) & ~3;
    533 		uint32 colorTableSize = ( bitstream.ReadU8() + 1 ) * 4;
    534 		idTempArray<byte> colorMapData( colorTableSize + ( paddedWidth * height ) );
    535 		uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
    536 		if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, colorMapData.Ptr(), (int)colorMapData.Size() ) ) {
    537 			idLib::Warning( "DefineBitsLossless2: Failed to inflate color map data" );
    538 			return;
    539 		}
    540 		byte * indices = colorMapData.Ptr() + colorTableSize;
    541 		for ( int h = 0; h < height; h++ ) {
    542 			for ( int w = 0; w < width; w++ ) {
    543 				byte index = indices[w + (h*paddedWidth)];
    544 				byte * pixel = &imageData[(w + (h*width)) * 4];
    545 				pixel[0] = colorMapData[index * 4 + 0];
    546 				pixel[1] = colorMapData[index * 4 + 1];
    547 				pixel[2] = colorMapData[index * 4 + 2];
    548 				pixel[3] = colorMapData[index * 4 + 3];
    549 			}
    550 		}
    551 	} else if ( format == 5 ) {
    552 		idTempArray<uint32> bitmapData( width * height );
    553 		uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
    554 		if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, (byte *)bitmapData.Ptr(), (int)bitmapData.Size() ) ) {
    555 			idLib::Warning( "DefineBitsLossless2: Failed to inflate bitmap data" );
    556 			return;
    557 		}
    558 		for ( int h = 0; h < height; h++ ) {
    559 			for ( int w = 0; w < width; w++ ) {
    560 				uint32 pix32 = bitmapData[w + (h*width)];
    561 				idSwap::Big( pix32 );
    562 				byte * pixel = &imageData[(w + (h*width)) * 4];
    563 				pixel[0] = ( pix32 >> 16 ) & 0xFF;
    564 				pixel[1] = ( pix32 >> 8  ) & 0xFF;
    565 				pixel[2] = ( pix32 >> 0  ) & 0xFF;
    566 				pixel[3] = ( pix32 >> 24 ) & 0xFF;
    567 			}
    568 		}
    569 	} else {
    570 		idLib::Warning( "DefineBitsLossless2: Unknown image format %d", format );
    571 		memset( imageData, 0xFF, width * height * 4 );
    572 	}
    573 
    574 	LoadImage( characterID, imageData, width, height );
    575 }