You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
11 KiB

/*==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 <http://www.gnu.org/licenses/>.
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 <d3d9.h>
#include <ddraw.h>
#include <d3dx9mesh.h>
#if HS_BUILD_FOR_MAC
#include <QuickDraw.h>
#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 );
}