PageRenderTime 97ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/MultiVideo/MultiVMR9/d3dfont.cpp

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