home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / bin / DXUtils / AppWizard / DXAppwiz.awx / TEMPLATE / D3DFONT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-25  |  23.2 KB  |  676 lines

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