Font.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "Font.h"
  23. const char * DEFAULT_FONT = "Arial_Narrow";
  24. static const float old_scale2 = 0.6f;
  25. static const float old_scale1 = 0.3f;
  26. /*
  27. ==============================
  28. Old_SelectValueForScale
  29. ==============================
  30. */
  31. ID_INLINE float Old_SelectValueForScale( float scale, float v0, float v1, float v2 ) {
  32. return ( scale >= old_scale2 ) ? v2 : ( scale >= old_scale1 ) ? v1 : v0;
  33. }
  34. /*
  35. ==============================
  36. idFont::RemapFont
  37. ==============================
  38. */
  39. idFont * idFont::RemapFont( const char * baseName ) {
  40. idStr cleanName = baseName;
  41. if ( cleanName == DEFAULT_FONT ) {
  42. return NULL;
  43. }
  44. const char * remapped = idLocalization::FindString( "#font_" + cleanName );
  45. if ( remapped != NULL ) {
  46. return renderSystem->RegisterFont( remapped );
  47. }
  48. const char * wildcard = idLocalization::FindString( "#font_*" );
  49. if ( wildcard != NULL && cleanName.Icmp( wildcard ) != 0 ) {
  50. return renderSystem->RegisterFont( wildcard );
  51. }
  52. // Note single | so both sides are always executed
  53. if ( cleanName.ReplaceChar( ' ', '_' ) | cleanName.ReplaceChar( '-', '_' ) ) {
  54. return renderSystem->RegisterFont( cleanName );
  55. }
  56. return NULL;
  57. }
  58. /*
  59. ==============================
  60. idFont::~idFont
  61. ==============================
  62. */
  63. idFont::~idFont() {
  64. delete fontInfo;
  65. }
  66. /*
  67. ==============================
  68. idFont::idFont
  69. ==============================
  70. */
  71. idFont::idFont( const char * n ) : name( n ) {
  72. fontInfo = NULL;
  73. alias = RemapFont( n );
  74. if ( alias != NULL ) {
  75. // Make sure we don't have a circular reference
  76. for ( idFont * f = alias; f != NULL; f = f->alias ) {
  77. if ( f == this ) {
  78. idLib::FatalError( "Font alias \"%s\" is a circular reference!", n );
  79. }
  80. }
  81. return;
  82. }
  83. if ( !LoadFont() ) {
  84. if ( name.Icmp( DEFAULT_FONT ) == 0 ) {
  85. idLib::FatalError( "Could not load default font \"%s\"", DEFAULT_FONT );
  86. } else {
  87. idLib::Warning( "Could not load font %s", n );
  88. alias = renderSystem->RegisterFont( DEFAULT_FONT );
  89. }
  90. }
  91. }
  92. struct oldGlyphInfo_t {
  93. int height; // number of scan lines
  94. int top; // top of glyph in buffer
  95. int bottom; // bottom of glyph in buffer
  96. int pitch; // width for copying
  97. int xSkip; // x adjustment
  98. int imageWidth; // width of actual image
  99. int imageHeight; // height of actual image
  100. float s; // x offset in image where glyph starts
  101. float t; // y offset in image where glyph starts
  102. float s2;
  103. float t2;
  104. int junk;
  105. char materialName[32];
  106. };
  107. static const int GLYPHS_PER_FONT = 256;
  108. /*
  109. ==============================
  110. LoadOldGlyphData
  111. ==============================
  112. */
  113. bool LoadOldGlyphData( const char * filename, oldGlyphInfo_t glyphInfo[GLYPHS_PER_FONT] ) {
  114. idFile * fd = fileSystem->OpenFileRead( filename );
  115. if ( fd == NULL ) {
  116. return false;
  117. }
  118. fd->Read( glyphInfo, GLYPHS_PER_FONT * sizeof( oldGlyphInfo_t ) );
  119. for ( int i = 0; i < GLYPHS_PER_FONT; i++ ) {
  120. idSwap::Little( glyphInfo[i].height );
  121. idSwap::Little( glyphInfo[i].top );
  122. idSwap::Little( glyphInfo[i].bottom );
  123. idSwap::Little( glyphInfo[i].pitch );
  124. idSwap::Little( glyphInfo[i].xSkip );
  125. idSwap::Little( glyphInfo[i].imageWidth );
  126. idSwap::Little( glyphInfo[i].imageHeight );
  127. idSwap::Little( glyphInfo[i].s );
  128. idSwap::Little( glyphInfo[i].t );
  129. idSwap::Little( glyphInfo[i].s2 );
  130. idSwap::Little( glyphInfo[i].t2 );
  131. assert( glyphInfo[i].imageWidth == glyphInfo[i].pitch );
  132. assert( glyphInfo[i].imageHeight == glyphInfo[i].height );
  133. assert( glyphInfo[i].imageWidth == ( glyphInfo[i].s2 - glyphInfo[i].s ) * 256 );
  134. assert( glyphInfo[i].imageHeight == ( glyphInfo[i].t2 - glyphInfo[i].t ) * 256 );
  135. assert( glyphInfo[i].junk == 0 );
  136. }
  137. delete fd;
  138. return true;
  139. }
  140. /*
  141. ==============================
  142. idFont::LoadFont
  143. ==============================
  144. */
  145. bool idFont::LoadFont() {
  146. idStr fontName = va( "newfonts/%s/48.dat", GetName() );
  147. idFile * fd = fileSystem->OpenFileRead( fontName );
  148. if ( fd == NULL ) {
  149. return false;
  150. }
  151. const int FONT_INFO_VERSION = 42;
  152. const int FONT_INFO_MAGIC = ( FONT_INFO_VERSION | ( 'i' << 24 ) | ( 'd' << 16 ) | ( 'f' << 8 ) );
  153. uint32 version = 0;
  154. fd->ReadBig( version );
  155. if ( version != FONT_INFO_MAGIC ) {
  156. idLib::Warning( "Wrong version in %s", GetName() );
  157. delete fd;
  158. return false;
  159. }
  160. fontInfo = new (TAG_FONT) fontInfo_t;
  161. short pointSize = 0;
  162. fd->ReadBig( pointSize );
  163. assert( pointSize == 48 );
  164. fd->ReadBig( fontInfo->ascender );
  165. fd->ReadBig( fontInfo->descender );
  166. fd->ReadBig( fontInfo->numGlyphs );
  167. fontInfo->glyphData = (glyphInfo_t *)Mem_Alloc( sizeof( glyphInfo_t ) * fontInfo->numGlyphs, TAG_FONT );
  168. fontInfo->charIndex = (uint32 *)Mem_Alloc( sizeof( uint32 ) * fontInfo->numGlyphs, TAG_FONT );
  169. fd->Read( fontInfo->glyphData, fontInfo->numGlyphs * sizeof( glyphInfo_t ) );
  170. for( int i = 0; i < fontInfo->numGlyphs; i++ ) {
  171. idSwap::Little( fontInfo->glyphData[i].width );
  172. idSwap::Little( fontInfo->glyphData[i].height );
  173. idSwap::Little( fontInfo->glyphData[i].top );
  174. idSwap::Little( fontInfo->glyphData[i].left );
  175. idSwap::Little( fontInfo->glyphData[i].xSkip );
  176. idSwap::Little( fontInfo->glyphData[i].s );
  177. idSwap::Little( fontInfo->glyphData[i].t );
  178. }
  179. fd->Read( fontInfo->charIndex, fontInfo->numGlyphs * sizeof( uint32 ) );
  180. idSwap::LittleArray( fontInfo->charIndex, fontInfo->numGlyphs );
  181. memset( fontInfo->ascii, -1, sizeof( fontInfo->ascii ) );
  182. for ( int i = 0; i < fontInfo->numGlyphs; i++ ) {
  183. if ( fontInfo->charIndex[i] < 128 ) {
  184. fontInfo->ascii[fontInfo->charIndex[i]] = i;
  185. } else {
  186. // Since the characters are sorted, as soon as we find a non-ascii character, we can stop
  187. break;
  188. }
  189. }
  190. idStr fontTextureName = fontName;
  191. fontTextureName.SetFileExtension( "tga" );
  192. fontInfo->material = declManager->FindMaterial( fontTextureName );
  193. fontInfo->material->SetSort( SS_GUI );
  194. // Load the old glyph data because we want our new fonts to fit in the old glyph metrics
  195. int pointSizes[3] = { 12, 24, 48 };
  196. float scales[3] = { 4.0f, 2.0f, 1.0f };
  197. for ( int i = 0; i < 3; i++ ) {
  198. oldGlyphInfo_t oldGlyphInfo[GLYPHS_PER_FONT];
  199. const char * oldFileName = va( "newfonts/%s/old_%d.dat", GetName(), pointSizes[i] );
  200. if ( LoadOldGlyphData( oldFileName, oldGlyphInfo ) ) {
  201. int mh = 0;
  202. int mw = 0;
  203. for ( int g = 0; g < GLYPHS_PER_FONT; g++ ) {
  204. if ( mh < oldGlyphInfo[g].height ) {
  205. mh = oldGlyphInfo[g].height;
  206. }
  207. if ( mw < oldGlyphInfo[g].xSkip ) {
  208. mw = oldGlyphInfo[g].xSkip;
  209. }
  210. }
  211. fontInfo->oldInfo[i].maxWidth = scales[i] * mw;
  212. fontInfo->oldInfo[i].maxHeight = scales[i] * mh;
  213. } else {
  214. int mh = 0;
  215. int mw = 0;
  216. for( int g = 0; g < fontInfo->numGlyphs; g++ ) {
  217. if ( mh < fontInfo->glyphData[g].height ) {
  218. mh = fontInfo->glyphData[g].height;
  219. }
  220. if ( mw < fontInfo->glyphData[g].xSkip ) {
  221. mw = fontInfo->glyphData[g].xSkip;
  222. }
  223. }
  224. fontInfo->oldInfo[i].maxWidth = mw;
  225. fontInfo->oldInfo[i].maxHeight = mh;
  226. }
  227. }
  228. delete fd;
  229. return true;
  230. }
  231. /*
  232. ==============================
  233. idFont::GetGlyphIndex
  234. ==============================
  235. */
  236. int idFont::GetGlyphIndex( uint32 idx ) const {
  237. if ( idx < 128 ) {
  238. return fontInfo->ascii[idx];
  239. }
  240. if ( fontInfo->numGlyphs == 0 ) {
  241. return -1;
  242. }
  243. if ( fontInfo->charIndex == NULL ) {
  244. return idx;
  245. }
  246. int len = fontInfo->numGlyphs;
  247. int mid = fontInfo->numGlyphs;
  248. int offset = 0;
  249. while ( mid > 0 ) {
  250. mid = len >> 1;
  251. if ( fontInfo->charIndex[offset+mid] <= idx ) {
  252. offset += mid;
  253. }
  254. len -= mid;
  255. }
  256. return ( fontInfo->charIndex[offset] == idx ) ? offset : -1;
  257. }
  258. /*
  259. ==============================
  260. idFont::GetLineHeight
  261. ==============================
  262. */
  263. float idFont::GetLineHeight( float scale ) const {
  264. if ( alias != NULL ) {
  265. return alias->GetLineHeight( scale );
  266. }
  267. if ( fontInfo != NULL ) {
  268. return scale * Old_SelectValueForScale( scale, fontInfo->oldInfo[0].maxHeight, fontInfo->oldInfo[1].maxHeight, fontInfo->oldInfo[2].maxHeight );
  269. }
  270. return 0.0f;
  271. }
  272. /*
  273. ==============================
  274. idFont::GetAscender
  275. ==============================
  276. */
  277. float idFont::GetAscender( float scale ) const {
  278. if ( alias != NULL ) {
  279. return alias->GetAscender( scale );
  280. }
  281. if ( fontInfo != NULL ) {
  282. return scale * fontInfo->ascender;
  283. }
  284. return 0.0f;
  285. }
  286. /*
  287. ==============================
  288. idFont::GetMaxCharWidth
  289. ==============================
  290. */
  291. float idFont::GetMaxCharWidth( float scale ) const {
  292. if ( alias != NULL ) {
  293. return alias->GetMaxCharWidth( scale );
  294. }
  295. if ( fontInfo != NULL ) {
  296. return scale * Old_SelectValueForScale( scale, fontInfo->oldInfo[0].maxWidth, fontInfo->oldInfo[1].maxWidth, fontInfo->oldInfo[2].maxWidth );
  297. }
  298. return 0.0f;
  299. }
  300. /*
  301. ==============================
  302. idFont::GetGlyphWidth
  303. ==============================
  304. */
  305. float idFont::GetGlyphWidth( float scale, uint32 idx ) const {
  306. if ( alias != NULL ) {
  307. return alias->GetGlyphWidth( scale, idx );
  308. }
  309. if ( fontInfo != NULL ) {
  310. int i = GetGlyphIndex( idx );
  311. const int asterisk = 42;
  312. if ( i == -1 && idx != asterisk ) {
  313. i = GetGlyphIndex( asterisk );
  314. }
  315. if ( i >= 0 ) {
  316. return scale * fontInfo->glyphData[i].xSkip;
  317. }
  318. }
  319. return 0.0f;
  320. }
  321. /*
  322. ==============================
  323. idFont::GetScaledGlyph
  324. ==============================
  325. */
  326. void idFont::GetScaledGlyph( float scale, uint32 idx, scaledGlyphInfo_t & glyphInfo ) const {
  327. if ( alias != NULL ) {
  328. return alias->GetScaledGlyph( scale, idx, glyphInfo );
  329. }
  330. if ( fontInfo != NULL ) {
  331. int i = GetGlyphIndex( idx );
  332. const int asterisk = 42;
  333. if ( i == -1 && idx != asterisk ) {
  334. i = GetGlyphIndex( asterisk );
  335. }
  336. if ( i >= 0 ) {
  337. float invMaterialWidth = 1.0f / fontInfo->material->GetImageWidth();
  338. float invMaterialHeight = 1.0f / fontInfo->material->GetImageHeight();
  339. glyphInfo_t & gi = fontInfo->glyphData[i];
  340. glyphInfo.xSkip = scale * gi.xSkip;
  341. glyphInfo.top = scale * gi.top;
  342. glyphInfo.left = scale * gi.left;
  343. glyphInfo.width = scale * gi.width;
  344. glyphInfo.height = scale * gi.height;
  345. glyphInfo.s1 = ( gi.s - 0.5f ) * invMaterialWidth;
  346. glyphInfo.t1 = ( gi.t - 0.5f ) * invMaterialHeight;
  347. glyphInfo.s2 = ( gi.s + gi.width + 0.5f ) * invMaterialWidth;
  348. glyphInfo.t2 = ( gi.t + gi.height + 0.5f ) * invMaterialHeight;
  349. glyphInfo.material = fontInfo->material;
  350. return;
  351. }
  352. }
  353. memset( &glyphInfo, 0, sizeof( glyphInfo ) );
  354. }
  355. /*
  356. ==============================
  357. idFont::Touch
  358. ==============================
  359. */
  360. void idFont::Touch() {
  361. if ( alias != NULL ) {
  362. alias->Touch();
  363. }
  364. if ( fontInfo != NULL ) {
  365. const_cast<idMaterial *>( fontInfo->material )->EnsureNotPurged();
  366. fontInfo->material->SetSort( SS_GUI );
  367. }
  368. }