123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "Font.h"
- const char * DEFAULT_FONT = "Arial_Narrow";
- static const float old_scale2 = 0.6f;
- static const float old_scale1 = 0.3f;
- /*
- ==============================
- Old_SelectValueForScale
- ==============================
- */
- ID_INLINE float Old_SelectValueForScale( float scale, float v0, float v1, float v2 ) {
- return ( scale >= old_scale2 ) ? v2 : ( scale >= old_scale1 ) ? v1 : v0;
- }
- /*
- ==============================
- idFont::RemapFont
- ==============================
- */
- idFont * idFont::RemapFont( const char * baseName ) {
- idStr cleanName = baseName;
- if ( cleanName == DEFAULT_FONT ) {
- return NULL;
- }
- const char * remapped = idLocalization::FindString( "#font_" + cleanName );
- if ( remapped != NULL ) {
- return renderSystem->RegisterFont( remapped );
- }
- const char * wildcard = idLocalization::FindString( "#font_*" );
- if ( wildcard != NULL && cleanName.Icmp( wildcard ) != 0 ) {
- return renderSystem->RegisterFont( wildcard );
- }
- // Note single | so both sides are always executed
- if ( cleanName.ReplaceChar( ' ', '_' ) | cleanName.ReplaceChar( '-', '_' ) ) {
- return renderSystem->RegisterFont( cleanName );
- }
- return NULL;
- }
- /*
- ==============================
- idFont::~idFont
- ==============================
- */
- idFont::~idFont() {
- delete fontInfo;
- }
- /*
- ==============================
- idFont::idFont
- ==============================
- */
- idFont::idFont( const char * n ) : name( n ) {
- fontInfo = NULL;
- alias = RemapFont( n );
- if ( alias != NULL ) {
- // Make sure we don't have a circular reference
- for ( idFont * f = alias; f != NULL; f = f->alias ) {
- if ( f == this ) {
- idLib::FatalError( "Font alias \"%s\" is a circular reference!", n );
- }
- }
- return;
- }
- if ( !LoadFont() ) {
- if ( name.Icmp( DEFAULT_FONT ) == 0 ) {
- idLib::FatalError( "Could not load default font \"%s\"", DEFAULT_FONT );
- } else {
- idLib::Warning( "Could not load font %s", n );
- alias = renderSystem->RegisterFont( DEFAULT_FONT );
- }
- }
- }
- struct oldGlyphInfo_t {
- int height; // number of scan lines
- int top; // top of glyph in buffer
- int bottom; // bottom of glyph in buffer
- int pitch; // width for copying
- int xSkip; // x adjustment
- int imageWidth; // width of actual image
- int imageHeight; // height of actual image
- float s; // x offset in image where glyph starts
- float t; // y offset in image where glyph starts
- float s2;
- float t2;
- int junk;
- char materialName[32];
- };
- static const int GLYPHS_PER_FONT = 256;
- /*
- ==============================
- LoadOldGlyphData
- ==============================
- */
- bool LoadOldGlyphData( const char * filename, oldGlyphInfo_t glyphInfo[GLYPHS_PER_FONT] ) {
- idFile * fd = fileSystem->OpenFileRead( filename );
- if ( fd == NULL ) {
- return false;
- }
- fd->Read( glyphInfo, GLYPHS_PER_FONT * sizeof( oldGlyphInfo_t ) );
- for ( int i = 0; i < GLYPHS_PER_FONT; i++ ) {
- idSwap::Little( glyphInfo[i].height );
- idSwap::Little( glyphInfo[i].top );
- idSwap::Little( glyphInfo[i].bottom );
- idSwap::Little( glyphInfo[i].pitch );
- idSwap::Little( glyphInfo[i].xSkip );
- idSwap::Little( glyphInfo[i].imageWidth );
- idSwap::Little( glyphInfo[i].imageHeight );
- idSwap::Little( glyphInfo[i].s );
- idSwap::Little( glyphInfo[i].t );
- idSwap::Little( glyphInfo[i].s2 );
- idSwap::Little( glyphInfo[i].t2 );
- assert( glyphInfo[i].imageWidth == glyphInfo[i].pitch );
- assert( glyphInfo[i].imageHeight == glyphInfo[i].height );
- assert( glyphInfo[i].imageWidth == ( glyphInfo[i].s2 - glyphInfo[i].s ) * 256 );
- assert( glyphInfo[i].imageHeight == ( glyphInfo[i].t2 - glyphInfo[i].t ) * 256 );
- assert( glyphInfo[i].junk == 0 );
- }
- delete fd;
- return true;
- }
- /*
- ==============================
- idFont::LoadFont
- ==============================
- */
- bool idFont::LoadFont() {
- idStr fontName = va( "newfonts/%s/48.dat", GetName() );
- idFile * fd = fileSystem->OpenFileRead( fontName );
- if ( fd == NULL ) {
- return false;
- }
- const int FONT_INFO_VERSION = 42;
- const int FONT_INFO_MAGIC = ( FONT_INFO_VERSION | ( 'i' << 24 ) | ( 'd' << 16 ) | ( 'f' << 8 ) );
- uint32 version = 0;
- fd->ReadBig( version );
- if ( version != FONT_INFO_MAGIC ) {
- idLib::Warning( "Wrong version in %s", GetName() );
- delete fd;
- return false;
- }
- fontInfo = new (TAG_FONT) fontInfo_t;
- short pointSize = 0;
- fd->ReadBig( pointSize );
- assert( pointSize == 48 );
- fd->ReadBig( fontInfo->ascender );
- fd->ReadBig( fontInfo->descender );
- fd->ReadBig( fontInfo->numGlyphs );
- fontInfo->glyphData = (glyphInfo_t *)Mem_Alloc( sizeof( glyphInfo_t ) * fontInfo->numGlyphs, TAG_FONT );
- fontInfo->charIndex = (uint32 *)Mem_Alloc( sizeof( uint32 ) * fontInfo->numGlyphs, TAG_FONT );
- fd->Read( fontInfo->glyphData, fontInfo->numGlyphs * sizeof( glyphInfo_t ) );
- for( int i = 0; i < fontInfo->numGlyphs; i++ ) {
- idSwap::Little( fontInfo->glyphData[i].width );
- idSwap::Little( fontInfo->glyphData[i].height );
- idSwap::Little( fontInfo->glyphData[i].top );
- idSwap::Little( fontInfo->glyphData[i].left );
- idSwap::Little( fontInfo->glyphData[i].xSkip );
- idSwap::Little( fontInfo->glyphData[i].s );
- idSwap::Little( fontInfo->glyphData[i].t );
- }
- fd->Read( fontInfo->charIndex, fontInfo->numGlyphs * sizeof( uint32 ) );
- idSwap::LittleArray( fontInfo->charIndex, fontInfo->numGlyphs );
- memset( fontInfo->ascii, -1, sizeof( fontInfo->ascii ) );
- for ( int i = 0; i < fontInfo->numGlyphs; i++ ) {
- if ( fontInfo->charIndex[i] < 128 ) {
- fontInfo->ascii[fontInfo->charIndex[i]] = i;
- } else {
- // Since the characters are sorted, as soon as we find a non-ascii character, we can stop
- break;
- }
- }
- idStr fontTextureName = fontName;
- fontTextureName.SetFileExtension( "tga" );
- fontInfo->material = declManager->FindMaterial( fontTextureName );
- fontInfo->material->SetSort( SS_GUI );
- // Load the old glyph data because we want our new fonts to fit in the old glyph metrics
- int pointSizes[3] = { 12, 24, 48 };
- float scales[3] = { 4.0f, 2.0f, 1.0f };
- for ( int i = 0; i < 3; i++ ) {
- oldGlyphInfo_t oldGlyphInfo[GLYPHS_PER_FONT];
- const char * oldFileName = va( "newfonts/%s/old_%d.dat", GetName(), pointSizes[i] );
- if ( LoadOldGlyphData( oldFileName, oldGlyphInfo ) ) {
- int mh = 0;
- int mw = 0;
- for ( int g = 0; g < GLYPHS_PER_FONT; g++ ) {
- if ( mh < oldGlyphInfo[g].height ) {
- mh = oldGlyphInfo[g].height;
- }
- if ( mw < oldGlyphInfo[g].xSkip ) {
- mw = oldGlyphInfo[g].xSkip;
- }
- }
- fontInfo->oldInfo[i].maxWidth = scales[i] * mw;
- fontInfo->oldInfo[i].maxHeight = scales[i] * mh;
- } else {
- int mh = 0;
- int mw = 0;
- for( int g = 0; g < fontInfo->numGlyphs; g++ ) {
- if ( mh < fontInfo->glyphData[g].height ) {
- mh = fontInfo->glyphData[g].height;
- }
- if ( mw < fontInfo->glyphData[g].xSkip ) {
- mw = fontInfo->glyphData[g].xSkip;
- }
- }
- fontInfo->oldInfo[i].maxWidth = mw;
- fontInfo->oldInfo[i].maxHeight = mh;
- }
- }
- delete fd;
- return true;
- }
- /*
- ==============================
- idFont::GetGlyphIndex
- ==============================
- */
- int idFont::GetGlyphIndex( uint32 idx ) const {
- if ( idx < 128 ) {
- return fontInfo->ascii[idx];
- }
- if ( fontInfo->numGlyphs == 0 ) {
- return -1;
- }
- if ( fontInfo->charIndex == NULL ) {
- return idx;
- }
- int len = fontInfo->numGlyphs;
- int mid = fontInfo->numGlyphs;
- int offset = 0;
- while ( mid > 0 ) {
- mid = len >> 1;
- if ( fontInfo->charIndex[offset+mid] <= idx ) {
- offset += mid;
- }
- len -= mid;
- }
- return ( fontInfo->charIndex[offset] == idx ) ? offset : -1;
- }
- /*
- ==============================
- idFont::GetLineHeight
- ==============================
- */
- float idFont::GetLineHeight( float scale ) const {
- if ( alias != NULL ) {
- return alias->GetLineHeight( scale );
- }
- if ( fontInfo != NULL ) {
- return scale * Old_SelectValueForScale( scale, fontInfo->oldInfo[0].maxHeight, fontInfo->oldInfo[1].maxHeight, fontInfo->oldInfo[2].maxHeight );
- }
- return 0.0f;
- }
- /*
- ==============================
- idFont::GetAscender
- ==============================
- */
- float idFont::GetAscender( float scale ) const {
- if ( alias != NULL ) {
- return alias->GetAscender( scale );
- }
- if ( fontInfo != NULL ) {
- return scale * fontInfo->ascender;
- }
- return 0.0f;
- }
- /*
- ==============================
- idFont::GetMaxCharWidth
- ==============================
- */
- float idFont::GetMaxCharWidth( float scale ) const {
- if ( alias != NULL ) {
- return alias->GetMaxCharWidth( scale );
- }
- if ( fontInfo != NULL ) {
- return scale * Old_SelectValueForScale( scale, fontInfo->oldInfo[0].maxWidth, fontInfo->oldInfo[1].maxWidth, fontInfo->oldInfo[2].maxWidth );
- }
- return 0.0f;
- }
- /*
- ==============================
- idFont::GetGlyphWidth
- ==============================
- */
- float idFont::GetGlyphWidth( float scale, uint32 idx ) const {
- if ( alias != NULL ) {
- return alias->GetGlyphWidth( scale, idx );
- }
- if ( fontInfo != NULL ) {
- int i = GetGlyphIndex( idx );
- const int asterisk = 42;
- if ( i == -1 && idx != asterisk ) {
- i = GetGlyphIndex( asterisk );
- }
- if ( i >= 0 ) {
- return scale * fontInfo->glyphData[i].xSkip;
- }
- }
- return 0.0f;
- }
- /*
- ==============================
- idFont::GetScaledGlyph
- ==============================
- */
- void idFont::GetScaledGlyph( float scale, uint32 idx, scaledGlyphInfo_t & glyphInfo ) const {
- if ( alias != NULL ) {
- return alias->GetScaledGlyph( scale, idx, glyphInfo );
- }
- if ( fontInfo != NULL ) {
- int i = GetGlyphIndex( idx );
- const int asterisk = 42;
- if ( i == -1 && idx != asterisk ) {
- i = GetGlyphIndex( asterisk );
- }
- if ( i >= 0 ) {
- float invMaterialWidth = 1.0f / fontInfo->material->GetImageWidth();
- float invMaterialHeight = 1.0f / fontInfo->material->GetImageHeight();
- glyphInfo_t & gi = fontInfo->glyphData[i];
- glyphInfo.xSkip = scale * gi.xSkip;
- glyphInfo.top = scale * gi.top;
- glyphInfo.left = scale * gi.left;
- glyphInfo.width = scale * gi.width;
- glyphInfo.height = scale * gi.height;
- glyphInfo.s1 = ( gi.s - 0.5f ) * invMaterialWidth;
- glyphInfo.t1 = ( gi.t - 0.5f ) * invMaterialHeight;
- glyphInfo.s2 = ( gi.s + gi.width + 0.5f ) * invMaterialWidth;
- glyphInfo.t2 = ( gi.t + gi.height + 0.5f ) * invMaterialHeight;
- glyphInfo.material = fontInfo->material;
- return;
- }
- }
- memset( &glyphInfo, 0, sizeof( glyphInfo ) );
- }
- /*
- ==============================
- idFont::Touch
- ==============================
- */
- void idFont::Touch() {
- if ( alias != NULL ) {
- alias->Touch();
- }
- if ( fontInfo != NULL ) {
- const_cast<idMaterial *>( fontInfo->material )->EnsureNotPurged();
- fontInfo->material->SetSort( SS_GUI );
- }
- }
|