/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ /////////////////////////////////////////////////////////////////////////////// // // // plDXTextFont Class Functions // // Cyan, Inc. // // // //// Version History ////////////////////////////////////////////////////////// // // // 2.19.2001 mcn - Created. // // // /////////////////////////////////////////////////////////////////////////////// #include "hsConfig.h" #include "hsWindows.h" #include #include #include #if HS_BUILD_FOR_MAC #include #endif #include "hsWinRef.h" #include "hsTypes.h" #include "plDXTextFont.h" #include "plDXPipeline.h" //// Local Stuff ////////////////////////////////////////////////////////////// static const long PLD3D_FONTFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0); static D3DXMATRIX d3dIdentityMatrix( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); // Following number needs to be at least: 64 chars max in plTextFont drawn at any one time // * 4 primitives per char max (for bold text) // * 3 verts per primitive //const UInt32 kNumVertsInBuffer(32768); const UInt32 kNumVertsInBuffer(4608); // See the declaration for plFontVertex in plTextFont.h for info const DWORD plDXTextFont::kFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0); IDirect3DVertexBuffer9* plDXTextFont::fBuffer = nil; UInt32 plDXTextFont::fBufferCursor = 0; //// Constructor & Destructor ///////////////////////////////////////////////// plDXTextFont::plDXTextFont( plPipeline *pipe, IDirect3DDevice9 *device ) : plTextFont( pipe ) { fDevice = device; fD3DTexture = nil; fOldStateBlock = fTextStateBlock = 0; } plDXTextFont::~plDXTextFont() { DestroyObjects(); } //// ICreateTexture /////////////////////////////////////////////////////////// void plDXTextFont::ICreateTexture( UInt16 *data ) { HRESULT hr; D3DLOCKED_RECT lockInfo; D3DCAPS9 d3dCaps; // Check to make sure we can support it fDevice->GetDeviceCaps( &d3dCaps ); hsAssert( fTextureWidth <= d3dCaps.MaxTextureWidth, "Cannot initialize DX font--texture size too big" ); // Create our texture object hr = fDevice->CreateTexture( fTextureWidth, fTextureHeight, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &fD3DTexture, NULL ); hsAssert( !FAILED( hr ), "Cannot create D3D texture" ); // Lock the texture and write our values out fD3DTexture->LockRect( 0, &lockInfo, 0, 0 ); memcpy( lockInfo.pBits, data, fTextureWidth * fTextureHeight * sizeof( UInt16 ) ); fD3DTexture->UnlockRect( nil ); } void plDXTextFont::CreateShared(IDirect3DDevice9* device) { if( FAILED( device->CreateVertexBuffer( sizeof( plFontVertex ) * kNumVertsInBuffer, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &fBuffer, NULL ) ) ) { hsAssert( false, "CreateVertexBuffer() call failed!" ); } } void plDXTextFont::ReleaseShared(IDirect3DDevice9* device) { ReleaseObject( fBuffer ); } //// IInitStateBlocks ///////////////////////////////////////////////////////// void plDXTextFont::IInitStateBlocks( void ) { for( int i = 0; i < 2; i++ ) { fDevice->BeginStateBlock(); fDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); fDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); fDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); fDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ); fDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 ); fDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL ); fDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); fDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); fDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); fDevice->SetRenderState( D3DRS_ZFUNC, D3DCMP_ALWAYS ); fDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE ); fDevice->SetRenderState( D3DRS_DEPTHBIAS, 0 ); fDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE ); fDevice->SetRenderState( D3DRS_CLIPPING, TRUE ); fDevice->SetRenderState( D3DRS_ANTIALIASEDLINEENABLE, FALSE ); fDevice->SetRenderState( D3DRS_VERTEXBLEND, FALSE ); fDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE ); fDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); fDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); fDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); fDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); fDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); fDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); fDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); fDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT ); fDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT ); fDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE ); fDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); fDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 ); fDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); fDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); fDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); if( i == 0 ) fDevice->EndStateBlock( &fOldStateBlock ); else fDevice->EndStateBlock( &fTextStateBlock ); } } //// DestroyObjects /////////////////////////////////////////////////////////// void plDXTextFont::DestroyObjects() { ReleaseObject(fOldStateBlock); ReleaseObject(fTextStateBlock); ReleaseObject(fD3DTexture); fOldStateBlock = fTextStateBlock = 0; fD3DTexture = nil; fInitialized = false; } //// IDrawPrimitive /////////////////////////////////////////////////////////// void plDXTextFont::IDrawPrimitive( UInt32 count, plFontVertex *array ) { plFontVertex *v; if( !fBuffer ) return; /// Lock the buffer and write to it if( fBufferCursor && (fBufferCursor + count * 3 < kNumVertsInBuffer) ) { // We can lock part of it if( FAILED( fBuffer->Lock( fBufferCursor * sizeof( plFontVertex ), count * 3 * sizeof( plFontVertex ), (void **)&v, D3DLOCK_NOOVERWRITE ) ) ) { hsAssert( false, "Failed to lock vertex buffer for writing" ); return; } fBufferCursor += count * 3; } else { // Gotta start over FlushDraws(); fBufferCursor = count * 3; if( FAILED( fBuffer->Lock( 0, count * 3 * sizeof( plFontVertex ), (void **)&v, D3DLOCK_DISCARD ) ) ) { hsAssert( false, "Failed to lock vertex buffer for writing" ); return; } } if( v != nil && array != nil ) { memcpy( v, array, count * sizeof( plFontVertex ) * 3 ); } fBuffer->Unlock(); } //// IDrawLines /////////////////////////////////////////////////////////////// void plDXTextFont::IDrawLines( UInt32 count, plFontVertex *array ) { if( !fBuffer ) return; if( count == 0 || array == nil ) return; fDevice->SetVertexShader(NULL); fDevice->SetFVF(kFVF); fDevice->SetStreamSource(0, fBuffer, 0, sizeof(plFontVertex)); fDevice->DrawPrimitiveUP( D3DPT_LINELIST, count, (const void *)array, sizeof( plFontVertex ) ); } //// FlushDraws /////////////////////////////////////////////////////////////// // Flushes out and finishes any drawing left to be done. void plDXTextFont::FlushDraws( void ) { if( !fBuffer ) return; if( fBufferCursor > 0 ) { fDevice->SetVertexShader( NULL ); fDevice->SetFVF(kFVF); fDevice->SetStreamSource( 0, fBuffer, 0, sizeof( plFontVertex ) ); fDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, fBufferCursor / 3 ); fBufferCursor = 0; } } //// SaveStates /////////////////////////////////////////////////////////////// void plDXTextFont::SaveStates( void ) { if( !fInitialized ) IInitObjects(); if (fOldStateBlock) fOldStateBlock->Capture(); if (fTextStateBlock) fTextStateBlock->Apply(); fDevice->SetTexture( 0, fD3DTexture ); fDevice->SetTransform( D3DTS_TEXTURE0, &d3dIdentityMatrix ); /// Set up the transform matrices so that the vertices can range (0-screenWidth,0-screenHeight) fDevice->SetTransform( D3DTS_WORLD, &d3dIdentityMatrix ); fDevice->SetTransform( D3DTS_VIEW, &d3dIdentityMatrix ); D3DXMATRIX mat; mat = d3dIdentityMatrix; mat(0,0) = 2.0f / (float)fPipe->Width(); mat(1,1) = -2.0f / (float)fPipe->Height(); mat(3,0) = -1.0; mat(3,1) = 1.0; fDevice->SetTransform( D3DTS_PROJECTION, &mat ); } //// RestoreStates //////////////////////////////////////////////////////////// void plDXTextFont::RestoreStates( void ) { if (fOldStateBlock) fOldStateBlock->Apply(); fDevice->SetTexture( 0, nil ); fDevice->SetTransform( D3DTS_TEXTURE0, &d3dIdentityMatrix ); }