Initial commit
This commit is contained in:
503
Minecraft.Client/Xbox/Font/XUI_Font.cpp
Normal file
503
Minecraft.Client/Xbox/Font/XUI_Font.cpp
Normal file
@@ -0,0 +1,503 @@
|
||||
#include "stdafx.h"
|
||||
#include "..\..\Tesselator.h"
|
||||
#include "XUI_FontData.h"
|
||||
#include "XUI_Font.h"
|
||||
|
||||
extern IDirect3DDevice9 *g_pD3DDevice;
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: XUI_Font()
|
||||
// Desc: Constructor
|
||||
//--------------------------------------------------------------------------------------
|
||||
XUI_Font::XUI_Font(int iFontData, float scaleFactor, XUI_FontData *fontData)
|
||||
: m_iFontData(iFontData), m_fScaleFactor(scaleFactor)
|
||||
{
|
||||
m_fontData = fontData;
|
||||
refCount = 0;
|
||||
|
||||
m_fCursorX = 0.0f;
|
||||
m_fCursorY = 0.0f;
|
||||
|
||||
m_fXScaleFactor = m_fYScaleFactor = scaleFactor;
|
||||
|
||||
m_fSlantFactor = 0.0f;
|
||||
m_bRotate = FALSE;
|
||||
m_dRotCos = cos( 0.0 );
|
||||
m_dRotSin = sin( 0.0 );
|
||||
|
||||
m_dwNestedBeginCount = 0L;
|
||||
|
||||
// Initialize the window
|
||||
D3DDISPLAYMODE DisplayMode;
|
||||
g_pD3DDevice->GetDisplayMode( 0, &DisplayMode );
|
||||
m_rcWindow.x1 = 0;
|
||||
m_rcWindow.y1 = 0;
|
||||
m_rcWindow.x2 = DisplayMode.Width;
|
||||
m_rcWindow.y2 = DisplayMode.Height;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: ~XUI_Font()
|
||||
// Desc: Destructor
|
||||
//--------------------------------------------------------------------------------------
|
||||
XUI_Font::~XUI_Font()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: GetTextExtent()
|
||||
// Desc: Get the dimensions of a text string
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
VOID XUI_Font::GetTextExtent( const WCHAR* strText, FLOAT* pWidth,
|
||||
FLOAT* pHeight, BOOL bFirstLineOnly ) const
|
||||
{
|
||||
assert( pWidth != NULL );
|
||||
assert( pHeight != NULL );
|
||||
|
||||
// Set default text extent in output parameters
|
||||
int iWidth = 0;
|
||||
FLOAT fHeight = 0.0f;
|
||||
|
||||
if( strText )
|
||||
{
|
||||
// Initialize counters that keep track of text extent
|
||||
int ix = 0;
|
||||
FLOAT fy = m_fontData->getFontHeight(); // One character high to start
|
||||
if( fy > fHeight )
|
||||
fHeight = fy;
|
||||
|
||||
// Loop through each character and update text extent
|
||||
DWORD letter;
|
||||
while( (letter = *strText) != 0 )
|
||||
{
|
||||
++strText;
|
||||
|
||||
// Handle newline character
|
||||
if( letter == L'\n' )
|
||||
{
|
||||
if( bFirstLineOnly )
|
||||
break;
|
||||
ix = 0;
|
||||
fy += m_fontData->getFontYAdvance();
|
||||
// since the height has changed, test against the height extent
|
||||
if( fy > fHeight )
|
||||
fHeight = fy;
|
||||
}
|
||||
|
||||
// Handle carriage return characters by ignoring them. This helps when
|
||||
// displaying text from a file.
|
||||
if( letter == L'\r' )
|
||||
continue;
|
||||
|
||||
// Translate unprintable characters
|
||||
XUI_FontData::SChar sChar = m_fontData->getChar(letter);
|
||||
|
||||
// Get text extent for this character's glyph
|
||||
ix += sChar.getOffset();
|
||||
ix += sChar.getWAdvance();
|
||||
|
||||
// Since the x widened, test against the x extent
|
||||
if (ix > iWidth) iWidth = ix;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the width to a float here, load/hit/store. :(
|
||||
FLOAT fWidth = static_cast<FLOAT>(iWidth); // Delay the use if fWidth to reduce LHS pain
|
||||
// Apply the scale factor to the result
|
||||
fHeight *= m_fYScaleFactor;
|
||||
// Store the final results
|
||||
*pHeight = fHeight;
|
||||
|
||||
fWidth *= m_fXScaleFactor;
|
||||
*pWidth = fWidth;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: GetTextWidth()
|
||||
// Desc: Returns the width in pixels of a text string
|
||||
//--------------------------------------------------------------------------------------
|
||||
FLOAT XUI_Font::GetTextWidth( const WCHAR* strText ) const
|
||||
{
|
||||
FLOAT fTextWidth;
|
||||
FLOAT fTextHeight;
|
||||
GetTextExtent( strText, &fTextWidth, &fTextHeight );
|
||||
return fTextWidth;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: Begin()
|
||||
// Desc: Prepares the font vertex buffers for rendering.
|
||||
//--------------------------------------------------------------------------------------
|
||||
VOID XUI_Font::Begin()
|
||||
{
|
||||
PIXBeginNamedEvent( 0, "Text Rendering" );
|
||||
|
||||
// Set state on the first call
|
||||
if( 0 == m_dwNestedBeginCount )
|
||||
{
|
||||
// Cache the global pointer into a register
|
||||
IDirect3DDevice9 *pD3dDevice = g_pD3DDevice;
|
||||
assert( pD3dDevice );
|
||||
|
||||
// Set the texture scaling factor as a vertex shader constant
|
||||
//D3DSURFACE_DESC TextureDesc;
|
||||
//m_pFontTexture->GetLevelDesc( 0, &TextureDesc ); // Get the description
|
||||
|
||||
// Set render state
|
||||
assert(m_fontData->m_pFontTexture != NULL || m_fontData->m_iFontTexture > 0);
|
||||
if(m_fontData->m_pFontTexture != NULL)
|
||||
{
|
||||
pD3dDevice->SetTexture( 0, m_fontData->m_pFontTexture );
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_fontData->m_iFontTexture);
|
||||
}
|
||||
|
||||
//// Read the TextureDesc here to ensure no load/hit/store from GetLevelDesc()
|
||||
//FLOAT vTexScale[4];
|
||||
//vTexScale[0] = 1.0f / TextureDesc.Width; // LHS due to int->float conversion
|
||||
//vTexScale[1] = 1.0f / TextureDesc.Height;
|
||||
//vTexScale[2] = 0.0f;
|
||||
//vTexScale[3] = 0.0f;
|
||||
//
|
||||
//pD3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
|
||||
//pD3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
|
||||
//pD3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
|
||||
//pD3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );
|
||||
//pD3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
|
||||
//pD3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 );
|
||||
//pD3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
|
||||
//pD3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
|
||||
//pD3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
|
||||
//pD3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
|
||||
//pD3dDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE );
|
||||
//pD3dDevice->SetRenderState( D3DRS_VIEWPORTENABLE, FALSE );
|
||||
//pD3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
|
||||
//pD3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
|
||||
//pD3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
|
||||
//pD3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
|
||||
}
|
||||
|
||||
// Keep track of the nested begin/end calls.
|
||||
m_dwNestedBeginCount++;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: DrawText()
|
||||
// Desc: Draws text as textured polygons
|
||||
//--------------------------------------------------------------------------------------
|
||||
VOID XUI_Font::DrawText( DWORD dwColor, const WCHAR* strText, DWORD dwFlags,
|
||||
FLOAT fMaxPixelWidth )
|
||||
{
|
||||
DrawText( m_fCursorX, m_fCursorY, dwColor, strText, dwFlags, fMaxPixelWidth );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: DrawShadowText()
|
||||
// Desc: Draws text as textured polygons
|
||||
//--------------------------------------------------------------------------------------
|
||||
VOID XUI_Font::DrawShadowText( FLOAT fOriginX, FLOAT fOriginY, DWORD dwColor, DWORD dwShadowColor,
|
||||
const WCHAR* strText, DWORD dwFlags, FLOAT fMaxPixelWidth)
|
||||
{
|
||||
float fXShadow=1.0f, fYShadow=1.0f;
|
||||
// 4J Stu - Don't move the drop shadow as much
|
||||
//DrawText( fOriginX + (1*m_fXScaleFactor), fOriginY + (1*m_fYScaleFactor), dwColor, strText, dwFlags, fMaxPixelWidth, true );
|
||||
|
||||
// 4J-PB - if we're in 480 widescreen, we need to draw the drop shadow at +2 pixels, so that when the scene is halved, it's at +1
|
||||
if(!RenderManager.IsHiDef())
|
||||
{
|
||||
if(RenderManager.IsWidescreen())
|
||||
{
|
||||
fXShadow=2.0f;
|
||||
fYShadow=2.0f;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// 480 SD mode - the draw text call will reposition the y
|
||||
//}
|
||||
}
|
||||
DrawText( fOriginX + fXShadow, fOriginY + fYShadow, dwColor, strText, dwFlags, fMaxPixelWidth, true );
|
||||
DrawText( fOriginX, fOriginY, dwColor, strText, dwFlags, fMaxPixelWidth );
|
||||
|
||||
//DrawText( fOriginX + 1, fOriginY + 1, dwShadowColor, strText, dwFlags, fMaxPixelWidth);
|
||||
//DrawText( fOriginX, fOriginY, dwColor, strText, dwFlags, fMaxPixelWidth );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: DrawText()
|
||||
// Desc: Draws text as textured polygons
|
||||
// TODO: This function should use the Begin/SetVertexData/End() API when it
|
||||
// becomes available.
|
||||
//--------------------------------------------------------------------------------------
|
||||
VOID XUI_Font::DrawText( FLOAT fOriginX, FLOAT fOriginY, DWORD dwColor,
|
||||
const WCHAR* strText, DWORD dwFlags, FLOAT fMaxPixelWidth, bool darken /*= false*/ )
|
||||
{
|
||||
if( NULL == strText ) return;
|
||||
if( L'\0' == strText[0] ) return;
|
||||
|
||||
// 4J-PB - if we're in 480 widescreen mode, we need to ensure that the font characters are aligned on an even boundary if they are a 2x multiple
|
||||
if(!RenderManager.IsHiDef())
|
||||
{
|
||||
if(RenderManager.IsWidescreen())
|
||||
{
|
||||
int iScaleX=(int)m_fXScaleFactor;
|
||||
int iOriginX;
|
||||
if(iScaleX%2==0)
|
||||
{
|
||||
iOriginX=(int)fOriginX;
|
||||
if(iOriginX%2==1)
|
||||
{
|
||||
fOriginX+=1.0f;
|
||||
}
|
||||
}
|
||||
int iScaleY=(int)m_fYScaleFactor;
|
||||
int iOriginY;
|
||||
if(iScaleY%2==0)
|
||||
{
|
||||
iOriginY=(int)fOriginY;
|
||||
if(iOriginY%2==1)
|
||||
{
|
||||
fOriginY+=1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 480 SD mode - y needs to be on a pixel boundary when multiplied by 1.5, so if it's an odd number, subtract 1/3 from it
|
||||
int iOriginY=(int)fOriginY;
|
||||
if(iOriginY%2==1)
|
||||
{
|
||||
fOriginY-=1.0f/3.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create a PIX user-defined event that encapsulates all of the text draw calls.
|
||||
// This makes DrawText calls easier to recognize in PIX captures, and it makes
|
||||
// them take up fewer entries in the event list.
|
||||
PIXBeginNamedEvent( dwColor, "DrawText: %S", strText );
|
||||
|
||||
// Set up stuff to prepare for drawing text
|
||||
Begin();
|
||||
|
||||
if (darken)
|
||||
{
|
||||
int oldAlpha = dwColor & 0xff000000;
|
||||
dwColor = (dwColor & 0xfcfcfc) >> 2;
|
||||
dwColor += oldAlpha;
|
||||
}
|
||||
|
||||
float r = ((dwColor >> 16) & 0xff) / 255.0f;
|
||||
float g = ((dwColor >> 8) & 0xff) / 255.0f;
|
||||
float b = ((dwColor) & 0xff) / 255.0f;
|
||||
float a = ((dwColor >> 24) & 0xff) / 255.0f;
|
||||
if (a == 0) a = 1;
|
||||
// a = 1;
|
||||
glColor4f(r, g, b, a);
|
||||
|
||||
// Set the starting screen position
|
||||
if( ( fOriginX < 0.0f ) || ( ( dwFlags & ATGFONT_RIGHT ) && ( fOriginX <= 0.0f ) ) )
|
||||
{
|
||||
fOriginX += ( m_rcWindow.x2 - m_rcWindow.x1 );
|
||||
}
|
||||
// 4J-PB - not sure what this code was intending to do, but it removed a line of text that is slightly off the top of the control, rather than having it partially render
|
||||
// if( fOriginY < 0.0f )
|
||||
// {
|
||||
// fOriginY += ( m_rcWindow.y2 - m_rcWindow.y1 );
|
||||
// }
|
||||
|
||||
m_fCursorX = floorf( fOriginX );
|
||||
m_fCursorY = floorf( fOriginY );
|
||||
|
||||
// Adjust for padding
|
||||
fOriginY -= m_fontData->getFontTopPadding();
|
||||
|
||||
XUI_FontData::SChar sChar = m_fontData->getChar(L'.');
|
||||
FLOAT fEllipsesPixelWidth = m_fXScaleFactor * 3.0f * (sChar.getOffset() + sChar.getWAdvance());
|
||||
|
||||
if( dwFlags & ATGFONT_TRUNCATED )
|
||||
{
|
||||
// Check if we will really need to truncate the string
|
||||
if( fMaxPixelWidth <= 0.0f )
|
||||
{
|
||||
dwFlags &= ( ~ATGFONT_TRUNCATED );
|
||||
}
|
||||
else
|
||||
{
|
||||
FLOAT w, h;
|
||||
GetTextExtent( strText, &w, &h, TRUE );
|
||||
|
||||
// If not, then clear the flag
|
||||
if( w <= fMaxPixelWidth )
|
||||
dwFlags &= ( ~ATGFONT_TRUNCATED );
|
||||
}
|
||||
}
|
||||
|
||||
// If vertically centered, offset the starting m_fCursorY value
|
||||
if( dwFlags & ATGFONT_CENTER_Y )
|
||||
{
|
||||
FLOAT w, h;
|
||||
GetTextExtent( strText, &w, &h );
|
||||
m_fCursorY = floorf( m_fCursorY - (h * 0.5f) );
|
||||
}
|
||||
|
||||
// Add window offsets
|
||||
FLOAT Winx = static_cast<FLOAT>(m_rcWindow.x1);
|
||||
FLOAT Winy = static_cast<FLOAT>(m_rcWindow.y1);
|
||||
fOriginX += Winx;
|
||||
fOriginY += Winy;
|
||||
m_fCursorX += Winx;
|
||||
m_fCursorY += Winy;
|
||||
|
||||
// Set a flag so we can determine initial justification effects
|
||||
BOOL bStartingNewLine = TRUE;
|
||||
|
||||
DWORD dwNumEllipsesToDraw = 0;
|
||||
|
||||
// Begin drawing the vertices
|
||||
|
||||
|
||||
DWORD dwNumChars = wcslen( strText ) + ( dwFlags & ATGFONT_TRUNCATED ? 3 : 0 );
|
||||
|
||||
bStartingNewLine = TRUE;
|
||||
|
||||
// Draw four vertices for each glyph
|
||||
while( *strText )
|
||||
{
|
||||
WCHAR letter;
|
||||
|
||||
if( dwNumEllipsesToDraw )
|
||||
{
|
||||
letter = L'.';
|
||||
}
|
||||
else
|
||||
{
|
||||
// If starting text on a new line, determine justification effects
|
||||
if( bStartingNewLine )
|
||||
{
|
||||
if( dwFlags & ( ATGFONT_RIGHT | ATGFONT_CENTER_X ) )
|
||||
{
|
||||
// Get the extent of this line
|
||||
FLOAT w, h;
|
||||
GetTextExtent( strText, &w, &h, TRUE );
|
||||
|
||||
// Offset this line's starting m_fCursorX value
|
||||
if( dwFlags & ATGFONT_RIGHT )
|
||||
m_fCursorX = floorf( fOriginX - w );
|
||||
if( dwFlags & ATGFONT_CENTER_X )
|
||||
m_fCursorX = floorf( fOriginX - w * 0.5f );
|
||||
}
|
||||
bStartingNewLine = FALSE;
|
||||
}
|
||||
|
||||
// Get the current letter in the string
|
||||
letter = *strText++;
|
||||
|
||||
// Handle the newline character
|
||||
if( letter == L'\n' )
|
||||
{
|
||||
m_fCursorX = fOriginX;
|
||||
m_fCursorY += m_fontData->getFontYAdvance() * m_fYScaleFactor;
|
||||
bStartingNewLine = TRUE;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle carriage return characters by ignoring them. This helps when
|
||||
// displaying text from a file.
|
||||
if( letter == L'\r' )
|
||||
continue;
|
||||
}
|
||||
|
||||
// Translate unprintable characters
|
||||
XUI_FontData::SChar sChar = m_fontData->getChar( letter );
|
||||
|
||||
FLOAT fOffset = m_fXScaleFactor * ( FLOAT )sChar.getOffset();
|
||||
FLOAT fAdvance = m_fXScaleFactor * ( FLOAT )sChar.getWAdvance();
|
||||
// 4J Use the font max width otherwise scaling doesnt look right
|
||||
FLOAT fWidth = m_fXScaleFactor * (sChar.tu2() - sChar.tu1());//( FLOAT )pGlyph->wWidth;
|
||||
FLOAT fHeight = m_fYScaleFactor * m_fontData->getFontHeight();
|
||||
|
||||
if( 0 == dwNumEllipsesToDraw )
|
||||
{
|
||||
if( dwFlags & ATGFONT_TRUNCATED )
|
||||
{
|
||||
// Check if we will be exceeded the max allowed width
|
||||
if( m_fCursorX + fOffset + fWidth + fEllipsesPixelWidth + m_fSlantFactor > fOriginX + fMaxPixelWidth )
|
||||
{
|
||||
// Yup, draw the three ellipses dots instead
|
||||
dwNumEllipsesToDraw = 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the screen coordinates
|
||||
m_fCursorX += fOffset;
|
||||
FLOAT X4 = m_fCursorX;
|
||||
FLOAT X1 = X4 + m_fSlantFactor;
|
||||
FLOAT X3 = X4 + fWidth;
|
||||
FLOAT X2 = X1 + fWidth;
|
||||
FLOAT Y1 = m_fCursorY;
|
||||
FLOAT Y3 = Y1 + fHeight;
|
||||
FLOAT Y2 = Y1;
|
||||
FLOAT Y4 = Y3;
|
||||
|
||||
m_fCursorX += fAdvance;
|
||||
|
||||
// Add the vertices to draw this glyph
|
||||
|
||||
FLOAT tu1 = sChar.tu1() / (float)m_fontData->getImageWidth();
|
||||
FLOAT tv1 = sChar.tv1() / (float)m_fontData->getImageHeight();
|
||||
FLOAT tu2 = sChar.tu2() / (float)m_fontData->getImageWidth();
|
||||
FLOAT tv2 = sChar.tv2() / (float)m_fontData->getImageHeight();
|
||||
|
||||
Tesselator *t = Tesselator::getInstance();
|
||||
t->begin();
|
||||
t->vertexUV(X1, Y1, 0.0f, tu1, tv1);
|
||||
t->vertexUV(X2, Y2, 0.0f, tu2, tv1);
|
||||
t->vertexUV(X3, Y3, 0.0f, tu2, tv2);
|
||||
t->vertexUV(X4, Y4, 0.0f, tu1, tv2);
|
||||
t->end();
|
||||
|
||||
|
||||
// If drawing ellipses, exit when they're all drawn
|
||||
if( dwNumEllipsesToDraw )
|
||||
{
|
||||
if( --dwNumEllipsesToDraw == 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
dwNumChars--;
|
||||
}
|
||||
|
||||
// Undo window offsets
|
||||
m_fCursorX -= Winx;
|
||||
m_fCursorY -= Winy;
|
||||
|
||||
// Call End() to complete the begin/end pair for drawing text
|
||||
End();
|
||||
|
||||
// Close off the user-defined event opened with PIXBeginNamedEvent.
|
||||
PIXEndNamedEvent();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: End()
|
||||
// Desc: Paired call that restores state set in the Begin() call.
|
||||
//--------------------------------------------------------------------------------------
|
||||
VOID XUI_Font::End()
|
||||
{
|
||||
assert( m_dwNestedBeginCount > 0 );
|
||||
if( --m_dwNestedBeginCount > 0 )
|
||||
{
|
||||
PIXEndNamedEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
PIXEndNamedEvent();
|
||||
}
|
||||
Reference in New Issue
Block a user