topical media & game development

talk show tell print

hush-src-multi-GamePlayer-d3dfont.cpp / cpp



  //-----------------------------------------------------------------------------
  // File: D3DFont.cpp
  //
  // Desc: Texture-based font class
  //
  // Copyright (c) Microsoft Corporation. All rights reserved.
  //-----------------------------------------------------------------------------
  
  define STRICT
  include <stdafx.h>
  include <stdio.h>
  include <tchar.h>
  include <D3DX9.h>
  include <D3DFont.h>
  include <D3DUtil.h>
  include <DXUtil.h>
  
  //-----------------------------------------------------------------------------
  // Custom vertex types for rendering text
  //-----------------------------------------------------------------------------
  define MAX_NUM_VERTICES 50*6
  
  struct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };
  struct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };
  
  define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  
  inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
                                        FLOAT tu, FLOAT tv )
  {
      FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;
      return v;
  }
  
  inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
                                        FLOAT tu, FLOAT tv )
  {
      FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;
      return v;
  }
  
  //-----------------------------------------------------------------------------
  // Name: CD3DFont()
  // Desc: Font class constructor
  //-----------------------------------------------------------------------------
  CD3DFont::CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )
  {
      _tcsncpy( m_strFontName, strFontName, sizeof(m_strFontName) / sizeof(TCHAR) );
      m_strFontName[sizeof(m_strFontName) / sizeof(TCHAR) - 1] = _T('\0');
  
      m_dwFontHeight         = dwHeight;
      m_dwFontFlags          = dwFlags;
      m_dwSpacing            = 0;
  
      m_pd3dDevice           = NULL;
      m_pTexture             = NULL;
      m_pVB                  = NULL;
  
      m_pStateBlockSaved     = NULL;
      m_pStateBlockDrawText  = NULL;
  }
  
  //-----------------------------------------------------------------------------
  // Name: ~CD3DFont()
  // Desc: Font class destructor
  //-----------------------------------------------------------------------------
  CD3DFont::~CD3DFont()
  {
      InvalidateDeviceObjects();
      DeleteDeviceObjects();
  }
  
  //-----------------------------------------------------------------------------
  // Name: InitDeviceObjects()
  // Desc: Initializes device-dependent objects, including the vertex buffer used
  //       for rendering text and the texture map which stores the font image.
  //-----------------------------------------------------------------------------
  HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
  {
      HRESULT hr;
  
      // Keep a local copy of the device
      m_pd3dDevice = pd3dDevice;
  
      // Establish the font and texture size
      m_fTextScale  = 1.0f; // Draw fonts into texture without scaling
  
      // Large fonts need larger textures
      if( m_dwFontHeight > 60 )
          m_dwTexWidth = m_dwTexHeight = 2048;
      else if( m_dwFontHeight > 30 )
          m_dwTexWidth = m_dwTexHeight = 1024;
      else if( m_dwFontHeight > 15 )
          m_dwTexWidth = m_dwTexHeight = 512;
      else
          m_dwTexWidth  = m_dwTexHeight = 256;
  
      // If requested texture is too big, use a smaller texture and smaller font,
      // and scale up when rendering.
      D3DCAPS9 d3dCaps;
      m_pd3dDevice->GetDeviceCaps( &d3dCaps );
  
      if( m_dwTexWidth > d3dCaps.MaxTextureWidth )
      {
          m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;
          m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;
      }
  
      // Create a new texture for the font
      hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
                                        0, D3DFMT_A4R4G4B4,
                                        D3DPOOL_MANAGED, &m_pTexture, NULL );
      if( FAILED(hr) )
          return hr;
  
      // Prepare to create a bitmap
      DWORD*      pBitmapBits;
      BITMAPINFO bmi;
  
      ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
      bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
      bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
      bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
      bmi.bmiHeader.biPlanes      = 1;
      bmi.bmiHeader.biCompression = BI_RGB;
      bmi.bmiHeader.biBitCount    = 32;
  
      // Create a DC and a bitmap for the font
      HDC     hDC       = CreateCompatibleDC( NULL );
      HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
                                            (void**)&pBitmapBits, NULL, 0 );
      SetMapMode( hDC, MM_TEXT );
  
      // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
      // antialiased font, but this is not guaranteed.
      INT nHeight    = -MulDiv( m_dwFontHeight, 
          (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
  
      DWORD dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
      DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;
      HFONT hFont    = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
                            FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
                            CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
                            VARIABLE_PITCH, m_strFontName );
      if( NULL==hFont )
          return E_FAIL;
  
      SelectObject( hDC, hbmBitmap );
      SelectObject( hDC, hFont );
  
      // Set text properties
      SetTextColor( hDC, RGB(255,255,255) );
      SetBkColor(   hDC, 0x00000000 );
      SetTextAlign( hDC, TA_TOP );
  
      // Loop through all printable character and output them to the bitmap..
      // Meanwhile, keep track of the corresponding tex coords for each character.
      DWORD x = 0;
      DWORD y = 0;
      TCHAR str[2] = _T("x");
      SIZE size;
  
      // Calculate the spacing between characters based on line height
      GetTextExtentPoint32( hDC, TEXT(" "), 1, &size );
      x = m_dwSpacing = (DWORD) ceil(size.cy * 0.3f);
  
      for( TCHAR c=32; c<127; c++ )
      {
          str[0] = c;
          GetTextExtentPoint32( hDC, str, 1, &size );
  
          if( (DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth )
          {
              x  = m_dwSpacing;
              y += size.cy+1;
          }
  
          ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL );
  
          m_fTexCoords[c-32][0] = ((FLOAT)(x + 0       - m_dwSpacing))/m_dwTexWidth;
          m_fTexCoords[c-32][1] = ((FLOAT)(y + 0       + 0          ))/m_dwTexHeight;
          m_fTexCoords[c-32][2] = ((FLOAT)(x + size.cx + m_dwSpacing))/m_dwTexWidth;
          m_fTexCoords[c-32][3] = ((FLOAT)(y + size.cy + 0          ))/m_dwTexHeight;
  
          x += size.cx + (2 * m_dwSpacing);
      }
  
      // Lock the surface and write the alpha values for the set pixels
      D3DLOCKED_RECT d3dlr;
      m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
      BYTE* pDstRow = (BYTE*)d3dlr.pBits;
      WORD* pDst16;
      BYTE bAlpha; // 4-bit measure of pixel intensity
  
      for( y=0; y < m_dwTexHeight; y++ )
      {
          pDst16 = (WORD*)pDstRow;
          for( x=0; x < m_dwTexWidth; x++ )
          {
              bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
              if (bAlpha > 0)
              {
                  *pDst16++ = (WORD) ((bAlpha << 12) | 0x0fff);
              }
              else
              {
                  *pDst16++ = 0x0000;
              }
          }
          pDstRow += d3dlr.Pitch;
      }
  
      // Done updating texture, so clean up used objects
      m_pTexture->UnlockRect(0);
      DeleteObject( hbmBitmap );
      DeleteDC( hDC );
      DeleteObject( hFont );
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: RestoreDeviceObjects()
  // Desc:
  //-----------------------------------------------------------------------------
  HRESULT CD3DFont::RestoreDeviceObjects()
  {
      HRESULT hr;
  
      // Create vertex buffer for the letters
      int vertexSize = max( sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX ) );
      if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES * vertexSize,
                                                         D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
                                                         D3DPOOL_DEFAULT, &m_pVB, NULL ) ) )
      {
          return hr;
      }
  
      // Create the state blocks for rendering text
      for( UINT which=0; which<2; which++ )
      {
          m_pd3dDevice->BeginStateBlock();
          m_pd3dDevice->SetTexture( 0, m_pTexture );
  
          if ( D3DFONT_ZENABLE & m_dwFontFlags )
              m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
          else
              m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
  
          m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
          m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,   D3DBLEND_SRCALPHA );
          m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
          m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
          m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
          m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );
          m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID );
          m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CCW );
          m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
          m_pd3dDevice->SetRenderState( D3DRS_CLIPPING,         TRUE );
          m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  FALSE );
          m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND,      D3DVBF_DISABLE );
          m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
          m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );
          m_pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE,
              D3DCOLORWRITEENABLE_RED  | D3DCOLORWRITEENABLE_GREEN |
              D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
          m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
          m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
          m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
          m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
          m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
          m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
          m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
          m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
          m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
          m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
  
          if( which==0 )
              m_pd3dDevice->EndStateBlock( &m_pStateBlockSaved );
          else
              m_pd3dDevice->EndStateBlock( &m_pStateBlockDrawText );
      }
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: InvalidateDeviceObjects()
  // Desc: Destroys all device-dependent objects
  //-----------------------------------------------------------------------------
  HRESULT CD3DFont::InvalidateDeviceObjects()
  {
      SAFE_RELEASE( m_pVB );
      SAFE_RELEASE( m_pStateBlockSaved );
      SAFE_RELEASE( m_pStateBlockDrawText );
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DeleteDeviceObjects()
  // Desc: Destroys all device-dependent objects
  //-----------------------------------------------------------------------------
  HRESULT CD3DFont::DeleteDeviceObjects()
  {
      SAFE_RELEASE( m_pTexture );
      m_pd3dDevice = NULL;
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: GetTextExtent()
  // Desc: Get the dimensions of a text string
  //-----------------------------------------------------------------------------
  HRESULT CD3DFont::GetTextExtent( const TCHAR* strText, SIZE* pSize )
  {
      if( NULL==strText || NULL==pSize )
          return E_FAIL;
  
      FLOAT fRowWidth  = 0.0f;
      FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
      FLOAT fWidth     = 0.0f;
      FLOAT fHeight    = fRowHeight;
  
      while( *strText )
      {
          TCHAR c = *strText++;
  
          if( c == _T('\n') )
          {
              fRowWidth = 0.0f;
              fHeight  += fRowHeight;
          }
  
          if( (c-32) < 0 || (c-32) >= 128-32 )
              continue;
  
          FLOAT tx1 = m_fTexCoords[c-32][0];
          FLOAT tx2 = m_fTexCoords[c-32][2];
  
          fRowWidth += (tx2-tx1)*m_dwTexWidth - 2*m_dwSpacing;
  
          if( fRowWidth > fWidth )
              fWidth = fRowWidth;
      }
  
      pSize->cx = (int)fWidth;
      pSize->cy = (int)fHeight;
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DrawTextScaled()
  // Desc: Draws scaled 2D text.  Note that x and y are in viewport coordinates
  //       (ranging from -1 to +1).  fXScale and fYScale are the size fraction 
  //       relative to the entire viewport.  For example, a fXScale of 0.25 is
  //       1/8th of the screen width.  This allows you to output text at a fixed
  //       fraction of the viewport, even if the screen or window size changes.
  //-----------------------------------------------------------------------------
  HRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,
                                    FLOAT fXScale, FLOAT fYScale, DWORD dwColor,
                                    const TCHAR* strText, DWORD dwFlags )
  {
      if( m_pd3dDevice == NULL )
          return E_FAIL;
  
      // Set up renderstate
      m_pStateBlockSaved->Capture();
      m_pStateBlockDrawText->Apply();
      m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
      m_pd3dDevice->SetPixelShader( NULL );
      m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
  
      // Set filter states
      if( dwFlags & D3DFONT_FILTERED )
      {
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
      }
  
      D3DVIEWPORT9 vp;
      m_pd3dDevice->GetViewport( &vp );
      FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight;
  
      // Center the text block in the viewport
      if( dwFlags & D3DFONT_CENTERED_X )
      {
          const TCHAR* strTextTmp = strText;
          float xFinal = 0.0f;
  
          while( *strTextTmp )
          {
              TCHAR c = *strTextTmp++;
      
              if( c == _T('\n') )
                  break;  // Isn't supported.  
              if( (c-32) < 0 || (c-32) >= 128-32 )
                  continue;
  
              FLOAT tx1 = m_fTexCoords[c-32][0];
              FLOAT tx2 = m_fTexCoords[c-32][2];
  
              FLOAT w = (tx2-tx1)*m_dwTexWidth;
  
              w *= (fXScale*vp.Height)/fLineHeight;
  
              xFinal += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
          }
  
          x = -xFinal/vp.Width;
      }
      if( dwFlags & D3DFONT_CENTERED_Y )
      {
          y = -fLineHeight/vp.Height;
      }
  
      FLOAT sx  = (x+1.0f)*vp.Width/2;
      FLOAT sy  = (y+1.0f)*vp.Height/2;
      FLOAT sz  = z;
      FLOAT rhw = 1.0f;
  
      // Adjust for character spacing
      sx -= m_dwSpacing * (fXScale*vp.Height)/fLineHeight;
      FLOAT fStartX = sx;
  
      // Fill vertex buffer
      FONT2DVERTEX* pVertices;
      DWORD         dwNumTriangles = 0L;
      m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  
      while( *strText )
      {
          TCHAR c = *strText++;
  
          if( c == _T('\n') )
          {
              sx  = fStartX;
              sy += fYScale*vp.Height;
          }
  
          if( (c-32) < 0 || (c-32) >= 128-32 )
              continue;
  
          FLOAT tx1 = m_fTexCoords[c-32][0];
          FLOAT ty1 = m_fTexCoords[c-32][1];
          FLOAT tx2 = m_fTexCoords[c-32][2];
          FLOAT ty2 = m_fTexCoords[c-32][3];
  
          FLOAT w = (tx2-tx1)*m_dwTexWidth;
          FLOAT h = (ty2-ty1)*m_dwTexHeight;
  
          w *= (fXScale*vp.Height)/fLineHeight;
          h *= (fYScale*vp.Height)/fLineHeight;
  
          if( c != _T(' ') )
          {
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
              dwNumTriangles += 2;
  
              if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
              {
                  // Unlock, render, and relock the vertex buffer
                  m_pVB->Unlock();
                  m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
                  m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
                  dwNumTriangles = 0L;
              }
          }
  
          sx += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
      }
  
      // Unlock and render the vertex buffer
      m_pVB->Unlock();
      if( dwNumTriangles > 0 )
          m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  
      // Restore the modified renderstates
      m_pStateBlockSaved->Apply();
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DrawText()
  // Desc: Draws 2D text. Note that sx and sy are in pixels
  //-----------------------------------------------------------------------------
  HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
                              const TCHAR* strText, DWORD dwFlags )
  {
      if( m_pd3dDevice == NULL )
          return E_FAIL;
  
      // Setup renderstate
      m_pStateBlockSaved->Capture();
      m_pStateBlockDrawText->Apply();
      m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
      m_pd3dDevice->SetPixelShader( NULL );
      m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
  
      // Set filter states
      if( dwFlags & D3DFONT_FILTERED )
      {
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
      }
  
      // Center the text block in the viewport
      if( dwFlags & D3DFONT_CENTERED_X )
      {
          D3DVIEWPORT9 vp;
          m_pd3dDevice->GetViewport( &vp );
          const TCHAR* strTextTmp = strText;
          float xFinal = 0.0f;
  
          while( *strTextTmp )
          {
              TCHAR c = *strTextTmp++;
      
              if( c == _T('\n') )
                  break;  // Isn't supported.  
              if( (c-32) < 0 || (c-32) >= 128-32 )
                  continue;
  
              FLOAT tx1 = m_fTexCoords[c-32][0];
              FLOAT tx2 = m_fTexCoords[c-32][2];
      
              FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
      
              xFinal += w - (2 * m_dwSpacing);
          }
  
          sx = (vp.Width-xFinal)/2.0f;
      }
      if( dwFlags & D3DFONT_CENTERED_Y )
      {
          D3DVIEWPORT9 vp;
          m_pd3dDevice->GetViewport( &vp );
          float fLineHeight = ((m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight);
          sy = (vp.Height-fLineHeight)/2;
      }
  
      // Adjust for character spacing
      sx -= m_dwSpacing;
      FLOAT fStartX = sx;
  
      // Fill vertex buffer
      FONT2DVERTEX* pVertices = NULL;
      DWORD         dwNumTriangles = 0;
      m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  
      while( *strText )
      {
          TCHAR c = *strText++;
  
          if( c == _T('\n') )
          {
              sx = fStartX;
              sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
          }
  
          if( (c-32) < 0 || (c-32) >= 128-32 )
              continue;
  
          FLOAT tx1 = m_fTexCoords[c-32][0];
          FLOAT ty1 = m_fTexCoords[c-32][1];
          FLOAT tx2 = m_fTexCoords[c-32][2];
          FLOAT ty2 = m_fTexCoords[c-32][3];
  
          FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
          FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
  
          if( c != _T(' ') )
          {
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
              *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
              dwNumTriangles += 2;
  
              if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
              {
                  // Unlock, render, and relock the vertex buffer
                  m_pVB->Unlock();
                  m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
                  pVertices = NULL;
                  m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
                  dwNumTriangles = 0L;
              }
          }
  
          sx += w - (2 * m_dwSpacing);
      }
  
      // Unlock and render the vertex buffer
      m_pVB->Unlock();
      if( dwNumTriangles > 0 )
          m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  
      // Restore the modified renderstates
      m_pStateBlockSaved->Apply();
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: Render3DText()
  // Desc: Renders 3D text
  //-----------------------------------------------------------------------------
  HRESULT CD3DFont::Render3DText( const TCHAR* strText, DWORD dwFlags )
  {
      if( m_pd3dDevice == NULL )
          return E_FAIL;
  
      // Setup renderstate
      m_pStateBlockSaved->Capture();
      m_pStateBlockDrawText->Apply();
      m_pd3dDevice->SetFVF( D3DFVF_FONT3DVERTEX );
      m_pd3dDevice->SetPixelShader( NULL );
      m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT3DVERTEX) );
  
      // Set filter states
      if( dwFlags & D3DFONT_FILTERED )
      {
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
          m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
      }
  
      // Position for each text element
      FLOAT x = 0.0f;
      FLOAT y = 0.0f;
  
      // Center the text block at the origin (not the viewport)
      if( dwFlags & D3DFONT_CENTERED_X )
      {
          SIZE sz;
          GetTextExtent( strText, &sz );
          x = -(((FLOAT)sz.cx)/10.0f)/2.0f;
      }
      if( dwFlags & D3DFONT_CENTERED_Y )
      {
          SIZE sz;
          GetTextExtent( strText, &sz );
          y = -(((FLOAT)sz.cy)/10.0f)/2.0f;
      }
  
      // Turn off culling for two-sided text
      if( dwFlags & D3DFONT_TWOSIDED )
          m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  
      // Adjust for character spacing
      x -= m_dwSpacing / 10.0f;
      FLOAT fStartX = x;
      TCHAR c;
  
      // Fill vertex buffer
      FONT3DVERTEX* pVertices;
      DWORD         dwNumTriangles = 0L;
      m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
  
      while( (c = *strText++) != 0 )
      {
          if( c == '\n' )
          {
              x = fStartX;
              y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;
          }
  
          if( (c-32) < 0 || (c-32) >= 128-32 )
              continue;
  
          FLOAT tx1 = m_fTexCoords[c-32][0];
          FLOAT ty1 = m_fTexCoords[c-32][1];
          FLOAT tx2 = m_fTexCoords[c-32][2];
          FLOAT ty2 = m_fTexCoords[c-32][3];
  
          FLOAT w = (tx2-tx1) * m_dwTexWidth  / ( 10.0f * m_fTextScale );
          FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );
  
          if( c != _T(' ') )
          {
              *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 );
              *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
              *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
              *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 );
              *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
              *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
              dwNumTriangles += 2;
  
              if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
              {
                  // Unlock, render, and relock the vertex buffer
                  m_pVB->Unlock();
                  m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
                  m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
                  dwNumTriangles = 0L;
              }
          }
  
          x += w - (2 * m_dwSpacing) / 10.0f;
      }
  
      // Unlock and render the vertex buffer
      m_pVB->Unlock();
      if( dwNumTriangles > 0 )
          m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  
      // Restore the modified renderstates
      m_pStateBlockSaved->Apply();
  
      return S_OK;
  }
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.