home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / common / src / d3dfont.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  22.6 KB  |  655 lines

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