Source code of Windows XP (NT5)
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.

669 lines
22 KiB

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