PageRenderTime 29ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/MultiVideo/MVMUSER/d3dfont.cpp

http://game-ui-solution.googlecode.com/
C++ | 743 lines | 507 code | 137 blank | 99 comment | 73 complexity | df24dbbbe2e680a2e27b4294fc0b3333 MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.1, ISC, Unlicense, MPL-2.0-no-copyleft-exception, GPL-2.0, BSD-3-Clause, MIT, LGPL-3.0
  1. //-----------------------------------------------------------------------------
  2. // File: D3DFont.cpp
  3. //
  4. // Desc: Texture-based font class
  5. //
  6. // Copyright (c) 1999-2002 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include "stdafx.h"
  10. #include <stdio.h>
  11. #include <tchar.h>
  12. #include <D3DX9.h>
  13. #include "D3DFont.h"
  14. #include "D3DUtil.h"
  15. #include "DXUtil.h"
  16. //-----------------------------------------------------------------------------
  17. // Custom vertex types for rendering text
  18. //-----------------------------------------------------------------------------
  19. #define MAX_NUM_VERTICES 50*6
  20. struct FONT2DVERTEX { D3DXVECTOR4 p; DWORD color; FLOAT tu, tv; };
  21. struct FONT3DVERTEX { D3DXVECTOR3 p; D3DXVECTOR3 n; FLOAT tu, tv; };
  22. #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  23. #define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  24. inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
  25. FLOAT tu, FLOAT tv )
  26. {
  27. FONT2DVERTEX v; v.p = p; v.color = color; v.tu = tu; v.tv = tv;
  28. return v;
  29. }
  30. inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
  31. FLOAT tu, FLOAT tv )
  32. {
  33. FONT3DVERTEX v; v.p = p; v.n = n; v.tu = tu; v.tv = tv;
  34. return v;
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Name: CD3DFont()
  38. // Desc: Font class constructor
  39. //-----------------------------------------------------------------------------
  40. CD3DFont::CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )
  41. {
  42. _tcsncpy( m_strFontName, strFontName, sizeof(m_strFontName) / sizeof(TCHAR) );
  43. m_strFontName[sizeof(m_strFontName) / sizeof(TCHAR) - 1] = _T('\0');
  44. m_dwFontHeight = dwHeight;
  45. m_dwFontFlags = dwFlags;
  46. m_dwSpacing = 0;
  47. m_pd3dDevice = NULL;
  48. m_pTexture = NULL;
  49. m_pVB = NULL;
  50. m_pStateBlockSaved = NULL;
  51. m_pStateBlockDrawText = NULL;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Name: ~CD3DFont()
  55. // Desc: Font class destructor
  56. //-----------------------------------------------------------------------------
  57. CD3DFont::~CD3DFont()
  58. {
  59. InvalidateDeviceObjects();
  60. DeleteDeviceObjects();
  61. }
  62. void CD3DFont::Release()
  63. {
  64. InvalidateDeviceObjects();
  65. DeleteDeviceObjects();
  66. delete this;
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Name: InitDeviceObjects()
  70. // Desc: Initializes device-dependent objects, including the vertex buffer used
  71. // for rendering text and the texture map which stores the font image.
  72. //-----------------------------------------------------------------------------
  73. HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
  74. {
  75. HRESULT hr;
  76. // Keep a local copy of the device
  77. m_pd3dDevice = pd3dDevice;
  78. // Establish the font and texture size
  79. m_fTextScale = 1.0f; // Draw fonts into texture without scaling
  80. // Large fonts need larger textures
  81. if( m_dwFontHeight > 60 )
  82. m_dwTexWidth = m_dwTexHeight = 2048;
  83. else if( m_dwFontHeight > 30 )
  84. m_dwTexWidth = m_dwTexHeight = 1024;
  85. else if( m_dwFontHeight > 15 )
  86. m_dwTexWidth = m_dwTexHeight = 512;
  87. else
  88. m_dwTexWidth = m_dwTexHeight = 256;
  89. // If requested texture is too big, use a smaller texture and smaller font,
  90. // and scale up when rendering.
  91. D3DCAPS9 d3dCaps;
  92. m_pd3dDevice->GetDeviceCaps( &d3dCaps );
  93. if( m_dwTexWidth > d3dCaps.MaxTextureWidth )
  94. {
  95. m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;
  96. m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;
  97. }
  98. // Create a new texture for the font
  99. hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
  100. 0, D3DFMT_A4R4G4B4,
  101. D3DPOOL_MANAGED, &m_pTexture, NULL );
  102. if( FAILED(hr) )
  103. return hr;
  104. // Prepare to create a bitmap
  105. DWORD* pBitmapBits;
  106. BITMAPINFO bmi;
  107. ZeroMemory( &bmi.bmiHeader, sizeof(BITMAPINFOHEADER) );
  108. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  109. bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
  110. bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
  111. bmi.bmiHeader.biPlanes = 1;
  112. bmi.bmiHeader.biCompression = BI_RGB;
  113. bmi.bmiHeader.biBitCount = 32;
  114. // Create a DC and a bitmap for the font
  115. HDC hDC = CreateCompatibleDC( NULL );
  116. HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
  117. (void**)&pBitmapBits, NULL, 0 );
  118. SetMapMode( hDC, MM_TEXT );
  119. // Create a font. By specifying ANTIALIASED_QUALITY, we might get an
  120. // antialiased font, but this is not guaranteed.
  121. INT nHeight = -MulDiv( m_dwFontHeight,
  122. (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
  123. DWORD dwBold = (m_dwFontFlags&D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL;
  124. DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE : FALSE;
  125. HFONT hFont = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
  126. FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
  127. CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
  128. VARIABLE_PITCH, m_strFontName );
  129. if( NULL==hFont )
  130. return E_FAIL;
  131. SelectObject( hDC, hbmBitmap );
  132. SelectObject( hDC, hFont );
  133. // Set text properties
  134. SetTextColor( hDC, RGB(255,255,255) );
  135. SetBkColor( hDC, 0x00000000 );
  136. SetTextAlign( hDC, TA_TOP );
  137. // Loop through all printable character and output them to the bitmap..
  138. // Meanwhile, keep track of the corresponding tex coords for each character.
  139. DWORD x = 0;
  140. DWORD y = 0;
  141. TCHAR str[2] = _T("x");
  142. SIZE size;
  143. // Calculate the spacing between characters based on line height
  144. GetTextExtentPoint32( hDC, TEXT(" "), 1, &size );
  145. x = m_dwSpacing = (DWORD) ceil(size.cy * 0.3f);
  146. for( TCHAR c=32; c<127; c++ )
  147. {
  148. str[0] = c;
  149. GetTextExtentPoint32( hDC, str, 1, &size );
  150. if( (DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth )
  151. {
  152. x = m_dwSpacing;
  153. y += size.cy+1;
  154. }
  155. ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL );
  156. m_fTexCoords[c-32][0] = ((FLOAT)(x + 0 - m_dwSpacing))/m_dwTexWidth;
  157. m_fTexCoords[c-32][1] = ((FLOAT)(y + 0 + 0 ))/m_dwTexHeight;
  158. m_fTexCoords[c-32][2] = ((FLOAT)(x + size.cx + m_dwSpacing))/m_dwTexWidth;
  159. m_fTexCoords[c-32][3] = ((FLOAT)(y + size.cy + 0 ))/m_dwTexHeight;
  160. x += size.cx + (2 * m_dwSpacing);
  161. }
  162. // Lock the surface and write the alpha values for the set pixels
  163. D3DLOCKED_RECT d3dlr;
  164. m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
  165. BYTE* pDstRow = (BYTE*)d3dlr.pBits;
  166. WORD* pDst16;
  167. BYTE bAlpha; // 4-bit measure of pixel intensity
  168. for( y=0; y < m_dwTexHeight; y++ )
  169. {
  170. pDst16 = (WORD*)pDstRow;
  171. for( x=0; x < m_dwTexWidth; x++ )
  172. {
  173. bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
  174. if (bAlpha > 0)
  175. {
  176. *pDst16++ = (WORD) ((bAlpha << 12) | 0x0fff);
  177. }
  178. else
  179. {
  180. *pDst16++ = 0x0000;
  181. }
  182. }
  183. pDstRow += d3dlr.Pitch;
  184. }
  185. // Done updating texture, so clean up used objects
  186. m_pTexture->UnlockRect(0);
  187. DeleteObject( hbmBitmap );
  188. DeleteDC( hDC );
  189. DeleteObject( hFont );
  190. return S_OK;
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Name: RestoreDeviceObjects()
  194. // Desc:
  195. //-----------------------------------------------------------------------------
  196. HRESULT CD3DFont::RestoreDeviceObjects()
  197. {
  198. HRESULT hr;
  199. // Create vertex buffer for the letters
  200. int vertexSize = max( sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX ) );
  201. if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES * vertexSize,
  202. D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
  203. D3DPOOL_DEFAULT, &m_pVB, NULL ) ) )
  204. {
  205. return hr;
  206. }
  207. // Create the state blocks for rendering text
  208. for( UINT which=0; which<2; which++ )
  209. {
  210. m_pd3dDevice->BeginStateBlock();
  211. m_pd3dDevice->SetTexture( 0, m_pTexture );
  212. if ( D3DFONT_ZENABLE & m_dwFontFlags )
  213. m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  214. else
  215. m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
  216. m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  217. m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  218. m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  219. m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
  220. m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 );
  221. m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
  222. m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
  223. m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
  224. m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE );
  225. m_pd3dDevice->SetRenderState( D3DRS_CLIPPING, TRUE );
  226. m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, FALSE );
  227. m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, D3DVBF_DISABLE );
  228. m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
  229. m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
  230. m_pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE,
  231. D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
  232. D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
  233. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  234. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  235. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  236. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  237. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  238. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  239. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
  240. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
  241. m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
  242. m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  243. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
  244. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
  245. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
  246. if( which==0 )
  247. m_pd3dDevice->EndStateBlock( &m_pStateBlockSaved );
  248. else
  249. m_pd3dDevice->EndStateBlock( &m_pStateBlockDrawText );
  250. }
  251. return S_OK;
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Name: InvalidateDeviceObjects()
  255. // Desc: Destroys all device-dependent objects
  256. //-----------------------------------------------------------------------------
  257. HRESULT CD3DFont::InvalidateDeviceObjects()
  258. {
  259. SAFE_RELEASE( m_pVB );
  260. SAFE_RELEASE( m_pStateBlockSaved );
  261. SAFE_RELEASE( m_pStateBlockDrawText );
  262. return S_OK;
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Name: DeleteDeviceObjects()
  266. // Desc: Destroys all device-dependent objects
  267. //-----------------------------------------------------------------------------
  268. HRESULT CD3DFont::DeleteDeviceObjects()
  269. {
  270. SAFE_RELEASE( m_pTexture );
  271. m_pd3dDevice = NULL;
  272. return S_OK;
  273. }
  274. //-----------------------------------------------------------------------------
  275. // Name: GetTextExtent()
  276. // Desc: Get the dimensions of a text string
  277. //-----------------------------------------------------------------------------
  278. HRESULT CD3DFont::GetTextExtent( const TCHAR* strText, SIZE* pSize )
  279. {
  280. if( NULL==strText || NULL==pSize )
  281. return E_FAIL;
  282. FLOAT fRowWidth = 0.0f;
  283. FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  284. FLOAT fWidth = 0.0f;
  285. FLOAT fHeight = fRowHeight;
  286. while( *strText )
  287. {
  288. TCHAR c = *strText++;
  289. if( c == _T('\n') )
  290. {
  291. fRowWidth = 0.0f;
  292. fHeight += fRowHeight;
  293. }
  294. if( (c-32) < 0 || (c-32) >= 128-32 )
  295. continue;
  296. FLOAT tx1 = m_fTexCoords[c-32][0];
  297. FLOAT tx2 = m_fTexCoords[c-32][2];
  298. fRowWidth += (tx2-tx1)*m_dwTexWidth - 2*m_dwSpacing;
  299. if( fRowWidth > fWidth )
  300. fWidth = fRowWidth;
  301. }
  302. pSize->cx = (int)fWidth;
  303. pSize->cy = (int)fHeight;
  304. return S_OK;
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Name: DrawTextScaled()
  308. // Desc: Draws scaled 2D text. Note that x and y are in viewport coordinates
  309. // (ranging from -1 to +1). fXScale and fYScale are the size fraction
  310. // relative to the entire viewport. For example, a fXScale of 0.25 is
  311. // 1/8th of the screen width. This allows you to output text at a fixed
  312. // fraction of the viewport, even if the screen or window size changes.
  313. //-----------------------------------------------------------------------------
  314. HRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,
  315. FLOAT fXScale, FLOAT fYScale, DWORD dwColor,
  316. const TCHAR* strText, DWORD dwFlags )
  317. {
  318. if( m_pd3dDevice == NULL )
  319. return E_FAIL;
  320. // Set up renderstate
  321. m_pStateBlockSaved->Capture();
  322. m_pStateBlockDrawText->Apply();
  323. m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
  324. m_pd3dDevice->SetPixelShader( NULL );
  325. m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
  326. // Set filter states
  327. if( dwFlags & D3DFONT_FILTERED )
  328. {
  329. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  330. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  331. }
  332. D3DVIEWPORT9 vp;
  333. m_pd3dDevice->GetViewport( &vp );
  334. FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight;
  335. // Center the text block in the viewport
  336. if( dwFlags & D3DFONT_CENTERED_X )
  337. {
  338. const TCHAR* strTextTmp = strText;
  339. float xFinal = 0.0f;
  340. while( *strTextTmp )
  341. {
  342. TCHAR c = *strTextTmp++;
  343. if( c == _T('\n') )
  344. break; // Isn't supported.
  345. if( (c-32) < 0 || (c-32) >= 128-32 )
  346. continue;
  347. FLOAT tx1 = m_fTexCoords[c-32][0];
  348. FLOAT tx2 = m_fTexCoords[c-32][2];
  349. FLOAT w = (tx2-tx1)*m_dwTexWidth;
  350. w *= (fXScale*vp.Height)/fLineHeight;
  351. xFinal += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
  352. }
  353. x = -xFinal/vp.Width;
  354. }
  355. if( dwFlags & D3DFONT_CENTERED_Y )
  356. {
  357. y = -fLineHeight/vp.Height;
  358. }
  359. FLOAT sx = (x+1.0f)*vp.Width/2;
  360. FLOAT sy = (y+1.0f)*vp.Height/2;
  361. FLOAT sz = z;
  362. FLOAT rhw = 1.0f;
  363. // Adjust for character spacing
  364. sx -= m_dwSpacing * (fXScale*vp.Height)/fLineHeight;
  365. FLOAT fStartX = sx;
  366. // Fill vertex buffer
  367. FONT2DVERTEX* pVertices;
  368. DWORD dwNumTriangles = 0L;
  369. m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  370. while( *strText )
  371. {
  372. TCHAR c = *strText++;
  373. if( c == _T('\n') )
  374. {
  375. sx = fStartX;
  376. sy += fYScale*vp.Height;
  377. }
  378. if( (c-32) < 0 || (c-32) >= 128-32 )
  379. continue;
  380. FLOAT tx1 = m_fTexCoords[c-32][0];
  381. FLOAT ty1 = m_fTexCoords[c-32][1];
  382. FLOAT tx2 = m_fTexCoords[c-32][2];
  383. FLOAT ty2 = m_fTexCoords[c-32][3];
  384. FLOAT w = (tx2-tx1)*m_dwTexWidth;
  385. FLOAT h = (ty2-ty1)*m_dwTexHeight;
  386. w *= (fXScale*vp.Height)/fLineHeight;
  387. h *= (fYScale*vp.Height)/fLineHeight;
  388. if( c != _T(' ') )
  389. {
  390. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 );
  391. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
  392. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
  393. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 );
  394. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
  395. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
  396. dwNumTriangles += 2;
  397. if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  398. {
  399. // Unlock, render, and relock the vertex buffer
  400. m_pVB->Unlock();
  401. m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  402. m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  403. dwNumTriangles = 0L;
  404. }
  405. }
  406. sx += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
  407. }
  408. // Unlock and render the vertex buffer
  409. m_pVB->Unlock();
  410. if( dwNumTriangles > 0 )
  411. m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  412. // Restore the modified renderstates
  413. m_pStateBlockSaved->Apply();
  414. return S_OK;
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Name: DrawText()
  418. // Desc: Draws 2D text. Note that sx and sy are in pixels
  419. //-----------------------------------------------------------------------------
  420. HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
  421. const TCHAR* strText, DWORD dwFlags )
  422. {
  423. if( m_pd3dDevice == NULL )
  424. return E_FAIL;
  425. // Setup renderstate
  426. m_pStateBlockSaved->Capture();
  427. m_pStateBlockDrawText->Apply();
  428. m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
  429. m_pd3dDevice->SetPixelShader( NULL );
  430. m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
  431. // Set filter states
  432. if( dwFlags & D3DFONT_FILTERED )
  433. {
  434. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  435. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  436. }
  437. // Center the text block in the viewport
  438. if( dwFlags & D3DFONT_CENTERED_X )
  439. {
  440. D3DVIEWPORT9 vp;
  441. m_pd3dDevice->GetViewport( &vp );
  442. const TCHAR* strTextTmp = strText;
  443. float xFinal = 0.0f;
  444. while( *strTextTmp )
  445. {
  446. TCHAR c = *strTextTmp++;
  447. if( c == _T('\n') )
  448. break; // Isn't supported.
  449. if( (c-32) < 0 || (c-32) >= 128-32 )
  450. continue;
  451. FLOAT tx1 = m_fTexCoords[c-32][0];
  452. FLOAT tx2 = m_fTexCoords[c-32][2];
  453. FLOAT w = (tx2-tx1) * m_dwTexWidth / m_fTextScale;
  454. xFinal += w - (2 * m_dwSpacing);
  455. }
  456. sx = (vp.Width-xFinal)/2.0f;
  457. }
  458. if( dwFlags & D3DFONT_CENTERED_Y )
  459. {
  460. D3DVIEWPORT9 vp;
  461. m_pd3dDevice->GetViewport( &vp );
  462. float fLineHeight = ((m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight);
  463. sy = (vp.Height-fLineHeight)/2;
  464. }
  465. // Adjust for character spacing
  466. sx -= m_dwSpacing;
  467. FLOAT fStartX = sx;
  468. // Fill vertex buffer
  469. FONT2DVERTEX* pVertices = NULL;
  470. DWORD dwNumTriangles = 0;
  471. m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  472. while( *strText )
  473. {
  474. TCHAR c = *strText++;
  475. if( c == _T('\n') )
  476. {
  477. sx = fStartX;
  478. sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  479. }
  480. if( (c-32) < 0 || (c-32) >= 128-32 )
  481. continue;
  482. FLOAT tx1 = m_fTexCoords[c-32][0];
  483. FLOAT ty1 = m_fTexCoords[c-32][1];
  484. FLOAT tx2 = m_fTexCoords[c-32][2];
  485. FLOAT ty2 = m_fTexCoords[c-32][3];
  486. FLOAT w = (tx2-tx1) * m_dwTexWidth / m_fTextScale;
  487. FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
  488. if( c != _T(' ') )
  489. {
  490. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
  491. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
  492. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
  493. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
  494. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
  495. *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
  496. dwNumTriangles += 2;
  497. if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  498. {
  499. // Unlock, render, and relock the vertex buffer
  500. m_pVB->Unlock();
  501. m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  502. pVertices = NULL;
  503. m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  504. dwNumTriangles = 0L;
  505. }
  506. }
  507. sx += w - (2 * m_dwSpacing);
  508. }
  509. // Unlock and render the vertex buffer
  510. m_pVB->Unlock();
  511. if( dwNumTriangles > 0 )
  512. m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  513. // Restore the modified renderstates
  514. m_pStateBlockSaved->Apply();
  515. return S_OK;
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Name: Render3DText()
  519. // Desc: Renders 3D text
  520. //-----------------------------------------------------------------------------
  521. HRESULT CD3DFont::Render3DText( const TCHAR* strText, DWORD dwFlags )
  522. {
  523. if( m_pd3dDevice == NULL )
  524. return E_FAIL;
  525. // Setup renderstate
  526. m_pStateBlockSaved->Capture();
  527. m_pStateBlockDrawText->Apply();
  528. m_pd3dDevice->SetFVF( D3DFVF_FONT3DVERTEX );
  529. m_pd3dDevice->SetPixelShader( NULL );
  530. m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT3DVERTEX) );
  531. // Set filter states
  532. if( dwFlags & D3DFONT_FILTERED )
  533. {
  534. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  535. m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  536. }
  537. // Position for each text element
  538. FLOAT x = 0.0f;
  539. FLOAT y = 0.0f;
  540. // Center the text block at the origin (not the viewport)
  541. if( dwFlags & D3DFONT_CENTERED_X )
  542. {
  543. SIZE sz;
  544. GetTextExtent( strText, &sz );
  545. x = -(((FLOAT)sz.cx)/10.0f)/2.0f;
  546. }
  547. if( dwFlags & D3DFONT_CENTERED_Y )
  548. {
  549. SIZE sz;
  550. GetTextExtent( strText, &sz );
  551. y = -(((FLOAT)sz.cy)/10.0f)/2.0f;
  552. }
  553. // Turn off culling for two-sided text
  554. if( dwFlags & D3DFONT_TWOSIDED )
  555. m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  556. // Adjust for character spacing
  557. x -= m_dwSpacing / 10.0f;
  558. FLOAT fStartX = x;
  559. TCHAR c;
  560. // Fill vertex buffer
  561. FONT3DVERTEX* pVertices;
  562. DWORD dwNumTriangles = 0L;
  563. m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  564. while( (c = *strText++) != 0 )
  565. {
  566. if( c == '\n' )
  567. {
  568. x = fStartX;
  569. y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;
  570. }
  571. if( (c-32) < 0 || (c-32) >= 128-32 )
  572. continue;
  573. FLOAT tx1 = m_fTexCoords[c-32][0];
  574. FLOAT ty1 = m_fTexCoords[c-32][1];
  575. FLOAT tx2 = m_fTexCoords[c-32][2];
  576. FLOAT ty2 = m_fTexCoords[c-32][3];
  577. FLOAT w = (tx2-tx1) * m_dwTexWidth / ( 10.0f * m_fTextScale );
  578. FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );
  579. if( c != _T(' ') )
  580. {
  581. *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 );
  582. *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
  583. *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
  584. *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 );
  585. *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
  586. *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
  587. dwNumTriangles += 2;
  588. if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  589. {
  590. // Unlock, render, and relock the vertex buffer
  591. m_pVB->Unlock();
  592. m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  593. m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  594. dwNumTriangles = 0L;
  595. }
  596. }
  597. x += w - (2 * m_dwSpacing) / 10.0f;
  598. }
  599. // Unlock and render the vertex buffer
  600. m_pVB->Unlock();
  601. if( dwNumTriangles > 0 )
  602. m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  603. // Restore the modified renderstates
  604. m_pStateBlockSaved->Apply();
  605. return S_OK;
  606. }