DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Font.cpp (12232B)


      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 "Font.h"
     31 
     32 const char * DEFAULT_FONT = "Arial_Narrow";
     33 
     34 static const float old_scale2 = 0.6f;
     35 static const float old_scale1 = 0.3f;
     36 
     37 /*
     38 ==============================
     39 Old_SelectValueForScale
     40 ==============================
     41 */
     42 ID_INLINE float Old_SelectValueForScale( float scale, float v0, float v1, float v2 ) {
     43 	return ( scale >= old_scale2 ) ? v2 : ( scale >= old_scale1 ) ? v1 : v0;
     44 }
     45 
     46 /*
     47 ==============================
     48 idFont::RemapFont
     49 ==============================
     50 */
     51 idFont * idFont::RemapFont( const char * baseName ) {
     52 	idStr cleanName = baseName;
     53 
     54 	if ( cleanName == DEFAULT_FONT ) {
     55 		return NULL;
     56 	}
     57 
     58 	const char * remapped = idLocalization::FindString( "#font_" + cleanName );
     59 	if ( remapped != NULL ) {
     60 		return renderSystem->RegisterFont( remapped );
     61 	}
     62 
     63 	const char * wildcard = idLocalization::FindString( "#font_*" );
     64 	if ( wildcard != NULL && cleanName.Icmp( wildcard ) != 0 ) {
     65 		return renderSystem->RegisterFont( wildcard );
     66 	}
     67 
     68 	// Note single | so both sides are always executed
     69 	if ( cleanName.ReplaceChar( ' ', '_' ) | cleanName.ReplaceChar( '-', '_' ) ) {
     70 		return renderSystem->RegisterFont( cleanName );
     71 	}
     72 
     73 	return NULL;
     74 }
     75 
     76 /*
     77 ==============================
     78 idFont::~idFont
     79 ==============================
     80 */
     81 idFont::~idFont() {
     82 	delete fontInfo;
     83 }
     84 
     85 /*
     86 ==============================
     87 idFont::idFont
     88 ==============================
     89 */
     90 idFont::idFont( const char * n ) : name( n ) {
     91 	fontInfo = NULL;
     92 	alias = RemapFont( n );
     93 
     94 	if ( alias != NULL ) {
     95 		// Make sure we don't have a circular reference
     96 		for ( idFont * f = alias; f != NULL; f = f->alias ) {
     97 			if ( f == this ) {
     98 				idLib::FatalError( "Font alias \"%s\" is a circular reference!", n );
     99 			}
    100 		}
    101 		return;
    102 	}
    103 
    104 	if ( !LoadFont() ) {
    105 		if ( name.Icmp( DEFAULT_FONT ) == 0 ) {
    106 			idLib::FatalError( "Could not load default font \"%s\"", DEFAULT_FONT );
    107 		} else {
    108 			idLib::Warning( "Could not load font %s", n );
    109 			alias = renderSystem->RegisterFont( DEFAULT_FONT );
    110 		}
    111 	}
    112 }
    113 
    114 struct oldGlyphInfo_t {
    115 	int					height;			// number of scan lines
    116 	int					top;			// top of glyph in buffer
    117 	int					bottom;			// bottom of glyph in buffer
    118 	int					pitch;			// width for copying
    119 	int					xSkip;			// x adjustment
    120 	int					imageWidth;		// width of actual image
    121 	int					imageHeight;	// height of actual image
    122 	float				s;				// x offset in image where glyph starts
    123 	float				t;				// y offset in image where glyph starts
    124 	float				s2;
    125 	float				t2;
    126 	int					junk;
    127 	char				materialName[32];
    128 };
    129 static const int GLYPHS_PER_FONT = 256;
    130 
    131 /*
    132 ==============================
    133 LoadOldGlyphData
    134 ==============================
    135 */
    136 bool LoadOldGlyphData( const char * filename, oldGlyphInfo_t glyphInfo[GLYPHS_PER_FONT] ) {
    137 	idFile * fd = fileSystem->OpenFileRead( filename );
    138 	if ( fd == NULL ) {
    139 		return false;
    140 	}
    141 	fd->Read( glyphInfo, GLYPHS_PER_FONT * sizeof( oldGlyphInfo_t ) );
    142 	for ( int i = 0; i < GLYPHS_PER_FONT; i++ ) {
    143 		idSwap::Little( glyphInfo[i].height );
    144 		idSwap::Little( glyphInfo[i].top );
    145 		idSwap::Little( glyphInfo[i].bottom );
    146 		idSwap::Little( glyphInfo[i].pitch );
    147 		idSwap::Little( glyphInfo[i].xSkip );
    148 		idSwap::Little( glyphInfo[i].imageWidth );
    149 		idSwap::Little( glyphInfo[i].imageHeight );
    150 		idSwap::Little( glyphInfo[i].s );
    151 		idSwap::Little( glyphInfo[i].t );
    152 		idSwap::Little( glyphInfo[i].s2 );
    153 		idSwap::Little( glyphInfo[i].t2 );
    154 		assert( glyphInfo[i].imageWidth == glyphInfo[i].pitch );
    155 		assert( glyphInfo[i].imageHeight == glyphInfo[i].height );
    156 		assert( glyphInfo[i].imageWidth == ( glyphInfo[i].s2 - glyphInfo[i].s ) * 256 );
    157 		assert( glyphInfo[i].imageHeight == ( glyphInfo[i].t2 - glyphInfo[i].t ) * 256 );
    158 		assert( glyphInfo[i].junk == 0 );
    159 	}
    160 	delete fd;
    161 	return true;
    162 }
    163 
    164 /*
    165 ==============================
    166 idFont::LoadFont
    167 ==============================
    168 */
    169 bool idFont::LoadFont() {
    170 	idStr fontName = va( "newfonts/%s/48.dat", GetName() );
    171 	idFile * fd = fileSystem->OpenFileRead( fontName );
    172 	if ( fd == NULL ) {
    173 		return false;
    174 	}
    175 
    176 	const int FONT_INFO_VERSION = 42;
    177 	const int FONT_INFO_MAGIC = ( FONT_INFO_VERSION | ( 'i' << 24 ) | ( 'd' << 16 ) | ( 'f' << 8 ) );
    178 
    179 	uint32 version = 0;
    180 	fd->ReadBig( version );
    181 	if ( version != FONT_INFO_MAGIC ) {
    182 		idLib::Warning( "Wrong version in %s", GetName() );
    183 		delete fd;
    184 		return false;
    185 	}
    186 
    187 	fontInfo = new (TAG_FONT) fontInfo_t;
    188 
    189 	short pointSize = 0;
    190 
    191 	fd->ReadBig( pointSize );
    192 	assert( pointSize == 48 );
    193 
    194 	fd->ReadBig( fontInfo->ascender );
    195 	fd->ReadBig( fontInfo->descender );
    196 
    197 	fd->ReadBig( fontInfo->numGlyphs );
    198 
    199 	fontInfo->glyphData = (glyphInfo_t *)Mem_Alloc( sizeof( glyphInfo_t ) * fontInfo->numGlyphs, TAG_FONT );
    200 	fontInfo->charIndex = (uint32 *)Mem_Alloc( sizeof( uint32 ) * fontInfo->numGlyphs, TAG_FONT );
    201 
    202 	fd->Read( fontInfo->glyphData, fontInfo->numGlyphs * sizeof( glyphInfo_t ) );
    203 
    204 	for( int i = 0; i < fontInfo->numGlyphs; i++ ) {
    205 		idSwap::Little( fontInfo->glyphData[i].width );
    206 		idSwap::Little( fontInfo->glyphData[i].height );
    207 		idSwap::Little( fontInfo->glyphData[i].top );
    208 		idSwap::Little( fontInfo->glyphData[i].left );
    209 		idSwap::Little( fontInfo->glyphData[i].xSkip );
    210 		idSwap::Little( fontInfo->glyphData[i].s );
    211 		idSwap::Little( fontInfo->glyphData[i].t );
    212 	}
    213 
    214 	fd->Read( fontInfo->charIndex, fontInfo->numGlyphs * sizeof( uint32 ) );
    215 	idSwap::LittleArray( fontInfo->charIndex, fontInfo->numGlyphs );
    216 
    217 	memset( fontInfo->ascii, -1, sizeof( fontInfo->ascii ) );
    218 	for ( int i = 0; i < fontInfo->numGlyphs; i++ ) {
    219 		if ( fontInfo->charIndex[i] < 128 ) {
    220 			fontInfo->ascii[fontInfo->charIndex[i]] = i;
    221 		} else {
    222 			// Since the characters are sorted, as soon as we find a non-ascii character, we can stop
    223 			break;
    224 		}
    225 	}
    226 
    227 	idStr fontTextureName = fontName;
    228 	fontTextureName.SetFileExtension( "tga" );
    229 
    230 	fontInfo->material = declManager->FindMaterial( fontTextureName );
    231 	fontInfo->material->SetSort( SS_GUI );
    232 
    233 	// Load the old glyph data because we want our new fonts to fit in the old glyph metrics
    234 	int pointSizes[3] = { 12, 24, 48 };
    235 	float scales[3] = { 4.0f, 2.0f, 1.0f };
    236 	for ( int i = 0; i < 3; i++ ) {
    237 		oldGlyphInfo_t oldGlyphInfo[GLYPHS_PER_FONT];
    238 		const char * oldFileName = va( "newfonts/%s/old_%d.dat", GetName(), pointSizes[i] );
    239 		if ( LoadOldGlyphData( oldFileName, oldGlyphInfo ) ) {
    240 			int mh = 0;
    241 			int mw = 0;
    242 			for ( int g = 0; g < GLYPHS_PER_FONT; g++ ) {
    243 				if ( mh < oldGlyphInfo[g].height ) {
    244 					mh = oldGlyphInfo[g].height;
    245 				}
    246 				if ( mw < oldGlyphInfo[g].xSkip ) {
    247 					mw = oldGlyphInfo[g].xSkip;
    248 				}
    249 			}
    250 			fontInfo->oldInfo[i].maxWidth = scales[i] * mw;
    251 			fontInfo->oldInfo[i].maxHeight = scales[i] * mh;
    252 		} else {
    253 			int mh = 0;
    254 			int mw = 0;
    255 			for( int g = 0; g < fontInfo->numGlyphs; g++ ) {
    256 				if ( mh < fontInfo->glyphData[g].height ) {
    257 					mh = fontInfo->glyphData[g].height;
    258 				}
    259 				if ( mw < fontInfo->glyphData[g].xSkip ) {
    260 					mw = fontInfo->glyphData[g].xSkip;
    261 				}
    262 			}
    263 			fontInfo->oldInfo[i].maxWidth = mw;
    264 			fontInfo->oldInfo[i].maxHeight = mh;
    265 		}
    266 	}
    267 	delete fd;
    268 	return true;
    269 }
    270 
    271 /*
    272 ==============================
    273 idFont::GetGlyphIndex
    274 ==============================
    275 */
    276 int	idFont::GetGlyphIndex( uint32 idx ) const {
    277 	if ( idx < 128 ) {
    278 		return fontInfo->ascii[idx];
    279 	}
    280 	if ( fontInfo->numGlyphs == 0 ) {
    281 		return -1;
    282 	}
    283 	if ( fontInfo->charIndex == NULL ) {
    284 		return idx;
    285 	}
    286 	int len = fontInfo->numGlyphs;
    287 	int mid = fontInfo->numGlyphs;
    288 	int offset = 0;
    289 	while ( mid > 0 ) {
    290 		mid = len >> 1;
    291 		if ( fontInfo->charIndex[offset+mid] <= idx ) {
    292 			offset += mid;
    293 		}
    294 		len -= mid;
    295 	}
    296 	return ( fontInfo->charIndex[offset] == idx ) ? offset : -1;
    297 }
    298 
    299 /*
    300 ==============================
    301 idFont::GetLineHeight
    302 ==============================
    303 */
    304 float idFont::GetLineHeight( float scale ) const {
    305 	if ( alias != NULL ) {
    306 		return alias->GetLineHeight( scale );
    307 	}
    308 	if ( fontInfo != NULL ) {
    309 		return scale * Old_SelectValueForScale( scale, fontInfo->oldInfo[0].maxHeight, fontInfo->oldInfo[1].maxHeight, fontInfo->oldInfo[2].maxHeight );
    310 	}
    311 	return 0.0f;
    312 }
    313 
    314 /*
    315 ==============================
    316 idFont::GetAscender
    317 ==============================
    318 */
    319 float idFont::GetAscender( float scale ) const {
    320 	if ( alias != NULL ) {
    321 		return alias->GetAscender( scale );
    322 	}
    323 	if ( fontInfo != NULL ) {
    324 		return scale * fontInfo->ascender;
    325 	}
    326 	return 0.0f;
    327 }
    328 
    329 /*
    330 ==============================
    331 idFont::GetMaxCharWidth
    332 ==============================
    333 */
    334 float idFont::GetMaxCharWidth( float scale ) const {
    335 	if ( alias != NULL ) {
    336 		return alias->GetMaxCharWidth( scale );
    337 	}
    338 	if ( fontInfo != NULL ) {
    339 		return scale * Old_SelectValueForScale( scale, fontInfo->oldInfo[0].maxWidth, fontInfo->oldInfo[1].maxWidth, fontInfo->oldInfo[2].maxWidth );
    340 	}
    341 	return 0.0f;
    342 }
    343 
    344 /*
    345 ==============================
    346 idFont::GetGlyphWidth
    347 ==============================
    348 */
    349 float idFont::GetGlyphWidth( float scale, uint32 idx ) const {
    350 	if ( alias != NULL ) {
    351 		return alias->GetGlyphWidth( scale, idx );
    352 	}
    353 	if ( fontInfo != NULL ) {
    354 		int i = GetGlyphIndex( idx );
    355 		const int asterisk = 42;
    356 		if ( i == -1 && idx != asterisk ) {
    357 			i = GetGlyphIndex( asterisk );
    358 		}
    359 		if ( i >= 0 ) {
    360 			return scale * fontInfo->glyphData[i].xSkip;
    361 		}
    362 	}
    363 	return 0.0f;
    364 }
    365 
    366 /*
    367 ==============================
    368 idFont::GetScaledGlyph
    369 ==============================
    370 */
    371 void idFont::GetScaledGlyph( float scale, uint32 idx, scaledGlyphInfo_t & glyphInfo ) const {
    372 	if ( alias != NULL ) {
    373 		return alias->GetScaledGlyph( scale, idx, glyphInfo );
    374 	}
    375 	if ( fontInfo != NULL ) {
    376 		int i = GetGlyphIndex( idx );
    377 		const int asterisk = 42;
    378 		if ( i == -1 && idx != asterisk ) {
    379 			i = GetGlyphIndex( asterisk );
    380 		}
    381 		if ( i >= 0 ) {
    382 			float invMaterialWidth = 1.0f / fontInfo->material->GetImageWidth();
    383 			float invMaterialHeight = 1.0f / fontInfo->material->GetImageHeight();
    384 			glyphInfo_t & gi = fontInfo->glyphData[i];
    385 			glyphInfo.xSkip = scale * gi.xSkip;
    386 			glyphInfo.top = scale * gi.top;
    387 			glyphInfo.left = scale * gi.left;
    388 			glyphInfo.width = scale * gi.width;
    389 			glyphInfo.height = scale * gi.height;
    390 			glyphInfo.s1 = ( gi.s - 0.5f ) * invMaterialWidth;
    391 			glyphInfo.t1 = ( gi.t - 0.5f ) * invMaterialHeight;
    392 			glyphInfo.s2 = ( gi.s + gi.width + 0.5f ) * invMaterialWidth;
    393 			glyphInfo.t2 = ( gi.t + gi.height + 0.5f ) * invMaterialHeight;
    394 			glyphInfo.material = fontInfo->material;
    395 			return;
    396 		}
    397 	}
    398 	memset( &glyphInfo, 0, sizeof( glyphInfo ) );
    399 }
    400 
    401 /*
    402 ==============================
    403 idFont::Touch
    404 ==============================
    405 */
    406 void idFont::Touch() {
    407 	if ( alias != NULL ) {
    408 		alias->Touch();
    409 	}
    410 	if ( fontInfo != NULL ) {
    411 		const_cast<idMaterial *>( fontInfo->material )->EnsureNotPurged();
    412 		fontInfo->material->SetSort( SS_GUI );
    413 	}
    414 }