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.

665 lines
20 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "gametext.h"
  8. #include "vgui/ilocalize.h"
  9. #include "vgui/vgui.h"
  10. #include <ctype.h>
  11. #include "gameuisystemsurface.h"
  12. #include "gameuisystemmgr.h"
  13. #include "gameuischeme.h"
  14. #include "graphicgroup.h"
  15. #include "gameuidefinition.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. // Class factory for scripting.
  19. class CGameTextClassFactory : IGameUIGraphicClassFactory
  20. {
  21. public:
  22. CGameTextClassFactory()
  23. {
  24. Assert( g_pGameUISystemMgrImpl );
  25. g_pGameUISystemMgrImpl->RegisterGraphicClassFactory( "text", this );
  26. }
  27. // Returns an instance of a graphic interface (keyvalues owned by caller)
  28. virtual CGameGraphic *CreateNewGraphicClass( KeyValues *kvRequest, CGameUIDefinition *pMenu )
  29. {
  30. Assert( pMenu );
  31. CGameText *pNewGraphic = NULL;
  32. const char *pName = kvRequest->GetString( "name", NULL );
  33. if ( pName )
  34. {
  35. pNewGraphic = new CGameText( pName );
  36. pMenu->AddGraphicToLayer( pNewGraphic, SUBLAYER_FONT );
  37. // Now set the attributes.
  38. for ( KeyValues *arg = kvRequest->GetFirstSubKey(); arg != NULL; arg = arg->GetNextKey() )
  39. {
  40. pNewGraphic->HandleScriptCommand( arg );
  41. }
  42. }
  43. return pNewGraphic;
  44. }
  45. };
  46. static CGameTextClassFactory g_CGameTextClassFactory;
  47. BEGIN_DMXELEMENT_UNPACK ( CGameText )
  48. DMXELEMENT_UNPACK_FIELD_UTLSTRING( "name", "", m_pName )
  49. DMXELEMENT_UNPACK_FIELD( "center", "0 0", Vector2D, m_Geometry.m_Center )
  50. DMXELEMENT_UNPACK_FIELD( "scale", "1 1", Vector2D, m_Geometry.m_Scale )
  51. DMXELEMENT_UNPACK_FIELD( "rotation", "0", float, m_Geometry.m_Rotation )
  52. DMXELEMENT_UNPACK_FIELD( "maintainaspectratio", "0", bool, m_Geometry.m_bMaintainAspectRatio )
  53. DMXELEMENT_UNPACK_FIELD( "sublayertype", "0", int, m_Geometry.m_Sublayer )
  54. DMXELEMENT_UNPACK_FIELD( "visible", "1", bool, m_Geometry.m_bVisible )
  55. DMXELEMENT_UNPACK_FIELD( "initialstate", "-1", int, m_CurrentState )
  56. DMXELEMENT_UNPACK_FIELD_UTLSTRING( "unlocalizedtext", "NONE", m_CharText )
  57. DMXELEMENT_UNPACK_FIELD( "allcaps", "0", bool, m_bAllCaps )
  58. DMXELEMENT_UNPACK_FIELD_UTLSTRING( "fontname", "Default", m_FontName )
  59. DMXELEMENT_UNPACK_FIELD( "justfication", "0", int, m_Justification )
  60. DMXELEMENT_UNPACK_FIELD( "color", "255 255 255 255", Color, m_Geometry.m_Color )
  61. DMXELEMENT_UNPACK_FIELD( "topcolor", "255 255 255 255", Color, m_Geometry.m_TopColor )
  62. DMXELEMENT_UNPACK_FIELD( "bottomcolor", "255 255 255 255", Color, m_Geometry.m_BottomColor )
  63. DMXELEMENT_UNPACK_FIELD( "horizgradient", "0", bool, m_Geometry.m_bHorizontalGradient )
  64. // color is gotten from log.
  65. END_DMXELEMENT_UNPACK( CGameText, s_GameTextUnpack )
  66. //-----------------------------------------------------------------------------
  67. // Constructor
  68. //-----------------------------------------------------------------------------
  69. CGameText::CGameText( const char *pName )
  70. {
  71. m_UnicodeText = NULL;
  72. m_TextBufferLen = 0;
  73. m_UnlocalizedTextSymbol = vgui::INVALID_STRING_INDEX;
  74. m_Font = vgui::INVALID_FONT;
  75. m_bCanAcceptInput = false;
  76. // DME default values.
  77. m_pName = pName;
  78. m_Geometry.m_Center.x = 0;
  79. m_Geometry.m_Center.y = 0;
  80. m_Geometry.m_Scale.x = 1;
  81. m_Geometry.m_Scale.y = 1;
  82. m_Geometry.m_Rotation = 0;
  83. m_Geometry.m_bMaintainAspectRatio = 1;
  84. m_Geometry.m_Sublayer = 0;
  85. m_Geometry.m_bVisible = true;
  86. m_CurrentState = -1;
  87. m_CharText = "NONE";
  88. m_bAllCaps = false;
  89. m_FontName = "Default";
  90. m_Justification = JUSTIFICATION_LEFT;
  91. m_Geometry.m_Color.r = 255;
  92. m_Geometry.m_Color.g = 255;
  93. m_Geometry.m_Color.b = 255;
  94. m_Geometry.m_Color.a = 255;
  95. m_Geometry.m_TopColor.r = 255;
  96. m_Geometry.m_TopColor.g = 255;
  97. m_Geometry.m_TopColor.b = 255;
  98. m_Geometry.m_TopColor.a = 255;
  99. m_Geometry.m_BottomColor.r = 255;
  100. m_Geometry.m_BottomColor.g = 255;
  101. m_Geometry.m_BottomColor.b = 255;
  102. m_Geometry.m_BottomColor.a = 255;
  103. m_Geometry.m_bHorizontalGradient = false;
  104. SetText( m_CharText );
  105. SetFont( m_FontName );
  106. }
  107. //-----------------------------------------------------------------------------
  108. //
  109. //-----------------------------------------------------------------------------
  110. CGameText::~CGameText()
  111. {
  112. if ( m_UnicodeText )
  113. {
  114. delete[] m_UnicodeText;
  115. m_UnicodeText = NULL;
  116. }
  117. };
  118. //-----------------------------------------------------------------------------
  119. // Create game text using dme elements
  120. //-----------------------------------------------------------------------------
  121. bool CGameText::Unserialize( CDmxElement *pGraphic )
  122. {
  123. pGraphic->UnpackIntoStructure( this, s_GameTextUnpack );
  124. // GEOMETRY
  125. // Geometry for text is generated. This is because you don't know it until you know the localized text.
  126. // ANIMSTATES
  127. CDmxAttribute *pImageAnims = pGraphic->GetAttribute( "imageanims" );
  128. if ( !pImageAnims || pImageAnims->GetType() != AT_ELEMENT_ARRAY )
  129. {
  130. return false;
  131. }
  132. const CUtlVector< CDmxElement * > &imageanims = pImageAnims->GetArray< CDmxElement * >( );
  133. int nCount = imageanims.Count();
  134. for ( int i = 0; i < nCount; ++i )
  135. {
  136. CAnimData *pAnimData = new CAnimData;
  137. if ( !pAnimData->Unserialize( imageanims[i] ) )
  138. {
  139. delete pAnimData;
  140. return false;
  141. }
  142. m_Anims.AddToTail( pAnimData );
  143. }
  144. SetText( m_CharText );
  145. SetFont( m_FontName );
  146. SetState( "default" );
  147. return true;
  148. }
  149. //-----------------------------------------------------------------------------
  150. // The attributes that can be modified by scripting are a subset of the DME ones.
  151. //-----------------------------------------------------------------------------
  152. KeyValues *CGameText::HandleScriptCommand( KeyValues *args )
  153. {
  154. char const *szCommand = args->GetName();
  155. if ( !Q_stricmp( "SetText", szCommand ) )
  156. {
  157. const char *text = args->GetString( "text" );
  158. SetText( text );
  159. return NULL;
  160. }
  161. else if ( !Q_stricmp( "SetAllCaps", szCommand ) )
  162. {
  163. m_bAllCaps = args->GetBool( "allcaps", false );
  164. return NULL;
  165. }
  166. else if ( !Q_stricmp( "SetFont", szCommand ) )
  167. {
  168. SetFont( args->GetString( "fontname" ) );
  169. return NULL;
  170. }
  171. else if ( !Q_stricmp( "SetJustification", szCommand ) )
  172. {
  173. // FIXME
  174. m_Justification = args->GetInt( "justfication", 0 );
  175. return NULL;
  176. }
  177. else if ( !Q_stricmp( "SetTopColor", szCommand ) )
  178. {
  179. Color c = args->GetColor( "color", Color( 255, 255, 255, 255 ) );
  180. m_Geometry.m_TopColor.r = c[0];
  181. m_Geometry.m_TopColor.g = c[1];
  182. m_Geometry.m_TopColor.b = c[2];
  183. m_Geometry.m_TopColor.a = c[3];
  184. return NULL;
  185. }
  186. else if ( !Q_stricmp( "SetBottomColor", szCommand ) )
  187. {
  188. Color c = args->GetColor( "color", Color( 255, 255, 255, 255 ) );
  189. m_Geometry.m_BottomColor.r = c[0];
  190. m_Geometry.m_BottomColor.g = c[1];
  191. m_Geometry.m_BottomColor.b = c[2];
  192. m_Geometry.m_BottomColor.a = c[3];
  193. return NULL;
  194. }
  195. else if ( !Q_stricmp( "GetFont", szCommand ) )
  196. {
  197. return new KeyValues( "", "font", m_FontName.Get() );
  198. }
  199. return CGameGraphic::HandleScriptCommand( args );
  200. }
  201. //-----------------------------------------------------------------------------
  202. //
  203. //-----------------------------------------------------------------------------
  204. void CGameText::SetFont( const char *pFontName )
  205. {
  206. m_FontName = pFontName;
  207. if ( m_FontName.Length() )
  208. {
  209. m_Font = g_pGameUISystemMgrImpl->GetCurrentScheme()->GetFont( m_FontName, true );
  210. }
  211. }
  212. //-----------------------------------------------------------------------------
  213. //
  214. //-----------------------------------------------------------------------------
  215. void CGameText::SetFont( FontHandle_t font )
  216. {
  217. m_Font = font;
  218. }
  219. //-----------------------------------------------------------------------------
  220. //
  221. //-----------------------------------------------------------------------------
  222. FontHandle_t CGameText::GetFont()
  223. {
  224. return m_Font;
  225. }
  226. //-----------------------------------------------------------------------------
  227. //
  228. //-----------------------------------------------------------------------------
  229. void CGameText::SetJustification( Justification_e justify )
  230. {
  231. m_Justification = justify;
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose: takes the string and looks it up in the localization file to convert it to unicode
  235. //-----------------------------------------------------------------------------
  236. void CGameText::SetText( const char *text )
  237. {
  238. if ( !text )
  239. {
  240. text = "";
  241. }
  242. // check for localization
  243. if ( *text == '#' )
  244. {
  245. // try lookup in localization tables
  246. m_UnlocalizedTextSymbol = g_pVGuiLocalize->FindIndex( text + 1 );
  247. if ( m_UnlocalizedTextSymbol != vgui::INVALID_STRING_INDEX )
  248. {
  249. wchar_t *unicode = g_pVGuiLocalize->GetValueByIndex( m_UnlocalizedTextSymbol );
  250. SetText(unicode);
  251. return;
  252. }
  253. }
  254. // convert the ansi string to unicode and use that
  255. wchar_t unicode[1024];
  256. g_pVGuiLocalize->ConvertANSIToUnicode( text, unicode, sizeof(unicode) );
  257. SetText( unicode );
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose: sets unicode text directly
  261. //-----------------------------------------------------------------------------
  262. void CGameText::SetText( const wchar_t *unicode, bool bClearUnlocalizedSymbol )
  263. {
  264. if ( bClearUnlocalizedSymbol )
  265. {
  266. // Clear out unlocalized text symbol so that changing dialog variables
  267. // doesn't stomp over the custom unicode string we're being set to.
  268. m_UnlocalizedTextSymbol = vgui::INVALID_STRING_INDEX;
  269. }
  270. if (!unicode)
  271. {
  272. unicode = L"";
  273. }
  274. // reallocate the buffer if necessary
  275. short textLen = (short)wcslen( unicode );
  276. if ( textLen >= m_TextBufferLen )
  277. {
  278. if ( m_UnicodeText )
  279. {
  280. delete [] m_UnicodeText;
  281. m_UnicodeText = NULL;
  282. }
  283. m_TextBufferLen = (short)( textLen + 1 );
  284. m_UnicodeText = new wchar_t[ m_TextBufferLen ];
  285. }
  286. // store the text as unicode
  287. wcscpy( m_UnicodeText, unicode );
  288. SetupVertexColors();
  289. }
  290. //-----------------------------------------------------------------------------
  291. //
  292. //-----------------------------------------------------------------------------
  293. void CGameText::UpdateGeometry()
  294. {
  295. if ( m_CurrentState == -1 )
  296. return;
  297. Assert( m_CurrentState < m_Anims.Count() );
  298. DmeTime_t flAnimTime = GetAnimationTimePassed();
  299. // Update color
  300. m_Anims[ m_CurrentState ]->m_ColorAnim.GetValue( flAnimTime, &m_Geometry.m_Color );
  301. // Update center location
  302. m_Anims[ m_CurrentState ]->m_CenterPosAnim.GetValue( flAnimTime, &m_Geometry.m_Center );
  303. // Update scale
  304. m_Anims[ m_CurrentState ]->m_ScaleAnim.GetValue( flAnimTime, &m_Geometry.m_Scale );
  305. // Update rotation
  306. m_Anims[ m_CurrentState ]->m_RotationAnim.GetValue( flAnimTime, &m_Geometry.m_Rotation );
  307. // Update rotation
  308. m_Anims[ m_CurrentState ]->m_FontAnim.GetValue( flAnimTime, &m_FontName );
  309. SetFont( m_FontName );
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Rendering helper
  313. // For text rendering the starting position is top left
  314. // Center text according to justification.
  315. //-----------------------------------------------------------------------------
  316. void CGameText::GetStartingTextPosition( int &x, int &y )
  317. {
  318. x = 0;
  319. y = -GetTextRenderHeight()/2;
  320. switch ( m_Justification )
  321. {
  322. case JUSTIFICATION_LEFT:
  323. break;
  324. case JUSTIFICATION_CENTER:
  325. x = -GetTextRenderWidth()/2;
  326. break;
  327. case JUSTIFICATION_RIGHT:
  328. x = -GetTextRenderWidth();
  329. break;
  330. default:
  331. Assert(0);
  332. break;
  333. }
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Rendering helper
  337. // Determine what list to put this quad into, and make an entry slot for it.
  338. //-----------------------------------------------------------------------------
  339. CRenderGeometry *CGameText::GetGeometryEntry( CUtlVector< RenderGeometryList_t > &renderGeometryLists, int firstListIndex, int fontTextureID )
  340. {
  341. CRenderGeometry *pRenderGeometry = NULL;
  342. if ( renderGeometryLists[firstListIndex].Count() != 0 )
  343. {
  344. for ( int j = firstListIndex; j < renderGeometryLists.Count(); ++j )
  345. {
  346. if ( fontTextureID == renderGeometryLists[j][0].m_FontTextureID )
  347. {
  348. int index = renderGeometryLists[j].AddToTail();
  349. pRenderGeometry = &renderGeometryLists[j][index];
  350. break;
  351. }
  352. }
  353. }
  354. // Didn't find a match for this textureID, time to make a new list of quads for this texture.
  355. if ( pRenderGeometry == NULL )
  356. {
  357. int newListIndex;
  358. if ( renderGeometryLists[firstListIndex].Count() == 0 ) // This is the first quad we are adding to this font layer.
  359. {
  360. newListIndex = firstListIndex;
  361. }
  362. else
  363. {
  364. newListIndex = renderGeometryLists.AddToTail();
  365. }
  366. int index = renderGeometryLists[newListIndex].AddToTail();
  367. pRenderGeometry = &renderGeometryLists[newListIndex][index];
  368. }
  369. return pRenderGeometry;
  370. }
  371. //-----------------------------------------------------------------------------
  372. //
  373. //-----------------------------------------------------------------------------
  374. void CGameText::SetupVertexColors()
  375. {
  376. // There is no text to generate if these are not set.
  377. if ( !m_UnicodeText )
  378. return;
  379. m_Geometry.m_VertexColors.RemoveAll();
  380. color32 c;
  381. c.r = 255;
  382. c.g = 255;
  383. c.b = 255;
  384. c.a = 255;
  385. for ( wchar_t *wsz = m_UnicodeText; *wsz != 0; wsz++ )
  386. {
  387. // Create 4 vertex colors per letter.
  388. m_Geometry.m_VertexColors.AddToTail( c );
  389. m_Geometry.m_VertexColors.AddToTail( c );
  390. m_Geometry.m_VertexColors.AddToTail( c );
  391. m_Geometry.m_VertexColors.AddToTail( c );
  392. }
  393. }
  394. //-----------------------------------------------------------------------------
  395. //
  396. //-----------------------------------------------------------------------------
  397. void CGameText::UpdateRenderData( color32 parentColor, CUtlVector< RenderGeometryList_t > &renderGeometryLists, int firstListIndex )
  398. {
  399. if ( !m_Geometry.m_bVisible )
  400. return;
  401. // There is no text to generate if these are not set.
  402. if ( !m_UnicodeText )
  403. return;
  404. if ( m_Font == vgui::INVALID_FONT)
  405. return;
  406. m_Geometry.SetResultantColor( parentColor );
  407. int x, y;
  408. GetStartingTextPosition( x, y );
  409. FontCharRenderInfo info;
  410. info.currentFont = m_Font;
  411. info.drawType = FONT_DRAW_DEFAULT;
  412. int letterIndex = 0;
  413. m_Geometry.m_RelativePositions.RemoveAll();
  414. for ( wchar_t *wsz = m_UnicodeText; *wsz != 0; wsz++, letterIndex += 4 )
  415. {
  416. Assert( letterIndex < m_Geometry.m_VertexColors.Count() );
  417. // Update FontCharRenderInfo
  418. info.x = x;
  419. info.y = y;
  420. info.ch = wsz[0];
  421. if ( m_bAllCaps )
  422. {
  423. info.ch = towupper( info.ch );
  424. }
  425. Vector2D relPositions[4];
  426. g_pGameUISystemSurface->GetUnicodeCharRenderPositions( info, relPositions );
  427. // get the character texture from the cache and the char's texture coords.
  428. float *texCoords = NULL; // note this returns the static from the fonttexturecache... FIXME?
  429. g_pGameUISystemSurface->GetTextureForChar( info, &texCoords );
  430. x += g_pGameUISystemSurface->GetCharacterWidth( m_Font, info.ch );
  431. // Get a geometry from the correct texture list.
  432. CRenderGeometry *pRenderGeometry = GetGeometryEntry( renderGeometryLists, firstListIndex, info.textureId );
  433. Assert( pRenderGeometry != NULL );
  434. // Populate the new entry.
  435. pRenderGeometry->m_FontTextureID = info.textureId;
  436. Vector screenPosition;
  437. Vector relativePosition;
  438. // Top left
  439. relativePosition.Init( relPositions[0].x, relPositions[0].y, 0 );
  440. m_Geometry.m_RelativePositions.AddToTail( Vector2D( relPositions[0].x, relPositions[0].y ) );
  441. VectorTransform( relativePosition, m_Geometry.m_RenderToScreen, screenPosition );
  442. pRenderGeometry->m_Positions.AddToTail( Vector2D( floor( screenPosition.x ), floor( screenPosition.y ) ) );
  443. pRenderGeometry->m_VertexColors.AddToTail( m_Geometry.m_VertexColors[letterIndex] );
  444. pRenderGeometry->m_TextureCoords.AddToTail( Vector2D( texCoords[0], texCoords[1] ) );
  445. // Top right
  446. relativePosition.Init( relPositions[1].x, relPositions[1].y, 0 );
  447. m_Geometry.m_RelativePositions.AddToTail( Vector2D( relPositions[1].x, relPositions[1].y ) );
  448. VectorTransform( relativePosition, m_Geometry.m_RenderToScreen, screenPosition );
  449. pRenderGeometry->m_Positions.AddToTail( Vector2D( floor( screenPosition.x ), floor( screenPosition.y ) ) );
  450. pRenderGeometry->m_VertexColors.AddToTail( m_Geometry.m_VertexColors[letterIndex + 1] );
  451. pRenderGeometry->m_TextureCoords.AddToTail( Vector2D( texCoords[2], texCoords[1] ) );
  452. // Bottom right
  453. relativePosition.Init( relPositions[2].x, relPositions[2].y, 0 );
  454. m_Geometry.m_RelativePositions.AddToTail( Vector2D( relPositions[2].x, relPositions[2].y ) );
  455. VectorTransform( relativePosition, m_Geometry.m_RenderToScreen, screenPosition );
  456. pRenderGeometry->m_Positions.AddToTail( Vector2D( floor( screenPosition.x ), floor( screenPosition.y ) ) );
  457. pRenderGeometry->m_VertexColors.AddToTail( m_Geometry.m_VertexColors[letterIndex + 2] );
  458. pRenderGeometry->m_TextureCoords.AddToTail( Vector2D( texCoords[2], texCoords[3] ) );
  459. // Bottom left
  460. relativePosition.Init( relPositions[3].x, relPositions[3].y, 0 );
  461. m_Geometry.m_RelativePositions.AddToTail( Vector2D( relPositions[3].x, relPositions[3].y ) );
  462. VectorTransform( relativePosition, m_Geometry.m_RenderToScreen, screenPosition );
  463. pRenderGeometry->m_Positions.AddToTail( Vector2D( floor( screenPosition.x ), floor( screenPosition.y ) ) );
  464. pRenderGeometry->m_VertexColors.AddToTail( m_Geometry.m_VertexColors[letterIndex + 3] );
  465. pRenderGeometry->m_TextureCoords.AddToTail( Vector2D( texCoords[0], texCoords[3] ) );
  466. pRenderGeometry->m_AnimationRate = m_Geometry.m_AnimationRate;
  467. pRenderGeometry->m_AnimStartTime = m_Geometry.m_AnimStartTime;
  468. pRenderGeometry->m_bAnimate = m_Geometry.m_bAnimate;
  469. pRenderGeometry->m_pImageAlias = NULL;
  470. }
  471. m_Geometry.CalculateExtents();
  472. }
  473. //-----------------------------------------------------------------------------
  474. // Have to do this separately because extents are drawn as rects.
  475. //-----------------------------------------------------------------------------
  476. void CGameText::DrawExtents( CUtlVector< RenderGeometryList_t > &renderGeometryLists, int firstListIndex )
  477. {
  478. color32 extentLineColor = { 0, 25, 255, 255 };
  479. m_Geometry.DrawExtents( renderGeometryLists, firstListIndex, extentLineColor );
  480. }
  481. //-----------------------------------------------------------------------------
  482. // Purpose: Get the size of a text string in pixels
  483. //-----------------------------------------------------------------------------
  484. void CGameText::GetTextSize( int &wide, int &tall )
  485. {
  486. wide = 0;
  487. tall = 0;
  488. if ( m_Font == vgui::INVALID_FONT )
  489. return;
  490. // For height, use the remapped font
  491. tall = GetTextRenderHeight();
  492. wide = GetTextRenderWidth();
  493. }
  494. //-----------------------------------------------------------------------------
  495. // Return height of text in pixels
  496. //-----------------------------------------------------------------------------
  497. int CGameText::GetTextRenderWidth()
  498. {
  499. int wordWidth = 0;
  500. int textLen = wcslen( m_UnicodeText );
  501. for ( int i = 0; i < textLen; i++ )
  502. {
  503. wchar_t ch = m_UnicodeText[ i ];
  504. if ( m_bAllCaps )
  505. {
  506. ch = towupper( ch );
  507. }
  508. // handle stupid special characters, these should be removed
  509. if ( ch == '&' && m_UnicodeText[ i + 1 ] != 0 )
  510. {
  511. continue;
  512. }
  513. wordWidth += g_pGameUISystemSurface->GetCharacterWidth( m_Font, ch );
  514. }
  515. return wordWidth;
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Return width of text in pixels
  519. //-----------------------------------------------------------------------------
  520. int CGameText::GetTextRenderHeight()
  521. {
  522. return g_pGameUISystemSurface->GetFontTall( m_Font );
  523. }
  524. //-----------------------------------------------------------------------------
  525. // Note corner colors will be stomped if the base graphic's color changes.
  526. //-----------------------------------------------------------------------------
  527. void CGameText::SetColor( color32 c )
  528. {
  529. m_Geometry.m_TopColor = c;
  530. m_Geometry.m_BottomColor = c;
  531. // Remove first to force the new colors in.
  532. m_Geometry.m_VertexColors.RemoveAll();
  533. SetupVertexColors();
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Determine if x,y is inside the graphic.
  537. //-----------------------------------------------------------------------------
  538. bool CGameText::HitTest( int x, int y )
  539. {
  540. if ( !m_Geometry.m_bVisible )
  541. return false;
  542. // Just using extents for now, note extents don't take into account rotation.
  543. Vector2D point0( m_Geometry.m_Extents.m_TopLeft.x, m_Geometry.m_Extents.m_TopLeft.y );
  544. Vector2D point1( m_Geometry.m_Extents.m_BottomRight.x, m_Geometry.m_Extents.m_TopLeft.y );
  545. Vector2D point2( m_Geometry.m_Extents.m_BottomRight.x, m_Geometry.m_Extents.m_BottomRight.y );
  546. Vector2D point3( m_Geometry.m_Extents.m_TopLeft.x, m_Geometry.m_Extents.m_BottomRight.y );
  547. if ( PointTriangleHitTest( point0, point1, point2, Vector2D( x, y ) ) )
  548. {
  549. //Msg( "%d, %d hit\n", x, y );
  550. return true;
  551. }
  552. if ( PointTriangleHitTest( point0, point2, point3, Vector2D( x, y ) ) )
  553. {
  554. //Msg( "%d, %d hit\n", x, y );
  555. return true;
  556. }
  557. return false;
  558. }