?? d3dfont.cpp
字號(hào):
//-----------------------------------------------------------------------------
// File: D3DFont.cpp
//
// Desc: Texture-based font class
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#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: CreateGDIFont
// Desc: Create a font based on the current state of related member variables
// and return the handle (or null on error)
//-----------------------------------------------------------------------------
HRESULT CD3DFont::CreateGDIFont( HDC hDC, HFONT* pFont )
{
// 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;
*pFont = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
VARIABLE_PITCH, m_strFontName );
if( *pFont == NULL )
return E_FAIL;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: PaintAlphabet
// Desc: Paint the printable characters for the given GDI font onto the
// provided device context. If the bMeasureOnly flag is set, no drawing
// will occur.
//-----------------------------------------------------------------------------
HRESULT CD3DFont::PaintAlphabet( HDC hDC, BOOL bMeasureOnly )
{
SIZE size;
TCHAR str[2] = _T("x"); // One-character, null-terminated string
// Calculate the spacing between characters based on line height
if( 0 == GetTextExtentPoint32( hDC, str, 1, &size ) )
return E_FAIL;
m_dwSpacing = (DWORD) ceil(size.cy * 0.3f);
// Set the starting point for the drawing
DWORD x = m_dwSpacing;
DWORD y = 0;
// For each character, draw text on the DC and advance the current position
for( char c = 32; c < 127; c++ )
{
str[0] = c;
if( 0 == GetTextExtentPoint32( hDC, str, 1, &size ) )
return E_FAIL;
if( (DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth )
{
x = m_dwSpacing;
y += size.cy + 1;
}
// Check to see if there's room to write the character here
if( y + size.cy > m_dwTexHeight )
return D3DERR_MOREDATA;
if( !bMeasureOnly )
{
// Perform the actual drawing
if( 0 == ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL ) )
return E_FAIL;
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);
}
return S_OK;
}
//-----------------------------------------------------------------------------
// 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 = S_OK;
HFONT hFont = NULL;
HFONT hFontOld = NULL;
HDC hDC = NULL;
HBITMAP hbmBitmap = NULL;
HGDIOBJ hbmOld = NULL;
// Keep a local copy of the device
m_pd3dDevice = pd3dDevice;
// Assume we will draw fonts into texture without scaling unless the
// required texture size is found to be larger than the device max
m_fTextScale = 1.0f;
hDC = CreateCompatibleDC( NULL );
SetMapMode( hDC, MM_TEXT );
hr = CreateGDIFont( hDC, &hFont );
if( FAILED(hr) )
goto LCleanReturn;
hFontOld = (HFONT) SelectObject( hDC, hFont );
// Calculate the dimensions for the smallest power-of-two texture which
// can hold all the printable characters
m_dwTexWidth = m_dwTexHeight = 128;
while( D3DERR_MOREDATA == ( hr = PaintAlphabet( hDC, true ) ) )
{
m_dwTexWidth *= 2;
m_dwTexHeight *= 2;
}
if( FAILED(hr) )
goto LCleanReturn;
// 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;
bool bFirstRun = true; // Flag clear after first run
do
{
// If we've already tried fitting the new text, the scale is still
// too large. Reduce and try again.
if( !bFirstRun)
m_fTextScale *= 0.9f;
// The font has to be scaled to fit on the maximum texture size; our
// current font is too big and needs to be recreated to scale.
DeleteObject( SelectObject( hDC, hFontOld ) );
hr = CreateGDIFont( hDC, &hFont );
if( FAILED(hr) )
goto LCleanReturn;
hFontOld = (HFONT) SelectObject( hDC, hFont );
bFirstRun = false;
}
while( D3DERR_MOREDATA == ( hr = PaintAlphabet( hDC, true ) ) );
}
// 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) )
goto LCleanReturn;
// 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 bitmap for the font
hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
(void**)&pBitmapBits, NULL, 0 );
hbmOld = SelectObject( hDC, hbmBitmap );
// Set text properties
SetTextColor( hDC, RGB(255,255,255) );
SetBkColor( hDC, 0x00000000 );
SetTextAlign( hDC, TA_TOP );
// Paint the alphabet onto the selected bitmap
hr = PaintAlphabet( hDC, false );
if( FAILED(hr) )
goto LCleanReturn;
// Lock the surface and write the alpha values for the set pixels
D3DLOCKED_RECT d3dlr;
m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
BYTE* pDstRow;
pDstRow = (BYTE*)d3dlr.pBits;
WORD* pDst16;
BYTE bAlpha; // 4-bit measure of pixel intensity
DWORD x, y;
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;
}
hr = S_OK;
// Done updating texture, so clean up used objects
LCleanReturn:
if( m_pTexture )
m_pTexture->UnlockRect(0);
SelectObject( hDC, hbmOld );
SelectObject( hDC, hFontOld );
DeleteObject( hbmBitmap );
DeleteObject( hFont );
DeleteDC( hDC );
return hr;
}
//-----------------------------------------------------------------------------
// 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;
}
bool bSupportsAlphaBlend = true;
LPDIRECT3D9 pd3d9 = NULL;
if( SUCCEEDED( m_pd3dDevice->GetDirect3D( &pd3d9 ) ) )
{
D3DCAPS9 Caps;
D3DDISPLAYMODE Mode;
LPDIRECT3DSURFACE9 pSurf = NULL;
D3DSURFACE_DESC Desc;
m_pd3dDevice->GetDeviceCaps( &Caps );
m_pd3dDevice->GetDisplayMode( 0, &Mode );
if( SUCCEEDED( m_pd3dDevice->GetRenderTarget( 0, &pSurf ) ) )
{
pSurf->GetDesc( &Desc );
if( FAILED( pd3d9->CheckDeviceFormat( Caps.AdapterOrdinal, Caps.DeviceType, Mode.Format,
D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_SURFACE,
Desc.Format ) ) )
{
bSupportsAlphaBlend = false;
}
SAFE_RELEASE( pSurf );
}
SAFE_RELEASE( pd3d9 );
}
// 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 );
if( bSupportsAlphaBlend )
{
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
}
else
{
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
}
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;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -