Team Fortress 2 Source Code as on 22/4/2020
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.

346 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Xbox 360 support for TrueType Fonts. The only cuurent solution is to use XUI
  4. // to mount the TTF, and rasterize glyph into a render target. XUI does not support
  5. // rasterization directly to a system memory region.
  6. //
  7. //=====================================================================================//
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <math.h>
  11. #include <malloc.h>
  12. #include <tier0/dbg.h>
  13. #include <vgui/ISurface.h>
  14. #include <tier0/mem.h>
  15. #include <utlbuffer.h>
  16. #include "filesystem.h"
  17. #include "materialsystem/imaterialsystem.h"
  18. #include "FontEffects.h"
  19. #include "vgui_surfacelib/Win32Font.h"
  20. #include "vgui_surfacelib/FontManager.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. bool s_bSupportsUnicode = true;
  24. //-----------------------------------------------------------------------------
  25. // Determine possible style from parameters.
  26. //-----------------------------------------------------------------------------
  27. int GetStyleFromParameters( int iFlags, int iWeight )
  28. {
  29. // Available xbox TTF styles are very restricted.
  30. int style = XUI_FONT_STYLE_NORMAL;
  31. if ( iFlags & vgui::ISurface::FONTFLAG_ITALIC )
  32. style |= XUI_FONT_STYLE_ITALIC;
  33. if ( iFlags & vgui::ISurface::FONTFLAG_UNDERLINE )
  34. style |= XUI_FONT_STYLE_UNDERLINE;
  35. if ( iWeight > 400 )
  36. style |= XUI_FONT_STYLE_BOLD;
  37. return style;
  38. }
  39. //-----------------------------------------------------------------------------
  40. // Purpose: Constructor
  41. //-----------------------------------------------------------------------------
  42. CWin32Font::CWin32Font()
  43. {
  44. m_szName = UTL_INVAL_SYMBOL;
  45. m_iTall = 0;
  46. m_iWeight = 0;
  47. m_iHeight = 0;
  48. m_iAscent = 0;
  49. m_iFlags = 0;
  50. m_iMaxCharWidth = 0;
  51. m_hFont = NULL;
  52. m_hDC = NULL;
  53. m_bAntiAliased = false;
  54. m_iBlur = 0;
  55. m_iScanLines = 0;
  56. m_bRotary = false;
  57. m_bAdditive = false;
  58. m_rgiBitmapSize[0] = 0;
  59. m_rgiBitmapSize[1] = 0;
  60. Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Purpose: Destructor
  64. //-----------------------------------------------------------------------------
  65. CWin32Font::~CWin32Font()
  66. {
  67. CloseResource();
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose: Creates the font.
  71. //-----------------------------------------------------------------------------
  72. bool CWin32Font::Create( const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags )
  73. {
  74. // setup font properties
  75. m_iTall = tall;
  76. m_iWeight = weight;
  77. m_iFlags = flags;
  78. m_bAntiAliased = (flags & vgui::ISurface::FONTFLAG_ANTIALIAS) ? 1 : 0;
  79. m_iDropShadowOffset = (flags & vgui::ISurface::FONTFLAG_DROPSHADOW) ? 1 : 0;
  80. m_iOutlineSize = (flags & vgui::ISurface::FONTFLAG_OUTLINE) ? 1 : 0;
  81. m_iBlur = blur;
  82. m_iScanLines = scanlines;
  83. m_bRotary = (flags & vgui::ISurface::FONTFLAG_ROTARY) ? 1 : 0;
  84. m_bAdditive = (flags & vgui::ISurface::FONTFLAG_ADDITIVE) ? 1 : 0;
  85. int style = GetStyleFromParameters( flags, weight );
  86. // must support > 128, there are characters in this range in the custom fonts
  87. COMPILE_TIME_ASSERT( ABCWIDTHS_CACHE_SIZE == 256 );
  88. XUIFontMetrics fontMetrics;
  89. XUICharMetrics charMetrics[256];
  90. // many redundant requests are made that are actually the same font metrics
  91. // find it in the metric cache first based on the true specific keys
  92. if ( !FontManager().GetCachedXUIMetrics( windowsFontName, tall, style, &fontMetrics, charMetrics ) )
  93. {
  94. m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( windowsFontName, tall, style );
  95. if ( !m_hFont )
  96. {
  97. return false;
  98. }
  99. // getting the metrics is an expensive i/o operation, cache results
  100. FontManager().MaterialSystem()->GetTrueTypeFontMetrics( m_hFont, &fontMetrics, charMetrics );
  101. FontManager().SetCachedXUIMetrics( windowsFontName, tall, style, &fontMetrics, charMetrics );
  102. }
  103. m_szName = windowsFontName;
  104. m_iHeight = fontMetrics.fMaxHeight + m_iDropShadowOffset + 2 * m_iOutlineSize;
  105. m_iMaxCharWidth = fontMetrics.fMaxWidth;
  106. m_iAscent = fontMetrics.fMaxAscent;
  107. // determine cell bounds
  108. m_rgiBitmapSize[0] = m_iMaxCharWidth + m_iOutlineSize * 2;
  109. m_rgiBitmapSize[1] = m_iHeight;
  110. // get char spacing
  111. // a is space before character (can be negative)
  112. // b is the width of the character
  113. // c is the space after the character
  114. Assert( ABCWIDTHS_CACHE_SIZE <= 256 );
  115. Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
  116. for ( int i = 1; i < ABCWIDTHS_CACHE_SIZE; i++ )
  117. {
  118. int a,b,c;
  119. // Determine real a,b,c mapping from XUI Character Metrics
  120. a = charMetrics[i].fMinX - 1; // Add one column of padding to make up for font rendering blurring into left column (and adjust in b)
  121. b = charMetrics[i].fMaxX - charMetrics[i].fMinX + 1;
  122. 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
  123. // Widen for blur, outline, and shadow. Need to widen b and reduce a and c.
  124. m_ABCWidthsCache[i].a = a - m_iBlur - m_iOutlineSize;
  125. m_ABCWidthsCache[i].b = b + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset;
  126. m_ABCWidthsCache[i].c = c - m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
  127. }
  128. return true;
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose: generates texture data (written into appropriate font page subrects) for multiple chars
  132. //-----------------------------------------------------------------------------
  133. void CWin32Font::GetCharsRGBA( newChar_t *newChars, int numNewChars, unsigned char *pRGBA )
  134. {
  135. if ( !m_hFont )
  136. {
  137. // demand request for font glyph, re-create font
  138. int style = GetStyleFromParameters( m_iFlags, m_iWeight );
  139. m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( GetName(), m_iTall, style );
  140. }
  141. wchar_t *pWch = (wchar_t *)_alloca( numNewChars*sizeof(wchar_t) );
  142. int *pOffsetX = (int *)_alloca( numNewChars*sizeof(int) );
  143. int *pOffsetY = (int *)_alloca( numNewChars*sizeof(int) );
  144. int *pWidth = (int *)_alloca( numNewChars*sizeof(int) );
  145. int *pHeight = (int *)_alloca( numNewChars*sizeof(int) );
  146. int *pRGBAOffset = (int *)_alloca( numNewChars*sizeof(int) );
  147. for ( int i = 0; i < numNewChars; i++ )
  148. {
  149. int a, c, wide;
  150. GetCharABCWidths( newChars[i].wch, a, wide, c );
  151. pWch[i] = newChars[i].wch;
  152. pOffsetX[i] = -a;
  153. pOffsetY[i] = 0;
  154. pWidth[i] = newChars[i].fontWide;
  155. pHeight[i] = newChars[i].fontTall;
  156. pRGBAOffset[i] = newChars[i].offset;
  157. }
  158. if ( !FontManager().MaterialSystem()->GetTrueTypeGlyphs( m_hFont, numNewChars, pWch, pOffsetX, pOffsetY, pWidth, pHeight, pRGBA, pRGBAOffset ) )
  159. {
  160. // failure
  161. return;
  162. }
  163. for ( int i = 0; i < numNewChars; i++ )
  164. {
  165. // apply requested effects in specified order
  166. unsigned char *pCharRGBA = pRGBA + newChars[i].offset;
  167. ApplyDropShadowToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iDropShadowOffset );
  168. ApplyOutlineToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iOutlineSize );
  169. ApplyGaussianBlurToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iBlur );
  170. ApplyScanlineEffectToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iScanLines );
  171. ApplyRotaryEffectToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_bRotary );
  172. }
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose: writes the char into the specified 32bpp texture at specified rect
  176. //-----------------------------------------------------------------------------
  177. void CWin32Font::GetCharRGBA( wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *pRGBA )
  178. {
  179. newChar_t newChar;
  180. newChar.wch = ch;
  181. newChar.fontWide = rgbaWide;
  182. newChar.fontTall = rgbaTall;
  183. newChar.offset = 0;
  184. GetCharsRGBA( &newChar, 1, pRGBA );
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Purpose: returns true if the font is equivalent to that specified
  188. //-----------------------------------------------------------------------------
  189. bool CWin32Font::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
  190. {
  191. // do an true comparison that accounts for non-supported behaviors that gets remapped
  192. // avoids creating fonts that are graphically equivalent, though specified differently
  193. if ( !stricmp( windowsFontName, m_szName.String() ) &&
  194. m_iTall == tall &&
  195. m_iBlur == blur &&
  196. m_iScanLines == scanlines )
  197. {
  198. // only these flags affect the font glyphs
  199. int validFlags = vgui::ISurface::FONTFLAG_DROPSHADOW |
  200. vgui::ISurface::FONTFLAG_OUTLINE |
  201. vgui::ISurface::FONTFLAG_ROTARY |
  202. vgui::ISurface::FONTFLAG_ITALIC |
  203. vgui::ISurface::FONTFLAG_UNDERLINE;
  204. if ( ( m_iFlags & validFlags ) == ( flags & validFlags ) )
  205. {
  206. if ( GetStyleFromParameters( m_iFlags, m_iWeight ) == GetStyleFromParameters( flags, weight ) )
  207. {
  208. // the font is equivalent
  209. return true;
  210. }
  211. }
  212. }
  213. return false;
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Purpose: returns true only if this font is valid for use
  217. //-----------------------------------------------------------------------------
  218. bool CWin32Font::IsValid()
  219. {
  220. if ( m_szName != UTL_INVAL_SYMBOL )
  221. return true;
  222. return false;
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose: set the font to be the one to currently draw with in the gdi
  226. //-----------------------------------------------------------------------------
  227. void CWin32Font::SetAsActiveFont( HDC hdc )
  228. {
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose: gets the abc widths for a character
  232. //-----------------------------------------------------------------------------
  233. void CWin32Font::GetCharABCWidths( int ch, int &a, int &b, int &c )
  234. {
  235. Assert( IsValid() );
  236. if ( ch < ABCWIDTHS_CACHE_SIZE )
  237. {
  238. // use the cache entry
  239. a = m_ABCWidthsCache[ch].a;
  240. b = m_ABCWidthsCache[ch].b;
  241. c = m_ABCWidthsCache[ch].c;
  242. }
  243. else
  244. {
  245. // cannot support getting character metrics outside of the font initialization
  246. DevMsg( "CWin32Font: Cannot resolve character %d in font %s\n", ch, m_szName.String() );
  247. Assert( 0 );
  248. a = 0;
  249. b = 0;
  250. c = 0;
  251. }
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Purpose: returns the height of the font, in pixels
  255. //-----------------------------------------------------------------------------
  256. int CWin32Font::GetHeight()
  257. {
  258. Assert( IsValid() );
  259. return m_iHeight;
  260. }
  261. //-----------------------------------------------------------------------------
  262. // Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
  263. //-----------------------------------------------------------------------------
  264. int CWin32Font::GetAscent()
  265. {
  266. Assert( IsValid() );
  267. return m_iAscent;
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Purpose: returns the maximum width of a character, in pixels
  271. //-----------------------------------------------------------------------------
  272. int CWin32Font::GetMaxCharWidth()
  273. {
  274. Assert( IsValid() );
  275. return m_iMaxCharWidth;
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose: returns the flags used to make this font, used by the dynamic resizing code
  279. //-----------------------------------------------------------------------------
  280. int CWin32Font::GetFlags()
  281. {
  282. Assert( IsValid() );
  283. return m_iFlags;
  284. }
  285. void CWin32Font::CloseResource()
  286. {
  287. if ( !m_hFont )
  288. {
  289. return;
  290. }
  291. // many fonts are blindly precached by vgui and never used
  292. // save memory and don't hold font open, re-open if glyph actually requested used during draw
  293. FontManager().MaterialSystem()->CloseTrueTypeFont( m_hFont );
  294. m_hFont = NULL;
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Purpose: Get the kerned size of a char, for win32 just pass thru for now
  298. //-----------------------------------------------------------------------------
  299. void CWin32Font::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA )
  300. {
  301. int a,b,c;
  302. GetCharABCWidths(ch, a, b, c );
  303. wide = ( a + b + c);
  304. abcA = a;
  305. }