123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "../renderer/Image.h"
- #include "../renderer/jpeg-6/jpeglib.h"
- void swf_jpeg_error_exit( jpeg_common_struct * cinfo ) {
- char buffer[JMSG_LENGTH_MAX] = {0};
- (*cinfo->err->format_message)( cinfo, buffer );
- throw idException( buffer );
- }
- void swf_jpeg_output_message( jpeg_common_struct * cinfo ) {
- char buffer[JMSG_LENGTH_MAX] = {0};
- (*cinfo->err->format_message)( cinfo, buffer );
- idLib::Printf( "%s\n", buffer );
- }
- void swf_jpeg_init_source( jpeg_decompress_struct * cinfo ) {
- }
- boolean swf_jpeg_fill_input_buffer( jpeg_decompress_struct * cinfo ) {
- return TRUE;
- }
- void swf_jpeg_skip_input_data( jpeg_decompress_struct * cinfo, long num_bytes ) {
- cinfo->src->next_input_byte += num_bytes;
- cinfo->src->bytes_in_buffer -= num_bytes;
- }
- void swf_jpeg_term_source( jpeg_decompress_struct * cinfo ) {
- }
- idSWF::idDecompressJPEG::idDecompressJPEG() {
- jpeg_decompress_struct * cinfo = new (TAG_SWF) jpeg_decompress_struct;
- memset( cinfo, 0, sizeof( *cinfo ) );
- cinfo->err = new (TAG_SWF) jpeg_error_mgr;
- memset( cinfo->err, 0, sizeof( jpeg_error_mgr ) );
- jpeg_std_error( cinfo->err );
- cinfo->err->error_exit = swf_jpeg_error_exit;
- cinfo->err->output_message = swf_jpeg_output_message;
- jpeg_create_decompress( cinfo );
- vinfo = cinfo;
- }
- idSWF::idDecompressJPEG::~idDecompressJPEG() {
- jpeg_decompress_struct * cinfo = (jpeg_decompress_struct *)vinfo;
- jpeg_destroy_decompress( cinfo );
- delete cinfo->err;
- delete cinfo;
- }
- byte * idSWF::idDecompressJPEG::Load( const byte * input, int inputSize, int & width, int & height ) {
- jpeg_decompress_struct * cinfo = (jpeg_decompress_struct *)vinfo;
- try {
- width = 0;
- height = 0;
- jpeg_source_mgr src;
- memset( &src, 0, sizeof( src ) );
- src.next_input_byte = (JOCTET *)input;
- src.bytes_in_buffer = inputSize;
- src.init_source = swf_jpeg_init_source;
- src.fill_input_buffer = swf_jpeg_fill_input_buffer;
- src.skip_input_data = swf_jpeg_skip_input_data;
- src.resync_to_restart = jpeg_resync_to_restart;
- src.term_source = swf_jpeg_term_source;
- cinfo->src = &src;
- int result = 0;
- do {
- result = jpeg_read_header( cinfo, FALSE );
- } while ( result == JPEG_HEADER_TABLES_ONLY );
- if ( result == JPEG_SUSPENDED ) {
- return NULL;
- }
- jpeg_start_decompress( cinfo );
- if ( cinfo->output_components != 4 ) {
-
- idLib::Warning( "JPEG output is not 4 components" );
- jpeg_abort_decompress( cinfo );
- cinfo->src = NULL;
- return NULL;
- }
- int outputSize = cinfo->output_width * cinfo->output_height * cinfo->output_components;
- byte * output = (byte *)Mem_Alloc( outputSize, TAG_SWF );
- memset( output, 255, outputSize );
- while ( cinfo->output_scanline < cinfo->output_height ) {
- JSAMPROW scanlines = output + cinfo->output_scanline * cinfo->output_width * cinfo->output_components;
- jpeg_read_scanlines( cinfo, &scanlines, 1 );
- }
- jpeg_finish_decompress( cinfo );
- width = cinfo->output_width;
- height = cinfo->output_height;
- cinfo->src = NULL;
- return output;
- } catch ( idException & ) {
- swf_jpeg_output_message( (jpeg_common_struct *)cinfo );
- return NULL;
- }
- }
- void RectAllocator( const idList<idVec2i> &inputSizes, idList<idVec2i> &outputPositions, idVec2i &totalSize );
- float RectPackingFraction( const idList<idVec2i> &inputSizes, const idVec2i totalSize );
- void idSWF::WriteSwfImageAtlas( const char *filename ) {
- idList<idVec2i> inputSizes;
- inputSizes.SetNum( packImages.Num() );
- for ( int i = 0 ; i < packImages.Num() ; i++ ) {
-
- inputSizes[i] = packImages[i].allocSize;
- }
- idList<idVec2i> outputPositions;
- idVec2i totalSize;
-
- RectAllocator( inputSizes, outputPositions, totalSize );
- float frac = RectPackingFraction( inputSizes, totalSize );
- idLib::Printf( "%5.2f packing fraction in %ix%i image\n", frac, totalSize.x*4, totalSize.y*4 );
- int atlasWidth = Max( 4, totalSize.x * 4 ) ;
- int atlasHeight = Max( 4, totalSize.y * 4 ) ;
-
-
-
- atlasWidth = ( atlasWidth + 127 ) & ~127;
-
- idTempArray<byte> swfAtlas( atlasWidth * atlasHeight * 4 );
-
- for ( int i = 0; i < atlasWidth * atlasHeight; i++ ) {
- swfAtlas[i*4+0] = 255;
- swfAtlas[i*4+1] = 0;
- swfAtlas[i*4+2] = 0;
- swfAtlas[i*4+3] = 255;
- }
-
- for ( int i = 0 ; i < packImages.Num() ; i++ ) {
- imageToPack_t & pack = packImages[i];
- assert( pack.imageData != NULL );
- int blockWidth = pack.allocSize.x;
- int blockHeight = pack.allocSize.y;
- int x = outputPositions[i].x;
- int y = outputPositions[i].y;
-
-
- int minV[4] = { 255, 255, 255, 255 };
- int maxV[4] = { 0, 0, 0, 0 };
- for ( int j = 0 ; j < pack.trueSize.x * pack.trueSize.y * 4 ; j++ ) {
- int v = pack.imageData[ j ];
- int x = j & 3;
- if ( v < minV[x] ) {
- minV[x] = v;
- }
- if ( v > maxV[x] ) {
- maxV[x] = v;
- }
- }
-
- for ( int x = 0 ; x < 4 ; x++ ) {
- if ( maxV[x] == 0 ) {
- maxV[x] = 1;
- }
- }
-
-
-
-
-
-
-
-
-
- for ( int j = 0; j < pack.trueSize.x * pack.trueSize.y * 4; j++ ) {
- int v = pack.imageData[ j ];
- int x = j & 3;
- v = v * 255 / maxV[x];
- pack.imageData[ j ] = v;
- }
- assert( ( x + blockWidth )* 4 <= atlasWidth );
- assert( ( y + blockHeight )* 4 <= atlasHeight );
-
-
-
- x <<= 2;
- y <<= 2;
- for ( int dstY = 0; dstY < blockHeight<<2; dstY++ ) {
- int srcY = dstY-1;
- if ( srcY < 0 ) {
- srcY = 0;
- }
- if ( srcY >= pack.trueSize.y ) {
- srcY = pack.trueSize.y - 1;
- }
- for ( int dstX = 0 ; dstX < blockWidth<<2 ; dstX++ ) {
- int srcX = dstX-1;
- if ( srcX < 0 ) {
- srcX = 0;
- }
- if ( srcX >= pack.trueSize.x ) {
- srcX = pack.trueSize.x - 1;
- }
- ((int *)swfAtlas.Ptr())[ (y+dstY) * atlasWidth + (x+dstX) ] =
- ((int *)pack.imageData)[ srcY * pack.trueSize.x + srcX ];
- }
- }
-
- idSWFDictionaryEntry * entry = FindDictionaryEntry( pack.characterID );
- assert( entry->material == NULL );
- entry->imageSize.x = pack.trueSize.x;
- entry->imageSize.y = pack.trueSize.y;
- entry->imageAtlasOffset.x = x + 1;
- entry->imageAtlasOffset.y = y + 1;
- for ( int i = 0; i < 4; i++ ) {
- entry->channelScale[i] = maxV[i] / 255.0f;
- }
- Mem_Free( pack.imageData );
- pack.imageData = NULL;
- }
-
- R_WriteTGA( filename, swfAtlas.Ptr(), atlasWidth, atlasHeight, false, "fs_basepath" );
- }
- void idSWF::LoadImage( int characterID, const byte * imageData, int width, int height ) {
- idSWFDictionaryEntry * entry = AddDictionaryEntry( characterID, SWF_DICT_IMAGE );
- if ( entry == NULL ) {
- return;
- }
-
-
- imageToPack_t pack;
- pack.characterID = characterID;
- pack.imageData = (byte *)Mem_Alloc( width*height*4, TAG_SWF );
- memcpy( pack.imageData, imageData, width*height*4 );
- pack.trueSize.x = width;
- pack.trueSize.y = height;
- for ( int i = 0 ; i < 2 ; i++ ) {
- int v = pack.trueSize[i];
-
-
-
- v = ( v + 3 ) >> 2;
-
-
- if ( ( v << 2 ) - pack.trueSize[i] < 2 ) {
- v++;
- }
- pack.allocSize[i] = v;
- }
- packImages.Append( pack );
- entry->material = NULL;
- }
- void idSWF::JPEGTables( idSWFBitStream & bitstream ) {
- if ( bitstream.Length() == 0 ) {
-
- return;
- }
- int width, height;
- jpeg.Load( bitstream.ReadData( bitstream.Length() ), bitstream.Length(), width, height );
- }
- void idSWF::DefineBits( idSWFBitStream & bitstream ) {
- uint16 characterID = bitstream.ReadU16();
- int jpegSize = bitstream.Length() - sizeof( uint16 );
- int width, height;
- byte * imageData = jpeg.Load( bitstream.ReadData( jpegSize ), jpegSize, width, height );
- if ( imageData == NULL ) {
- return;
- }
- LoadImage( characterID, imageData, width, height );
- Mem_Free( imageData );
- }
- void idSWF::DefineBitsJPEG2( idSWFBitStream & bitstream ) {
- uint16 characterID = bitstream.ReadU16();
- idDecompressJPEG jpeg;
- int jpegSize = bitstream.Length() - sizeof( uint16 );
- int width, height;
- byte * imageData = jpeg.Load( bitstream.ReadData( jpegSize ), jpegSize, width, height );
- if ( imageData == NULL ) {
- return;
- }
- LoadImage( characterID, imageData, width, height );
- Mem_Free( imageData );
- }
- void idSWF::DefineBitsJPEG3( idSWFBitStream & bitstream ) {
- uint16 characterID = bitstream.ReadU16();
- uint32 jpegSize = bitstream.ReadU32();
- idDecompressJPEG jpeg;
- int width, height;
- byte * imageData = jpeg.Load( bitstream.ReadData( jpegSize ), jpegSize, width, height );
- if ( imageData == NULL ) {
- return;
- }
- {
- idTempArray<byte> alphaMap( width * height );
- int alphaSize = bitstream.Length() - jpegSize - sizeof( characterID ) - sizeof( jpegSize );
- if ( !Inflate( bitstream.ReadData( alphaSize ), alphaSize, alphaMap.Ptr(), (int)alphaMap.Size() ) ) {
- idLib::Warning( "DefineBitsJPEG3: Failed to inflate alpha data" );
- Mem_Free( imageData );
- return;
- }
- for ( int i = 0; i < width * height; i++ ) {
- imageData[i*4+3] = alphaMap[i];
- }
- }
- LoadImage( characterID, imageData, width, height );
- Mem_Free( imageData );
- }
- void idSWF::DefineBitsLossless( idSWFBitStream & bitstream ) {
- uint16 characterID = bitstream.ReadU16();
- uint8 format = bitstream.ReadU8();
- uint16 width = bitstream.ReadU16();
- uint16 height = bitstream.ReadU16();
- idTempArray< byte > buf( width * height * 4 );
- byte * imageData = buf.Ptr();
- if ( format == 3 ) {
- uint32 paddedWidth = ( width + 3 ) & ~3;
- uint32 colorTableSize = ( bitstream.ReadU8() + 1 ) * 3;
- idTempArray<byte> colorMapData( colorTableSize + ( paddedWidth * height ) );
- uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
- if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, colorMapData.Ptr(), (int)colorMapData.Size() ) ) {
- idLib::Warning( "DefineBitsLossless: Failed to inflate color map data" );
- return;
- }
- byte * indices = colorMapData.Ptr() + colorTableSize;
- for ( int h = 0; h < height; h++ ) {
- for ( int w = 0; w < width; w++ ) {
- byte index = indices[w + (h*paddedWidth)];
- byte * pixel = &imageData[(w + (h*width)) * 4];
- pixel[0] = colorMapData[index * 3 + 0];
- pixel[1] = colorMapData[index * 3 + 1];
- pixel[2] = colorMapData[index * 3 + 2];
- pixel[3] = 0xFF;
- }
- }
- } else if ( format == 4 ) {
- uint32 paddedWidth = ( width + 1 ) & 1;
- idTempArray<uint16> bitmapData( paddedWidth * height * 2 );
- uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
- if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, (byte *)bitmapData.Ptr(), (int)bitmapData.Size() ) ) {
- idLib::Warning( "DefineBitsLossless: Failed to inflate bitmap data" );
- return;
- }
- for ( int h = 0; h < height; h++ ) {
- for ( int w = 0; w < width; w++ ) {
- uint16 pix15 = bitmapData[w + (h*paddedWidth)];
- idSwap::Big( pix15 );
- byte * pixel = &imageData[(w + (h*width)) * 4];
- pixel[0] = ( pix15 >> 10 ) & 0x1F;
- pixel[1] = ( pix15 >> 5 ) & 0x1F;
- pixel[2] = ( pix15 >> 0 ) & 0x1F;
- pixel[3] = 0xFF;
- }
- }
- } else if ( format == 5 ) {
- idTempArray<uint32> bitmapData( width * height );
- uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
- if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, (byte *)bitmapData.Ptr(), (int)bitmapData.Size() ) ) {
- idLib::Warning( "DefineBitsLossless: Failed to inflate bitmap data" );
- return;
- }
- for ( int h = 0; h < height; h++ ) {
- for ( int w = 0; w < width; w++ ) {
- uint32 pix24 = bitmapData[w + (h*width)];
- idSwap::Big( pix24 );
- byte * pixel = &imageData[(w + (h*width)) * 4];
- pixel[0] = ( pix24 >> 16 ) & 0xFF;
- pixel[1] = ( pix24 >> 8 ) & 0xFF;
- pixel[2] = ( pix24 >> 0 ) & 0xFF;
- pixel[3] = 0xFF;
- }
- }
- } else {
- idLib::Warning( "DefineBitsLossless: Unknown image format %d", format );
- memset( imageData, 0xFF, width * height * 4 );
- }
- LoadImage( characterID, imageData, width, height );
- }
- void idSWF::DefineBitsLossless2( idSWFBitStream & bitstream ) {
- uint16 characterID = bitstream.ReadU16();
- uint8 format = bitstream.ReadU8();
- uint16 width = bitstream.ReadU16();
- uint16 height = bitstream.ReadU16();
- idTempArray< byte > buf( width * height * 4 );
- byte * imageData = buf.Ptr();
- if ( format == 3 ) {
- uint32 paddedWidth = ( width + 3 ) & ~3;
- uint32 colorTableSize = ( bitstream.ReadU8() + 1 ) * 4;
- idTempArray<byte> colorMapData( colorTableSize + ( paddedWidth * height ) );
- uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
- if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, colorMapData.Ptr(), (int)colorMapData.Size() ) ) {
- idLib::Warning( "DefineBitsLossless2: Failed to inflate color map data" );
- return;
- }
- byte * indices = colorMapData.Ptr() + colorTableSize;
- for ( int h = 0; h < height; h++ ) {
- for ( int w = 0; w < width; w++ ) {
- byte index = indices[w + (h*paddedWidth)];
- byte * pixel = &imageData[(w + (h*width)) * 4];
- pixel[0] = colorMapData[index * 4 + 0];
- pixel[1] = colorMapData[index * 4 + 1];
- pixel[2] = colorMapData[index * 4 + 2];
- pixel[3] = colorMapData[index * 4 + 3];
- }
- }
- } else if ( format == 5 ) {
- idTempArray<uint32> bitmapData( width * height );
- uint32 colorDataSize = bitstream.Length() - bitstream.Tell();
- if ( !Inflate( bitstream.ReadData( colorDataSize ), colorDataSize, (byte *)bitmapData.Ptr(), (int)bitmapData.Size() ) ) {
- idLib::Warning( "DefineBitsLossless2: Failed to inflate bitmap data" );
- return;
- }
- for ( int h = 0; h < height; h++ ) {
- for ( int w = 0; w < width; w++ ) {
- uint32 pix32 = bitmapData[w + (h*width)];
- idSwap::Big( pix32 );
- byte * pixel = &imageData[(w + (h*width)) * 4];
- pixel[0] = ( pix32 >> 16 ) & 0xFF;
- pixel[1] = ( pix32 >> 8 ) & 0xFF;
- pixel[2] = ( pix32 >> 0 ) & 0xFF;
- pixel[3] = ( pix32 >> 24 ) & 0xFF;
- }
- }
- } else {
- idLib::Warning( "DefineBitsLossless2: Unknown image format %d", format );
- memset( imageData, 0xFF, width * height * 4 );
- }
- LoadImage( characterID, imageData, width, height );
- }
|