Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

421 lines
14 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: PS3 support for TrueType Fonts as hastily bastardized from Xbox 360 code.
  4. // On 360, the only solution is to use XUI
  5. // to mount the TTF, and rasterize glyph into a render target. XUI does not support
  6. // rasterization directly to a system memory region.
  7. // On PS3 that is not a problem, but rather than reimplement this whole class,
  8. // the minimal-code-change approach is just to patch some functions in shaderapi,
  9. // even though we don't need to do the work in shaderapi. I hang my head in shame
  10. // for this unworthy laziness/haste.
  11. //
  12. //=====================================================================================//
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <math.h>
  16. #include <tier0/dbg.h>
  17. #include <vgui/ISurface.h>
  18. #include <tier0/mem.h>
  19. #include <utlbuffer.h>
  20. #include "filesystem.h"
  21. #include "materialsystem/imaterialsystem.h"
  22. #include "FontEffects.h"
  23. #include "vgui_surfacelib/vguifont.h"
  24. #include "vgui_surfacelib/FontManager.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. bool s_bSupportsUnicode = true;
  28. //-----------------------------------------------------------------------------
  29. // Determine possible style from parameters.
  30. //-----------------------------------------------------------------------------
  31. int GetStyleFromParameters( int iFlags, int iWeight )
  32. {
  33. // Available xbox TTF styles are very restricted.
  34. int style = CPS3Font::kFONT_STYLE_NORMAL;
  35. if ( iFlags & FONTFLAG_ITALIC )
  36. style |= CPS3Font::kFONT_STYLE_ITALIC;
  37. if ( iFlags & FONTFLAG_UNDERLINE )
  38. style |= CPS3Font::kFONT_STYLE_UNDERLINE;
  39. if ( iWeight > 400 )
  40. style |= CPS3Font::kFONT_STYLE_BOLD;
  41. return style;
  42. }
  43. //-----------------------------------------------------------------------------
  44. // Purpose: Constructor
  45. //-----------------------------------------------------------------------------
  46. CPS3Font::CPS3Font() : m_ExtendedABCWidthsCache( 256, 0, &ExtendedABCWidthsCacheLessFunc )
  47. {
  48. m_szName = UTL_INVAL_SYMBOL;
  49. m_iTall = 0;
  50. m_iWeight = 0;
  51. m_iHeight = 0;
  52. m_iAscent = 0;
  53. m_iFlags = 0;
  54. m_iMaxCharWidth = 0;
  55. m_hFont = NULL;
  56. m_bAntiAliased = false;
  57. m_bUnderlined = false;
  58. m_iBlur = 0;
  59. m_iScanLines = 0;
  60. m_bRotary = false;
  61. m_bAdditive = false;
  62. m_rgiBitmapSize[0] = 0;
  63. m_rgiBitmapSize[1] = 0;
  64. s_bSupportsUnicode = true;
  65. Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose: Destructor
  69. //-----------------------------------------------------------------------------
  70. CPS3Font::~CPS3Font()
  71. {
  72. if ( m_hFont != NULL )
  73. {
  74. // many fonts are blindly precached by vgui and never used
  75. // save memory and don't hold font open, re-open if glyph actually requested used during draw
  76. if ( IMaterialSystem *pMS = FontManager().MaterialSystem() )
  77. pMS->CloseTrueTypeFont( m_hFont );
  78. }
  79. m_hFont = NULL;
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose: Creates the font.
  83. //-----------------------------------------------------------------------------
  84. bool CPS3Font::Create( const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags )
  85. {
  86. // setup font properties
  87. m_iTall = tall;
  88. m_iWeight = weight;
  89. m_iFlags = flags;
  90. m_bAntiAliased = (flags & FONTFLAG_ANTIALIAS) ? 1 : 0;
  91. m_bUnderlined = (flags & FONTFLAG_UNDERLINE) ? 1 : 0;
  92. m_iDropShadowOffset = (flags & FONTFLAG_DROPSHADOW) ? 1 : 0;
  93. m_iOutlineSize = (flags & FONTFLAG_OUTLINE) ? 1 : 0;
  94. m_iBlur = blur;
  95. m_iScanLines = scanlines;
  96. m_bRotary = (flags & FONTFLAG_ROTARY) ? 1 : 0;
  97. m_bAdditive = (flags & FONTFLAG_ADDITIVE) ? 1 : 0;
  98. int style = GetStyleFromParameters( flags, weight );
  99. // must support > 128, there are characters in this range in the custom fonts
  100. COMPILE_TIME_ASSERT( ABCWIDTHS_CACHE_SIZE == 256 );
  101. CPS3FontMetrics fontMetrics;
  102. CPS3CharMetrics charMetrics[ABCWIDTHS_CACHE_SIZE];
  103. // many redundant requests are made that are actually the same font metrics
  104. // find it in the metric cache first based on the true specific keys
  105. if ( !FontManager().GetCachedPS3Metrics( windowsFontName, tall, style, &fontMetrics, charMetrics ) )
  106. {
  107. if ( !m_hFont )
  108. {
  109. m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( windowsFontName, tall, style );
  110. // no you're not seeing double
  111. if ( !m_hFont )
  112. {
  113. return false;
  114. }
  115. }
  116. // get the predominant font metrics now [1-255], the extended set [256-65535] is on-demand
  117. FontManager().MaterialSystem()->GetTrueTypeFontMetrics( m_hFont, m_iTall, 1, 255, &fontMetrics, &charMetrics[1] );
  118. // getting the metrics is an expensive i/o operation, cache results
  119. FontManager().SetCachedPS3Metrics( windowsFontName, tall, style, &fontMetrics, charMetrics );
  120. }
  121. m_szName = windowsFontName;
  122. m_iHeight = fontMetrics.lineHeight + fontMetrics.effectHeight + m_iDropShadowOffset + 2 * m_iOutlineSize;
  123. m_iMaxCharWidth = ceilf(fontMetrics.fMaxWidth);
  124. m_iAscent = fontMetrics.baseLineY;
  125. // determine cell bounds
  126. m_rgiBitmapSize[0] = m_iMaxCharWidth + m_iOutlineSize * 2;
  127. m_rgiBitmapSize[1] = m_iHeight;
  128. // get char spacing
  129. // a is space before character (can be negative)
  130. // b is the width of the character
  131. // c is the space after the character
  132. Assert( ABCWIDTHS_CACHE_SIZE <= 256 );
  133. Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
  134. for ( int i = 1; i < ABCWIDTHS_CACHE_SIZE; i++ )
  135. {
  136. int a,b,c;
  137. /*
  138. // Determine real a,b,c mapping from XUI Character Metrics
  139. a = charMetrics[i].fMinX - 1; // Add one column of padding to make up for font rendering blurring into left column (and adjust in b)
  140. b = charMetrics[i].fMaxX - charMetrics[i].fMinX + 1;
  141. c = charMetrics[i].fAdvance - charMetrics[i].fMaxX; // NOTE: We probably should add a column here, but it's rarely needed in our current fonts so we're opting to save memory instead
  142. */
  143. a = charMetrics[i].A();
  144. b = charMetrics[i].B();
  145. c = charMetrics[i].C();
  146. // Widen for blur, outline, and shadow. Need to widen b and reduce a and c.
  147. m_ABCWidthsCache[i].a = a - m_iOutlineSize;
  148. m_ABCWidthsCache[i].b = b + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset;
  149. m_ABCWidthsCache[i].c = c - 2*m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
  150. }
  151. return true;
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: generates texture data (written into appropriate font page subrects) for multiple chars
  155. //-----------------------------------------------------------------------------
  156. void CPS3Font::GetCharsRGBA( newChar_t *newChars, int numNewChars, unsigned char *pRGBA )
  157. {
  158. if ( !m_hFont )
  159. {
  160. // demand request for font glyph, re-create font
  161. int style = GetStyleFromParameters( m_iFlags, m_iWeight );
  162. m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( GetName(), m_iTall, style );
  163. }
  164. wchar_t *pWch = (wchar_t *)_alloca( numNewChars*sizeof(wchar_t) );
  165. int *pOffsetX = (int *)_alloca( numNewChars*sizeof(int) );
  166. int *pOffsetY = (int *)_alloca( numNewChars*sizeof(int) );
  167. int *pWidth = (int *)_alloca( numNewChars*sizeof(int) );
  168. int *pHeight = (int *)_alloca( numNewChars*sizeof(int) );
  169. int *pRGBAOffset = (int *)_alloca( numNewChars*sizeof(int) );
  170. for ( int i = 0; i < numNewChars; i++ )
  171. {
  172. int a, c, wide;
  173. GetCharABCWidths( newChars[i].wch, a, wide, c );
  174. pWch[i] = newChars[i].wch;
  175. pOffsetX[i] = -a;
  176. pOffsetY[i] = 0;
  177. pWidth[i] = newChars[i].fontWide;
  178. pHeight[i] = newChars[i].fontTall;
  179. pRGBAOffset[i] = newChars[i].offset;
  180. }
  181. if ( !FontManager().MaterialSystem()->GetTrueTypeGlyphs( m_hFont, m_iTall, numNewChars, pWch, pOffsetX, pOffsetY, pWidth, pHeight, pRGBA, pRGBAOffset ) )
  182. {
  183. // failure
  184. return;
  185. }
  186. for ( int i = 0; i < numNewChars; i++ )
  187. {
  188. // apply requested effects in specified order
  189. unsigned char *pCharRGBA = pRGBA + newChars[i].offset;
  190. ApplyDropShadowToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iDropShadowOffset );
  191. ApplyOutlineToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iOutlineSize );
  192. ApplyGaussianBlurToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iBlur );
  193. ApplyScanlineEffectToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iScanLines );
  194. ApplyRotaryEffectToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_bRotary );
  195. }
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose: writes the char into the specified 32bpp texture at specified rect
  199. //-----------------------------------------------------------------------------
  200. void CPS3Font::GetCharRGBA( wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *pRGBA )
  201. {
  202. newChar_t newChar;
  203. newChar.wch = ch;
  204. newChar.fontWide = rgbaWide;
  205. newChar.fontTall = rgbaTall;
  206. newChar.offset = 0;
  207. GetCharsRGBA( &newChar, 1, pRGBA );
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Purpose: returns true if the font is equivalent to that specified
  211. //-----------------------------------------------------------------------------
  212. bool CPS3Font::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
  213. {
  214. // do an true comparison that accounts for non-supported behaviors that gets remapped
  215. // avoids creating fonts that are graphically equivalent, though specified differently
  216. if ( !stricmp( windowsFontName, m_szName.String() ) &&
  217. m_iTall == tall &&
  218. m_iBlur == blur &&
  219. m_iScanLines == scanlines )
  220. {
  221. // only these flags affect the font glyphs
  222. int validFlags = FONTFLAG_DROPSHADOW |
  223. FONTFLAG_OUTLINE |
  224. FONTFLAG_ROTARY |
  225. FONTFLAG_ITALIC |
  226. FONTFLAG_UNDERLINE;
  227. if ( ( m_iFlags & validFlags ) == ( flags & validFlags ) )
  228. {
  229. if ( GetStyleFromParameters( m_iFlags, m_iWeight ) == GetStyleFromParameters( flags, weight ) )
  230. {
  231. // the font is equivalent
  232. return true;
  233. }
  234. }
  235. }
  236. return false;
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose: returns true only if this font is valid for use
  240. //-----------------------------------------------------------------------------
  241. bool CPS3Font::IsValid()
  242. {
  243. if ( m_szName != UTL_INVAL_SYMBOL )
  244. return true;
  245. return false;
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Purpose: gets the abc widths for a character
  249. //-----------------------------------------------------------------------------
  250. void CPS3Font::GetCharABCWidths( int ch, int &a, int &b, int &c )
  251. {
  252. Assert( IsValid() );
  253. if ( ch < ABCWIDTHS_CACHE_SIZE )
  254. {
  255. // use the cache entry
  256. a = m_ABCWidthsCache[ch].a;
  257. b = m_ABCWidthsCache[ch].b;
  258. c = m_ABCWidthsCache[ch].c;
  259. }
  260. else
  261. {
  262. // look for it in the extended cache
  263. abc_cache_t finder = { (wchar_t)ch };
  264. unsigned short i = m_ExtendedABCWidthsCache.Find( finder );
  265. if ( m_ExtendedABCWidthsCache.IsValidIndex( i ) )
  266. {
  267. a = m_ExtendedABCWidthsCache[i].abc.a;
  268. b = m_ExtendedABCWidthsCache[i].abc.b;
  269. c = m_ExtendedABCWidthsCache[i].abc.c;
  270. return;
  271. }
  272. // not in the cache, get from system
  273. // getting the metrics is an expensive i/o operation
  274. if ( !m_hFont )
  275. {
  276. // demand request for font metrics, re-open font
  277. int style = GetStyleFromParameters( m_iFlags, m_iWeight );
  278. m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( GetName(), m_iTall, style );
  279. }
  280. if ( m_hFont )
  281. {
  282. CPS3FontMetrics fontMetrics;
  283. CPS3CharMetrics charMetrics;
  284. FontManager().MaterialSystem()->GetTrueTypeFontMetrics( m_hFont, m_iTall, ch, ch, &fontMetrics, &charMetrics );
  285. /*
  286. // Determine real a,b,c mapping from XUI Character Metrics
  287. a = charMetrics.fMinX - 1; // Add one column of padding to make up for font rendering blurring into left column (and adjust in b)
  288. b = charMetrics.fMaxX - charMetrics.fMinX + 1;
  289. c = charMetrics.fAdvance - charMetrics.fMaxX; // NOTE: We probably should add a column here, but it's rarely needed in our current fonts so we're opting to save memory instead
  290. */
  291. a = charMetrics.A();
  292. b = charMetrics.B();
  293. c = charMetrics.C();
  294. // Widen for blur, outline, and shadow. Need to widen b and reduce a and c.
  295. a = a - m_iOutlineSize;
  296. b = b + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset;
  297. c = c - 2*m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
  298. }
  299. else
  300. {
  301. a = 0;
  302. b = 0;
  303. c = 0;
  304. }
  305. // add to the cache
  306. finder.abc.a = a;
  307. finder.abc.b = b;
  308. finder.abc.c = c;
  309. m_ExtendedABCWidthsCache.Insert( finder );
  310. }
  311. }
  312. void CPS3Font::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC )
  313. {
  314. int a, b, c;
  315. GetCharABCWidths( ch, a, b, c );
  316. wide = a+b+c;
  317. abcA = a;
  318. abcC = c;
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose: returns the height of the font, in pixels
  322. //-----------------------------------------------------------------------------
  323. int CPS3Font::GetHeight()
  324. {
  325. Assert( IsValid() );
  326. return m_iHeight;
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
  330. //-----------------------------------------------------------------------------
  331. int CPS3Font::GetAscent()
  332. {
  333. Assert( IsValid() );
  334. return m_iAscent;
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Purpose: returns the maximum width of a character, in pixels
  338. //-----------------------------------------------------------------------------
  339. int CPS3Font::GetMaxCharWidth()
  340. {
  341. Assert( IsValid() );
  342. return m_iMaxCharWidth;
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose: returns the flags used to make this font, used by the dynamic resizing code
  346. //-----------------------------------------------------------------------------
  347. int CPS3Font::GetFlags()
  348. {
  349. Assert( IsValid() );
  350. return m_iFlags;
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Purpose: Comparison function for abc widths storage
  354. //-----------------------------------------------------------------------------
  355. bool CPS3Font::ExtendedABCWidthsCacheLessFunc( const abc_cache_t &lhs, const abc_cache_t &rhs )
  356. {
  357. return lhs.wch < rhs.wch;
  358. }
  359. void CPS3Font::CloseResource()
  360. {
  361. if ( !m_hFont )
  362. {
  363. return;
  364. }
  365. // many fonts are blindly precached by vgui and never used
  366. // save memory and don't hold font open, re-open if glyph actually requested used during draw
  367. FontManager().MaterialSystem()->CloseTrueTypeFont( m_hFont );
  368. m_hFont = NULL;
  369. }