DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Image_load.cpp (19199B)


      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 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "tr_local.h"
     33 
     34 /*
     35 ================
     36 BitsForFormat
     37 ================
     38 */
     39 int BitsForFormat( textureFormat_t format ) {
     40 	switch ( format ) {
     41 		case FMT_NONE:		return 0;
     42 		case FMT_RGBA8:		return 32;
     43 		case FMT_XRGB8:		return 32;
     44 		case FMT_RGB565:	return 16;
     45 		case FMT_L8A8:		return 16;
     46 		case FMT_ALPHA:		return 8;
     47 		case FMT_LUM8:		return 8;
     48 		case FMT_INT8:		return 8;
     49 		case FMT_DXT1:		return 4;
     50 		case FMT_DXT5:		return 8;
     51 		case FMT_DEPTH:		return 32;
     52 		case FMT_X16:		return 16;
     53 		case FMT_Y16_X16:	return 32;
     54 		default:
     55 			assert( 0 );
     56 			return 0;
     57 	}
     58 }
     59 
     60 /*
     61 ========================
     62 idImage::DeriveOpts
     63 ========================
     64 */
     65 ID_INLINE void idImage::DeriveOpts() {
     66 
     67 	if ( opts.format == FMT_NONE ) {
     68 		opts.colorFormat = CFM_DEFAULT;
     69 
     70 		switch ( usage ) {
     71 			case TD_COVERAGE:
     72 				opts.format = FMT_DXT1;
     73 				opts.colorFormat = CFM_GREEN_ALPHA;
     74 				break;
     75 			case TD_DEPTH:
     76 				opts.format = FMT_DEPTH;
     77 				break;
     78 			case TD_DIFFUSE: 
     79 				// TD_DIFFUSE gets only set to when its a diffuse texture for an interaction
     80 				opts.gammaMips = true;
     81 				opts.format = FMT_DXT5;
     82 				opts.colorFormat = CFM_YCOCG_DXT5;
     83 				break;
     84 			case TD_SPECULAR:
     85 				opts.gammaMips = true;
     86 				opts.format = FMT_DXT1;
     87 				opts.colorFormat = CFM_DEFAULT;
     88 				break;
     89 			case TD_DEFAULT:
     90 				opts.gammaMips = true;
     91 				opts.format = FMT_DXT5;
     92 				opts.colorFormat = CFM_DEFAULT;
     93 				break;
     94 			case TD_BUMP:
     95 				opts.format = FMT_DXT5;
     96 				opts.colorFormat = CFM_NORMAL_DXT5;
     97 				break;
     98 			case TD_FONT:
     99 				opts.format = FMT_DXT1;
    100 				opts.colorFormat = CFM_GREEN_ALPHA;
    101 				opts.numLevels = 4; // We only support 4 levels because we align to 16 in the exporter
    102 				opts.gammaMips = true;
    103 				break;
    104 			case TD_LIGHT:
    105 				opts.format = FMT_RGB565;
    106 				opts.gammaMips = true;
    107 				break;
    108 			case TD_LOOKUP_TABLE_MONO:
    109 				opts.format = FMT_INT8;
    110 				break;
    111 			case TD_LOOKUP_TABLE_ALPHA:
    112 				opts.format = FMT_ALPHA;
    113 				break;
    114 			case TD_LOOKUP_TABLE_RGB1:
    115 			case TD_LOOKUP_TABLE_RGBA:
    116 				opts.format = FMT_RGBA8;
    117 				break;
    118 			default:
    119 				assert( false );
    120 				opts.format = FMT_RGBA8;
    121 		}
    122 	}
    123 
    124 	if ( opts.numLevels == 0 ) {
    125 		opts.numLevels = 1;
    126 
    127 		if ( filter == TF_LINEAR || filter == TF_NEAREST ) {
    128 			// don't create mip maps if we aren't going to be using them
    129 		} else {
    130 			int	temp_width = opts.width;
    131 			int	temp_height = opts.height;
    132 			while ( temp_width > 1 || temp_height > 1 ) {
    133 				temp_width >>= 1;
    134 				temp_height >>= 1;
    135 				if ( ( opts.format == FMT_DXT1 || opts.format == FMT_DXT5 ) &&
    136 					( ( temp_width & 0x3 ) != 0 || ( temp_height & 0x3 ) != 0 ) ) {
    137 						break;
    138 				}
    139 				opts.numLevels++;
    140 			}
    141 		}
    142 	}
    143 }
    144 
    145 /*
    146 ========================
    147 idImage::AllocImage
    148 ========================
    149 */
    150 void idImage::AllocImage( const idImageOpts &imgOpts, textureFilter_t tf, textureRepeat_t tr ) {
    151 	filter = tf;
    152 	repeat = tr;
    153 	opts = imgOpts;
    154 	DeriveOpts();
    155 	AllocImage();
    156 }
    157 
    158 /*
    159 ================
    160 GenerateImage
    161 ================
    162 */
    163 void idImage::GenerateImage( const byte *pic, int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm ) {
    164 	PurgeImage();
    165 
    166 	filter = filterParm;
    167 	repeat = repeatParm;
    168 	usage = usageParm;
    169 	cubeFiles = CF_2D;
    170 
    171 	opts.textureType = TT_2D;
    172 	opts.width = width;
    173 	opts.height = height;
    174 	opts.numLevels = 0;
    175 	DeriveOpts();
    176 
    177 	// if we don't have a rendering context, just return after we
    178 	// have filled in the parms.  We must have the values set, or
    179 	// an image match from a shader before the render starts would miss
    180 	// the generated texture
    181 	if ( !R_IsInitialized() ) {
    182 		return;
    183 	}
    184 
    185 	idBinaryImage im( GetName() );
    186 	im.Load2DFromMemory( width, height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips );
    187 
    188 	AllocImage();
    189 
    190 	for ( int i = 0; i < im.NumImages(); i++ ) {
    191 		const bimageImage_t & img = im.GetImageHeader( i );
    192 		const byte * data = im.GetImageData( i );
    193 		SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data );
    194 	}
    195 }
    196 
    197 /*
    198 ====================
    199 GenerateCubeImage
    200 
    201 Non-square cube sides are not allowed
    202 ====================
    203 */
    204 void idImage::GenerateCubeImage( const byte *pic[6], int size, textureFilter_t filterParm, textureUsage_t usageParm ) {
    205 	PurgeImage();
    206 
    207 	filter = filterParm;
    208 	repeat = TR_CLAMP;
    209 	usage = usageParm;
    210 	cubeFiles = CF_NATIVE;
    211 
    212 	opts.textureType = TT_CUBIC;
    213 	opts.width = size;
    214 	opts.height = size;
    215 	opts.numLevels = 0;
    216 	DeriveOpts();
    217 
    218 	// if we don't have a rendering context, just return after we
    219 	// have filled in the parms.  We must have the values set, or
    220 	// an image match from a shader before the render starts would miss
    221 	// the generated texture
    222 	if ( !R_IsInitialized() ) {
    223 		return;
    224 	}
    225 
    226 	idBinaryImage im( GetName() );
    227 	im.LoadCubeFromMemory( size, pic, opts.numLevels, opts.format, opts.gammaMips );
    228 
    229 	AllocImage();
    230 
    231 	for ( int i = 0; i < im.NumImages(); i++ ) {
    232 		const bimageImage_t & img = im.GetImageHeader( i );
    233 		const byte * data = im.GetImageData( i );
    234 		SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data );
    235 	}
    236 }
    237 
    238 /*
    239 ===============
    240 GetGeneratedName
    241 
    242 name contains GetName() upon entry
    243 ===============
    244 */
    245  void idImage::GetGeneratedName( idStr &_name, const textureUsage_t &_usage, const cubeFiles_t &_cube ) {
    246 	idStrStatic< 64 > extension;
    247 
    248 	_name.ExtractFileExtension( extension );
    249 	_name.StripFileExtension();
    250 
    251 	_name += va( "#__%02d%02d", (int)_usage, (int)_cube );
    252 	if ( extension.Length() > 0 ) {
    253 		_name.SetFileExtension( extension );
    254 	}
    255 }
    256 
    257 
    258 /*
    259 ===============
    260 ActuallyLoadImage
    261 
    262 Absolutely every image goes through this path
    263 On exit, the idImage will have a valid OpenGL texture number that can be bound
    264 ===============
    265 */
    266 void idImage::ActuallyLoadImage( bool fromBackEnd ) {
    267 
    268 	// if we don't have a rendering context yet, just return
    269 	if ( !R_IsInitialized() ) {
    270 		return;
    271 	}
    272 
    273 	// this is the ONLY place generatorFunction will ever be called
    274 	if ( generatorFunction ) {
    275 		generatorFunction( this );
    276 		return;
    277 	}
    278 
    279 	if ( com_productionMode.GetInteger() != 0 ) {
    280 		sourceFileTime = FILE_NOT_FOUND_TIMESTAMP;
    281 		if ( cubeFiles != CF_2D ) {
    282 			opts.textureType = TT_CUBIC;
    283 			repeat = TR_CLAMP;
    284 		}
    285 	} else {
    286 		if ( cubeFiles != CF_2D ) {
    287 			opts.textureType = TT_CUBIC;
    288 			repeat = TR_CLAMP;
    289 			R_LoadCubeImages( GetName(), cubeFiles, NULL, NULL, &sourceFileTime );
    290 		} else {
    291 			opts.textureType = TT_2D;
    292 			R_LoadImageProgram( GetName(), NULL, NULL, NULL, &sourceFileTime, &usage );
    293 		}
    294 	}
    295 
    296 	// Figure out opts.colorFormat and opts.format so we can make sure the binary image is up to date
    297 	DeriveOpts();
    298 
    299 	idStrStatic< MAX_OSPATH > generatedName = GetName();
    300 	GetGeneratedName( generatedName, usage, cubeFiles );
    301 
    302 	idBinaryImage im( generatedName );
    303 	binaryFileTime = im.LoadFromGeneratedFile( sourceFileTime );
    304 
    305 	// BFHACK, do not want to tweak on buildgame so catch these images here
    306 	if ( binaryFileTime == FILE_NOT_FOUND_TIMESTAMP && fileSystem->UsingResourceFiles() ) {
    307 		int c = 1;
    308 		while ( c-- > 0 ) {
    309 			if ( generatedName.Find( "guis/assets/white#__0000", false ) >= 0 ) {
    310 				generatedName.Replace( "white#__0000", "white#__0200" );
    311 				im.SetName( generatedName );
    312 				binaryFileTime = im.LoadFromGeneratedFile( sourceFileTime );
    313 				break;
    314 			}
    315 			if ( generatedName.Find( "guis/assets/white#__0100", false ) >= 0 ) {
    316 				generatedName.Replace( "white#__0100", "white#__0200" );
    317 				im.SetName( generatedName );
    318 				binaryFileTime = im.LoadFromGeneratedFile( sourceFileTime );
    319 				break;
    320 			}
    321 			if ( generatedName.Find( "textures/black#__0100", false ) >= 0 ) {
    322 				generatedName.Replace( "black#__0100", "black#__0200" );
    323 				im.SetName( generatedName );
    324 				binaryFileTime = im.LoadFromGeneratedFile( sourceFileTime );
    325 				break;
    326 			}
    327 			if ( generatedName.Find( "textures/decals/bulletglass1_d#__0100", false ) >= 0 ) {
    328 				generatedName.Replace( "bulletglass1_d#__0100", "bulletglass1_d#__0200" );
    329 				im.SetName( generatedName );
    330 				binaryFileTime = im.LoadFromGeneratedFile( sourceFileTime );
    331 				break;
    332 			}
    333 			if ( generatedName.Find( "models/monsters/skeleton/skeleton01_d#__1000", false ) >= 0 ) {
    334 				generatedName.Replace( "skeleton01_d#__1000", "skeleton01_d#__0100" );
    335 				im.SetName( generatedName );
    336 				binaryFileTime = im.LoadFromGeneratedFile( sourceFileTime );
    337 				break;
    338 			}
    339 		}
    340 	}
    341 	const bimageFile_t & header = im.GetFileHeader();
    342 
    343 	if ( ( fileSystem->InProductionMode() && binaryFileTime != FILE_NOT_FOUND_TIMESTAMP ) || ( ( binaryFileTime != FILE_NOT_FOUND_TIMESTAMP )
    344 		&& ( header.colorFormat == opts.colorFormat )
    345 		&& ( header.format == opts.format )
    346 		&& ( header.textureType == opts.textureType )
    347 		) ) {
    348 		opts.width = header.width;
    349 		opts.height = header.height;
    350 		opts.numLevels = header.numLevels;
    351 		opts.colorFormat = (textureColor_t)header.colorFormat;
    352 		opts.format = (textureFormat_t)header.format;
    353 		opts.textureType = (textureType_t)header.textureType;
    354 		if ( cvarSystem->GetCVarBool( "fs_buildresources" ) ) {
    355 			// for resource gathering write this image to the preload file for this map
    356 			fileSystem->AddImagePreload( GetName(), filter, repeat, usage, cubeFiles );
    357 		}
    358 	} else {
    359 		if ( cubeFiles != CF_2D ) {
    360 			int size;
    361 			byte * pics[6];
    362 
    363 			if ( !R_LoadCubeImages( GetName(), cubeFiles, pics, &size, &sourceFileTime ) || size == 0 ) {
    364 				idLib::Warning( "Couldn't load cube image: %s", GetName() );
    365 				return;
    366 			}
    367 
    368 			opts.textureType = TT_CUBIC;
    369 			repeat = TR_CLAMP;
    370 			opts.width = size;
    371 			opts.height = size;
    372 			opts.numLevels = 0;
    373 			DeriveOpts();
    374 			im.LoadCubeFromMemory( size, (const byte **)pics, opts.numLevels, opts.format, opts.gammaMips );
    375 			repeat = TR_CLAMP;
    376 
    377 			for ( int i = 0; i < 6; i++ ) {
    378 				if ( pics[i] ) {
    379 					Mem_Free( pics[i] );
    380 				}
    381 			}
    382 		} else {
    383 			int width, height;
    384 			byte * pic;
    385 
    386 			// load the full specification, and perform any image program calculations
    387 			R_LoadImageProgram( GetName(), &pic, &width, &height, &sourceFileTime, &usage );
    388 
    389 			if ( pic == NULL ) {
    390 				idLib::Warning( "Couldn't load image: %s : %s", GetName(), generatedName.c_str() );
    391 				// create a default so it doesn't get continuously reloaded
    392 				opts.width = 8;
    393 				opts.height = 8;
    394 				opts.numLevels = 1;
    395 				DeriveOpts();
    396 				AllocImage();
    397 				
    398 				// clear the data so it's not left uninitialized
    399 				idTempArray<byte> clear( opts.width * opts.height * 4 );
    400 				memset( clear.Ptr(), 0, clear.Size() );
    401 				for ( int level = 0; level < opts.numLevels; level++ ) {
    402 					SubImageUpload( level, 0, 0, 0, opts.width >> level, opts.height >> level, clear.Ptr() );
    403 				}
    404 
    405 				return;
    406 			}
    407 
    408 			opts.width = width;
    409 			opts.height = height;
    410 			opts.numLevels = 0;
    411 			DeriveOpts();
    412 			im.Load2DFromMemory( opts.width, opts.height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips );
    413 
    414 			Mem_Free( pic );
    415 		}
    416 		binaryFileTime = im.WriteGeneratedFile( sourceFileTime );
    417 	}
    418 
    419 	AllocImage();
    420 
    421 
    422 	for ( int i = 0; i < im.NumImages(); i++ ) {
    423 		const bimageImage_t & img = im.GetImageHeader( i );
    424 		const byte * data = im.GetImageData( i );
    425 		SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data );
    426 	}
    427 }
    428 
    429 /*
    430 ==============
    431 Bind
    432 
    433 Automatically enables 2D mapping or cube mapping if needed
    434 ==============
    435 */
    436 void idImage::Bind() {
    437 
    438 	RENDERLOG_PRINTF( "idImage::Bind( %s )\n", GetName() );
    439 
    440 	// load the image if necessary (FIXME: not SMP safe!)
    441 	if ( !IsLoaded() ) {
    442 		// load the image on demand here, which isn't our normal game operating mode
    443 		ActuallyLoadImage( true );
    444 	}
    445 
    446 	const int texUnit = backEnd.glState.currenttmu;
    447 
    448 	tmu_t * tmu = &backEnd.glState.tmu[texUnit];
    449 	// bind the texture
    450 	if ( opts.textureType == TT_2D ) {
    451 		if ( tmu->current2DMap != texnum ) {
    452 			tmu->current2DMap = texnum;
    453 			qglBindMultiTextureEXT( GL_TEXTURE0_ARB + texUnit, GL_TEXTURE_2D, texnum );
    454 		}
    455 	} else if ( opts.textureType == TT_CUBIC ) {
    456 		if ( tmu->currentCubeMap != texnum ) {
    457 			tmu->currentCubeMap = texnum;
    458 			qglBindMultiTextureEXT( GL_TEXTURE0_ARB + texUnit, GL_TEXTURE_CUBE_MAP_EXT, texnum );
    459 		}
    460 	}
    461 
    462 }
    463 
    464 /*
    465 ================
    466 MakePowerOfTwo
    467 ================
    468 */
    469 int MakePowerOfTwo( int num ) {
    470 	int	pot;
    471 	for ( pot = 1; pot < num; pot <<= 1 ) {
    472 	}
    473 	return pot;
    474 }
    475 
    476 /*
    477 ====================
    478 CopyFramebuffer
    479 ====================
    480 */
    481 void idImage::CopyFramebuffer( int x, int y, int imageWidth, int imageHeight ) {
    482 
    483 
    484 	qglBindTexture( ( opts.textureType == TT_CUBIC ) ? GL_TEXTURE_CUBE_MAP_EXT : GL_TEXTURE_2D, texnum );
    485 
    486 	qglReadBuffer( GL_BACK );
    487 
    488 	opts.width = imageWidth;
    489 	opts.height = imageHeight;
    490 	qglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, x, y, imageWidth, imageHeight, 0 );
    491 
    492 	// these shouldn't be necessary if the image was initialized properly
    493 	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    494 	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    495 
    496 	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    497 	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    498 
    499 	backEnd.pc.c_copyFrameBuffer++;
    500 }
    501 
    502 /*
    503 ====================
    504 CopyDepthbuffer
    505 ====================
    506 */
    507 void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight ) {
    508 	qglBindTexture( ( opts.textureType == TT_CUBIC ) ? GL_TEXTURE_CUBE_MAP_EXT : GL_TEXTURE_2D, texnum );
    509 
    510 	opts.width = imageWidth;
    511 	opts.height = imageHeight;
    512 	qglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, x, y, imageWidth, imageHeight, 0 );
    513 
    514 	backEnd.pc.c_copyFrameBuffer++;
    515 }
    516 
    517 /*
    518 =============
    519 RB_UploadScratchImage
    520 
    521 if rows = cols * 6, assume it is a cube map animation
    522 =============
    523 */
    524 void idImage::UploadScratch( const byte * data, int cols, int rows ) {
    525 
    526 	// if rows = cols * 6, assume it is a cube map animation
    527 	if ( rows == cols * 6 ) {
    528 		rows /= 6;
    529 		const byte * pic[6];
    530 		for ( int i = 0; i < 6; i++ ) {
    531 			pic[i] = data + cols * rows * 4 * i;
    532 		}
    533 
    534 		if ( opts.textureType != TT_CUBIC || usage != TD_LOOKUP_TABLE_RGBA ) {
    535 			GenerateCubeImage( pic, cols, TF_LINEAR, TD_LOOKUP_TABLE_RGBA );
    536 			return;
    537 		}
    538 		if ( opts.width != cols || opts.height != rows ) {
    539 			opts.width = cols;
    540 			opts.height = rows;
    541 			AllocImage();
    542 		}
    543 		SetSamplerState( TF_LINEAR, TR_CLAMP );
    544 		for ( int i = 0; i < 6; i++ ) {
    545 			SubImageUpload( 0, 0, 0, i, opts.width, opts.height, pic[i] );
    546 		}
    547 
    548 	} else {
    549 		if ( opts.textureType != TT_2D || usage != TD_LOOKUP_TABLE_RGBA ) {
    550 			GenerateImage( data, cols, rows, TF_LINEAR, TR_REPEAT, TD_LOOKUP_TABLE_RGBA );
    551 			return;
    552 		}
    553 		if ( opts.width != cols || opts.height != rows ) {
    554 			opts.width = cols;
    555 			opts.height = rows;
    556 			AllocImage();
    557 		}
    558 		SetSamplerState( TF_LINEAR, TR_REPEAT );
    559 		SubImageUpload( 0, 0, 0, 0, opts.width, opts.height, data );
    560 	}
    561 }
    562 
    563 /*
    564 ==================
    565 StorageSize
    566 ==================
    567 */
    568 int idImage::StorageSize() const {
    569 
    570 	if ( !IsLoaded() ) {
    571 		return 0;
    572 	}
    573 	int baseSize = opts.width * opts.height;
    574 	if ( opts.numLevels > 1 ) {
    575 		baseSize *= 4;
    576 		baseSize /= 3;
    577 	}
    578 	baseSize *= BitsForFormat( opts.format );
    579 	baseSize /= 8;
    580 	return baseSize;
    581 }
    582 
    583 /*
    584 ==================
    585 Print
    586 ==================
    587 */
    588 void idImage::Print() const {
    589 	if ( generatorFunction ) {
    590 		common->Printf( "F" );
    591 	} else {
    592 		common->Printf( " " );
    593 	}
    594 
    595 	switch ( opts.textureType ) {
    596 		case TT_2D:
    597 			common->Printf( " " );
    598 			break;
    599 		case TT_CUBIC:
    600 			common->Printf( "C" );
    601 			break;
    602 		default:
    603 			common->Printf( "<BAD TYPE:%i>", opts.textureType );
    604 			break;
    605 	}
    606 
    607 	common->Printf( "%4i %4i ",	opts.width, opts.height );
    608 
    609 	switch ( opts.format ) {
    610 #define NAME_FORMAT( x ) case FMT_##x: common->Printf( "%-6s ", #x ); break;
    611 		NAME_FORMAT( NONE );
    612 		NAME_FORMAT( RGBA8 );
    613 		NAME_FORMAT( XRGB8 );
    614 		NAME_FORMAT( RGB565 );
    615 		NAME_FORMAT( L8A8 );
    616 		NAME_FORMAT( ALPHA );
    617 		NAME_FORMAT( LUM8 );
    618 		NAME_FORMAT( INT8 );
    619 		NAME_FORMAT( DXT1 );
    620 		NAME_FORMAT( DXT5 );
    621 		NAME_FORMAT( DEPTH );
    622 		NAME_FORMAT( X16 );
    623 		NAME_FORMAT( Y16_X16 );
    624 		default:
    625 			common->Printf( "<%3i>", opts.format );
    626 			break;
    627 	}
    628 
    629 	switch( filter ) {
    630 		case TF_DEFAULT:
    631 			common->Printf( "mip  " );
    632 			break;
    633 		case TF_LINEAR:
    634 			common->Printf( "linr " );
    635 			break;
    636 		case TF_NEAREST:
    637 			common->Printf( "nrst " );
    638 			break;
    639 		default:
    640 			common->Printf( "<BAD FILTER:%i>", filter );
    641 			break;
    642 	}
    643 
    644 	switch ( repeat ) {
    645 		case TR_REPEAT:
    646 			common->Printf( "rept " );
    647 			break;
    648 		case TR_CLAMP_TO_ZERO:
    649 			common->Printf( "zero " );
    650 			break;
    651 		case TR_CLAMP_TO_ZERO_ALPHA:
    652 			common->Printf( "azro " );
    653 			break;
    654 		case TR_CLAMP:
    655 			common->Printf( "clmp " );
    656 			break;
    657 		default:
    658 			common->Printf( "<BAD REPEAT:%i>", repeat );
    659 			break;
    660 	}
    661 
    662 	common->Printf( "%4ik ", StorageSize() / 1024 );
    663 
    664 	common->Printf( " %s\n", GetName() );
    665 }
    666 
    667 /*
    668 ===============
    669 idImage::Reload
    670 ===============
    671 */
    672 void idImage::Reload( bool force ) {
    673 	// always regenerate functional images
    674 	if ( generatorFunction ) {
    675 		common->DPrintf( "regenerating %s.\n", GetName() );
    676 		generatorFunction( this );
    677 		return;
    678 	}
    679 
    680 	// check file times
    681 	if ( !force ) {
    682 		ID_TIME_T current;
    683 		if ( cubeFiles != CF_2D ) {
    684 			R_LoadCubeImages( imgName, cubeFiles, NULL, NULL, &current );
    685 		} else {
    686 			// get the current values
    687 			R_LoadImageProgram( imgName, NULL, NULL, NULL, &current );
    688 		}
    689 		if ( current <= sourceFileTime ) {
    690 			return;
    691 		}
    692 	}
    693 
    694 	common->DPrintf( "reloading %s.\n", GetName() );
    695 
    696 	PurgeImage();
    697 
    698 	// Load is from the front end, so the back end must be synced
    699 	ActuallyLoadImage( false );
    700 }
    701 
    702 /*
    703 ========================
    704 idImage::SetSamplerState
    705 ========================
    706 */
    707 void idImage::SetSamplerState( textureFilter_t tf, textureRepeat_t tr ) {
    708 	if ( tf == filter && tr == repeat ) {
    709 		return;
    710 	}
    711 	filter = tf;
    712 	repeat = tr;
    713 	qglBindTexture( ( opts.textureType == TT_CUBIC ) ? GL_TEXTURE_CUBE_MAP_EXT : GL_TEXTURE_2D, texnum );
    714 	SetTexParameters();
    715 }