d3dfont.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:29k
源码类别:

游戏

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: D3DFont.cpp
  3. //
  4. // Desc: Texture-based font class
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "D3DFont.h"
  10. //-----------------------------------------------------------------------------
  11. // Custom vertex types for rendering text
  12. //-----------------------------------------------------------------------------
  13. #define MAX_NUM_VERTICES 50*6
  14. struct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };
  15. struct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };
  16. #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  17. #define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  18. inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
  19.                                       FLOAT tu, FLOAT tv )
  20. {
  21.     FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;
  22.     return v;
  23. }
  24. inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
  25.                                       FLOAT tu, FLOAT tv )
  26. {
  27.     FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;
  28.     return v;
  29. }
  30. //-----------------------------------------------------------------------------
  31. // Name: CD3DFont()
  32. // Desc: Font class constructor
  33. //-----------------------------------------------------------------------------
  34. CD3DFont::CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )
  35. {
  36.     _tcsncpy( m_strFontName, strFontName, sizeof(m_strFontName) / sizeof(TCHAR) );
  37.     m_strFontName[sizeof(m_strFontName) / sizeof(TCHAR) - 1] = _T('');
  38.     m_dwFontHeight         = dwHeight;
  39.     m_dwFontFlags          = dwFlags;
  40.     m_dwSpacing            = 0;
  41.     m_pd3dDevice           = NULL;
  42.     m_pTexture             = NULL;
  43.     m_pVB                  = NULL;
  44.     m_pStateBlockSaved     = NULL;
  45.     m_pStateBlockDrawText  = NULL;
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Name: ~CD3DFont()
  49. // Desc: Font class destructor
  50. //-----------------------------------------------------------------------------
  51. CD3DFont::~CD3DFont()
  52. {
  53.     InvalidateDeviceObjects();
  54.     DeleteDeviceObjects();
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Name: CreateGDIFont
  58. // Desc: Create a font based on the current state of related member variables
  59. //       and return the handle (or null on error)
  60. //-----------------------------------------------------------------------------
  61. HRESULT CD3DFont::CreateGDIFont( HDC hDC, HFONT* pFont )
  62. {
  63.     // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
  64.     // antialiased font, but this is not guaranteed.
  65.     INT nHeight    = -MulDiv( m_dwFontHeight, 
  66.                               (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 
  67.                               72 );
  68.     DWORD dwBold   = (m_dwFontFlags & D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
  69.     DWORD dwItalic = (m_dwFontFlags & D3DFONT_ITALIC) ? TRUE    : FALSE;
  70.     *pFont         = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
  71.                                  FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
  72.                                  CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
  73.                                  VARIABLE_PITCH, m_strFontName );
  74.     if( *pFont == NULL )
  75.         return E_FAIL;
  76.     return S_OK;
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Name: PaintAlphabet
  80. // Desc: Paint the printable characters for the given GDI font onto the
  81. //       provided device context. If the bMeasureOnly flag is set, no drawing 
  82. //       will occur.
  83. //-----------------------------------------------------------------------------
  84. HRESULT CD3DFont::PaintAlphabet( HDC hDC, BOOL bMeasureOnly )
  85. {
  86.     SIZE size;
  87.     TCHAR str[2] = _T("x"); // One-character, null-terminated string
  88.     
  89.     // Calculate the spacing between characters based on line height
  90.     if( 0 == GetTextExtentPoint32( hDC, str, 1, &size ) )
  91.         return E_FAIL;
  92.     m_dwSpacing = (DWORD) ceil(size.cy * 0.3f);
  93.     // Set the starting point for the drawing
  94.     DWORD x = m_dwSpacing;
  95.     DWORD y = 0;
  96.     
  97.     // For each character, draw text on the DC and advance the current position
  98.     for( char c = 32; c < 127; c++ )
  99.     {
  100.         str[0] = c;
  101.         if( 0 == GetTextExtentPoint32( hDC, str, 1, &size ) )
  102.             return E_FAIL;
  103.         if( (DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth )
  104.         {
  105.             x  = m_dwSpacing;
  106.             y += size.cy + 1;
  107.         }
  108.         // Check to see if there's room to write the character here
  109.         if( y + size.cy > m_dwTexHeight )
  110.             return D3DERR_MOREDATA;
  111.            
  112.         if( !bMeasureOnly )
  113.         {
  114.             // Perform the actual drawing
  115.             if( 0 == ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL ) )
  116.                 return E_FAIL;
  117.             m_fTexCoords[c-32][0] = ((FLOAT)(x + 0       - m_dwSpacing))/m_dwTexWidth;
  118.             m_fTexCoords[c-32][1] = ((FLOAT)(y + 0       + 0          ))/m_dwTexHeight;
  119.             m_fTexCoords[c-32][2] = ((FLOAT)(x + size.cx + m_dwSpacing))/m_dwTexWidth;
  120.             m_fTexCoords[c-32][3] = ((FLOAT)(y + size.cy + 0          ))/m_dwTexHeight;
  121.         }
  122.         x += size.cx + (2 * m_dwSpacing);
  123.     }
  124.     return S_OK;
  125. }
  126. //-----------------------------------------------------------------------------
  127. // Name: InitDeviceObjects()
  128. // Desc: Initializes device-dependent objects, including the vertex buffer used
  129. //       for rendering text and the texture map which stores the font image.
  130. //-----------------------------------------------------------------------------
  131. HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
  132. {
  133.     HRESULT hr = S_OK;
  134.     HFONT hFont = NULL;
  135.     HFONT hFontOld = NULL;
  136.     HDC hDC = NULL;
  137.     HBITMAP hbmBitmap = NULL;
  138.     HGDIOBJ hbmOld = NULL;
  139.     // Keep a local copy of the device
  140.     m_pd3dDevice = pd3dDevice;
  141.     // Assume we will draw fonts into texture without scaling unless the
  142.     // required texture size is found to be larger than the device max
  143.     m_fTextScale  = 1.0f; 
  144.     hDC = CreateCompatibleDC( NULL );
  145.     SetMapMode( hDC, MM_TEXT );
  146.     hr = CreateGDIFont( hDC, &hFont );
  147.     if( FAILED(hr) )
  148.         goto LCleanReturn;
  149.     hFontOld = (HFONT) SelectObject( hDC, hFont );
  150.     // Calculate the dimensions for the smallest power-of-two texture which
  151.     // can hold all the printable characters
  152.     m_dwTexWidth = m_dwTexHeight = 128;
  153.     while( D3DERR_MOREDATA == ( hr = PaintAlphabet( hDC, true ) ) )
  154.     {
  155.         m_dwTexWidth *= 2;
  156.         m_dwTexHeight *= 2;
  157.     }
  158.     if( FAILED(hr) )
  159.         goto LCleanReturn;
  160.     
  161.     // If requested texture is too big, use a smaller texture and smaller font,
  162.     // and scale up when rendering.
  163.     D3DCAPS9 d3dCaps;
  164.     m_pd3dDevice->GetDeviceCaps( &d3dCaps );
  165.     if( m_dwTexWidth > d3dCaps.MaxTextureWidth )
  166.     {
  167.         m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;
  168.         m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;
  169.    
  170.         bool bFirstRun = true; // Flag clear after first run
  171.         do
  172.         {
  173.             // If we've already tried fitting the new text, the scale is still 
  174.             // too large. Reduce and try again.
  175.             if( !bFirstRun)
  176.                 m_fTextScale *= 0.9f;
  177.             // The font has to be scaled to fit on the maximum texture size; our
  178.             // current font is too big and needs to be recreated to scale.
  179.             DeleteObject( SelectObject( hDC, hFontOld ) );
  180.             hr = CreateGDIFont( hDC, &hFont );
  181.             if( FAILED(hr) )
  182.                 goto LCleanReturn;
  183.             hFontOld = (HFONT) SelectObject( hDC, hFont );
  184.             bFirstRun = false;
  185.         } 
  186.         while( D3DERR_MOREDATA == ( hr = PaintAlphabet( hDC, true ) ) );
  187.     }
  188.     
  189.     // Create a new texture for the font
  190.     hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
  191.                                       0, D3DFMT_A4R4G4B4,
  192.                                       D3DPOOL_MANAGED, &m_pTexture, NULL );
  193.     if( FAILED(hr) )
  194.         goto LCleanReturn;
  195.     // Prepare to create a bitmap
  196.     DWORD*      pBitmapBits;
  197.     BITMAPINFO bmi;
  198.     ZeroMemory( &bmi.bmiHeader, sizeof(BITMAPINFOHEADER) );
  199.     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
  200.     bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
  201.     bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
  202.     bmi.bmiHeader.biPlanes      = 1;
  203.     bmi.bmiHeader.biCompression = BI_RGB;
  204.     bmi.bmiHeader.biBitCount    = 32;
  205.     // Create a bitmap for the font
  206.     hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
  207.                                   (void**)&pBitmapBits, NULL, 0 );
  208.     hbmOld = SelectObject( hDC, hbmBitmap );
  209.     
  210.     // Set text properties
  211.     SetTextColor( hDC, RGB(255,255,255) );
  212.     SetBkColor(   hDC, 0x00000000 );
  213.     SetTextAlign( hDC, TA_TOP );
  214.     // Paint the alphabet onto the selected bitmap
  215.     hr = PaintAlphabet( hDC, false );
  216.     if( FAILED(hr) )
  217.         goto LCleanReturn;
  218.     // Lock the surface and write the alpha values for the set pixels
  219.     D3DLOCKED_RECT d3dlr;
  220.     m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
  221.     BYTE* pDstRow;
  222.     pDstRow = (BYTE*)d3dlr.pBits;
  223.     WORD* pDst16;
  224.     BYTE bAlpha; // 4-bit measure of pixel intensity
  225.     DWORD x, y;
  226.     for( y=0; y < m_dwTexHeight; y++ )
  227.     {
  228.         pDst16 = (WORD*)pDstRow;
  229.         for( x=0; x < m_dwTexWidth; x++ )
  230.         {
  231.             bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
  232.             if (bAlpha > 0)
  233.             {
  234.                 *pDst16++ = (WORD) ((bAlpha << 12) | 0x0fff);
  235.             }
  236.             else
  237.             {
  238.                 *pDst16++ = 0x0000;
  239.             }
  240.         }
  241.         pDstRow += d3dlr.Pitch;
  242.     }
  243.     hr = S_OK;
  244.     // Done updating texture, so clean up used objects
  245. LCleanReturn:
  246.     if( m_pTexture )
  247.         m_pTexture->UnlockRect(0);
  248.     SelectObject( hDC, hbmOld );
  249.     SelectObject( hDC, hFontOld );
  250.     DeleteObject( hbmBitmap );
  251.     DeleteObject( hFont );
  252.     DeleteDC( hDC );
  253.     return hr;
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Name: RestoreDeviceObjects()
  257. // Desc:
  258. //-----------------------------------------------------------------------------
  259. HRESULT CD3DFont::RestoreDeviceObjects()
  260. {
  261.     HRESULT hr;
  262.     // Create vertex buffer for the letters
  263.     int vertexSize = max( sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX ) );
  264.     if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES * vertexSize,
  265.                                                        D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
  266.                                                        D3DPOOL_DEFAULT, &m_pVB, NULL ) ) )
  267.     {
  268.         return hr;
  269.     }
  270.     bool bSupportsAlphaBlend = true;
  271.     LPDIRECT3D9 pd3d9 = NULL;
  272.     if( SUCCEEDED( m_pd3dDevice->GetDirect3D( &pd3d9 ) ) )
  273.     {
  274.         D3DCAPS9 Caps;
  275.         D3DDISPLAYMODE Mode;
  276.         LPDIRECT3DSURFACE9 pSurf = NULL;
  277.         D3DSURFACE_DESC Desc;
  278.         m_pd3dDevice->GetDeviceCaps( &Caps );
  279.         m_pd3dDevice->GetDisplayMode( 0, &Mode );
  280.         if( SUCCEEDED( m_pd3dDevice->GetRenderTarget( 0, &pSurf ) ) )
  281.         {
  282.             pSurf->GetDesc( &Desc );
  283.             if( FAILED( pd3d9->CheckDeviceFormat( Caps.AdapterOrdinal, Caps.DeviceType, Mode.Format,
  284.                 D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_SURFACE, 
  285.                 Desc.Format ) ) )
  286.             {
  287.                 bSupportsAlphaBlend = false;
  288.             }
  289.             SAFE_RELEASE( pSurf );
  290.         }
  291.         SAFE_RELEASE( pd3d9 );
  292.     }
  293.     // Create the state blocks for rendering text
  294.     for( UINT which=0; which<2; which++ )
  295.     {
  296.         m_pd3dDevice->BeginStateBlock();
  297.         m_pd3dDevice->SetTexture( 0, m_pTexture );
  298.         if ( D3DFONT_ZENABLE & m_dwFontFlags )
  299.             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  300.         else
  301.             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
  302.         if( bSupportsAlphaBlend )
  303.         {
  304.             m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  305.             m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,   D3DBLEND_SRCALPHA );
  306.             m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
  307.         }
  308.         else
  309.         {
  310.             m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  311.         }
  312.         m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
  313.         m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
  314.         m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );
  315.         m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID );
  316.         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CCW );
  317.         m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
  318.         m_pd3dDevice->SetRenderState( D3DRS_CLIPPING,         TRUE );
  319.         m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  FALSE );
  320.         m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND,      D3DVBF_DISABLE );
  321.         m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
  322.         m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );
  323.         m_pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE,
  324.             D3DCOLORWRITEENABLE_RED  | D3DCOLORWRITEENABLE_GREEN |
  325.             D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
  326.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  327.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  328.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  329.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
  330.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  331.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  332.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
  333.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
  334.         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  335.         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
  336.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
  337.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
  338.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
  339.         if( which==0 )
  340.             m_pd3dDevice->EndStateBlock( &m_pStateBlockSaved );
  341.         else
  342.             m_pd3dDevice->EndStateBlock( &m_pStateBlockDrawText );
  343.     }
  344.     return S_OK;
  345. }
  346. //-----------------------------------------------------------------------------
  347. // Name: InvalidateDeviceObjects()
  348. // Desc: Destroys all device-dependent objects
  349. //-----------------------------------------------------------------------------
  350. HRESULT CD3DFont::InvalidateDeviceObjects()
  351. {
  352.     SAFE_RELEASE( m_pVB );
  353.     SAFE_RELEASE( m_pStateBlockSaved );
  354.     SAFE_RELEASE( m_pStateBlockDrawText );
  355.     return S_OK;
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Name: DeleteDeviceObjects()
  359. // Desc: Destroys all device-dependent objects
  360. //-----------------------------------------------------------------------------
  361. HRESULT CD3DFont::DeleteDeviceObjects()
  362. {
  363.     SAFE_RELEASE( m_pTexture );
  364.     m_pd3dDevice = NULL;
  365.     return S_OK;
  366. }
  367. //-----------------------------------------------------------------------------
  368. // Name: GetTextExtent()
  369. // Desc: Get the dimensions of a text string
  370. //-----------------------------------------------------------------------------
  371. HRESULT CD3DFont::GetTextExtent( const TCHAR* strText, SIZE* pSize )
  372. {
  373.     if( NULL==strText || NULL==pSize )
  374.         return E_FAIL;
  375.     FLOAT fRowWidth  = 0.0f;
  376.     FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  377.     FLOAT fWidth     = 0.0f;
  378.     FLOAT fHeight    = fRowHeight;
  379.     while( *strText )
  380.     {
  381.         TCHAR c = *strText++;
  382.         if( c == _T('n') )
  383.         {
  384.             fRowWidth = 0.0f;
  385.             fHeight  += fRowHeight;
  386.         }
  387.         if( (c-32) < 0 || (c-32) >= 128-32 )
  388.             continue;
  389.         FLOAT tx1 = m_fTexCoords[c-32][0];
  390.         FLOAT tx2 = m_fTexCoords[c-32][2];
  391.         fRowWidth += (tx2-tx1)*m_dwTexWidth - 2*m_dwSpacing;
  392.         if( fRowWidth > fWidth )
  393.             fWidth = fRowWidth;
  394.     }
  395.     pSize->cx = (int)fWidth;
  396.     pSize->cy = (int)fHeight;
  397.     return S_OK;
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Name: DrawTextScaled()
  401. // Desc: Draws scaled 2D text.  Note that x and y are in viewport coordinates
  402. //       (ranging from -1 to +1).  fXScale and fYScale are the size fraction 
  403. //       relative to the entire viewport.  For example, a fXScale of 0.25 is
  404. //       1/8th of the screen width.  This allows you to output text at a fixed
  405. //       fraction of the viewport, even if the screen or window size changes.
  406. //-----------------------------------------------------------------------------
  407. HRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,
  408.                                   FLOAT fXScale, FLOAT fYScale, DWORD dwColor,
  409.                                   const TCHAR* strText, DWORD dwFlags )
  410. {
  411.     if( m_pd3dDevice == NULL )
  412.         return E_FAIL;
  413.     // Set up renderstate
  414.     m_pStateBlockSaved->Capture();
  415.     m_pStateBlockDrawText->Apply();
  416.     m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
  417.     m_pd3dDevice->SetPixelShader( NULL );
  418.     m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
  419.     // Set filter states
  420.     if( dwFlags & D3DFONT_FILTERED )
  421.     {
  422.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  423.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  424.     }
  425.     D3DVIEWPORT9 vp;
  426.     m_pd3dDevice->GetViewport( &vp );
  427.     FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight;
  428.     // Center the text block in the viewport
  429.     if( dwFlags & D3DFONT_CENTERED_X )
  430.     {
  431.         const TCHAR* strTextTmp = strText;
  432.         float xFinal = 0.0f;
  433.         while( *strTextTmp )
  434.         {
  435.             TCHAR c = *strTextTmp++;
  436.     
  437.             if( c == _T('n') )
  438.                 break;  // Isn't supported.  
  439.             if( (c-32) < 0 || (c-32) >= 128-32 )
  440.                 continue;
  441.             FLOAT tx1 = m_fTexCoords[c-32][0];
  442.             FLOAT tx2 = m_fTexCoords[c-32][2];
  443.             FLOAT w = (tx2-tx1)*m_dwTexWidth;
  444.             w *= (fXScale*vp.Height)/fLineHeight;
  445.             xFinal += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
  446.         }
  447.         x = -xFinal/vp.Width;
  448.     }
  449.     if( dwFlags & D3DFONT_CENTERED_Y )
  450.     {
  451.         y = -fLineHeight/vp.Height;
  452.     }
  453.     FLOAT sx  = (x+1.0f)*vp.Width/2;
  454.     FLOAT sy  = (y+1.0f)*vp.Height/2;
  455.     FLOAT sz  = z;
  456.     FLOAT rhw = 1.0f;
  457.     // Adjust for character spacing
  458.     sx -= m_dwSpacing * (fXScale*vp.Height)/fLineHeight;
  459.     FLOAT fStartX = sx;
  460.     // Fill vertex buffer
  461.     FONT2DVERTEX* pVertices;
  462.     DWORD         dwNumTriangles = 0L;
  463.     m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  464.     while( *strText )
  465.     {
  466.         TCHAR c = *strText++;
  467.         if( c == _T('n') )
  468.         {
  469.             sx  = fStartX;
  470.             sy += fYScale*vp.Height;
  471.         }
  472.         if( (c-32) < 0 || (c-32) >= 128-32 )
  473.             continue;
  474.         FLOAT tx1 = m_fTexCoords[c-32][0];
  475.         FLOAT ty1 = m_fTexCoords[c-32][1];
  476.         FLOAT tx2 = m_fTexCoords[c-32][2];
  477.         FLOAT ty2 = m_fTexCoords[c-32][3];
  478.         FLOAT w = (tx2-tx1)*m_dwTexWidth;
  479.         FLOAT h = (ty2-ty1)*m_dwTexHeight;
  480.         w *= (fXScale*vp.Height)/fLineHeight;
  481.         h *= (fYScale*vp.Height)/fLineHeight;
  482.         if( c != _T(' ') )
  483.         {
  484.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 );
  485.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
  486.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
  487.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 );
  488.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
  489.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), 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.                 m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  497.                 dwNumTriangles = 0L;
  498.             }
  499.         }
  500.         sx += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
  501.     }
  502.     // Unlock and render the vertex buffer
  503.     m_pVB->Unlock();
  504.     if( dwNumTriangles > 0 )
  505.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  506.     // Restore the modified renderstates
  507.     m_pStateBlockSaved->Apply();
  508.     return S_OK;
  509. }
  510. //-----------------------------------------------------------------------------
  511. // Name: DrawText()
  512. // Desc: Draws 2D text. Note that sx and sy are in pixels
  513. //-----------------------------------------------------------------------------
  514. HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
  515.                             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_FONT2DVERTEX );
  523.     m_pd3dDevice->SetPixelShader( NULL );
  524.     m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
  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.     // Center the text block in the viewport
  532.     if( dwFlags & D3DFONT_CENTERED_X )
  533.     {
  534.         D3DVIEWPORT9 vp;
  535.         m_pd3dDevice->GetViewport( &vp );
  536.         const TCHAR* strTextTmp = strText;
  537.         float xFinal = 0.0f;
  538.         while( *strTextTmp )
  539.         {
  540.             TCHAR c = *strTextTmp++;
  541.     
  542.             if( c == _T('n') )
  543.                 break;  // Isn't supported.  
  544.             if( (c-32) < 0 || (c-32) >= 128-32 )
  545.                 continue;
  546.             FLOAT tx1 = m_fTexCoords[c-32][0];
  547.             FLOAT tx2 = m_fTexCoords[c-32][2];
  548.     
  549.             FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
  550.     
  551.             xFinal += w - (2 * m_dwSpacing);
  552.         }
  553.         sx = (vp.Width-xFinal)/2.0f;
  554.     }
  555.     if( dwFlags & D3DFONT_CENTERED_Y )
  556.     {
  557.         D3DVIEWPORT9 vp;
  558.         m_pd3dDevice->GetViewport( &vp );
  559.         float fLineHeight = ((m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight);
  560.         sy = (vp.Height-fLineHeight)/2;
  561.     }
  562.     // Adjust for character spacing
  563.     sx -= m_dwSpacing;
  564.     FLOAT fStartX = sx;
  565.     // Fill vertex buffer
  566.     FONT2DVERTEX* pVertices = NULL;
  567.     DWORD         dwNumTriangles = 0;
  568.     m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  569.     while( *strText )
  570.     {
  571.         TCHAR c = *strText++;
  572.         if( c == _T('n') )
  573.         {
  574.             sx = fStartX;
  575.             sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  576.         }
  577.         if( (c-32) < 0 || (c-32) >= 128-32 )
  578.             continue;
  579.         FLOAT tx1 = m_fTexCoords[c-32][0];
  580.         FLOAT ty1 = m_fTexCoords[c-32][1];
  581.         FLOAT tx2 = m_fTexCoords[c-32][2];
  582.         FLOAT ty2 = m_fTexCoords[c-32][3];
  583.         FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
  584.         FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
  585.         if( c != _T(' ') )
  586.         {
  587.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
  588.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
  589.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
  590.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
  591.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
  592.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
  593.             dwNumTriangles += 2;
  594.             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  595.             {
  596.                 // Unlock, render, and relock the vertex buffer
  597.                 m_pVB->Unlock();
  598.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  599.                 pVertices = NULL;
  600.                 m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  601.                 dwNumTriangles = 0L;
  602.             }
  603.         }
  604.         sx += w - (2 * m_dwSpacing);
  605.     }
  606.     // Unlock and render the vertex buffer
  607.     m_pVB->Unlock();
  608.     if( dwNumTriangles > 0 )
  609.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  610.     // Restore the modified renderstates
  611.     m_pStateBlockSaved->Apply();
  612.     return S_OK;
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Name: Render3DText()
  616. // Desc: Renders 3D text
  617. //-----------------------------------------------------------------------------
  618. HRESULT CD3DFont::Render3DText( const TCHAR* strText, DWORD dwFlags )
  619. {
  620.     if( m_pd3dDevice == NULL )
  621.         return E_FAIL;
  622.     // Setup renderstate
  623.     m_pStateBlockSaved->Capture();
  624.     m_pStateBlockDrawText->Apply();
  625.     m_pd3dDevice->SetFVF( D3DFVF_FONT3DVERTEX );
  626.     m_pd3dDevice->SetPixelShader( NULL );
  627.     m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT3DVERTEX) );
  628.     // Set filter states
  629.     if( dwFlags & D3DFONT_FILTERED )
  630.     {
  631.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  632.         m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  633.     }
  634.     // Position for each text element
  635.     FLOAT x = 0.0f;
  636.     FLOAT y = 0.0f;
  637.     // Center the text block at the origin (not the viewport)
  638.     if( dwFlags & D3DFONT_CENTERED_X )
  639.     {
  640.         SIZE sz;
  641.         GetTextExtent( strText, &sz );
  642.         x = -(((FLOAT)sz.cx)/10.0f)/2.0f;
  643.     }
  644.     if( dwFlags & D3DFONT_CENTERED_Y )
  645.     {
  646.         SIZE sz;
  647.         GetTextExtent( strText, &sz );
  648.         y = -(((FLOAT)sz.cy)/10.0f)/2.0f;
  649.     }
  650.     // Turn off culling for two-sided text
  651.     if( dwFlags & D3DFONT_TWOSIDED )
  652.         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  653.     // Adjust for character spacing
  654.     x -= m_dwSpacing / 10.0f;
  655.     FLOAT fStartX = x;
  656.     TCHAR c;
  657.     // Fill vertex buffer
  658.     FONT3DVERTEX* pVertices;
  659.     DWORD         dwNumTriangles = 0L;
  660.     m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  661.     while( (c = *strText++) != 0 )
  662.     {
  663.         if( c == 'n' )
  664.         {
  665.             x = fStartX;
  666.             y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;
  667.         }
  668.         if( (c-32) < 0 || (c-32) >= 128-32 )
  669.             continue;
  670.         FLOAT tx1 = m_fTexCoords[c-32][0];
  671.         FLOAT ty1 = m_fTexCoords[c-32][1];
  672.         FLOAT tx2 = m_fTexCoords[c-32][2];
  673.         FLOAT ty2 = m_fTexCoords[c-32][3];
  674.         FLOAT w = (tx2-tx1) * m_dwTexWidth  / ( 10.0f * m_fTextScale );
  675.         FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );
  676.         if( c != _T(' ') )
  677.         {
  678.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 );
  679.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
  680.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
  681.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 );
  682.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
  683.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
  684.             dwNumTriangles += 2;
  685.             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  686.             {
  687.                 // Unlock, render, and relock the vertex buffer
  688.                 m_pVB->Unlock();
  689.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  690.                 m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  691.                 dwNumTriangles = 0L;
  692.             }
  693.         }
  694.         x += w - (2 * m_dwSpacing) / 10.0f;
  695.     }
  696.     // Unlock and render the vertex buffer
  697.     m_pVB->Unlock();
  698.     if( dwNumTriangles > 0 )
  699.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  700.     // Restore the modified renderstates
  701.     m_pStateBlockSaved->Apply();
  702.     return S_OK;
  703. }