Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/dxgsg8/d3dfont8.cxx

Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 // File: D3DFont.cpp
00003 //
00004 // Desc: Texture-based font class
00005 //       modified from a modified version of DXSDK CD3DFont from http://www.lafaqmfc.com/directx.htm
00006 //       Note that this is faster than ID3DXFont, which calls GDI in Draw()
00007 //-----------------------------------------------------------------------------
00008 #ifndef STRICT
00009 #define STRICT
00010 #endif
00011 
00012 #include "dxgsg8base.h"
00013 #include <stdio.h>
00014 #include <tchar.h>
00015 #include <d3dx8.h>
00016 #include "d3dfont8.h"
00017 
00018 //-----------------------------------------------------------------------------
00019 // Custom vertex types for rendering text
00020 //-----------------------------------------------------------------------------
00021 
00022 struct FONT2DVERTEX {
00023     D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv;
00024 };
00025 struct FONT3DVERTEX {
00026     D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv;
00027 };
00028 
00029 inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
00030                                       FLOAT tu, FLOAT tv ) {
00031     FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;
00032     return v;
00033 }
00034 
00035 inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
00036                                       FLOAT tu, FLOAT tv ) {
00037     FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;
00038     return v;
00039 }
00040 
00041 //-----------------------------------------------------------------------------
00042 // Name: CD3DFont()
00043 // Desc: Font class constructor
00044 //-----------------------------------------------------------------------------
00045 CD3DFont::CD3DFont( TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags ) {
00046     _tcscpy( m_strFontName, strFontName );
00047     m_dwFontHeight         = dwHeight;
00048     m_dwFontFlags          = dwFlags;
00049 
00050     m_pd3dDevice           = NULL;
00051     m_pTexture             = NULL;
00052     m_pVB                  = NULL;
00053 
00054     m_dwSavedStateBlock    = NULL;
00055     m_dwDrawTextStateBlock = NULL;
00056 
00057     ClearBeginEndData ( ) ; 
00058     m_bBeginText = false ; 
00059 }
00060 
00061 //-----------------------------------------------------------------------------
00062 // Name: ~CD3DFont()
00063 // Desc: Font class destructor
00064 //-----------------------------------------------------------------------------
00065 CD3DFont::~CD3DFont() {
00066     DeleteDeviceObjects();
00067 }
00068 
00069 //-----------------------------------------------------------------------------
00070 // Name: InitDeviceObjects()
00071 // Desc: Initializes device-dependent objects, including the vertex buffer used
00072 //       for rendering text and the texture map which stores the font image.
00073 //-----------------------------------------------------------------------------
00074 HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE8 pd3dDevice ) {
00075     HRESULT hr;
00076 
00077     // Keep a local copy of the device
00078     m_pd3dDevice = pd3dDevice;
00079 
00080     // Establish the font and texture size
00081     m_fTextScale  = 1.0f; // Draw fonts into texture without scaling
00082 
00083     // Large fonts need larger textures 
00084     // We can be generous at this step, this is an estimate
00085     if(m_dwFontHeight > 40)
00086         m_dwTexWidth = m_dwTexHeight = 2048;
00087     else if(m_dwFontHeight > 32)
00088         m_dwTexWidth = m_dwTexHeight = 1024;
00089     else if(m_dwFontHeight > 16)
00090         m_dwTexWidth = m_dwTexHeight = 512;
00091     else
00092         m_dwTexWidth = m_dwTexHeight = 256;
00093 
00094     // Prepare to create a bitmap
00095     DWORD*      pBitmapBits;
00096     BITMAPINFO bmi;
00097     ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
00098     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
00099     bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
00100     bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
00101     bmi.bmiHeader.biPlanes      = 1;
00102     bmi.bmiHeader.biCompression = BI_RGB;
00103     bmi.bmiHeader.biBitCount    = 32;
00104 
00105     // Create a DC and a bitmap for the font
00106     HDC     hDC       = CreateCompatibleDC( NULL );
00107     HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
00108                                           (VOID**)&pBitmapBits, NULL, 0 );
00109     SetMapMode( hDC, MM_TEXT );
00110 
00111     // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
00112     // antialiased font, but this is not guaranteed.
00113     INT nHeight    = -MulDiv( m_dwFontHeight, 
00114                               (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
00115     DWORD dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
00116     DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;
00117     HFONT hFont    = CreateFont( nHeight, 0, 0, 0, dwBold, 
00118 
00119                                  FALSE ,   // dwItalic, // NO! We should not do that...
00120                                     // See below comment about GetTextExtentPoint32
00121 
00122                                  FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
00123                                  CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
00124                                  VARIABLE_PITCH, m_strFontName );
00125     if(NULL==hFont) {
00126         dxgsg8_cat.error() << "CD3DFont InitDeviceObjects(): initial CreateFont failed!  GetLastError=" << GetLastError() << endl;
00127         return E_FAIL;
00128     }
00129 
00130     HBITMAP hbmOld = ( HBITMAP ) SelectObject ( hDC, hbmBitmap );
00131     HFONT   hfOld  = ( HFONT ) SelectObject ( hDC, hFont );
00132 
00133     // Set text properties
00134     SetTextColor( hDC, RGB(255,255,255) );
00135     SetBkColor(   hDC, 0x00000000 );
00136     SetTextAlign( hDC, TA_TOP );
00137 
00138     // First Loop through all printable characters 
00139     // in order to determine the smallest necessary texture
00140     DWORD x = 0;
00141     DWORD y = 0;
00142     TCHAR str[2] = _T("x");
00143     SIZE size;
00144     SIZE sizes [ 127 - 32 ] ;
00145 
00146     for(TCHAR c=32; c<127; c++) {
00147         str[0] = c;
00148         // GetTextExtentPoint32 does not care that the font is Italic or not, it will 
00149         // return the same value. However, if we specify an Italic font, the output 
00150         // on the bitmap will use more pixels. 
00151         // If the font is Italic we have to output the standard character 
00152         // and bend our vertices.
00153         GetTextExtentPoint32 ( hDC, str, 1, & sizes [ c - 32 ] );
00154     } ; 
00155 
00156     static DWORD TexturesSizes [ 5 ] = { 128 , 256 , 512 , 1024 , 2048} ; 
00157     DWORD dwTexSize = 0 ;  
00158     for(DWORD iTex = 0 ; iTex < 5 ; ++ iTex) {
00159         // fake the tex coord loop calculation 
00160         x = 0 ; 
00161         y = 0 ; 
00162         for(TCHAR c=32; c<127; c++) {
00163             if((DWORD)( x + sizes[ c - 32 ].cx+1) > TexturesSizes [ iTex ]) {
00164                 x  = 0;
00165                 y += sizes[ c - 32 ].cy+1;
00166                 // new y size 
00167                 if((DWORD) ( y + sizes[ 0 ].cy + 1 ) >= TexturesSizes [ iTex ]) {
00168                     // does not fit, let's try a larger one 
00169                     break ; 
00170                 }; 
00171             }; 
00172             x += sizes[ c - 32 ].cx + 2 ;
00173         } ; 
00174 
00175         if((DWORD) ( y + sizes[ 0 ].cy + 1 ) < TexturesSizes [ iTex ]) {
00176             // Yahoo! it fits! 
00177             dwTexSize = TexturesSizes [ iTex ] ; 
00178             break ; 
00179         }; 
00180     } ; 
00181 
00182     m_dwTexWidth = m_dwTexHeight = dwTexSize ;
00183 
00184     // Select old objects ( added ) 
00185     // Is this needed for compatible DCs? 
00186     // The old handles are not not NULL, so it is done "by the book"
00187     SelectObject ( hDC, hbmOld );
00188     SelectObject ( hDC, hfOld );
00189 
00190     // delete our gdi objects
00191     DeleteObject( hbmBitmap );
00192     DeleteObject( hFont );
00193     DeleteDC( hDC );
00194 
00195     // moved here to allow deletion of GDI objects 
00196     if(dwTexSize == 0) {
00197         dxgsg8_cat.error() << "CD3DFont InitDeviceObjects() error: Texture didnt fit, creation failed!\n";
00198         return E_FAIL;
00199     }
00200 
00201     // Re-Create new GDI stuff with the optimal size 
00202     // 
00203     // Prepare to create a bitmap
00204     ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
00205     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
00206     bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
00207     bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
00208     bmi.bmiHeader.biPlanes      = 1;
00209     bmi.bmiHeader.biCompression = BI_RGB;
00210     bmi.bmiHeader.biBitCount    = 32;
00211 
00212     // Create a DC and a bitmap for the font
00213     hDC       = CreateCompatibleDC( NULL );
00214     hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
00215                                   (VOID**)&pBitmapBits, NULL, 0 );
00216     SetMapMode( hDC, MM_TEXT );
00217 
00218     // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
00219     // antialiased font, but this is not guaranteed.
00220     nHeight  = -MulDiv( m_dwFontHeight, 
00221                         (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
00222     dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
00223     dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;
00224     hFont    = CreateFont( nHeight, 0, 0, 0, dwBold, 
00225                            FALSE , // was dwItalic, // see above 
00226                            FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
00227                            CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
00228                            VARIABLE_PITCH, m_strFontName );
00229 
00230     if(NULL==hFont) {
00231         dxgsg8_cat.error() << "CD3DFont InitDeviceObjects(): optimal CreateFont failed!  GetLastError=" << GetLastError() << endl;
00232         return E_FAIL;
00233     }
00234 
00235     hbmOld = ( HBITMAP ) SelectObject ( hDC, hbmBitmap );
00236     hfOld  = ( HFONT ) SelectObject ( hDC, hFont );
00237 
00238     // Set text properties
00239     SetTextColor( hDC, RGB(255,255,255) );
00240     SetBkColor(   hDC, 0x00000000 );
00241     SetTextAlign( hDC, TA_TOP );
00242 
00243     // If requested texture is too big, use a smaller texture and smaller font,
00244     // and scale up when rendering.
00245     D3DCAPS8 d3dCaps;
00246     m_pd3dDevice->GetDeviceCaps( &d3dCaps );
00247 
00248     if(m_dwTexWidth > d3dCaps.MaxTextureWidth) {
00249         m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;
00250         m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;
00251     }; 
00252 
00253     // Create a new texture for the font
00254     hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
00255                                       0, D3DFMT_A4R4G4B4,
00256                                       D3DPOOL_MANAGED, &m_pTexture );
00257 
00258     if(FAILED(hr)) {
00259         SelectObject ( hDC, hbmOld );
00260         SelectObject ( hDC, hfOld );
00261 
00262         DeleteObject( hbmBitmap );
00263         DeleteObject( hFont );
00264         DeleteDC( hDC );
00265 
00266         dxgsg8_cat.error() << "CD3DFont InitDeviceObjs CreateTexture failed!" << D3DERRORSTRING(hr);
00267         return hr;
00268     }; 
00269 
00270     // Loop through all printable character and output them to the bitmap..
00271     // Meanwhile, keep track of the corresponding tex coords for each character.
00272     x = 0 ; 
00273     y = 0 ; 
00274 
00275     for(TCHAR c=32; c<127; c++) {
00276         str[0] = c;
00277         GetTextExtentPoint32( hDC, str, 1, &size );
00278         if((DWORD)(x+size.cx+1) > m_dwTexWidth) {
00279             x  = 0;
00280             y += size.cy+1;
00281         }
00282 
00283         // We need one pixel on both sides 
00284 
00285         // plus one here for one pixel on the left
00286         ExtTextOut( hDC, x + 1, y, ETO_OPAQUE, NULL, str, 1, NULL );
00287 
00288         m_fTexCoords[c-32][0] = ( (FLOAT) x + 0.5f ) / m_dwTexWidth ;
00289         m_fTexCoords[c-32][1] = ( (FLOAT) y + 0.5f ) / m_dwTexHeight ;
00290         m_fTexCoords[c-32][2] = ( (FLOAT) x + 0.5f + size.cx ) / m_dwTexWidth;
00291         m_fTexCoords[c-32][3] = ( (FLOAT) y + 0.5f + size.cy ) / m_dwTexHeight;
00292 
00293         // plus two here because we also need one more pixel on the right side
00294         x += size.cx + 2 ;
00295     }
00296 
00297     // Lock the surface and write the alpha values for the set pixels
00298     D3DLOCKED_RECT d3dlr;
00299     m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
00300     BYTE* pDstRow = (BYTE*)d3dlr.pBits;
00301     WORD* pDst16;
00302     BYTE bAlpha; // 4-bit measure of pixel intensity
00303 
00304     for(y=0; y < m_dwTexHeight; y++) {
00305         pDst16 = (WORD*)pDstRow;
00306         for(x=0; x < m_dwTexWidth; x++) {
00307             bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
00308             if(bAlpha > 0) {
00309                 *pDst16++ = (bAlpha << 12) | 0x0fff;
00310             } else {
00311                 *pDst16++ = 0x0000;
00312             }
00313         }
00314         pDstRow += d3dlr.Pitch;
00315     }
00316 
00317     // Done updating texture, so clean up used objects
00318     m_pTexture->UnlockRect(0);
00319 
00320     SelectObject ( hDC, hbmOld );
00321     SelectObject ( hDC, hfOld );
00322 
00323     DeleteObject( hbmBitmap );
00324     DeleteObject( hFont );
00325     DeleteDC( hDC );
00326 
00327     return RestoreDeviceObjects();
00328 }
00329 
00330 //-----------------------------------------------------------------------------
00331 // Name: RestoreDeviceObjects()
00332 // Desc:
00333 //-----------------------------------------------------------------------------
00334 HRESULT CD3DFont::RestoreDeviceObjects() {
00335     HRESULT hr;
00336 
00337     // Create vertex buffer for the letters
00338     if(FAILED( hr = m_pd3dDevice->CreateVertexBuffer(
00339             // can be rendered 3d 
00340                                                     MAX_NUM_VERTICES*sizeof(FONT3DVERTEX /*FONT2DVERTEX */ ),
00341                                                     D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
00342                                                     D3DPOOL_DEFAULT,  // D3DUSAGE_DYNAMIC makes D3DPOOL_MANAGED impossible
00343                                                     &m_pVB ) )) {
00344         dxgsg8_cat.error() << "CD3DFont CreateVB failed!" << D3DERRORSTRING(hr);
00345         return hr;
00346     }
00347 
00348     PRINT_REFCNT(dxgsg8,m_pd3dDevice);
00349 
00350     // Create the state blocks for rendering text
00351     for(UINT which=0; which<2; which++) {
00352         m_pd3dDevice->BeginStateBlock();
00353         m_pd3dDevice->SetTexture( 0, m_pTexture );
00354 
00355         if(D3DFONT_ZENABLE & m_dwFontFlags)
00356             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
00357         else
00358             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
00359 
00360         m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
00361         m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,   D3DBLEND_SRCALPHA );
00362         m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
00363         m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
00364         m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
00365         m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );
00366         m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID );
00367         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CCW );
00368         m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
00369         m_pd3dDevice->SetRenderState( D3DRS_CLIPPING,         TRUE );
00370         m_pd3dDevice->SetRenderState( D3DRS_EDGEANTIALIAS,    FALSE );
00371         m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  FALSE );
00372         m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND,      FALSE );
00373         m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
00374         m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );
00375         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
00376         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
00377         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
00378         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
00379         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
00380         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
00381         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
00382         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
00383         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE );
00384         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
00385         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
00386         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
00387         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
00388 
00389         if(which==0)
00390             m_pd3dDevice->EndStateBlock( &m_dwSavedStateBlock );
00391         else
00392             m_pd3dDevice->EndStateBlock( &m_dwDrawTextStateBlock );
00393     }
00394 
00395     return S_OK;
00396 }
00397 
00398 
00399 //-----------------------------------------------------------------------------
00400 // Name: InvalidateDeviceObjects()
00401 // Desc: Destroys all device-dependent objects
00402 //-----------------------------------------------------------------------------
00403 HRESULT CD3DFont::InvalidateDeviceObjects() {
00404     HRESULT hr;
00405 
00406     PRINT_REFCNT(dxgsg8,m_pd3dDevice);
00407 
00408     if(IS_VALID_PTR(m_pd3dDevice)) {
00409         // undo SetStreamSource before releasing VB
00410 
00411         IDirect3DVertexBuffer8 *pStreamData=NULL;
00412         UINT StreamStride;
00413         hr = m_pd3dDevice->GetStreamSource(0,&pStreamData,&StreamStride);
00414         SAFE_RELEASE(pStreamData);  // undo GetStreamSource AddRef
00415         if(pStreamData==m_pVB)
00416             hr = m_pd3dDevice->SetStreamSource(0,NULL,0);
00417     }
00418 
00419     PRINT_REFCNT(dxgsg8,m_pVB);
00420 
00421     RELEASE(m_pVB,dxgsg8,"d3dfont VB",RELEASE_ONCE);
00422 
00423     PRINT_REFCNT(dxgsg8,m_pd3dDevice);
00424 
00425     // Delete the state blocks
00426     if(m_pd3dDevice) {
00427         assert(IS_VALID_PTR(m_pd3dDevice));
00428         if(m_dwSavedStateBlock)
00429             m_pd3dDevice->DeleteStateBlock( m_dwSavedStateBlock );
00430         if(m_dwDrawTextStateBlock)
00431             m_pd3dDevice->DeleteStateBlock( m_dwDrawTextStateBlock );
00432     }
00433 
00434     PRINT_REFCNT(dxgsg8,m_pd3dDevice);
00435 
00436     m_dwSavedStateBlock    = NULL;
00437     m_dwDrawTextStateBlock = NULL;
00438 
00439     return S_OK;
00440 }
00441 
00442 
00443 //-----------------------------------------------------------------------------
00444 // Name: DeleteDeviceObjects()
00445 // Desc: Destroys all device-dependent objects
00446 //-----------------------------------------------------------------------------
00447 HRESULT CD3DFont::DeleteDeviceObjects() {
00448     PRINT_REFCNT(dxgsg8,m_pd3dDevice);
00449 
00450     InvalidateDeviceObjects();
00451 
00452     SAFE_RELEASE( m_pTexture );
00453 
00454     PRINT_REFCNT(dxgsg8,m_pd3dDevice);
00455 
00456     m_pd3dDevice = NULL;
00457 
00458     return S_OK;
00459 }
00460 
00461 
00462 //-----------------------------------------------------------------------------
00463 // Name: GetTextExtent()
00464 // Desc: Get the dimensions of a text string
00465 //-----------------------------------------------------------------------------
00466 HRESULT CD3DFont::GetTextExtent( TCHAR* strText, SIZE* pSize ) {
00467     if(NULL==strText || NULL==pSize)
00468         return E_FAIL;
00469 
00470     FLOAT fRowWidth  = 0.0f;
00471     FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
00472     FLOAT fWidth     = 0.0f;
00473     FLOAT fHeight    = fRowHeight;
00474 
00475     while(*strText) {
00476         TCHAR c = *strText++;
00477 
00478         if(c == _T('\n')) {
00479             fRowWidth = 0.0f;
00480             fHeight  += fRowHeight;
00481         }
00482         if(c < _T(' '))
00483             continue;
00484 
00485         FLOAT tx1 = m_fTexCoords[c-32][0];
00486         FLOAT tx2 = m_fTexCoords[c-32][2];
00487 
00488         fRowWidth += (tx2-tx1)*m_dwTexWidth;
00489 
00490         if(fRowWidth > fWidth)
00491             fWidth = fRowWidth;
00492     }
00493 
00494     pSize->cx = (int)fWidth;
00495     pSize->cy = (int)fHeight;
00496 
00497     return S_OK;
00498 }
00499 
00500 //-----------------------------------------------------------------------------
00501 // Name: DrawTextScaled()
00502 // Desc: Draws scaled 2D text.  Note that x and y are in viewport coordinates
00503 //       (ranging from -1 to +1).  fXScale and fYScale are the size fraction 
00504 //       relative to the entire viewport.  For example, a fXScale of 0.25 is
00505 //       1/8th of the screen width.  This allows you to output text at a fixed
00506 //       fraction of the viewport, even if the screen or window size changes.
00507 //-----------------------------------------------------------------------------
00508 HRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,
00509                                   FLOAT fXScale, FLOAT fYScale, DWORD dwColor,
00510                                   TCHAR* strText, DWORD dwFlags ) {
00511     if(m_pd3dDevice == NULL)
00512         return E_FAIL;
00513 
00514     HRESULT hr ; 
00515     if(m_bBeginText) {
00516         hr = DeferedDrawTextScaled ( x, y, z, fXScale, fYScale, dwColor, strText, dwFlags ) ; 
00517     } else {
00518         BeginText ( ) ; 
00519         hr = DeferedDrawTextScaled ( x, y, z, fXScale, fYScale, dwColor, strText, dwFlags ) ; 
00520         if(! FAILED ( hr ))
00521             EndText ( ) ;
00522     } ; 
00523 
00524     return hr ;
00525 }
00526 
00527 //-----------------------------------------------------------------------------
00528 // Name: DrawText()
00529 // Desc: Draws 2D text
00530 //-----------------------------------------------------------------------------
00531 HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
00532                             TCHAR* strText, DWORD dwFlags ) {
00533     if(m_pd3dDevice == NULL)
00534         return E_FAIL;
00535 
00536     HRESULT hr ; 
00537     if(m_bBeginText) {
00538         hr = DeferedDrawText ( sx, sy, dwColor, strText, dwFlags ) ; 
00539     } else {
00540         BeginText(); 
00541         hr = DeferedDrawText ( sx, sy, dwColor, strText, dwFlags ) ; 
00542         if(! FAILED ( hr ))
00543             EndText ( ) ;
00544     } ; 
00545 
00546     return hr ;
00547 }
00548 
00549 
00550 void CD3DFont::ClearBeginEndData ( void ) {
00551     m_nDeferedCalls = 0 ; 
00552     m_TextBuffer [ 0 ] = 0 ; 
00553     m_pTextBuffer = & m_TextBuffer [ 0 ] ; 
00554 } 
00555 
00556 HRESULT CD3DFont::BeginText ( void ) {
00557     m_bBeginText = true ; 
00558     ClearBeginEndData() ; 
00559 
00560     return S_OK ; 
00561 } 
00562 
00563 HRESULT CD3DFont::DeferedDrawTextScaled
00564 ( FLOAT x, FLOAT y, FLOAT z, 
00565   FLOAT fXScale, FLOAT fYScale, DWORD dwColor, 
00566   TCHAR* strText, DWORD dwFlags ) {
00567     return 
00568     DeferedDraw ( true , x, y, z, fXScale, fYScale, dwColor, strText, dwFlags ) ; 
00569 } 
00570 
00571 HRESULT CD3DFont::DeferedDrawText
00572 ( FLOAT x, FLOAT y, DWORD dwColor, 
00573   TCHAR* strText, DWORD dwFlags ) {
00574     return 
00575     DeferedDraw ( false , x, y, 0.0f , 0.0f , 0.0f , dwColor, strText, dwFlags ) ; 
00576 } 
00577 
00578 HRESULT CD3DFont::DeferedDraw
00579 ( bool bScaled , 
00580   FLOAT x, FLOAT y, FLOAT z, 
00581   FLOAT fXScale, FLOAT fYScale, DWORD dwColor, 
00582   TCHAR* strText, DWORD dwFlags ) {
00583     if(m_nDeferedCalls >= MaxCalls) {
00584         dxgsg8_cat.error() << "CD3DFont DeferedDraw() error, MaxCalls exceeded!\n";
00585         return E_FAIL ;
00586     }
00587 
00588     // we need to make a deep copy of the string 
00589     // the user object might have fallen out of scope
00590     // when it will be time to render 
00591     int nStrLen = strlen ( strText ) + 1 ; 
00592     int nUsed = m_pTextBuffer - & m_pTextBuffer [ 0 ] ; 
00593     if(nUsed + nStrLen > TextBufferLength) {
00594         dxgsg8_cat.error() << "CD3DFont DeferedDraw() error, TextBufferLength exceeded!\n";
00595         return E_FAIL ;
00596     }
00597 
00598     strcpy ( m_pTextBuffer , strText ) ; 
00599     m_DTArgs [ m_nDeferedCalls ].m_strText = m_pTextBuffer ; 
00600     m_pTextBuffer += nStrLen ; 
00601 
00602     m_DTArgs [ m_nDeferedCalls ].m_bScaled = bScaled ; 
00603     m_DTArgs [ m_nDeferedCalls ].m_x = x ; 
00604     m_DTArgs [ m_nDeferedCalls ].m_y = y ; 
00605     m_DTArgs [ m_nDeferedCalls ].m_z = z ; 
00606     m_DTArgs [ m_nDeferedCalls ].m_fXScale = fXScale ; 
00607     m_DTArgs [ m_nDeferedCalls ].m_fYScale = fYScale ; 
00608     m_DTArgs [ m_nDeferedCalls ].m_dwColor = dwColor ; 
00609     m_DTArgs [ m_nDeferedCalls ].m_dwFlags = dwFlags ; 
00610 
00611     m_nDeferedCalls ++ ; 
00612 
00613     return S_OK ; 
00614 } 
00615 
00616 HRESULT CD3DFont::EndText ( void ) {
00617     if(m_pd3dDevice == NULL)
00618         return E_FAIL;
00619     HRESULT hr;
00620 
00621     assert(IS_VALID_PTR(m_pVB));
00622 
00623     DWORD hSavedVertexShader,hSavedPixelShader;
00624     UINT SavedStreamStride;
00625     IDirect3DVertexBuffer8 *pSavedStreamData=NULL;
00626 
00627     hr = m_pd3dDevice->GetVertexShader(&hSavedVertexShader);
00628     hr = m_pd3dDevice->GetPixelShader(&hSavedPixelShader);
00629 
00630     // Set up renderstate
00631     hr = m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
00632     hr = m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
00633     if(hSavedVertexShader!=D3DFVF_FONT2DVERTEX)
00634         hr = m_pd3dDevice->SetVertexShader(D3DFVF_FONT2DVERTEX);
00635     if(hSavedPixelShader!=NULL)
00636         hr = m_pd3dDevice->SetPixelShader(NULL);
00637 
00638     hr = m_pd3dDevice->GetStreamSource(0,&pSavedStreamData,&SavedStreamStride);
00639     if(FAILED(hr)) {
00640         dxgsg8_cat.error() << "CD3DFont EndText GetStreamSource() failed!" << D3DERRORSTRING(hr);
00641         return E_FAIL;
00642     }
00643 
00644     // undo GetStreamSource AddRef
00645     SAFE_RELEASE(pSavedStreamData);
00646 
00647     if((pSavedStreamData!=m_pVB)||(SavedStreamStride!=sizeof(FONT2DVERTEX))) {
00648         hr = m_pd3dDevice->SetStreamSource(0,m_pVB,sizeof(FONT2DVERTEX));
00649         if(FAILED(hr)) {
00650             dxgsg8_cat.error() << "CD3DFont EndText initial SetStreamSource() failed!" << D3DERRORSTRING(hr);
00651             return E_FAIL;
00652         }
00653     }
00654 
00655     // Set filter states
00656     //
00657     // filter if any in our list is specified filtered 
00658     //
00659     // This functionality is different from the original D3DFont 
00660     // but is a significant speed increase
00661     //
00662     // User will make another batch if necessary
00663     //  
00664     bool bFiltered = false ; 
00665     for(UINT i = 0 ; i < m_nDeferedCalls ; ++ i) {
00666         DWORD   dwFlags = m_DTArgs [ i ].m_dwFlags ; 
00667         if(dwFlags & D3DFONT_FILTERED) {
00668             bFiltered = true ; 
00669             break ; 
00670         }
00671     } ; 
00672     if(bFiltered) {
00673         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
00674         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
00675     }; 
00676 
00677     // useless if nothing is scaled but should be fast enough 
00678     D3DVIEWPORT8 vp;
00679     m_pd3dDevice->GetViewport( &vp );
00680     FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight;
00681 
00682     // Fill vertex buffer
00683     FONT2DVERTEX* pVertices;
00684     DWORD         dwNumTriangles = 0L;
00685     m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
00686 
00687     bool bItalic = 0 != ( m_dwFontFlags & D3DFONT_ITALIC ) ; 
00688     // loop on our batched sets of arguments 
00689     for(UINT i = 0 ; i < m_nDeferedCalls ; ++ i) {
00690         bool    bScaled = m_DTArgs [ i ].m_bScaled ; 
00691         FLOAT   x       = m_DTArgs [ i ].m_x       ; 
00692         FLOAT   y       = m_DTArgs [ i ].m_y       ; 
00693         FLOAT   z       = m_DTArgs [ i ].m_z       ; 
00694         FLOAT   fXScale = m_DTArgs [ i ].m_fXScale ; 
00695         FLOAT   fYScale = m_DTArgs [ i ].m_fYScale ; 
00696         DWORD   dwColor = m_DTArgs [ i ].m_dwColor ; 
00697         TCHAR * strText = m_DTArgs [ i ].m_strText ; 
00698 
00699         if(bScaled) {
00700 
00701             FLOAT sx  = (x+1.0f)*vp.Width/2;
00702             FLOAT sy  = (y-1.0f)*vp.Height/2;
00703             FLOAT sz  = z;
00704             FLOAT rhw = 1.0f;
00705             FLOAT fStartX = sx;
00706 
00707             FLOAT fBend = 0.0f ; 
00708             if(bItalic)
00709                 fBend = fYScale*vp.Height / 4.0f ;
00710 
00711             while(*strText) {
00712                 TCHAR c = *strText++;
00713 
00714                 if(c == _T('\n')) {
00715                     sx  = fStartX;
00716                     sy += fYScale*vp.Height;
00717                 }
00718                 if(c < _T(' '))
00719                     continue;
00720 
00721                 FLOAT tx1 = m_fTexCoords[c-32][0];
00722                 FLOAT ty1 = m_fTexCoords[c-32][1];
00723                 FLOAT tx2 = m_fTexCoords[c-32][2];
00724                 FLOAT ty2 = m_fTexCoords[c-32][3];
00725 
00726                 FLOAT w = (tx2-tx1)*m_dwTexWidth;
00727                 FLOAT h = (ty2-ty1)*m_dwTexHeight;
00728 
00729                 w *= (fXScale*vp.Height)/fLineHeight;
00730                 h *= (fYScale*vp.Height)/fLineHeight;
00731 
00732                 if(c != _T(' ')) {
00733                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 );
00734                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f + fBend,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
00735                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
00736                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f + fBend,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 );
00737                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
00738                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f + fBend,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
00739                     dwNumTriangles += 2;
00740 
00741                     if(dwNumTriangles*3 > (MAX_NUM_VERTICES-6)) {
00742                         // Unlock, render, and relock the vertex buffer
00743                         m_pVB->Unlock();
00744                         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
00745                         m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
00746                         dwNumTriangles = 0L;
00747                     }
00748                 }
00749 
00750                 sx += w;
00751             } ; 
00752         } else {  // not scaled 
00753             FLOAT fBend = 0.0f ; 
00754             if(bItalic)
00755                 fBend = fLineHeight / 4.0f ;
00756 
00757             // Lazy guy...
00758             FLOAT sx = x ; 
00759             FLOAT sy = y ; 
00760 
00761             FLOAT fStartX = sx;
00762             while(*strText) {
00763                 TCHAR c = *strText++;
00764 
00765                 if(c == _T('\n')) {
00766                     sx = fStartX ;
00767                     sy += fLineHeight ;
00768                 }
00769                 if(c < _T(' '))
00770                     continue;
00771 
00772                 FLOAT tx1 = m_fTexCoords[c-32][0];
00773                 FLOAT ty1 = m_fTexCoords[c-32][1];
00774                 FLOAT tx2 = m_fTexCoords[c-32][2];
00775                 FLOAT ty2 = m_fTexCoords[c-32][3];
00776 
00777                 FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
00778                 FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
00779 
00780                 if(c != _T(' ')) {
00781                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
00782                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f + fBend,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
00783                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
00784                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f + fBend,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
00785                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
00786                     *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f + fBend,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
00787                     dwNumTriangles += 2;
00788 
00789                     if(dwNumTriangles*3 > (MAX_NUM_VERTICES-6)) {
00790                         // Unlock, render, and relock the vertex buffer
00791                         m_pVB->Unlock();
00792                         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
00793                         pVertices = NULL;
00794                         m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
00795                         dwNumTriangles = 0L;
00796                     }
00797                 };  // endif not blank 
00798 
00799                 sx += w;
00800             } ; // end while 
00801 
00802         } ; // end if else scaled 
00803 
00804     } ; // end for 
00805 
00806     m_bBeginText = false ; 
00807     ClearBeginEndData ( ) ; 
00808 
00809     // Unlock and render the vertex buffer
00810     m_pVB->Unlock();
00811     if(dwNumTriangles > 0)
00812         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
00813 
00814     // Restore the modified renderstates
00815     m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
00816     if((hSavedVertexShader!=NULL) && (hSavedVertexShader!=D3DFVF_FONT2DVERTEX))
00817         m_pd3dDevice->SetVertexShader(hSavedVertexShader);
00818     if(hSavedPixelShader!=NULL)
00819         m_pd3dDevice->SetPixelShader(hSavedPixelShader);
00820 
00821     if(IS_VALID_PTR(pSavedStreamData) && ((pSavedStreamData!=m_pVB)||(SavedStreamStride!=sizeof(FONT2DVERTEX)))) {
00822         hr = m_pd3dDevice->SetStreamSource(0,pSavedStreamData,SavedStreamStride);
00823         if(FAILED(hr)) {
00824             dxgsg8_cat.error() << "CD3DFont EndText restore SetStreamSource() failed!" << D3DERRORSTRING(hr);
00825             return E_FAIL;
00826         }
00827         pSavedStreamData->Release();
00828     }
00829 
00830     return S_OK;
00831 } 
00832 
00833 #if 0
00834 // dont need this now
00835 //-----------------------------------------------------------------------------
00836 // Name: Render3DText()
00837 // Desc: Renders 3D text
00838 //-----------------------------------------------------------------------------
00839 HRESULT CD3DFont::Render3DText( TCHAR* strText, DWORD dwFlags ) {
00840     if(m_pd3dDevice == NULL)
00841         return E_FAIL;
00842 
00843     // Setup renderstate
00844     m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
00845     m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
00846     m_pd3dDevice->SetVertexShader( D3DFVF_FONT3DVERTEX );
00847     m_pd3dDevice->SetPixelShader( NULL );
00848     m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT3DVERTEX) );
00849 
00850     // Set filter states
00851     if(dwFlags & D3DFONT_FILTERED) {
00852         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
00853         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
00854     }
00855 
00856     // Position for each text element
00857     FLOAT x = 0.0f;
00858     FLOAT y = 0.0f;
00859 
00860     // Center the text block at the origin
00861     if(dwFlags & D3DFONT_CENTERED) {
00862         SIZE sz;
00863         GetTextExtent( strText, &sz );
00864         x = -(((FLOAT)sz.cx)/10.0f)/2.0f;
00865         y = -(((FLOAT)sz.cy)/10.0f)/2.0f;
00866     }
00867 
00868     // Turn off culling for two-sided text
00869     if(dwFlags & D3DFONT_TWOSIDED)
00870         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
00871 
00872     FLOAT fStartX = x;
00873     TCHAR c;
00874 
00875     // Fill vertex buffer
00876     FONT3DVERTEX* pVertices;
00877     // DWORD         dwVertex       = 0L; // not ref'ed
00878     DWORD         dwNumTriangles = 0L;
00879     m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
00880 
00881     bool bItalic = 0 != ( m_dwFontFlags & D3DFONT_ITALIC ) ; 
00882     FLOAT fBend = 0.0f ; 
00883     if(bItalic)
00884         fBend = ( ( m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f ) / 4.0f ;
00885 
00886     while(c = *strText++) {
00887         if(c == '\n') {
00888             x = fStartX;
00889             y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;
00890         }
00891         if(c < 32)
00892             continue;
00893 
00894         FLOAT tx1 = m_fTexCoords[c-32][0];
00895         FLOAT ty1 = m_fTexCoords[c-32][1];
00896         FLOAT tx2 = m_fTexCoords[c-32][2];
00897         FLOAT ty2 = m_fTexCoords[c-32][3];
00898 
00899         FLOAT w = (tx2-tx1) * m_dwTexWidth  / ( 10.0f * m_fTextScale );
00900         FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );
00901 
00902         if(c != _T(' ')) {
00903             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 );
00904             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0 + fBend ,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
00905             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
00906             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w + fBend ,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 );
00907             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
00908             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0 + fBend ,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
00909             dwNumTriangles += 2;
00910 
00911             if(dwNumTriangles*3 > (MAX_NUM_VERTICES-6)) {
00912                 // Unlock, render, and relock the vertex buffer
00913                 m_pVB->Unlock();
00914                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
00915                 m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
00916                 dwNumTriangles = 0L;
00917             }
00918         }
00919 
00920         x += w;
00921     }
00922 
00923     // Unlock and render the vertex buffer
00924     m_pVB->Unlock();
00925     if(dwNumTriangles > 0)
00926         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
00927 
00928     // Restore the modified renderstates
00929     m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
00930 
00931     return S_OK;
00932 }
00933 #endif

Generated on Fri May 2 00:37:09 2003 for Panda by doxygen1.3