From b63d9bed718e77830d7960cb83ad0e2a77c6c5c9 Mon Sep 17 00:00:00 2001 From: cxgeorge <> Date: Thu, 28 Mar 2002 06:13:32 +0000 Subject: [PATCH] update resize stuff, add d3dfont --- panda/src/dxgsg8/Sources.pp | 4 +- panda/src/dxgsg8/d3dfont8.cxx | 633 ++++++++++++++++++ panda/src/dxgsg8/d3dfont8.h | 70 ++ panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 79 ++- panda/src/dxgsg8/dxGraphicsStateGuardian8.h | 18 +- panda/src/dxgsg8/dxgsg8_composite1.cxx | 1 + panda/src/dxgsg8/dxgsg8base.h | 3 + 7 files changed, 781 insertions(+), 27 deletions(-) create mode 100644 panda/src/dxgsg8/d3dfont8.cxx create mode 100644 panda/src/dxgsg8/d3dfont8.h diff --git a/panda/src/dxgsg8/Sources.pp b/panda/src/dxgsg8/Sources.pp index a867fb66d9..662f44e579 100644 --- a/panda/src/dxgsg8/Sources.pp +++ b/panda/src/dxgsg8/Sources.pp @@ -15,7 +15,7 @@ // need to install these due to external projects that link directly with libpandadx (bartop) #define INSTALL_HEADERS \ dxgsg8base.h config_dxgsg8.h dxGraphicsStateGuardian8.I dxGraphicsStateGuardian8.h \ - dxTextureContext8.h dxGeomNodeContext8.h dxGeomNodeContext8.I + dxTextureContext8.h dxGeomNodeContext8.h dxGeomNodeContext8.I d3dfont8.h // build dxGraphicsStateGuardian separately since its so big @@ -23,6 +23,6 @@ dxGraphicsStateGuardian8.cxx dxSavedFrameBuffer8.I dxSavedFrameBuffer8.h $[INSTALL_HEADERS] #define INCLUDED_SOURCES \ - config_dxgsg8.cxx dxSavedFrameBuffer8.cxx dxTextureContext8.cxx dxGeomNodeContext8.cxx + config_dxgsg8.cxx dxSavedFrameBuffer8.cxx dxTextureContext8.cxx dxGeomNodeContext8.cxx d3dfont8.cxx #end lib_target diff --git a/panda/src/dxgsg8/d3dfont8.cxx b/panda/src/dxgsg8/d3dfont8.cxx new file mode 100644 index 0000000000..0b3c39ffb7 --- /dev/null +++ b/panda/src/dxgsg8/d3dfont8.cxx @@ -0,0 +1,633 @@ +//----------------------------------------------------------------------------- +// File: D3DFont.cpp +// +// Desc: Texture-based font class +// +//----------------------------------------------------------------------------- + +#ifndef STRICT +#define STRICT +#endif + +#include "dxgsg8base.h" +#include +#include +#include +#include "d3dfont8.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( TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags ) { + _tcscpy( m_strFontName, strFontName ); + m_dwFontHeight = dwHeight; + m_dwFontFlags = dwFlags; + + m_pd3dDevice = NULL; + m_pTexture = NULL; + m_pVB = NULL; + + m_dwSavedStateBlock = 0L; + m_dwDrawTextStateBlock = 0L; +} + +//----------------------------------------------------------------------------- +// 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( LPDIRECT3DDEVICE8 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 > 40) + m_dwTexWidth = m_dwTexHeight = 1024; + else if(m_dwFontHeight > 20) + 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. + D3DCAPS8 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 ); + if(FAILED(hr)) { + cout << "CD3DFONT CreateTexture failed!" << D3DERRORSTRING(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) { + cout << "CD3DFONT CreateFont failed!\n"; + 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; + + for(TCHAR c=32; c<127; c++) { + str[0] = c; + GetTextExtentPoint32( hDC, str, 1, &size ); + + if((DWORD)(x+size.cx+1) > m_dwTexWidth) { + x = 0; + 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_dwTexWidth; + m_fTexCoords[c-32][1] = ((FLOAT)(y+0))/m_dwTexHeight; + m_fTexCoords[c-32][2] = ((FLOAT)(x+0+size.cx))/m_dwTexWidth; + m_fTexCoords[c-32][3] = ((FLOAT)(y+0+size.cy))/m_dwTexHeight; + + x += size.cx+1; + } + + // 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++ = (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 RestoreDeviceObjects(); +} + +//----------------------------------------------------------------------------- +// Name: RestoreDeviceObjects() +// Desc: +//----------------------------------------------------------------------------- +HRESULT CD3DFont::RestoreDeviceObjects(void) { + HRESULT hr; + + // Create vertex buffer for the letters + if(FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), + D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, + D3DPOOL_DEFAULT, &m_pVB ) )) { + cout << "CD3DFONT::RestoreDevObjs() CreateVB failed!" << D3DERRORSTRING(hr); + 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_EDGEANTIALIAS, FALSE ); + m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, FALSE ); + m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, FALSE ); + m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE ); + m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); + 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_MINFILTER, D3DTEXF_POINT ); + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT ); + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE ); + 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 ); + + if(which==0) + m_pd3dDevice->EndStateBlock( &m_dwSavedStateBlock ); + else + m_pd3dDevice->EndStateBlock( &m_dwDrawTextStateBlock ); + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: InvalidateDeviceObjects() +// Desc: Destroys all device-dependent objects +//----------------------------------------------------------------------------- +HRESULT CD3DFont::InvalidateDeviceObjects() { + SAFE_RELEASE( m_pVB ); + + // Delete the state blocks + if(IS_VALID_PTR(m_pd3dDevice)) { + if(m_dwSavedStateBlock) + m_pd3dDevice->DeleteStateBlock( m_dwSavedStateBlock ); + if(m_dwDrawTextStateBlock) + m_pd3dDevice->DeleteStateBlock( m_dwDrawTextStateBlock ); + } + + m_dwSavedStateBlock = NULL; + m_dwDrawTextStateBlock = NULL; + + 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( 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 < _T(' ')) + continue; + + FLOAT tx1 = m_fTexCoords[c-32][0]; + FLOAT tx2 = m_fTexCoords[c-32][2]; + + fRowWidth += (tx2-tx1)*m_dwTexWidth; + + 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, + TCHAR* strText, DWORD dwFlags ) { + if(m_pd3dDevice == NULL) + return E_FAIL; + + // Set up renderstate + m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock ); + m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock ); + m_pd3dDevice->SetVertexShader( D3DFVF_FONT2DVERTEX ); + m_pd3dDevice->SetPixelShader( NULL ); + m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT2DVERTEX) ); + + // Set filter states + if(dwFlags & D3DFONT_FILTERED) { + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); + } + + D3DVIEWPORT8 vp; + m_pd3dDevice->GetViewport( &vp ); + FLOAT sx = (x+1.0f)*vp.Width/2; + FLOAT sy = (y+1.0f)*vp.Height/2; + FLOAT sz = z; + FLOAT rhw = 1.0f; + FLOAT fStartX = sx; + + FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight; + + // Fill vertex buffer + FONT2DVERTEX* pVertices; + DWORD dwNumTriangles = 0L; + m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD ); + + while(*strText) { + TCHAR c = *strText++; + + if(c == _T('\n')) { + sx = fStartX; + sy += fYScale*vp.Height; + } + if(c < _T(' ')) + 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.Width)/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, (BYTE**)&pVertices, D3DLOCK_DISCARD ); + dwNumTriangles = 0L; + } + } + + sx += w; + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if(dwNumTriangles > 0) + m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles ); + + // Restore the modified renderstates + m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock ); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: DrawText() +// Desc: Draws 2D text +//----------------------------------------------------------------------------- +HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor, + TCHAR* strText, DWORD dwFlags ) { + if(m_pd3dDevice == NULL) + return E_FAIL; + + // Setup renderstate + m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock ); + m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock ); + m_pd3dDevice->SetVertexShader( D3DFVF_FONT2DVERTEX ); + m_pd3dDevice->SetPixelShader( NULL ); + m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT2DVERTEX) ); + + // Set filter states + if(dwFlags & D3DFONT_FILTERED) { + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); + } + + FLOAT fStartX = sx; + + // Fill vertex buffer + FONT2DVERTEX* pVertices = NULL; + DWORD dwNumTriangles = 0; + m_pVB->Lock( 0, 0, (BYTE**)&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 < _T(' ')) + 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, (BYTE**)&pVertices, D3DLOCK_DISCARD ); + dwNumTriangles = 0L; + } + } + + sx += w; + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if(dwNumTriangles > 0) + m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles ); + + // Restore the modified renderstates + m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock ); + + return S_OK; +} + + +/* + +//----------------------------------------------------------------------------- +// Name: Render3DText() +// Desc: Renders 3D text +//----------------------------------------------------------------------------- +HRESULT CD3DFont::Render3DText( TCHAR* strText, DWORD dwFlags ) +{ + if( m_pd3dDevice == NULL ) + return E_FAIL; + + // Setup renderstate + m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock ); + m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock ); + m_pd3dDevice->SetVertexShader( D3DFVF_FONT3DVERTEX ); + m_pd3dDevice->SetPixelShader( NULL ); + m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT3DVERTEX) ); + + // Set filter states + if( dwFlags & D3DFONT_FILTERED ) + { + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); + } + + // Position for each text element + FLOAT x = 0.0f; + FLOAT y = 0.0f; + + // Center the text block at the origin + if( dwFlags & D3DFONT_CENTERED ) + { + SIZE sz; + GetTextExtent( strText, &sz ); + x = -(((FLOAT)sz.cx)/10.0f)/2.0f; + 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 ); + + FLOAT fStartX = x; + TCHAR c; + + // Fill vertex buffer + FONT3DVERTEX* pVertices; + DWORD dwVertex = 0L; + DWORD dwNumTriangles = 0L; + m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD ); + + while( c = *strText++ ) + { + if( c == '\n' ) + { + x = fStartX; + y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f; + } + if( c < 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, (BYTE**)&pVertices, D3DLOCK_DISCARD ); + dwNumTriangles = 0L; + } + } + + x += w; + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if( dwNumTriangles > 0 ) + m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles ); + + // Restore the modified renderstates + m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock ); + + return S_OK; +} +*/ diff --git a/panda/src/dxgsg8/d3dfont8.h b/panda/src/dxgsg8/d3dfont8.h new file mode 100644 index 0000000000..785b846e31 --- /dev/null +++ b/panda/src/dxgsg8/d3dfont8.h @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// File: D3DFont.h +// +// Desc: Texture-based font class +//----------------------------------------------------------------------------- +#ifndef D3DFONT_H +#define D3DFONT_H +#include +#include + + +// Font creation flags +#define D3DFONT_BOLD 0x0001 +#define D3DFONT_ITALIC 0x0002 +#define D3DFONT_ZENABLE 0x0004 + +// Font rendering flags +#define D3DFONT_CENTERED 0x0001 +#define D3DFONT_TWOSIDED 0x0002 +#define D3DFONT_FILTERED 0x0004 + + +//----------------------------------------------------------------------------- +// Name: class CD3DFont +// Desc: Texture-based font class for doing text in a 3D scene. +//----------------------------------------------------------------------------- +class CD3DFont +{ + TCHAR m_strFontName[80]; // Font properties + DWORD m_dwFontHeight; + DWORD m_dwFontFlags; + + LPDIRECT3DDEVICE8 m_pd3dDevice; // A D3DDevice used for rendering + LPDIRECT3DTEXTURE8 m_pTexture; // The d3d texture for this font + LPDIRECT3DVERTEXBUFFER8 m_pVB; // VertexBuffer for rendering text + DWORD m_dwTexWidth; // Texture dimensions + DWORD m_dwTexHeight; + FLOAT m_fTextScale; + FLOAT m_fTexCoords[128-32][4]; + + // Stateblocks for setting and restoring render states + DWORD m_dwSavedStateBlock; + DWORD m_dwDrawTextStateBlock; + +public: + // 2D and 3D text drawing functions + HRESULT DrawText( FLOAT x, FLOAT y, DWORD dwColor, + TCHAR* strText, DWORD dwFlags=0L ); + HRESULT DrawTextScaled( FLOAT x, FLOAT y, FLOAT z, + FLOAT fXScale, FLOAT fYScale, DWORD dwColor, + TCHAR* strText, DWORD dwFlags=0L ); +// HRESULT Render3DText( TCHAR* strText, DWORD dwFlags=0L ); + + // Function to get extent of text + HRESULT GetTextExtent( TCHAR* strText, SIZE* pSize ); + + // Initializing and destroying device-dependent objects + HRESULT InitDeviceObjects( LPDIRECT3DDEVICE8 pd3dDevice ); + HRESULT RestoreDeviceObjects(void); + HRESULT InvalidateDeviceObjects(void); + HRESULT DeleteDeviceObjects(void); + + // Constructor / destructor + CD3DFont( TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags=0L ); + ~CD3DFont(); +}; + +#endif + + diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index b125c3e24b..529ae10049 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -272,6 +272,7 @@ set_color_clear_value(const Colorf& value) { _d3dcolor_clear_value = Colorf_to_D3DCOLOR(value); } +#if 0 void DXGraphicsStateGuardian::SetFPSMeterPosition(void) { if(_fpsmeter_verts==NULL) return; @@ -339,7 +340,6 @@ void DXGraphicsStateGuardian::SetFPSMeterPosition(void) { } void DXGraphicsStateGuardian::FillFPSMeterTexture(void) { -/* assert(_fpsmeter_font_surf!=NULL); HRESULT hr; @@ -412,8 +412,9 @@ void DXGraphicsStateGuardian::FillFPSMeterTexture(void) { } #endif _fpsmeter_font_surf->Unlock(NULL); -*/ } +#endif + void DXGraphicsStateGuardian:: reset_panda_gsg(void) { @@ -455,18 +456,19 @@ DXGraphicsStateGuardian(GraphicsWindow *win) : GraphicsStateGuardian(win) { // allocate local buffers used during rendering ZeroMemory(&scrn,sizeof(DXScreenData)); - _bShowFPSMeter = false; _bDXisReady = false; _pFvfBufBasePtr = NULL; _index_buf=NULL; - _fpsmeter_verts=NULL; _light_enabled = NULL; _cur_light_enabled = NULL; _clip_plane_enabled = (bool *)NULL; _cur_clip_plane_enabled = (bool *)NULL; - _fpsmeter_font_surf=NULL; +// _fpsmeter_verts=NULL; +// _fpsmeter_font_surf=NULL; + _pFPSFont=NULL; + _bShowFPSMeter = false; _max_light_range = __D3DLIGHT_RANGE_MAX; @@ -874,6 +876,16 @@ dx_init(HCURSOR hMouseCursor) { if(FAILED(hr)) dxgsg_cat.error() << "CreateDX8Cursor failed!\n"; + if(_bShowFPSMeter) { + assert(_pFPSFont == NULL); + _pFPSFont = new CD3DFont(_T("Arial"),12,0x0); + assert(IS_VALID_PTR(_pFPSFont)); + hr=_pFPSFont->InitDeviceObjects(scrn.pD3DDevice); + if(FAILED(hr)) { + _bShowFPSMeter=false; + } + } + // comment out FPS meter stuff for the moment #if 0 // need to release this better, so dx_init can be called multiple times @@ -5583,7 +5595,7 @@ void DXGraphicsStateGuardian:: free_pointers() { SAFE_DELETE_ARRAY(_index_buf); SAFE_DELETE_ARRAY(_pFvfBufBasePtr); - SAFE_DELETE_ARRAY(_fpsmeter_verts); +// SAFE_DELETE_ARRAY(_fpsmeter_verts); SAFE_DELETE_ARRAY(_cur_clip_plane_enabled); SAFE_DELETE_ARRAY(_clip_plane_enabled); SAFE_DELETE_ARRAY(_cur_light_enabled); @@ -5794,20 +5806,17 @@ bool recreate_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) { // release all textures and vertex/index buffers HRESULT DXGraphicsStateGuardian::DeleteAllDeviceObjects(void) { - // BUGBUG: need to handle vertexbuffer handling here + // BUGBUG: need to release any vertexbuffers here // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it traverse_prepared_textures(delete_tex_callback,this); -#if 0 - ULONG refcnt; - - if(_bShowFPSMeter) - RELEASE(_fpsmeter_font_surf,dxgsg,"fpsmeter fontsurf",false); -#endif - if(dxgsg_cat.is_debug()) dxgsg_cat.debug() << "release of all textures complete\n"; + + if(IS_VALID_PTR(_pFPSFont)) { + _pFPSFont->DeleteDeviceObjects(); + } return S_OK; } @@ -5815,6 +5824,10 @@ HRESULT DXGraphicsStateGuardian::DeleteAllDeviceObjects(void) { HRESULT DXGraphicsStateGuardian::RecreateAllDeviceObjects(void) { // BUGBUG: need to handle vertexbuffer handling here + if(IS_VALID_PTR(_pFPSFont)) { + _pFPSFont->RestoreDeviceObjects(); + } + // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it traverse_prepared_textures(recreate_tex_callback,this); @@ -5824,7 +5837,11 @@ HRESULT DXGraphicsStateGuardian::RecreateAllDeviceObjects(void) { } HRESULT DXGraphicsStateGuardian::ReleaseAllDeviceObjects(void) { - // release any D3DPOOL_DEFAULT objects + // release any D3DPOOL_DEFAULT objects here (currently none) + + if(IS_VALID_PTR(_pFPSFont)) { + _pFPSFont->InvalidateDeviceObjects(); + } return S_OK; } @@ -5848,7 +5865,8 @@ HRESULT DXGraphicsStateGuardian::RestoreAllDeviceObjects(void) { // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it // traverse_prepared_textures(refill_tex_callback,this); -// if(_bShowFPSMeter) + if(IS_VALID_PTR(_pFPSFont)) + _pFPSFont->RestoreDeviceObjects(); // FillFPSMeterTexture(); if(dxgsg_cat.is_debug()) @@ -5966,6 +5984,19 @@ void DXGraphicsStateGuardian::show_windowed_frame(void) { } */ +HRESULT DXGraphicsStateGuardian::reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams) { + HRESULT hr; + + ReleaseAllDeviceObjects(); + + hr=scrn.pD3DDevice->Reset(pPresParams); + if(SUCCEEDED(hr)) { + if(pPresParams!=&scrn.PresParams) + memcpy(&scrn.PresParams,pPresParams,sizeof(D3DPRESENT_PARAMETERS)); + } + return hr; +} + bool DXGraphicsStateGuardian::CheckCooperativeLevel(bool bDoReactivateWindow) { HRESULT hr = scrn.pD3DDevice->TestCooperativeLevel(); @@ -5977,13 +6008,23 @@ bool DXGraphicsStateGuardian::CheckCooperativeLevel(bool bDoReactivateWindow) { switch(hr) { case D3DERR_DEVICENOTRESET: _bDXisReady = false; - ReleaseAllDeviceObjects(); - hr=scrn.pD3DDevice->Reset(&scrn.PresParams); + hr=reset_d3d_device(&scrn.PresParams); + if(FAILED(hr)) { + // I think this shouldnt fail unless I've screwed up the PresParams from the original working ones somehow + dxgsg_cat.error() << "CheckCooperativeLevel Reset() failed, hr = " << D3DERRORSTRING(hr); + exit(1); + } + if(bDoReactivateWindow) _win->reactivate_window(); //must reactivate window before you can restore surfaces (otherwise you are in WRONGVIDEOMODE, and DDraw RestoreAllSurfaces fails) RestoreAllDeviceObjects(); hr = scrn.pD3DDevice->TestCooperativeLevel(); - assert(SUCCEEDED(hr)); + if(FAILED(hr)) { + // internal chk, shouldnt fail + dxgsg_cat.error() << "TestCooperativeLevel following Reset() failed, hr = " << D3DERRORSTRING(hr); + exit(1); + } + break; case D3DERR_DEVICELOST: diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index b16ae29dca..091926aa30 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -41,6 +41,8 @@ #include "dxgsg8base.h" #include "dxGeomNodeContext8.h" #include "dxTextureContext8.h" +#include "d3dfont8.h" + #include class PlaneNode; @@ -370,14 +372,17 @@ protected: DWORD _start_frame_count; DWORD _cur_frame_count; float _current_fps; - DWORD *_fpsmeter_verts; - DWORD _fpsmeter_fvfflags; +// DWORD *_fpsmeter_verts; +// DWORD _fpsmeter_fvfflags; // LPDIRECTDRAWSURFACE7 _fpsmeter_font_surf; - void *_fpsmeter_font_surf; - float _fps_u_usedwidth,_fps_v_usedheight; // fraction of fps font texture actually used - DWORD _fps_vertexsize; // size of verts used to render fps meter +// void *_fpsmeter_font_surf; +// float _fps_u_usedwidth,_fps_v_usedheight; // fraction of fps font texture actually used +// DWORD _fps_vertexsize; // size of verts used to render fps meter +// void FillFPSMeterTexture(void); + ::CD3DFont *_pFPSFont; + void SetFPSMeterPosition(void); - void FillFPSMeterTexture(void); + public: static GraphicsStateGuardian* @@ -393,6 +398,7 @@ public: void dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled); void reset_panda_gsg(void); + HRESULT reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams); #define DO_REACTIVATE_WINDOW true bool CheckCooperativeLevel(bool bDoReactivateWindow = false); diff --git a/panda/src/dxgsg8/dxgsg8_composite1.cxx b/panda/src/dxgsg8/dxgsg8_composite1.cxx index e29eaeed22..b73e8772fe 100644 --- a/panda/src/dxgsg8/dxgsg8_composite1.cxx +++ b/panda/src/dxgsg8/dxgsg8_composite1.cxx @@ -2,3 +2,4 @@ #include "dxSavedFrameBuffer8.cxx" #include "dxTextureContext8.cxx" #include "dxGeomNodeContext8.cxx" +#include "d3dfont8.cxx" diff --git a/panda/src/dxgsg8/dxgsg8base.h b/panda/src/dxgsg8/dxgsg8base.h index bcbca557d0..4fdba1f9cb 100644 --- a/panda/src/dxgsg8/dxgsg8base.h +++ b/panda/src/dxgsg8/dxgsg8base.h @@ -72,6 +72,9 @@ #define SAFE_DELETE(p) { if(p) { assert(IS_VALID_PTR(p)); delete (p); (p)=NULL; } } #define SAFE_DELETE_ARRAY(p) { if(p) { assert(IS_VALID_PTR(p)); delete[] (p); (p)=NULL; } } +// for stuff outside a panda class +#define SAFE_RELEASE(p) { if(p) { assert(IS_VALID_PTR(p)); (p)->Release(); (p)=NULL; } } + // this is bDoDownToZero argument to RELEASE() #define RELEASE_DOWN_TO_ZERO true #define RELEASE_ONCE false