DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

SWF_Load.cpp (16595B)


      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/Font.h"
     31 
     32 #pragma warning(disable: 4355) // 'this' : used in base member initializer list
     33 
     34 #define BSWF_VERSION 16		// bumped to 16 for storing atlas image dimensions for unbuffered loads
     35 #define BSWF_MAGIC ( ( 'B' << 24 ) | ( 'S' << 16 ) | ( 'W' << 8 ) | BSWF_VERSION )
     36 
     37 /*
     38 ===================
     39 idSWF::LoadSWF
     40 ===================
     41 */
     42 bool idSWF::LoadSWF( const char * fullpath ) {
     43 
     44 	idFile * rawfile = fileSystem->OpenFileRead( fullpath );
     45 	if ( rawfile == NULL ) {
     46 		idLib::Printf( "SWF File not found %s\n", fullpath );
     47 		return false;
     48 	}
     49 
     50 	swfHeader_t header;
     51 	rawfile->Read( &header, sizeof( header ) );
     52 
     53 	if ( header.W != 'W' || header.S != 'S' ) {
     54 		idLib::Warning( "Wrong signature bytes" );
     55 		delete rawfile;
     56 		return false;
     57 	}
     58 
     59 	if ( header.version > 9 ) {
     60 		idLib::Warning( "Unsupported version %d", header.version );
     61 		delete rawfile;
     62 		return false;
     63 	}
     64 
     65 	bool compressed;
     66 	if ( header.compression == 'F' ) {
     67 		compressed = false;
     68 	} else if ( header.compression == 'C' ) {
     69 		compressed = true;
     70 	} else {
     71 		idLib::Warning( "Unsupported compression type %c", header.compression );
     72 		delete rawfile;
     73 		return false;
     74 	}
     75 	idSwap::Little( header.fileLength );
     76 
     77 	// header.fileLength somewhat annoyingly includes the size of the header
     78 	uint32 fileLength2 = header.fileLength - (uint32)sizeof( swfHeader_t );
     79 
     80 	// slurp the raw file into a giant array, which is somewhat atrocious when loading from the preload since it's already an idFile_Memory
     81 	byte * fileData = (byte *)Mem_Alloc( fileLength2, TAG_SWF );
     82 	size_t fileSize = rawfile->Read( fileData, fileLength2 );
     83 	delete rawfile;
     84 
     85 	if ( compressed ) {
     86 		byte * uncompressed = (byte *)Mem_Alloc( fileLength2, TAG_SWF );
     87 		if ( !Inflate( fileData, (int)fileSize, uncompressed, fileLength2 ) ) {
     88 			idLib::Warning( "Inflate error" );
     89 			Mem_Free( uncompressed );
     90 			return false;
     91 		}
     92 		Mem_Free( fileData );
     93 		fileData = uncompressed;
     94 	}
     95 	idSWFBitStream bitstream( fileData, fileLength2, false );
     96 
     97 	swfRect_t frameSize;
     98 	bitstream.ReadRect( frameSize );
     99 
    100 	if ( !frameSize.tl.Compare( vec2_zero ) ) {
    101 		idLib::Warning( "Invalid frameSize top left" );
    102 		Mem_Free( fileData );
    103 		return false;
    104 	}
    105 
    106 	frameWidth = frameSize.br.x;
    107 	frameHeight = frameSize.br.y;
    108 	frameRate = bitstream.ReadU16();
    109 
    110 	// parse everything
    111 	mainsprite->Load( bitstream, true );
    112 
    113 	// now that all images have been loaded, write out the combined image
    114 	idStr atlasFileName = "generated/";
    115 	atlasFileName += fullpath;
    116 	atlasFileName.SetFileExtension( ".tga" );
    117 
    118 	WriteSwfImageAtlas( atlasFileName );
    119 
    120 	Mem_Free( fileData );
    121 
    122 	return true;
    123 }
    124 
    125 /*
    126 ===================
    127 idSWF::LoadBinary
    128 ===================
    129 */
    130 bool idSWF::LoadBinary( const char * bfilename, ID_TIME_T sourceTime ) {
    131 	idFile * f = fileSystem->OpenFileReadMemory( bfilename );
    132 	if ( f == NULL || f->Length() <= 0 ) {
    133 		return false;
    134 	}
    135 
    136 	uint32 magic = 0;
    137 	ID_TIME_T btimestamp = 0;
    138 	f->ReadBig( magic );
    139 	f->ReadBig( btimestamp );
    140 
    141 	if (  magic != BSWF_MAGIC || ( !fileSystem->InProductionMode() && sourceTime != btimestamp ) )  {
    142 		delete f;
    143 		return false;
    144 	}
    145 
    146 	f->ReadBig( frameWidth );
    147 	f->ReadBig( frameHeight );
    148 	f->ReadBig( frameRate );
    149 
    150 	if ( mouseX == -1 ) {
    151 		mouseX = ( frameWidth / 2 );
    152 	}
    153 
    154 	if ( mouseY == -1 ) {
    155 		mouseY = ( frameHeight / 2 );
    156 	}
    157 
    158 	mainsprite->Read( f );
    159 
    160 	int num = 0;
    161 	f->ReadBig( num );
    162 	dictionary.SetNum( num );
    163 	for ( int i = 0; i < dictionary.Num(); i++ ) {
    164 		f->ReadBig( dictionary[i].type );
    165 		switch ( dictionary[i].type ) {
    166 			case SWF_DICT_IMAGE: {
    167 				idStr imageName;
    168 				f->ReadString( imageName );
    169 				if ( imageName[0] == '.' ) {
    170 					// internal image in the atlas
    171 					dictionary[i].material = NULL;
    172 				} else {
    173 					dictionary[i].material = declManager->FindMaterial( imageName );
    174 				}
    175 				for ( int j = 0 ; j < 2 ; j++ ) {
    176 					f->ReadBig( dictionary[i].imageSize[j] );
    177 					f->ReadBig( dictionary[i].imageAtlasOffset[j] );
    178 				}
    179 				for ( int j = 0 ; j < 4 ; j++ ) {
    180 					f->ReadBig( dictionary[i].channelScale[j] );
    181 				}
    182 				break;
    183 			}
    184 			case SWF_DICT_MORPH:
    185 			case SWF_DICT_SHAPE: {
    186 				dictionary[i].shape = new (TAG_SWF) idSWFShape;
    187 				idSWFShape * shape = dictionary[i].shape;
    188 				f->ReadBig( shape->startBounds.tl );
    189 				f->ReadBig( shape->startBounds.br );
    190 				f->ReadBig( shape->endBounds.tl );
    191 				f->ReadBig( shape->endBounds.br );
    192 				f->ReadBig( num ); shape->fillDraws.SetNum( num );
    193 				for ( int d = 0; d < shape->fillDraws.Num(); d++ ) {
    194 					idSWFShapeDrawFill & fillDraw = shape->fillDraws[d];
    195 					f->ReadBig( fillDraw.style.type );
    196 					f->ReadBig( fillDraw.style.subType );
    197 					f->Read( &fillDraw.style.startColor, 4 );
    198 					f->Read( &fillDraw.style.endColor, 4 );
    199 					f->ReadBigArray( (float *)&fillDraw.style.startMatrix, 6 );
    200 					f->ReadBigArray( (float *)&fillDraw.style.endMatrix, 6 );
    201 					f->ReadBig( fillDraw.style.gradient.numGradients );
    202 					for ( int g = 0; g < fillDraw.style.gradient.numGradients; g++ ) {
    203 						f->ReadBig( fillDraw.style.gradient.gradientRecords[g].startRatio );
    204 						f->ReadBig( fillDraw.style.gradient.gradientRecords[g].endRatio );
    205 						f->Read( &fillDraw.style.gradient.gradientRecords[g].startColor, 4 );
    206 						f->Read( &fillDraw.style.gradient.gradientRecords[g].endColor, 4 );
    207 					}
    208 					f->ReadBig( fillDraw.style.focalPoint );
    209 					f->ReadBig( fillDraw.style.bitmapID );
    210 					f->ReadBig( num ); fillDraw.startVerts.SetNum( num );
    211 					f->ReadBigArray( fillDraw.startVerts.Ptr(), fillDraw.startVerts.Num() );
    212 					f->ReadBig( num ); fillDraw.endVerts.SetNum( num );
    213 					f->ReadBigArray( fillDraw.endVerts.Ptr(), fillDraw.endVerts.Num() );
    214 					f->ReadBig( num ); fillDraw.indices.SetNum( num );
    215 					f->ReadBigArray( fillDraw.indices.Ptr(), fillDraw.indices.Num() );
    216 				}
    217 				f->ReadBig( num ); shape->lineDraws.SetNum( num );
    218 				for ( int d = 0; d < shape->lineDraws.Num(); d++ ) {
    219 					idSWFShapeDrawLine & lineDraw = shape->lineDraws[d];
    220 					f->ReadBig( lineDraw.style.startWidth );
    221 					f->ReadBig( lineDraw.style.endWidth );
    222 					f->Read( &lineDraw.style.startColor, 4 );
    223 					f->Read( &lineDraw.style.endColor, 4 );
    224 					f->ReadBig( num ); lineDraw.startVerts.SetNum( num );
    225 					f->ReadBigArray( lineDraw.startVerts.Ptr(), lineDraw.startVerts.Num() );
    226 					f->ReadBig( num ); lineDraw.endVerts.SetNum( num );
    227 					f->ReadBigArray( lineDraw.endVerts.Ptr(), lineDraw.endVerts.Num() );
    228 					f->ReadBig( num ); lineDraw.indices.SetNum( num );
    229 					f->ReadBigArray( lineDraw.indices.Ptr(), lineDraw.indices.Num() );
    230 				}
    231 				break;
    232 			}
    233 			case SWF_DICT_SPRITE: {
    234 				dictionary[i].sprite = new (TAG_SWF) idSWFSprite( this );
    235 				dictionary[i].sprite->Read( f );
    236 				break;
    237 			}
    238 			case SWF_DICT_FONT: {
    239 				dictionary[i].font = new (TAG_SWF) idSWFFont;
    240 				idSWFFont * font = dictionary[i].font;
    241 				idStr fontName;
    242 				f->ReadString( fontName );
    243 				font->fontID = renderSystem->RegisterFont( fontName );
    244 				f->ReadBig( font->ascent );
    245 				f->ReadBig( font->descent );
    246 				f->ReadBig( font->leading );
    247 				f->ReadBig( num ); font->glyphs.SetNum( num );
    248 				for ( int g = 0; g < font->glyphs.Num(); g++ ) {
    249 					f->ReadBig( font->glyphs[g].code );
    250 					f->ReadBig( font->glyphs[g].advance );
    251 					f->ReadBig( num ); font->glyphs[g].verts.SetNum( num );
    252 					f->ReadBigArray( font->glyphs[g].verts.Ptr(), font->glyphs[g].verts.Num() );
    253 					f->ReadBig( num ); font->glyphs[g].indices.SetNum( num );
    254 					f->ReadBigArray( font->glyphs[g].indices.Ptr(), font->glyphs[g].indices.Num() );
    255 				}
    256 				break;
    257 			}
    258 			case SWF_DICT_TEXT: {
    259 				dictionary[i].text = new (TAG_SWF) idSWFText;
    260 				idSWFText * text = dictionary[i].text;
    261 				f->ReadBig( text->bounds.tl );
    262 				f->ReadBig( text->bounds.br );
    263 				f->ReadBigArray( (float *)&text->matrix, 6 );
    264 				f->ReadBig( num ); text->textRecords.SetNum( num );
    265 				for ( int t = 0; t < text->textRecords.Num(); t++ ) {
    266 					idSWFTextRecord & textRecord = text->textRecords[t];
    267 					f->ReadBig( textRecord.fontID );
    268 					f->Read( &textRecord.color, 4 );
    269 					f->ReadBig( textRecord.xOffset );
    270 					f->ReadBig( textRecord.yOffset );
    271 					f->ReadBig( textRecord.textHeight );
    272 					f->ReadBig( textRecord.firstGlyph );
    273 					f->ReadBig( textRecord.numGlyphs );
    274 				}
    275 				f->ReadBig( num ); text->glyphs.SetNum( num );
    276 				for ( int g = 0; g < text->glyphs.Num(); g++ ) {
    277 					f->ReadBig( text->glyphs[g].index );
    278 					f->ReadBig( text->glyphs[g].advance );
    279 				}
    280 				break;
    281 			}
    282 			case SWF_DICT_EDITTEXT: {
    283 				dictionary[i].edittext = new (TAG_SWF) idSWFEditText;
    284 				idSWFEditText * edittext = dictionary[i].edittext;
    285 				f->ReadBig( edittext->bounds.tl );
    286 				f->ReadBig( edittext->bounds.br );
    287 				f->ReadBig( edittext->flags );
    288 				f->ReadBig( edittext->fontID );
    289 				f->ReadBig( edittext->fontHeight );
    290 				f->Read( &edittext->color, 4 );
    291 				f->ReadBig( edittext->maxLength );
    292 				f->ReadBig( edittext->align );
    293 				f->ReadBig( edittext->leftMargin );
    294 				f->ReadBig( edittext->rightMargin );
    295 				f->ReadBig( edittext->indent );
    296 				f->ReadBig( edittext->leading );
    297 				f->ReadString( edittext->variable );
    298 				f->ReadString( edittext->initialText );
    299 				break;
    300 			}
    301 		}
    302 	}
    303 	delete f;
    304 
    305 	return true;
    306 }
    307 
    308 /*
    309 ===================
    310 idSWF::WriteBinary
    311 ===================
    312 */
    313 void idSWF::WriteBinary( const char * bfilename ) {
    314 	idFileLocal file( fileSystem->OpenFileWrite( bfilename, "fs_basepath" ) );
    315 	if ( file == NULL ) {
    316 		return;
    317 	}
    318 	file->WriteBig( BSWF_MAGIC );
    319 	file->WriteBig( timestamp );
    320 
    321 	file->WriteBig( frameWidth );
    322 	file->WriteBig( frameHeight );
    323 	file->WriteBig( frameRate );
    324 
    325 	mainsprite->Write( file );
    326 
    327 	file->WriteBig( dictionary.Num() );
    328 	for ( int i = 0; i < dictionary.Num(); i++ ) {
    329 		file->WriteBig( dictionary[i].type );
    330 		switch ( dictionary[i].type ) {
    331 			case SWF_DICT_IMAGE: {
    332 				if ( dictionary[i].material ) {
    333 					file->WriteString( dictionary[i].material->GetName() );
    334 				} else {
    335 					file->WriteString( "." );
    336 				}
    337 				for ( int j = 0 ; j < 2 ; j++ ) {
    338 					file->WriteBig( dictionary[i].imageSize[j] );
    339 					file->WriteBig( dictionary[i].imageAtlasOffset[j] );
    340 				}
    341 				for ( int j = 0 ; j < 4 ; j++ ) {
    342 					file->WriteBig( dictionary[i].channelScale[j] );
    343 				}
    344 				break;
    345 			}
    346 			case SWF_DICT_MORPH:
    347 			case SWF_DICT_SHAPE: {
    348 				idSWFShape * shape = dictionary[i].shape;
    349 				file->WriteBig( shape->startBounds.tl );
    350 				file->WriteBig( shape->startBounds.br );
    351 				file->WriteBig( shape->endBounds.tl );
    352 				file->WriteBig( shape->endBounds.br );
    353 				file->WriteBig( shape->fillDraws.Num() );
    354 				for ( int d = 0; d < shape->fillDraws.Num(); d++ ) {
    355 					idSWFShapeDrawFill & fillDraw = shape->fillDraws[d];
    356 					file->WriteBig( fillDraw.style.type );
    357 					file->WriteBig( fillDraw.style.subType );
    358 					file->Write( &fillDraw.style.startColor, 4 );
    359 					file->Write( &fillDraw.style.endColor, 4 );
    360 					file->WriteBigArray( (float *)&fillDraw.style.startMatrix, 6 );
    361 					file->WriteBigArray( (float *)&fillDraw.style.endMatrix, 6 );
    362 					file->WriteBig( fillDraw.style.gradient.numGradients );
    363 					for ( int g = 0; g < fillDraw.style.gradient.numGradients; g++ ) {
    364 						file->WriteBig( fillDraw.style.gradient.gradientRecords[g].startRatio );
    365 						file->WriteBig( fillDraw.style.gradient.gradientRecords[g].endRatio );
    366 						file->Write( &fillDraw.style.gradient.gradientRecords[g].startColor, 4 );
    367 						file->Write( &fillDraw.style.gradient.gradientRecords[g].endColor, 4 );
    368 					}
    369 					file->WriteBig( fillDraw.style.focalPoint );
    370 					file->WriteBig( fillDraw.style.bitmapID );
    371 					file->WriteBig( fillDraw.startVerts.Num() );
    372 					file->WriteBigArray( fillDraw.startVerts.Ptr(), fillDraw.startVerts.Num() );
    373 					file->WriteBig( fillDraw.endVerts.Num() );
    374 					file->WriteBigArray( fillDraw.endVerts.Ptr(), fillDraw.endVerts.Num() );
    375 					file->WriteBig( fillDraw.indices.Num() );
    376 					file->WriteBigArray( fillDraw.indices.Ptr(), fillDraw.indices.Num() );
    377 				}
    378 				file->WriteBig( shape->lineDraws.Num() );
    379 				for ( int d = 0; d < shape->lineDraws.Num(); d++ ) {
    380 					idSWFShapeDrawLine & lineDraw = shape->lineDraws[d];
    381 					file->WriteBig( lineDraw.style.startWidth );
    382 					file->WriteBig( lineDraw.style.endWidth );
    383 					file->Write( &lineDraw.style.startColor, 4 );
    384 					file->Write( &lineDraw.style.endColor, 4 );
    385 					file->WriteBig( lineDraw.startVerts.Num() );
    386 					file->WriteBigArray( lineDraw.startVerts.Ptr(), lineDraw.startVerts.Num() );
    387 					file->WriteBig( lineDraw.endVerts.Num() );
    388 					file->WriteBigArray( lineDraw.endVerts.Ptr(), lineDraw.endVerts.Num() );
    389 					file->WriteBig( lineDraw.indices.Num() );
    390 					file->WriteBigArray( lineDraw.indices.Ptr(), lineDraw.indices.Num() );
    391 				}
    392 				break;
    393 			}
    394 			case SWF_DICT_SPRITE: {
    395 				dictionary[i].sprite->Write( file );
    396 				break;
    397 			}
    398 			case SWF_DICT_FONT: {
    399 				idSWFFont * font = dictionary[i].font;
    400 				file->WriteString( font->fontID->GetName() );
    401 				file->WriteBig( font->ascent );
    402 				file->WriteBig( font->descent );
    403 				file->WriteBig( font->leading );
    404 				file->WriteBig( font->glyphs.Num() );
    405 				for ( int g = 0; g < font->glyphs.Num(); g++ ) {
    406 					file->WriteBig( font->glyphs[g].code );
    407 					file->WriteBig( font->glyphs[g].advance );
    408 					file->WriteBig( font->glyphs[g].verts.Num() );
    409 					file->WriteBigArray( font->glyphs[g].verts.Ptr(), font->glyphs[g].verts.Num() );
    410 					file->WriteBig( font->glyphs[g].indices.Num() );
    411 					file->WriteBigArray( font->glyphs[g].indices.Ptr(), font->glyphs[g].indices.Num() );
    412 				}
    413 				break;
    414 			}
    415 			case SWF_DICT_TEXT: {
    416 				idSWFText * text = dictionary[i].text;
    417 				file->WriteBig( text->bounds.tl );
    418 				file->WriteBig( text->bounds.br );
    419 				file->WriteBigArray( (float *)&text->matrix, 6 );
    420 				file->WriteBig( text->textRecords.Num() );
    421 				for ( int t = 0; t < text->textRecords.Num(); t++ ) {
    422 					idSWFTextRecord & textRecord = text->textRecords[t];
    423 					file->WriteBig( textRecord.fontID );
    424 					file->Write( &textRecord.color, 4 );
    425 					file->WriteBig( textRecord.xOffset );
    426 					file->WriteBig( textRecord.yOffset );
    427 					file->WriteBig( textRecord.textHeight );
    428 					file->WriteBig( textRecord.firstGlyph );
    429 					file->WriteBig( textRecord.numGlyphs );
    430 				}
    431 				file->WriteBig( text->glyphs.Num() );
    432 				for ( int g = 0; g < text->glyphs.Num(); g++ ) {
    433 					file->WriteBig( text->glyphs[g].index );
    434 					file->WriteBig( text->glyphs[g].advance );
    435 				}
    436 				break;
    437 			}
    438 			case SWF_DICT_EDITTEXT: {
    439 				idSWFEditText * edittext = dictionary[i].edittext;
    440 				file->WriteBig( edittext->bounds.tl );
    441 				file->WriteBig( edittext->bounds.br );
    442 				file->WriteBig( edittext->flags );
    443 				file->WriteBig( edittext->fontID );
    444 				file->WriteBig( edittext->fontHeight );
    445 				file->Write( &edittext->color, 4 );
    446 				file->WriteBig( edittext->maxLength );
    447 				file->WriteBig( edittext->align );
    448 				file->WriteBig( edittext->leftMargin );
    449 				file->WriteBig( edittext->rightMargin );
    450 				file->WriteBig( edittext->indent );
    451 				file->WriteBig( edittext->leading );
    452 				file->WriteString( edittext->variable );
    453 				file->WriteString( edittext->initialText );
    454 				break;
    455 			}
    456 		}
    457 	}
    458 }