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 }