d3dfont.cpp
上传用户:fengshi120
上传日期:2014-07-17
资源大小:6155k
文件大小:26k
源码类别:

3D图形编程

开发平台:

C/C++

  1. //-----------------------------------------------------------------------------
  2. // File: D3DFont.cpp
  3. //
  4. // Desc: Texture-based font class
  5. //-----------------------------------------------------------------------------
  6. #define STRICT
  7. #include "stdafx.h"
  8. #include <stdio.h>
  9. #include <tchar.h>
  10. #include <D3DX9.h>
  11. #include "D3DFont.h"
  12. #include "D3DUtil.h"
  13. #include "DXUtil.h"
  14. //-----------------------------------------------------------------------------
  15. // Custom vertex types for rendering text
  16. //-----------------------------------------------------------------------------
  17. #define MAX_NUM_VERTICES 50*6
  18. struct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };
  19. struct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };
  20. #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  21. #define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  22. inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
  23.                                       FLOAT tu, FLOAT tv )
  24. {
  25.     FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;
  26.     return v;
  27. }
  28. inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
  29.                                       FLOAT tu, FLOAT tv )
  30. {
  31.     FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;
  32.     return v;
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Name: CD3DFont()
  36. // Desc: Font class constructor
  37. //-----------------------------------------------------------------------------
  38. CD3DFont::CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )
  39. {
  40.     _tcsncpy( m_strFontName, strFontName, sizeof(m_strFontName) / sizeof(TCHAR) );
  41.     m_strFontName[sizeof(m_strFontName) / sizeof(TCHAR) - 1] = _T('');
  42.     m_dwFontHeight         = dwHeight;
  43.     m_dwFontFlags          = dwFlags;
  44.     m_dwSpacing            = 0;
  45.     m_pd3dDevice           = NULL;
  46.     m_pTexture             = NULL;
  47.     m_pVB                  = NULL;
  48.     m_pStateBlockSaved     = NULL;
  49.     m_pStateBlockDrawText  = NULL;
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Name: ~CD3DFont()
  53. // Desc: Font class destructor
  54. //-----------------------------------------------------------------------------
  55. CD3DFont::~CD3DFont()
  56. {
  57.     InvalidateDeviceObjects();
  58.     DeleteDeviceObjects();
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Name: InitDeviceObjects()
  62. // Desc: Initializes device-dependent objects, including the vertex buffer used
  63. //       for rendering text and the texture map which stores the font image.
  64. //-----------------------------------------------------------------------------
  65. HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
  66. {
  67.     HRESULT hr;
  68.     // Keep a local copy of the device
  69.     m_pd3dDevice = pd3dDevice;
  70.     // Establish the font and texture size
  71.     m_fTextScale  = 1.0f; // Draw fonts into texture without scaling
  72.     // Large fonts need larger textures
  73.     if( m_dwFontHeight > 60 )
  74.         m_dwTexWidth = m_dwTexHeight = 2048;
  75.     else if( m_dwFontHeight > 30 )
  76.         m_dwTexWidth = m_dwTexHeight = 1024;
  77.     else if( m_dwFontHeight > 15 )
  78.         m_dwTexWidth = m_dwTexHeight = 512;
  79.     else
  80.         m_dwTexWidth  = m_dwTexHeight = 256;
  81.     // If requested texture is too big, use a smaller texture and smaller font,
  82.     // and scale up when rendering.
  83.     D3DCAPS9 d3dCaps;
  84.     m_pd3dDevice->GetDeviceCaps( &d3dCaps );
  85.     if( m_dwTexWidth > d3dCaps.MaxTextureWidth )
  86.     {
  87.         m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;
  88.         m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;
  89.     }
  90.     // Create a new texture for the font
  91.     hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
  92.                                       0, D3DFMT_A4R4G4B4,
  93.                                       D3DPOOL_MANAGED, &m_pTexture, NULL );
  94.     if( FAILED(hr) )
  95.         return hr;
  96.     // Prepare to create a bitmap
  97.     DWORD*      pBitmapBits;
  98.     BITMAPINFO bmi;
  99.     ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
  100.     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
  101.     bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
  102.     bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
  103.     bmi.bmiHeader.biPlanes      = 1;
  104.     bmi.bmiHeader.biCompression = BI_RGB;
  105.     bmi.bmiHeader.biBitCount    = 32;
  106.     // Create a DC and a bitmap for the font
  107.     HDC     hDC       = CreateCompatibleDC( NULL );
  108.     HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
  109.                                           (void**)&pBitmapBits, NULL, 0 );
  110.     SetMapMode( hDC, MM_TEXT );
  111.     // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
  112.     // antialiased font, but this is not guaranteed.
  113.     INT nHeight    = -MulDiv( m_dwFontHeight, 
  114.         (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
  115.     DWORD dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
  116.     DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;
  117.     HFONT hFont    = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
  118.                           FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
  119.                           CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
  120.                           VARIABLE_PITCH, m_strFontName );
  121.     if( NULL==hFont )
  122.         return E_FAIL;
  123.     HGDIOBJ hbmOld = SelectObject( hDC, hbmBitmap );
  124.     HGDIOBJ hFontOld = SelectObject( hDC, hFont );
  125.     // Set text properties
  126.     SetTextColor( hDC, RGB(255,255,255) );
  127.     SetBkColor(   hDC, 0x00000000 );
  128.     SetTextAlign( hDC, TA_TOP );
  129.     // Loop through all printable character and output them to the bitmap..
  130.     // Meanwhile, keep track of the corresponding tex coords for each character.
  131.     DWORD x = 0;
  132.     DWORD y = 0;
  133.     TCHAR str[2] = _T("x");
  134.     SIZE size;
  135.     // Calculate the spacing between characters based on line height
  136.     GetTextExtentPoint32( hDC, TEXT(" "), 1, &size );
  137.     x = m_dwSpacing = (DWORD) ceil(size.cy * 0.3f);
  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 + m_dwSpacing) > m_dwTexWidth )
  143.         {
  144.             x  = m_dwSpacing;
  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_dwSpacing))/m_dwTexWidth;
  149.         m_fTexCoords[c-32][1] = ((FLOAT)(y + 0       + 0          ))/m_dwTexHeight;
  150.         m_fTexCoords[c-32][2] = ((FLOAT)(x + size.cx + m_dwSpacing))/m_dwTexWidth;
  151.         m_fTexCoords[c-32][3] = ((FLOAT)(y + size.cy + 0          ))/m_dwTexHeight;
  152.         x += size.cx + (2 * m_dwSpacing);
  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.     BYTE* pDstRow = (BYTE*)d3dlr.pBits;
  158.     WORD* pDst16;
  159.     BYTE bAlpha; // 4-bit measure of pixel intensity
  160.     for( y=0; y < m_dwTexHeight; y++ )
  161.     {
  162.         pDst16 = (WORD*)pDstRow;
  163.         for( x=0; x < m_dwTexWidth; x++ )
  164.         {
  165.             bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
  166.             if (bAlpha > 0)
  167.             {
  168.                 *pDst16++ = (WORD) ((bAlpha << 12) | 0x0fff);
  169.             }
  170.             else
  171.             {
  172.                 *pDst16++ = 0x0000;
  173.             }
  174.         }
  175.         pDstRow += d3dlr.Pitch;
  176.     }
  177.     // Done updating texture, so clean up used objects
  178.     m_pTexture->UnlockRect(0);
  179.     SelectObject( hDC, hbmOld );
  180.     SelectObject( hDC, hFontOld );
  181.     DeleteObject( hbmBitmap );
  182.     DeleteObject( hFont );
  183.     DeleteDC( hDC );
  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.     
  338.             if( c == _T('n') )
  339.                 break;  // Isn't supported.  
  340.             if( (c-32) < 0 || (c-32) >= 128-32 )
  341.                 continue;
  342.             FLOAT tx1 = m_fTexCoords[c-32][0];
  343.             FLOAT tx2 = m_fTexCoords[c-32][2];
  344.             FLOAT w = (tx2-tx1)*m_dwTexWidth;
  345.             w *= (fXScale*vp.Height)/fLineHeight;
  346.             xFinal += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
  347.         }
  348.         x = -xFinal/vp.Width;
  349.     }
  350.     if( dwFlags & D3DFONT_CENTERED_Y )
  351.     {
  352.         y = -fLineHeight/vp.Height;
  353.     }
  354.     FLOAT sx  = (x+1.0f)*vp.Width/2;
  355.     FLOAT sy  = (y+1.0f)*vp.Height/2;
  356.     FLOAT sz  = z;
  357.     FLOAT rhw = 1.0f;
  358.     // Adjust for character spacing
  359.     sx -= m_dwSpacing * (fXScale*vp.Height)/fLineHeight;
  360.     FLOAT fStartX = sx;
  361.     // Fill vertex buffer
  362.     FONT2DVERTEX* pVertices;
  363.     DWORD         dwNumTriangles = 0L;
  364.     m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  365.     while( *strText )
  366.     {
  367.         TCHAR c = *strText++;
  368.         if( c == _T('n') )
  369.         {
  370.             sx  = fStartX;
  371.             sy += fYScale*vp.Height;
  372.         }
  373.         if( (c-32) < 0 || (c-32) >= 128-32 )
  374.             continue;
  375.         FLOAT tx1 = m_fTexCoords[c-32][0];
  376.         FLOAT ty1 = m_fTexCoords[c-32][1];
  377.         FLOAT tx2 = m_fTexCoords[c-32][2];
  378.         FLOAT ty2 = m_fTexCoords[c-32][3];
  379.         FLOAT w = (tx2-tx1)*m_dwTexWidth;
  380.         FLOAT h = (ty2-ty1)*m_dwTexHeight;
  381.         w *= (fXScale*vp.Height)/fLineHeight;
  382.         h *= (fYScale*vp.Height)/fLineHeight;
  383.         if( c != _T(' ') )
  384.         {
  385.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 );
  386.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
  387.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
  388.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 );
  389.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
  390.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
  391.             dwNumTriangles += 2;
  392.             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  393.             {
  394.                 // Unlock, render, and relock the vertex buffer
  395.                 m_pVB->Unlock();
  396.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  397.                 m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  398.                 dwNumTriangles = 0L;
  399.             }
  400.         }
  401.         sx += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
  402.     }
  403.     // Unlock and render the vertex buffer
  404.     m_pVB->Unlock();
  405.     if( dwNumTriangles > 0 )
  406.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  407.     // Restore the modified renderstates
  408.     m_pStateBlockSaved->Apply();
  409.     return S_OK;
  410. }
  411. //-----------------------------------------------------------------------------
  412. // Name: DrawText()
  413. // Desc: Draws 2D text. Note that sx and sy are in pixels
  414. //-----------------------------------------------------------------------------
  415. HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
  416.                             const TCHAR* strText, DWORD dwFlags )
  417. {
  418.     if( m_pd3dDevice == NULL )
  419.         return E_FAIL;
  420.     // Setup renderstate
  421.     m_pStateBlockSaved->Capture();
  422.     m_pStateBlockDrawText->Apply();
  423.     m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
  424.     m_pd3dDevice->SetPixelShader( NULL );
  425.     m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
  426.     // Set filter states
  427.     if( dwFlags & D3DFONT_FILTERED )
  428.     {
  429.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  430.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  431.     }
  432.     // Center the text block in the viewport
  433.     if( dwFlags & D3DFONT_CENTERED_X )
  434.     {
  435.         D3DVIEWPORT9 vp;
  436.         m_pd3dDevice->GetViewport( &vp );
  437.         const TCHAR* strTextTmp = strText;
  438.         float xFinal = 0.0f;
  439.         while( *strTextTmp )
  440.         {
  441.             TCHAR c = *strTextTmp++;
  442.     
  443.             if( c == _T('n') )
  444.                 break;  // Isn't supported.  
  445.             if( (c-32) < 0 || (c-32) >= 128-32 )
  446.                 continue;
  447.             FLOAT tx1 = m_fTexCoords[c-32][0];
  448.             FLOAT tx2 = m_fTexCoords[c-32][2];
  449.     
  450.             FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
  451.     
  452.             xFinal += w - (2 * m_dwSpacing);
  453.         }
  454.         sx = (vp.Width-xFinal)/2.0f;
  455.     }
  456.     if( dwFlags & D3DFONT_CENTERED_Y )
  457.     {
  458.         D3DVIEWPORT9 vp;
  459.         m_pd3dDevice->GetViewport( &vp );
  460.         float fLineHeight = ((m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight);
  461.         sy = (vp.Height-fLineHeight)/2;
  462.     }
  463.     // Adjust for character spacing
  464.     sx -= m_dwSpacing;
  465.     FLOAT fStartX = sx;
  466.     // Fill vertex buffer
  467.     FONT2DVERTEX* pVertices = NULL;
  468.     DWORD         dwNumTriangles = 0;
  469.     m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  470.     while( *strText )
  471.     {
  472.         TCHAR c = *strText++;
  473.         if( c == _T('n') )
  474.         {
  475.             sx = fStartX;
  476.             sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  477.         }
  478.         if( (c-32) < 0 || (c-32) >= 128-32 )
  479.             continue;
  480.         FLOAT tx1 = m_fTexCoords[c-32][0];
  481.         FLOAT ty1 = m_fTexCoords[c-32][1];
  482.         FLOAT tx2 = m_fTexCoords[c-32][2];
  483.         FLOAT ty2 = m_fTexCoords[c-32][3];
  484.         FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
  485.         FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
  486.         if( c != _T(' ') )
  487.         {
  488.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
  489.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
  490.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
  491.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, 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+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
  494.             dwNumTriangles += 2;
  495.             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  496.             {
  497.                 // Unlock, render, and relock the vertex buffer
  498.                 m_pVB->Unlock();
  499.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  500.                 pVertices = NULL;
  501.                 m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  502.                 dwNumTriangles = 0L;
  503.             }
  504.         }
  505.         sx += w - (2 * m_dwSpacing);
  506.     }
  507.     // Unlock and render the vertex buffer
  508.     m_pVB->Unlock();
  509.     if( dwNumTriangles > 0 )
  510.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  511.     // Restore the modified renderstates
  512.     m_pStateBlockSaved->Apply();
  513.     return S_OK;
  514. }
  515. //-----------------------------------------------------------------------------
  516. // Name: Render3DText()
  517. // Desc: Renders 3D text
  518. //-----------------------------------------------------------------------------
  519. HRESULT CD3DFont::Render3DText( const TCHAR* strText, DWORD dwFlags )
  520. {
  521.     if( m_pd3dDevice == NULL )
  522.         return E_FAIL;
  523.     // Setup renderstate
  524.     m_pStateBlockSaved->Capture();
  525.     m_pStateBlockDrawText->Apply();
  526.     m_pd3dDevice->SetFVF( D3DFVF_FONT3DVERTEX );
  527.     m_pd3dDevice->SetPixelShader( NULL );
  528.     m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT3DVERTEX) );
  529.     // Set filter states
  530.     if( dwFlags & D3DFONT_FILTERED )
  531.     {
  532.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  533.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  534.     }
  535.     // Position for each text element
  536.     FLOAT x = 0.0f;
  537.     FLOAT y = 0.0f;
  538.     // Center the text block at the origin (not the viewport)
  539.     if( dwFlags & D3DFONT_CENTERED_X )
  540.     {
  541.         SIZE sz;
  542.         GetTextExtent( strText, &sz );
  543.         x = -(((FLOAT)sz.cx)/10.0f)/2.0f;
  544.     }
  545.     if( dwFlags & D3DFONT_CENTERED_Y )
  546.     {
  547.         SIZE sz;
  548.         GetTextExtent( strText, &sz );
  549.         y = -(((FLOAT)sz.cy)/10.0f)/2.0f;
  550.     }
  551.     // Turn off culling for two-sided text
  552.     if( dwFlags & D3DFONT_TWOSIDED )
  553.         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  554.     // Adjust for character spacing
  555.     x -= m_dwSpacing / 10.0f;
  556.     FLOAT fStartX = x;
  557.     TCHAR c;
  558.     // Fill vertex buffer
  559.     FONT3DVERTEX* pVertices;
  560.     DWORD         dwNumTriangles = 0L;
  561.     m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  562.     while( (c = *strText++) != 0 )
  563.     {
  564.         if( c == 'n' )
  565.         {
  566.             x = fStartX;
  567.             y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;
  568.         }
  569.         if( (c-32) < 0 || (c-32) >= 128-32 )
  570.             continue;
  571.         FLOAT tx1 = m_fTexCoords[c-32][0];
  572.         FLOAT ty1 = m_fTexCoords[c-32][1];
  573.         FLOAT tx2 = m_fTexCoords[c-32][2];
  574.         FLOAT ty2 = m_fTexCoords[c-32][3];
  575.         FLOAT w = (tx2-tx1) * m_dwTexWidth  / ( 10.0f * m_fTextScale );
  576.         FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );
  577.         if( c != _T(' ') )
  578.         {
  579.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 );
  580.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
  581.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
  582.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 );
  583.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
  584.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
  585.             dwNumTriangles += 2;
  586.             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  587.             {
  588.                 // Unlock, render, and relock the vertex buffer
  589.                 m_pVB->Unlock();
  590.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  591.                 m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  592.                 dwNumTriangles = 0L;
  593.             }
  594.         }
  595.         x += w - (2 * m_dwSpacing) / 10.0f;
  596.     }
  597.     // Unlock and render the vertex buffer
  598.     m_pVB->Unlock();
  599.     if( dwNumTriangles > 0 )
  600.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  601.     // Restore the modified renderstates
  602.     m_pStateBlockSaved->Apply();
  603.     return S_OK;
  604. }