0001: //-----------------------------------------------------------------------------
0002: // File: D3DFont.cpp
0003: //
0004: // Desc: Texture-based font class
0005: //-----------------------------------------------------------------------------
0006: #define STRICT
0007: #include <stdio.h>
0008: #include <tchar.h>
0009: #include <D3DX8.h>
0010: #include "D3DFont.h"
0011: #include "D3DUtil.h"
0012: #include "DXUtil.h"
0013: 
0014: 
0015: 
0016: 
0017: //-----------------------------------------------------------------------------
0018: // Custom vertex types for rendering text
0019: //-----------------------------------------------------------------------------
0020: #define MAX_NUM_VERTICES 50*6
0021: 
0022: struct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };
0023: struct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };
0024: 
0025: #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
0026: #define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
0027: 
0028: inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
0029:                                       FLOAT tu, FLOAT tv )
0030: {
0031:     FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;
0032:     return v;
0033: }
0034: 
0035: inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
0036:                                       FLOAT tu, FLOAT tv )
0037: {
0038:     FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;
0039:     return v;
0040: }
0041: 
0042: 
0043: 
0044: 
0045: //-----------------------------------------------------------------------------
0046: // Name: CD3DFont()
0047: // Desc: Font class constructor
0048: //-----------------------------------------------------------------------------
0049: CD3DFont::CD3DFont( TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )
0050: {
0051:     _tcscpy( m_strFontName, strFontName );
0052:     m_dwFontHeight         = dwHeight;
0053:     m_dwFontFlags          = dwFlags;
0054: 
0055:     m_pd3dDevice           = NULL;
0056:     m_pTexture             = NULL;
0057:     m_pVB                  = NULL;
0058: 
0059:     m_dwSavedStateBlock    = 0L;
0060:     m_dwDrawTextStateBlock = 0L;
0061: }
0062: 
0063: 
0064: 
0065: 
0066: //-----------------------------------------------------------------------------
0067: // Name: ~CD3DFont()
0068: // Desc: Font class destructor
0069: //-----------------------------------------------------------------------------
0070: CD3DFont::~CD3DFont()
0071: {
0072:     InvalidateDeviceObjects();
0073:     DeleteDeviceObjects();
0074: }
0075: 
0076: 
0077: 
0078: 
0079: //-----------------------------------------------------------------------------
0080: // Name: InitDeviceObjects()
0081: // Desc: Initializes device-dependent objects, including the vertex buffer used
0082: //       for rendering text and the texture map which stores the font image.
0083: //-----------------------------------------------------------------------------
0084: HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE8 pd3dDevice )
0085: {
0086:     HRESULT hr;
0087: 
0088:     // Keep a local copy of the device
0089:     m_pd3dDevice = pd3dDevice;
0090: 
0091:     // Establish the font and texture size
0092:     m_fTextScale  = 1.0f; // Draw fonts into texture without scaling
0093: 
0094:     // Large fonts need larger textures
0095:     if( m_dwFontHeight > 40 )
0096:         m_dwTexWidth = m_dwTexHeight = 1024;
0097:     else if( m_dwFontHeight > 20 )
0098:         m_dwTexWidth = m_dwTexHeight = 512;
0099:     else
0100:         m_dwTexWidth  = m_dwTexHeight = 256;
0101: 
0102:     // If requested texture is too big, use a smaller texture and smaller font,
0103:     // and scale up when rendering.
0104:     D3DCAPS8 d3dCaps;
0105:     m_pd3dDevice->GetDeviceCaps( &d3dCaps );
0106: 
0107:     if( m_dwTexWidth > d3dCaps.MaxTextureWidth )
0108:     {
0109:         m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;
0110:         m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;
0111:     }
0112: 
0113:     // Create a new texture for the font
0114:     hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
0115:                                       0, D3DFMT_A4R4G4B4,
0116:                                       D3DPOOL_MANAGED, &m_pTexture );
0117:     if( FAILED(hr) )
0118:         return hr;
0119: 
0120:     // Prepare to create a bitmap
0121:     DWORD*      pBitmapBits;
0122:     BITMAPINFO bmi;
0123:     ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
0124:     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
0125:     bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
0126:     bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
0127:     bmi.bmiHeader.biPlanes      = 1;
0128:     bmi.bmiHeader.biCompression = BI_RGB;
0129:     bmi.bmiHeader.biBitCount    = 32;
0130: 
0131:     // Create a DC and a bitmap for the font
0132:     HDC     hDC       = CreateCompatibleDC( NULL );
0133:     HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
0134:                                           (VOID**)&pBitmapBits, NULL, 0 );
0135:     SetMapMode( hDC, MM_TEXT );
0136: 
0137:     // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
0138:     // antialiased font, but this is not guaranteed.
0139:     INT nHeight    = -MulDiv( m_dwFontHeight, 
0140:         (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
0141:     DWORD dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
0142:     DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;
0143:     HFONT hFont    = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
0144:                           FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
0145:                           CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
0146:                           VARIABLE_PITCH, m_strFontName );
0147:     if( NULL==hFont )
0148:         return E_FAIL;
0149: 
0150:     SelectObject( hDC, hbmBitmap );
0151:     SelectObject( hDC, hFont );
0152: 
0153:     // Set text properties
0154:     SetTextColor( hDC, RGB(255,255,255) );
0155:     SetBkColor(   hDC, 0x00000000 );
0156:     SetTextAlign( hDC, TA_TOP );
0157: 
0158:     // Loop through all printable character and output them to the bitmap..
0159:     // Meanwhile, keep track of the corresponding tex coords for each character.
0160:     DWORD x = 0;
0161:     DWORD y = 0;
0162:     TCHAR str[2] = _T("x");
0163:     SIZE size;
0164: 
0165:     for( TCHAR c=32; c<127; c++ )
0166:     {
0167:         str[0] = c;
0168:         GetTextExtentPoint32( hDC, str, 1, &size );
0169: 
0170:         if( (DWORD)(x+size.cx+1) > m_dwTexWidth )
0171:         {
0172:             x  = 0;
0173:             y += size.cy+1;
0174:         }
0175: 
0176:         ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL );
0177: 
0178:         m_fTexCoords[c-32][0] = ((FLOAT)(x+0))/m_dwTexWidth;
0179:         m_fTexCoords[c-32][1] = ((FLOAT)(y+0))/m_dwTexHeight;
0180:         m_fTexCoords[c-32][2] = ((FLOAT)(x+0+size.cx))/m_dwTexWidth;
0181:         m_fTexCoords[c-32][3] = ((FLOAT)(y+0+size.cy))/m_dwTexHeight;
0182: 
0183:         x += size.cx+1;
0184:     }
0185: 
0186:     // Lock the surface and write the alpha values for the set pixels
0187:     D3DLOCKED_RECT d3dlr;
0188:     m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
0189:     BYTE* pDstRow = (BYTE*)d3dlr.pBits;
0190:     WORD* pDst16;
0191:     BYTE bAlpha; // 4-bit measure of pixel intensity
0192: 
0193:     for( y=0; y < m_dwTexHeight; y++ )
0194:     {
0195:         pDst16 = (WORD*)pDstRow;
0196:         for( x=0; x < m_dwTexWidth; x++ )
0197:         {
0198:             bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
0199:             if (bAlpha > 0)
0200:             {
0201:                 *pDst16++ = (bAlpha << 12) | 0x0fff;
0202:             }
0203:             else
0204:             {
0205:                 *pDst16++ = 0x0000;
0206:             }
0207:         }
0208:         pDstRow += d3dlr.Pitch;
0209:     }
0210: 
0211:     // Done updating texture, so clean up used objects
0212:     m_pTexture->UnlockRect(0);
0213:     DeleteObject( hbmBitmap );
0214:     DeleteDC( hDC );
0215:     DeleteObject( hFont );
0216: 
0217:     return S_OK;
0218: }
0219: 
0220: 
0221: 
0222: 
0223: //-----------------------------------------------------------------------------
0224: // Name: RestoreDeviceObjects()
0225: // Desc:
0226: //-----------------------------------------------------------------------------
0227: HRESULT CD3DFont::RestoreDeviceObjects()
0228: {
0229:     HRESULT hr;
0230: 
0231:     // Create vertex buffer for the letters
0232:     if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES*sizeof(FONT2DVERTEX),
0233:                                                        D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
0234:                                                        D3DPOOL_DEFAULT, &m_pVB ) ) )
0235:     {
0236:         return hr;
0237:     }
0238: 
0239:     // Create the state blocks for rendering text
0240:     for( UINT which=0; which<2; which++ )
0241:     {
0242:         m_pd3dDevice->BeginStateBlock();
0243:         m_pd3dDevice->SetTexture( 0, m_pTexture );
0244: 
0245:         if ( D3DFONT_ZENABLE & m_dwFontFlags )
0246:             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
0247:         else
0248:             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
0249: 
0250:         m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
0251:         m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,   D3DBLEND_SRCALPHA );
0252:         m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
0253:         m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
0254:         m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
0255:         m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );
0256:         m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID );
0257:         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CCW );
0258:         m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
0259:         m_pd3dDevice->SetRenderState( D3DRS_CLIPPING,         TRUE );
0260:         m_pd3dDevice->SetRenderState( D3DRS_EDGEANTIALIAS,    FALSE );
0261:         m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  FALSE );
0262:         m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND,      FALSE );
0263:         m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
0264:         m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );
0265:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
0266:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
0267:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
0268:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
0269:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
0270:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
0271:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
0272:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
0273:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE );
0274:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
0275:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
0276:         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
0277:         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
0278: 
0279:         if( which==0 )
0280:             m_pd3dDevice->EndStateBlock( &m_dwSavedStateBlock );
0281:         else
0282:             m_pd3dDevice->EndStateBlock( &m_dwDrawTextStateBlock );
0283:     }
0284: 
0285:     return S_OK;
0286: }
0287: 
0288: 
0289: 
0290: 
0291: //-----------------------------------------------------------------------------
0292: // Name: InvalidateDeviceObjects()
0293: // Desc: Destroys all device-dependent objects
0294: //-----------------------------------------------------------------------------
0295: HRESULT CD3DFont::InvalidateDeviceObjects()
0296: {
0297:     SAFE_RELEASE( m_pVB );
0298: 
0299:     // Delete the state blocks
0300:     if( m_pd3dDevice )
0301:     {
0302:         if( m_dwSavedStateBlock )
0303:             m_pd3dDevice->DeleteStateBlock( m_dwSavedStateBlock );
0304:         if( m_dwDrawTextStateBlock )
0305:             m_pd3dDevice->DeleteStateBlock( m_dwDrawTextStateBlock );
0306:     }
0307: 
0308:     m_dwSavedStateBlock    = 0L;
0309:     m_dwDrawTextStateBlock = 0L;
0310: 
0311:     return S_OK;
0312: }
0313: 
0314: 
0315: 
0316: 
0317: //-----------------------------------------------------------------------------
0318: // Name: DeleteDeviceObjects()
0319: // Desc: Destroys all device-dependent objects
0320: //-----------------------------------------------------------------------------
0321: HRESULT CD3DFont::DeleteDeviceObjects()
0322: {
0323:     SAFE_RELEASE( m_pTexture );
0324:     m_pd3dDevice = NULL;
0325: 
0326:     return S_OK;
0327: }
0328: 
0329: 
0330: 
0331: 
0332: //-----------------------------------------------------------------------------
0333: // Name: GetTextExtent()
0334: // Desc: Get the dimensions of a text string
0335: //-----------------------------------------------------------------------------
0336: HRESULT CD3DFont::GetTextExtent( TCHAR* strText, SIZE* pSize )
0337: {
0338:     if( NULL==strText || NULL==pSize )
0339:         return E_FAIL;
0340: 
0341:     FLOAT fRowWidth  = 0.0f;
0342:     FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
0343:     FLOAT fWidth     = 0.0f;
0344:     FLOAT fHeight    = fRowHeight;
0345: 
0346:     while( *strText )
0347:     {
0348:         TCHAR c = *strText++;
0349: 
0350:         if( c == _T('\n') )
0351:         {
0352:             fRowWidth = 0.0f;
0353:             fHeight  += fRowHeight;
0354:         }
0355:         if( c < _T(' ') )
0356:             continue;
0357: 
0358:         FLOAT tx1 = m_fTexCoords[c-32][0];
0359:         FLOAT tx2 = m_fTexCoords[c-32][2];
0360: 
0361:         fRowWidth += (tx2-tx1)*m_dwTexWidth;
0362: 
0363:         if( fRowWidth > fWidth )
0364:             fWidth = fRowWidth;
0365:     }
0366: 
0367:     pSize->cx = (int)fWidth;
0368:     pSize->cy = (int)fHeight;
0369: 
0370:     return S_OK;
0371: }
0372: 
0373: 
0374: 
0375: 
0376: //-----------------------------------------------------------------------------
0377: // Name: DrawTextScaled()
0378: // Desc: Draws scaled 2D text.  Note that x and y are in viewport coordinates
0379: //       (ranging from -1 to +1).  fXScale and fYScale are the size fraction 
0380: //       relative to the entire viewport.  For example, a fXScale of 0.25 is
0381: //       1/8th of the screen width.  This allows you to output text at a fixed
0382: //       fraction of the viewport, even if the screen or window size changes.
0383: //-----------------------------------------------------------------------------
0384: HRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,
0385:                                   FLOAT fXScale, FLOAT fYScale, DWORD dwColor,
0386:                                   TCHAR* strText, DWORD dwFlags )
0387: {
0388:     if( m_pd3dDevice == NULL )
0389:         return E_FAIL;
0390: 
0391:     // Set up renderstate
0392:     m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
0393:     m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
0394:     m_pd3dDevice->SetVertexShader( D3DFVF_FONT2DVERTEX );
0395:     m_pd3dDevice->SetPixelShader( NULL );
0396:     m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT2DVERTEX) );
0397: 
0398:     // Set filter states
0399:     if( dwFlags & D3DFONT_FILTERED )
0400:     {
0401:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
0402:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
0403:     }
0404: 
0405:     D3DVIEWPORT8 vp;
0406:     m_pd3dDevice->GetViewport( &vp );
0407:     FLOAT sx  = (x+1.0f)*vp.Width/2;
0408:     FLOAT sy  = (y-1.0f)*vp.Height/2;
0409:     FLOAT sz  = z;
0410:     FLOAT rhw = 1.0f;
0411:     FLOAT fStartX = sx;
0412: 
0413:     FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight;
0414: 
0415:     // Fill vertex buffer
0416:     FONT2DVERTEX* pVertices;
0417:     DWORD         dwNumTriangles = 0L;
0418:     m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
0419: 
0420:     while( *strText )
0421:     {
0422:         TCHAR c = *strText++;
0423: 
0424:         if( c == _T('\n') )
0425:         {
0426:             sx  = fStartX;
0427:             sy += fYScale*vp.Height;
0428:         }
0429:         if( c < _T(' ') )
0430:             continue;
0431: 
0432:         FLOAT tx1 = m_fTexCoords[c-32][0];
0433:         FLOAT ty1 = m_fTexCoords[c-32][1];
0434:         FLOAT tx2 = m_fTexCoords[c-32][2];
0435:         FLOAT ty2 = m_fTexCoords[c-32][3];
0436: 
0437:         FLOAT w = (tx2-tx1)*m_dwTexWidth;
0438:         FLOAT h = (ty2-ty1)*m_dwTexHeight;
0439: 
0440:         w *= (fXScale*vp.Height)/fLineHeight;
0441:         h *= (fYScale*vp.Height)/fLineHeight;
0442: 
0443:         if( c != _T(' ') )
0444:         {
0445:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 );
0446:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
0447:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
0448:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 );
0449:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
0450:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
0451:             dwNumTriangles += 2;
0452: 
0453:             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
0454:             {
0455:                 // Unlock, render, and relock the vertex buffer
0456:                 m_pVB->Unlock();
0457:                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
0458:                 m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
0459:                 dwNumTriangles = 0L;
0460:             }
0461:         }
0462: 
0463:         sx += w;
0464:     }
0465: 
0466:     // Unlock and render the vertex buffer
0467:     m_pVB->Unlock();
0468:     if( dwNumTriangles > 0 )
0469:         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
0470: 
0471:     // Restore the modified renderstates
0472:     m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
0473: 
0474:     return S_OK;
0475: }
0476: 
0477: 
0478: 
0479: 
0480: //-----------------------------------------------------------------------------
0481: // Name: DrawText()
0482: // Desc: Draws 2D text
0483: //-----------------------------------------------------------------------------
0484: HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
0485:                             TCHAR* strText, DWORD dwFlags )
0486: {
0487:     if( m_pd3dDevice == NULL )
0488:         return E_FAIL;
0489: 
0490:     // Setup renderstate
0491:     m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
0492:     m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
0493:     m_pd3dDevice->SetVertexShader( D3DFVF_FONT2DVERTEX );
0494:     m_pd3dDevice->SetPixelShader( NULL );
0495:     m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT2DVERTEX) );
0496: 
0497:     // Set filter states
0498:     if( dwFlags & D3DFONT_FILTERED )
0499:     {
0500:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
0501:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
0502:     }
0503: 
0504:     FLOAT fStartX = sx;
0505: 
0506:     // Fill vertex buffer
0507:     FONT2DVERTEX* pVertices = NULL;
0508:     DWORD         dwNumTriangles = 0;
0509:     m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
0510: 
0511:     while( *strText )
0512:     {
0513:         TCHAR c = *strText++;
0514: 
0515:         if( c == _T('\n') )
0516:         {
0517:             sx = fStartX;
0518:             sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
0519:         }
0520:         if( c < _T(' ') )
0521:             continue;
0522: 
0523:         FLOAT tx1 = m_fTexCoords[c-32][0];
0524:         FLOAT ty1 = m_fTexCoords[c-32][1];
0525:         FLOAT tx2 = m_fTexCoords[c-32][2];
0526:         FLOAT ty2 = m_fTexCoords[c-32][3];
0527: 
0528:         FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
0529:         FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
0530: 
0531:         if( c != _T(' ') )
0532:         {
0533:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
0534:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
0535:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
0536:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
0537:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
0538:             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
0539:             dwNumTriangles += 2;
0540: 
0541:             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
0542:             {
0543:                 // Unlock, render, and relock the vertex buffer
0544:                 m_pVB->Unlock();
0545:                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
0546:                 pVertices = NULL;
0547:                 m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
0548:                 dwNumTriangles = 0L;
0549:             }
0550:         }
0551: 
0552:         sx += w;
0553:     }
0554: 
0555:     // Unlock and render the vertex buffer
0556:     m_pVB->Unlock();
0557:     if( dwNumTriangles > 0 )
0558:         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
0559: 
0560:     // Restore the modified renderstates
0561:     m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
0562: 
0563:     return S_OK;
0564: }
0565: 
0566: 
0567: 
0568: 
0569: //-----------------------------------------------------------------------------
0570: // Name: Render3DText()
0571: // Desc: Renders 3D text
0572: //-----------------------------------------------------------------------------
0573: HRESULT CD3DFont::Render3DText( TCHAR* strText, DWORD dwFlags )
0574: {
0575:     if( m_pd3dDevice == NULL )
0576:         return E_FAIL;
0577: 
0578:     // Setup renderstate
0579:     m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
0580:     m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
0581:     m_pd3dDevice->SetVertexShader( D3DFVF_FONT3DVERTEX );
0582:     m_pd3dDevice->SetPixelShader( NULL );
0583:     m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT3DVERTEX) );
0584: 
0585:     // Set filter states
0586:     if( dwFlags & D3DFONT_FILTERED )
0587:     {
0588:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
0589:         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
0590:     }
0591: 
0592:     // Position for each text element
0593:     FLOAT x = 0.0f;
0594:     FLOAT y = 0.0f;
0595: 
0596:     // Center the text block at the origin
0597:     if( dwFlags & D3DFONT_CENTERED )
0598:     {
0599:         SIZE sz;
0600:         GetTextExtent( strText, &sz );
0601:         x = -(((FLOAT)sz.cx)/10.0f)/2.0f;
0602:         y = -(((FLOAT)sz.cy)/10.0f)/2.0f;
0603:     }
0604: 
0605:     // Turn off culling for two-sided text
0606:     if( dwFlags & D3DFONT_TWOSIDED )
0607:         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
0608: 
0609:     FLOAT fStartX = x;
0610:     TCHAR c;
0611: 
0612:     // Fill vertex buffer
0613:     FONT3DVERTEX* pVertices;
0614:     DWORD         dwVertex       = 0L;
0615:     DWORD         dwNumTriangles = 0L;
0616:     m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
0617: 
0618:     while( c = *strText++ )
0619:     {
0620:         if( c == '\n' )
0621:         {
0622:             x = fStartX;
0623:             y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;
0624:         }
0625:         if( c < 32 )
0626:             continue;
0627: 
0628:         FLOAT tx1 = m_fTexCoords[c-32][0];
0629:         FLOAT ty1 = m_fTexCoords[c-32][1];
0630:         FLOAT tx2 = m_fTexCoords[c-32][2];
0631:         FLOAT ty2 = m_fTexCoords[c-32][3];
0632: 
0633:         FLOAT w = (tx2-tx1) * m_dwTexWidth  / ( 10.0f * m_fTextScale );
0634:         FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );
0635: 
0636:         if( c != _T(' ') )
0637:         {
0638:             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 );
0639:             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
0640:             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
0641:             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 );
0642:             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
0643:             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
0644:             dwNumTriangles += 2;
0645: 
0646:             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
0647:             {
0648:                 // Unlock, render, and relock the vertex buffer
0649:                 m_pVB->Unlock();
0650:                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
0651:                 m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
0652:                 dwNumTriangles = 0L;
0653:             }
0654:         }
0655: 
0656:         x += w;
0657:     }
0658: 
0659:     // Unlock and render the vertex buffer
0660:     m_pVB->Unlock();
0661:     if( dwNumTriangles > 0 )
0662:         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
0663: 
0664:     // Restore the modified renderstates
0665:     m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
0666: 
0667:     return S_OK;
0668: }
0669: 
0670: 
0671: 
0672: 
0673: