first 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();
|
||||
}
|
||||
93
Minecraft.Client/Xbox/Font/XUI_Font.h
Normal file
93
Minecraft.Client/Xbox/Font/XUI_Font.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
class XUI_FontData;
|
||||
|
||||
// 4J This class is partially based of the ATG font implementation, modified to suit our uses for XUI
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Flags for the Font::DrawText() function (Or them together to combine features)
|
||||
//--------------------------------------------------------------------------------------
|
||||
#define ATGFONT_LEFT 0x00000000
|
||||
#define ATGFONT_RIGHT 0x00000001
|
||||
#define ATGFONT_CENTER_X 0x00000002
|
||||
#define ATGFONT_CENTER_Y 0x00000004
|
||||
#define ATGFONT_TRUNCATED 0x00000008
|
||||
|
||||
class XUI_Font
|
||||
{
|
||||
public:
|
||||
XUI_FontData *m_fontData;
|
||||
|
||||
public:
|
||||
const int m_iFontData;
|
||||
const float m_fScaleFactor;
|
||||
|
||||
FLOAT m_fXScaleFactor; // Scaling constants
|
||||
FLOAT m_fYScaleFactor;
|
||||
FLOAT m_fSlantFactor; // For italics
|
||||
DOUBLE m_dRotCos; // Precalculated sine and cosine for italic like rotation
|
||||
DOUBLE m_dRotSin;
|
||||
|
||||
D3DRECT m_rcWindow; // Bounds rect if the text window, modify via accessors only!
|
||||
FLOAT m_fCursorX; // Current text cursor
|
||||
FLOAT m_fCursorY;
|
||||
|
||||
BOOL m_bRotate;
|
||||
|
||||
DWORD m_dwNestedBeginCount;
|
||||
|
||||
wstring m_fontName;
|
||||
wstring m_fallbackFont;
|
||||
DWORD refCount;
|
||||
public:
|
||||
float getScaleFactor() { return m_fScaleFactor; }
|
||||
void GetScaleFactors(FLOAT *pfXScaleFactor, FLOAT *pfYScaleFactor) { *pfXScaleFactor = m_fScaleFactor; *pfYScaleFactor = m_fScaleFactor; }
|
||||
// Accessor functions
|
||||
inline VOID SetSlantFactor( FLOAT fSlantFactor )
|
||||
{
|
||||
m_fSlantFactor = fSlantFactor;
|
||||
}
|
||||
|
||||
inline VOID SetScaleFactors( FLOAT fXScaleFactor, FLOAT fYScaleFactor )
|
||||
{
|
||||
// m_fXScaleFactor = m_fYScaleFactor = m_fScaleFactor;
|
||||
}
|
||||
|
||||
void SetFallbackFont(const wstring &fallbackFont) { m_fallbackFont = fallbackFont; }
|
||||
void IncRefCount() { ++refCount; }
|
||||
void DecRefCount() { --refCount; }
|
||||
|
||||
public:
|
||||
XUI_Font(int iFontData, float scaleFactor, XUI_FontData *fontData);
|
||||
~XUI_Font();
|
||||
|
||||
// Returns the dimensions of a text string
|
||||
VOID GetTextExtent( const WCHAR* strText, FLOAT* pWidth,
|
||||
FLOAT* pHeight, BOOL bFirstLineOnly=FALSE ) const;
|
||||
FLOAT GetTextWidth( const WCHAR* strText ) const;
|
||||
FLOAT GetCharAdvance( const WCHAR* strChar ) const;
|
||||
|
||||
VOID SetWindow(const D3DRECT &rcWindow );
|
||||
VOID SetWindow( LONG x1, LONG y1, LONG x2, LONG y2 );
|
||||
VOID GetWindow(D3DRECT &rcWindow) const;
|
||||
VOID SetCursorPosition( FLOAT fCursorX, FLOAT fCursorY );
|
||||
VOID SetRotationFactor( FLOAT fRotationFactor );
|
||||
|
||||
// Function to create a texture containing rendered text
|
||||
D3DTexture* CreateTexture( const WCHAR* strText,
|
||||
D3DCOLOR dwBackgroundColor = 0x00000000,
|
||||
D3DCOLOR dwTextColor = 0xffffffff,
|
||||
D3DFORMAT d3dFormat = D3DFMT_A8R8G8B8 );
|
||||
|
||||
// Public calls to render text. Callers can simply call DrawText(), but for
|
||||
// performance, they should batch multiple calls together, bracketed by calls to
|
||||
// Begin() and End().
|
||||
VOID Begin();
|
||||
VOID DrawText( DWORD dwColor, const WCHAR* strText, DWORD dwFlags=0L,
|
||||
FLOAT fMaxPixelWidth = 0.0f );
|
||||
VOID DrawText( FLOAT sx, FLOAT sy, DWORD dwColor, const WCHAR* strText,
|
||||
DWORD dwFlags=0L, FLOAT fMaxPixelWidth = 0.0f, bool darken = false );
|
||||
VOID DrawShadowText( FLOAT sx, FLOAT sy, DWORD dwColor, DWORD dwShadowColor, const WCHAR* strText,
|
||||
DWORD dwFlags=0L, FLOAT fMaxPixelWidth = 0.0f );
|
||||
VOID End();
|
||||
};
|
||||
395
Minecraft.Client/Xbox/Font/XUI_FontData.cpp
Normal file
395
Minecraft.Client/Xbox/Font/XUI_FontData.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
#include "stdafx.h"
|
||||
#include "..\..\stubs.h"
|
||||
#include "..\..\Minecraft.h"
|
||||
#include "..\..\Textures.h"
|
||||
#include "XUI_FontData.h"
|
||||
#include "..\..\..\Minecraft.World\StringHelpers.h"
|
||||
|
||||
|
||||
#define USE_NEW 0
|
||||
|
||||
|
||||
extern IDirect3DDevice9 *g_pD3DDevice;
|
||||
|
||||
int XUI_FontData::getMaxGlyph()
|
||||
{
|
||||
return m_fontData->getFontData()->m_uiGlyphCount;
|
||||
}
|
||||
|
||||
float XUI_FontData::getFontHeight()
|
||||
{
|
||||
return m_fontData->getFontData()->m_uiGlyphHeight;
|
||||
}
|
||||
|
||||
float XUI_FontData::getFontTopPadding()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float XUI_FontData::getFontBottomPadding()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float XUI_FontData::getFontYAdvance()
|
||||
{
|
||||
return m_fontData->getFontData()->m_uiGlyphHeight - 1;
|
||||
}
|
||||
|
||||
float XUI_FontData::getFontMaxWidth()
|
||||
{
|
||||
return m_fontData->getFontData()->m_uiGlyphWidth;
|
||||
}
|
||||
|
||||
float XUI_FontData::getMaxDescent()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float XUI_FontData::getMaxAscent()
|
||||
{
|
||||
return m_fontData->getFontData()->m_uiGlyphHeight;
|
||||
}
|
||||
|
||||
int XUI_FontData::getImageWidth()
|
||||
{
|
||||
return m_fontData->getFontData()->m_uiGlyphMapX;
|
||||
}
|
||||
|
||||
int XUI_FontData::getImageHeight()
|
||||
{
|
||||
return m_fontData->getFontData()->m_uiGlyphMapY;
|
||||
}
|
||||
|
||||
float XUI_FontData::SChar::getMinX()
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float XUI_FontData::SChar::getMaxX()
|
||||
{
|
||||
return (float) m_parent->m_fontData->getFontData()->m_uiGlyphWidth;
|
||||
}
|
||||
|
||||
float XUI_FontData::SChar::getMinY()
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float XUI_FontData::SChar::getMaxY()
|
||||
{
|
||||
return 0.0f; //m_parent->m_fontData->getFontData()->m_uiGlyphHeight;
|
||||
}
|
||||
|
||||
float XUI_FontData::SChar::getAdvance()
|
||||
{
|
||||
return (float) m_parent->m_fontData->getWidth(m_glyphId);
|
||||
}
|
||||
|
||||
int XUI_FontData::SChar::getGlyphId()
|
||||
{
|
||||
return m_glyphId;
|
||||
}
|
||||
|
||||
#define USE_NEW_UV 1
|
||||
|
||||
int XUI_FontData::SChar::tu1()
|
||||
{
|
||||
#if USE_NEW_UV
|
||||
int row = 0, col = 0;
|
||||
m_parent->m_fontData->getPos(m_glyphId, row, col);
|
||||
return col * m_parent->m_fontData->getFontData()->m_uiGlyphWidth;
|
||||
#else
|
||||
return m_parent->m_Glyphs[m_glyphId].tu1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int XUI_FontData::SChar::tu2()
|
||||
{
|
||||
#if USE_NEW_UV
|
||||
return tu1() + m_parent->m_fontData->getFontData()->m_uiGlyphWidth;
|
||||
#else
|
||||
return m_parent->m_Glyphs[m_glyphId].tu2;
|
||||
#endif
|
||||
}
|
||||
|
||||
int XUI_FontData::SChar::tv1()
|
||||
{
|
||||
#if USE_NEW_UV
|
||||
int row = 0, col = 0;
|
||||
m_parent->m_fontData->getPos(m_glyphId, row, col);
|
||||
return row * m_parent->m_fontData->getFontData()->m_uiGlyphHeight + 1;
|
||||
#else
|
||||
return m_parent->m_Glyphs[m_glyphId].tv1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int XUI_FontData::SChar::tv2()
|
||||
{
|
||||
#if USE_NEW_UV
|
||||
return tv1() + m_parent->m_fontData->getFontData()->m_uiGlyphHeight;
|
||||
#else
|
||||
return m_parent->m_Glyphs[m_glyphId].tv2;
|
||||
#endif
|
||||
}
|
||||
|
||||
short XUI_FontData::SChar::getOffset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
short XUI_FontData::SChar::getWAdvance()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
XUI_FontData::SChar XUI_FontData::getChar(const wchar_t strChar)
|
||||
{
|
||||
SChar out;
|
||||
out.m_glyphId = m_fontData->getGlyphId((unsigned int) strChar);
|
||||
out.m_parent = this;
|
||||
return out;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: XUI_FontData()
|
||||
// Desc: Constructor
|
||||
//--------------------------------------------------------------------------------------
|
||||
XUI_FontData::XUI_FontData()
|
||||
{
|
||||
m_pFontTexture = NULL;
|
||||
m_iFontTexture = -1;
|
||||
|
||||
m_dwNumGlyphs = 0L;
|
||||
m_Glyphs = NULL;
|
||||
|
||||
m_cMaxGlyph = 0;
|
||||
|
||||
m_dwNestedBeginCount = 0L;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: ~XUI_FontData()
|
||||
// Desc: Destructor
|
||||
//--------------------------------------------------------------------------------------
|
||||
XUI_FontData::~XUI_FontData()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: Create()
|
||||
// Desc: Create the font's internal objects (texture and array of glyph info)
|
||||
// using the XPR packed resource file
|
||||
//--------------------------------------------------------------------------------------
|
||||
HRESULT XUI_FontData::Create( SFontData &sfontdata )
|
||||
{
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
app.DebugPrintf("Attempting to load font data for font: '%s'\n", sfontdata.m_strFontName.c_str());
|
||||
#endif
|
||||
|
||||
BufferedImage *img = new BufferedImage(sfontdata.m_wstrFilename, false, true);
|
||||
|
||||
m_iFontTexture = Minecraft::GetInstance()->textures->getTexture(img, C4JRender::TEXTURE_FORMAT_RxGyBzAw, false);
|
||||
|
||||
int imgWidth = img->getWidth(), imgHeight = img->getHeight();
|
||||
intArray rawPixels(imgWidth * imgHeight);
|
||||
img->getRGB(0, 0, imgWidth, imgHeight, rawPixels, 0, imgWidth);
|
||||
delete img;
|
||||
|
||||
m_fontData = new CFontData( sfontdata, rawPixels.data );
|
||||
|
||||
if (rawPixels.data != NULL) delete [] rawPixels.data;
|
||||
|
||||
#if 0
|
||||
{ // 4J-JEV: Load in FontData (ABC) file, and initialize member variables from it.
|
||||
|
||||
const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL);
|
||||
|
||||
//wsprintfW(szResourceLocator,L"section://%X,%s#%s",c_ModuleHandle,L"media", L"media/font/Mojangles_10.abc");
|
||||
wsprintfW(szResourceLocator,L"section://%X,%s#%s%s%s",c_ModuleHandle,L"media", L"media/font/",strFontFileName.c_str(),L".abc");
|
||||
|
||||
BYTE *buffer;
|
||||
UINT bufferSize;
|
||||
hr = XuiResourceLoadAllNoLoc(
|
||||
szResourceLocator,
|
||||
&buffer,
|
||||
&bufferSize
|
||||
);
|
||||
if( FAILED(hr) ) app.FatalLoadError();
|
||||
|
||||
//return Create( tex, buffer );
|
||||
hr = Create( m_iFontTexture, buffer );
|
||||
XuiFree(buffer);
|
||||
}
|
||||
|
||||
// The ABC's are wrong, so recalc
|
||||
// TODO 4J Stu - This isn't going to change every time we run the app, so really the FontMaker tool needs
|
||||
// changed, or at the very least the .abc files need pre-processed to store the values we want
|
||||
int rowV = 0;
|
||||
int rowXOffset = 0;
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < 299; i++)
|
||||
{
|
||||
// Translate unprintable characters
|
||||
GLYPH_ATTR* pGlyph;
|
||||
|
||||
DWORD letter = m_fontData->getGlyphId(i);
|
||||
if( letter == 0 || letter >= 280 ) continue;
|
||||
pGlyph = (GLYPH_ATTR*)&m_Glyphs[letter]; // Get the requested glyph
|
||||
|
||||
// 4J Stu - The original ABC's were generated for a font height that is 1 pixel higher than our cleaned up version
|
||||
// We adjust for 1 pixel padding in the y at the top of each box.
|
||||
pGlyph->tv1++;
|
||||
|
||||
if( pGlyph->tv1 != rowV )
|
||||
{
|
||||
rowV = pGlyph->tv1;
|
||||
rowXOffset = 0;
|
||||
}
|
||||
if( pGlyph->wOffset > 0 )
|
||||
{
|
||||
rowXOffset += pGlyph->wOffset;
|
||||
pGlyph->wOffset = 0;
|
||||
}
|
||||
|
||||
pGlyph->tu1 -= rowXOffset;
|
||||
pGlyph->tu2 -= rowXOffset;
|
||||
|
||||
int x = pGlyph->tu2-1;
|
||||
int emptyColumnX = x;
|
||||
for (; x >= pGlyph->tu1; x--)
|
||||
{
|
||||
bool emptyColumn = true;
|
||||
for (int y = pGlyph->tv1; y < pGlyph->tv2; y++)
|
||||
{
|
||||
int rawPix = rawPixels[x + (y*imgWidth)];
|
||||
DWORD pixel = rawPixels[x + (y*imgWidth)] & 0xff000000;
|
||||
if (pixel > 0) emptyColumn = false;
|
||||
}
|
||||
|
||||
if (!emptyColumn && emptyColumnX == pGlyph->tu2-1)
|
||||
{
|
||||
emptyColumnX = x;
|
||||
}
|
||||
}
|
||||
if(emptyColumnX != pGlyph->tu2-1)
|
||||
{
|
||||
pGlyph->wWidth = emptyColumnX-pGlyph->tu1;
|
||||
pGlyph->wAdvance = pGlyph->wWidth + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: Create()
|
||||
// Desc: Create the font's internal objects (texture and array of glyph info)
|
||||
//--------------------------------------------------------------------------------------
|
||||
//HRESULT XUI_FontData::Create( D3DTexture* pFontTexture, const VOID* pFontData )
|
||||
HRESULT XUI_FontData::Create( int iFontTexture, const VOID* pFontData )
|
||||
{
|
||||
// Save a copy of the texture
|
||||
//m_pFontTexture = pFontTexture;
|
||||
#if 0
|
||||
m_iFontTexture = iFontTexture;
|
||||
|
||||
// Check version of file (to make sure it matches up with the FontMaker tool)
|
||||
const BYTE* pData = static_cast<const BYTE*>(pFontData);
|
||||
DWORD dwFileVersion = reinterpret_cast<const FontFileHeaderImage_t *>(pData)->m_dwFileVersion;
|
||||
|
||||
if( dwFileVersion == ATGFONTFILEVERSION )
|
||||
{
|
||||
//m_fFontHeight = reinterpret_cast<const FontFileHeaderImage_t *>(pData)->m_fFontHeight;
|
||||
//m_fFontTopPadding = reinterpret_cast<const FontFileHeaderImage_t *>(pData)->m_fFontTopPadding;
|
||||
//m_fFontBottomPadding = reinterpret_cast<const FontFileHeaderImage_t *>(pData)->m_fFontBottomPadding;
|
||||
//m_fFontYAdvance = reinterpret_cast<const FontFileHeaderImage_t *>(pData)->m_fFontYAdvance;
|
||||
|
||||
// Point to the translator string which immediately follows the 4 floats
|
||||
m_cMaxGlyph = reinterpret_cast<const FontFileHeaderImage_t *>(pData)->m_cMaxGlyph;
|
||||
|
||||
WCHAR* translatorTable = const_cast<FontFileHeaderImage_t*>(reinterpret_cast<const FontFileHeaderImage_t *>(pData))->m_TranslatorTable;
|
||||
|
||||
// 4J Stu - This map saves us some memory because the translatorTable is largely empty
|
||||
// If we were ever to use >50% of the table then we should store it and use directly rather than the map
|
||||
for( unsigned short i = 0; i < m_cMaxGlyph + 1; ++i )
|
||||
{
|
||||
if( translatorTable[i] == 0 ) continue;
|
||||
m_TranslatorMap.insert( unordered_map<wchar_t, unsigned short>::value_type(i, translatorTable[i]) );
|
||||
}
|
||||
|
||||
pData += ATGCALCFONTFILEHEADERSIZE( m_cMaxGlyph + 1 );
|
||||
|
||||
// Read the glyph attributes from the file
|
||||
m_dwNumGlyphs = reinterpret_cast<const FontFileStrikesImage_t *>(pData)->m_dwNumGlyphs;
|
||||
m_Glyphs = new GLYPH_ATTR[m_dwNumGlyphs];
|
||||
memcpy(m_Glyphs, reinterpret_cast<const FontFileStrikesImage_t *>(pData)->m_Glyphs, sizeof(GLYPH_ATTR) * m_dwNumGlyphs);
|
||||
|
||||
//m_dwNumGlyphs = m_fontData->getFontData()->m_uiGlyphCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
app.DebugPrintf( "Incorrect version number on font file!\n" );
|
||||
return E_FAIL;
|
||||
}
|
||||
#endif
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: Destroy()
|
||||
// Desc: Destroy the font object
|
||||
//--------------------------------------------------------------------------------------
|
||||
VOID XUI_FontData::Destroy()
|
||||
{
|
||||
if(m_pFontTexture!=NULL)
|
||||
{
|
||||
m_pFontTexture->Release();
|
||||
delete m_pFontTexture;
|
||||
}
|
||||
|
||||
m_fontData->release();
|
||||
|
||||
m_pFontTexture = NULL;
|
||||
m_dwNumGlyphs = 0L;
|
||||
m_cMaxGlyph = 0;
|
||||
|
||||
m_dwNestedBeginCount = 0L;
|
||||
}
|
||||
|
||||
/*
|
||||
FLOAT XUI_FontData::GetCharAdvance( const WCHAR* strChar )
|
||||
{
|
||||
unsigned int uiChar = (unsigned int) *strChar;
|
||||
return 0.0f;// m_fontData.getAdvance(m_fontData.getGlyphId(uiChar));
|
||||
}
|
||||
|
||||
FLOAT XUI_FontData::GetCharWidth( const WCHAR* strChar )
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void XUI_FontData::GetCharMetrics( const WCHAR* strChar, XUICharMetrics *xuiMetrics)
|
||||
{
|
||||
unsigned int uiChar = (unsigned int) *strChar;
|
||||
unsigned short usGlyph = m_fontData->getGlyphId(uiChar);
|
||||
|
||||
xuiMetrics->fAdvance = m_fontData->getWidth(usGlyph); //.getAdvance(usGlyph) * (float) m_fontData.getFontData()->m_uiGlyphHeight;
|
||||
xuiMetrics->fMaxX = (float) m_fontData->getFontData()->m_uiGlyphWidth;
|
||||
xuiMetrics->fMinX = 0.0f;
|
||||
xuiMetrics->fMaxY = 0;// m_fontData.getFontData()->m_fAscent * (float) m_fontData.getFontData()->m_uiGlyphHeight;
|
||||
xuiMetrics->fMinY = 0;//m_fontData.getFontData()->m_fDescent * (float) m_fontData.getFontData()->m_uiGlyphHeight;
|
||||
}
|
||||
|
||||
unsigned short XUI_FontData::getGlyphId(wchar_t character)
|
||||
{
|
||||
return m_fontData->getGlyphId( (unsigned int) character );
|
||||
}
|
||||
*/
|
||||
147
Minecraft.Client/Xbox/Font/XUI_FontData.h
Normal file
147
Minecraft.Client/Xbox/Font/XUI_FontData.h
Normal file
@@ -0,0 +1,147 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
#include <xuirender.h>
|
||||
|
||||
#include "..\..\Common\UI\UIFontData.h"
|
||||
|
||||
// 4J This class is partially based of the ATG font implementation
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: GLYPH_ATTR
|
||||
// Desc: Structure to hold information about one glyph (font character image)
|
||||
//--------------------------------------------------------------------------------------
|
||||
typedef struct GLYPH_ATTR
|
||||
{
|
||||
WORD tu1, tv1, tu2, tv2; // Texture coordinates for the image
|
||||
SHORT wOffset; // Pixel offset for glyph start
|
||||
SHORT wWidth; // Pixel width of the glyph
|
||||
SHORT wAdvance; // Pixels to advance after the glyph
|
||||
WORD wMask; // Channel mask
|
||||
} GLYPH_ATTR;
|
||||
|
||||
//
|
||||
// These two structures are mapped to data loaded from disk.
|
||||
// DO NOT ALTER ANY ENTRIES OR YOU WILL BREAK
|
||||
// COMPATIBILITY WITH THE FONT FILE
|
||||
//
|
||||
|
||||
// Font description
|
||||
|
||||
#define ATGCALCFONTFILEHEADERSIZE(x) ( sizeof(DWORD) + (sizeof(FLOAT)*4) + sizeof(WORD) + (sizeof(WCHAR)*(x)) )
|
||||
#define ATGFONTFILEVERSION 5
|
||||
|
||||
typedef struct FontFileHeaderImage_t {
|
||||
DWORD m_dwFileVersion; // Version of the font file (Must match FONTFILEVERSION)
|
||||
FLOAT m_fFontHeight; // Height of the font strike in pixels
|
||||
FLOAT m_fFontTopPadding; // Padding above the strike zone
|
||||
FLOAT m_fFontBottomPadding; // Padding below the strike zone
|
||||
FLOAT m_fFontYAdvance; // Number of pixels to move the cursor for a line feed
|
||||
WORD m_cMaxGlyph; // Number of font characters (Should be an odd number to maintain DWORD Alignment)
|
||||
WCHAR m_TranslatorTable[1]; // ASCII to Glyph lookup table, NOTE: It's m_cMaxGlyph+1 in size.
|
||||
// Entry 0 maps to the "Unknown" glyph.
|
||||
} FontFileHeaderImage_t;
|
||||
|
||||
// Font strike array. Immediately follows the FontFileHeaderImage_t
|
||||
// structure image
|
||||
|
||||
typedef struct FontFileStrikesImage_t {
|
||||
DWORD m_dwNumGlyphs; // Size of font strike array (First entry is the unknown glyph)
|
||||
GLYPH_ATTR m_Glyphs[1]; // Array of font strike uv's etc... NOTE: It's m_dwNumGlyphs in size
|
||||
} FontFileStrikesImage_t;
|
||||
|
||||
typedef struct _CharMetrics
|
||||
{
|
||||
// units are pixels at current font size
|
||||
|
||||
float fMinX; // min x coordinate
|
||||
float fMinY; // min y coordinate
|
||||
float fMaxX; // max x coordinate
|
||||
float fMaxY; // max y coordinate
|
||||
float fAdvance; // advance value
|
||||
} CharMetrics;
|
||||
|
||||
class XUI_FontData
|
||||
{
|
||||
public:
|
||||
int getMaxGlyph();
|
||||
float getFontHeight();
|
||||
float getFontTopPadding();
|
||||
float getFontBottomPadding();
|
||||
float getFontYAdvance();
|
||||
float getFontMaxWidth();
|
||||
float getMaxDescent();
|
||||
float getMaxAscent();
|
||||
int getImageWidth();
|
||||
int getImageHeight();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
friend class XUI_FontData;
|
||||
|
||||
private:
|
||||
unsigned short m_glyphId;
|
||||
XUI_FontData *m_parent;
|
||||
|
||||
public:
|
||||
bool hasChar() { return true; }
|
||||
float getMinX();
|
||||
float getMinY();
|
||||
float getMaxX();
|
||||
float getMaxY();
|
||||
float getAdvance();
|
||||
int getGlyphId();
|
||||
int tu1();
|
||||
int tu2();
|
||||
int tv1();
|
||||
int tv2(); // Texture coordinates for the image
|
||||
short getOffset(); // Pixel offset for glyph start
|
||||
short getWidth(); // Pixel width of the glyph
|
||||
short getWAdvance(); // Pixels to advance after the glyph
|
||||
WORD getMask(); // Channel mask, tv2;
|
||||
} SChar;
|
||||
|
||||
SChar getChar(const wchar_t strChar);
|
||||
|
||||
// D3D rendering objects
|
||||
D3DTexture* m_pFontTexture;
|
||||
int m_iFontTexture;
|
||||
|
||||
private:
|
||||
unordered_map<wchar_t, unsigned short> m_TranslatorMap;
|
||||
|
||||
CharMetrics *m_characterMetrics;
|
||||
|
||||
// Translator table for supporting unicode ranges
|
||||
DWORD m_cMaxGlyph; // Number of entries in the translator table
|
||||
|
||||
// Glyph data for the font
|
||||
DWORD m_dwNumGlyphs; // Number of valid glyphs
|
||||
GLYPH_ATTR* m_Glyphs; // Array of glyphs
|
||||
|
||||
DWORD m_dwNestedBeginCount;
|
||||
|
||||
|
||||
protected:
|
||||
CFontData *m_fontData;
|
||||
|
||||
public:
|
||||
// Accessor functions
|
||||
inline D3DTexture* GetTexture() const
|
||||
{
|
||||
return m_pFontTexture;
|
||||
}
|
||||
|
||||
public:
|
||||
XUI_FontData();
|
||||
~XUI_FontData();
|
||||
|
||||
// Functions to create and destroy the internal objects
|
||||
HRESULT Create( SFontData &sfontdata );
|
||||
//HRESULT Create( D3DTexture* pFontTexture, const VOID* pFontData );
|
||||
HRESULT Create( int iFontTexture, const VOID* pFontData );
|
||||
VOID Destroy();
|
||||
|
||||
//FLOAT GetCharAdvance( const WCHAR* strChar );
|
||||
//FLOAT GetCharWidth( const WCHAR* strChar );
|
||||
//void GetCharMetrics( const WCHAR* strChar, XUICharMetrics *xuiMetrics);
|
||||
//unsigned short getGlyphId(wchar_t character);
|
||||
};
|
||||
307
Minecraft.Client/Xbox/Font/XUI_FontRenderer.cpp
Normal file
307
Minecraft.Client/Xbox/Font/XUI_FontRenderer.cpp
Normal file
@@ -0,0 +1,307 @@
|
||||
#include "stdafx.h"
|
||||
#include "XUI_FontRenderer.h"
|
||||
#include "XUI_Font.h"
|
||||
#include "XUI_FontData.h"
|
||||
#include "..\..\..\Minecraft.World\StringHelpers.h"
|
||||
|
||||
extern IDirect3DDevice9 *g_pD3DDevice;
|
||||
extern void GetRenderAndSamplerStates(IDirect3DDevice9 *pDevice,DWORD *RenderStateA,DWORD *SamplerStateA);
|
||||
extern void SetRenderAndSamplerStates(IDirect3DDevice9 *pDevice,DWORD *RenderStateA,DWORD *SamplerStateA);
|
||||
|
||||
XUI_FontRenderer::XUI_FontRenderer()
|
||||
{
|
||||
ZeroMemory(m_loadedFontData, sizeof(XUI_FontData*) * eFontData_MAX);
|
||||
|
||||
//XuiFontSetRenderer(this);
|
||||
|
||||
//Minecraft *pMinecraft=Minecraft::GetInstance();
|
||||
|
||||
//ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys);
|
||||
//m_fScreenWidth=(float)pMinecraft->width_phys;
|
||||
//m_fRawWidth=(float)ssc.rawWidth;
|
||||
//m_fScreenHeight=(float)pMinecraft->height_phys;
|
||||
//m_fRawHeight=(float)ssc.rawHeight;
|
||||
}
|
||||
|
||||
HRESULT XUI_FontRenderer::Init( float fDpi )
|
||||
{
|
||||
return( S_OK );
|
||||
|
||||
}
|
||||
|
||||
VOID XUI_FontRenderer::Term()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT XUI_FontRenderer::GetCaps( DWORD * pdwCaps )
|
||||
{
|
||||
if( pdwCaps != NULL )
|
||||
{
|
||||
// setting this means XUI calls the DrawCharsToDevice method
|
||||
*pdwCaps = XUI_FONT_RENDERER_CAP_INTERNAL_GLYPH_CACHE | XUI_FONT_RENDERER_CAP_POINT_SIZE_RESPECTED | XUI_FONT_RENDERER_STYLE_DROPSHADOW;
|
||||
}
|
||||
return ( S_OK );
|
||||
}
|
||||
|
||||
HRESULT XUI_FontRenderer::CreateFont( const TypefaceDescriptor * pTypefaceDescriptor, float fPointSize, DWORD dwStyle, DWORD dwReserved, HFONTOBJ * phFont )
|
||||
{
|
||||
float fXuiSize = fPointSize * ( 16.0f / 14.0f );
|
||||
//float fXuiSize = fPointSize * ( 16.0f / 16.0f );
|
||||
fXuiSize /= 4.0f;
|
||||
fXuiSize = floor( fXuiSize );
|
||||
int xuiSize = (int)(fXuiSize * 4.0f);
|
||||
if( xuiSize < 1 ) xuiSize = 8;
|
||||
|
||||
// 4J Stu - We have fonts based on multiples of 8 or 12
|
||||
// We don't want to make the text larger as then it may not fit in the box specified
|
||||
// so we decrease the size until we find one that will look ok
|
||||
while( xuiSize%8!=0 && xuiSize%12!=0 ) xuiSize -= 2;
|
||||
|
||||
//app.DebugPrintf("point size is: %f, xuiSize is: %d\n", fPointSize, xuiSize);
|
||||
|
||||
XUI_Font *font = NULL;
|
||||
XUI_FontData *fontData = NULL;
|
||||
FLOAT scale = 1;
|
||||
|
||||
eFontData efontdata;
|
||||
if( xuiSize%12==0 )
|
||||
{
|
||||
scale = xuiSize/12;
|
||||
efontdata = eFontData_Mojangles_11;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = xuiSize/8;
|
||||
efontdata = eFontData_Mojangles_7;
|
||||
}
|
||||
|
||||
font = m_loadedFonts[efontdata][scale];
|
||||
if (font == NULL)
|
||||
{
|
||||
fontData = m_loadedFontData[efontdata];
|
||||
if (fontData == NULL)
|
||||
{
|
||||
SFontData *sfontdata;
|
||||
switch (efontdata)
|
||||
{
|
||||
case eFontData_Mojangles_7: sfontdata = &SFontData::Mojangles_7; break;
|
||||
case eFontData_Mojangles_11: sfontdata = &SFontData::Mojangles_11; break;
|
||||
default: sfontdata = NULL; break;
|
||||
}
|
||||
|
||||
fontData = new XUI_FontData();
|
||||
fontData->Create(*sfontdata);
|
||||
|
||||
m_loadedFontData[efontdata] = fontData;
|
||||
}
|
||||
|
||||
font = new XUI_Font( efontdata, scale, fontData );
|
||||
m_loadedFonts[efontdata][scale] = font;
|
||||
}
|
||||
font->IncRefCount();
|
||||
|
||||
*phFont = (HFONTOBJ)font;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
VOID XUI_FontRenderer::ReleaseFont( HFONTOBJ hFont )
|
||||
{
|
||||
XUI_Font *xuiFont = (XUI_Font*) hFont;
|
||||
if (xuiFont != NULL)
|
||||
{
|
||||
xuiFont->DecRefCount();
|
||||
if (xuiFont->refCount <= 0)
|
||||
{
|
||||
AUTO_VAR(it, m_loadedFonts[xuiFont->m_iFontData].find(xuiFont->m_fScaleFactor) );
|
||||
if (it != m_loadedFonts[xuiFont->m_iFontData].end()) m_loadedFonts[xuiFont->m_iFontData].erase(it);
|
||||
delete hFont;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT XUI_FontRenderer::GetFontMetrics( HFONTOBJ hFont, XUIFontMetrics *pFontMetrics )
|
||||
{
|
||||
if( hFont == 0 || pFontMetrics == 0 ) return E_INVALIDARG;
|
||||
|
||||
XUI_Font *font = (XUI_Font *)hFont;
|
||||
|
||||
pFontMetrics->fLineHeight = (font->m_fontData->getFontYAdvance() + 1) * font->m_fYScaleFactor;
|
||||
pFontMetrics->fMaxAscent = font->m_fontData->getMaxAscent() * font->m_fYScaleFactor;
|
||||
pFontMetrics->fMaxDescent = font->m_fontData->getMaxDescent() * font->m_fYScaleFactor;
|
||||
pFontMetrics->fMaxHeight = font->m_fontData->getFontHeight() * font->m_fYScaleFactor;
|
||||
pFontMetrics->fMaxWidth = font->m_fontData->getFontMaxWidth() * font->m_fXScaleFactor;
|
||||
pFontMetrics->fMaxAdvance = font->m_fontData->getFontMaxWidth() * font->m_fXScaleFactor;
|
||||
|
||||
//*pFontMetrics = font->m_fontMetrics; // g_fontMetrics;
|
||||
return( S_OK );
|
||||
}
|
||||
|
||||
HRESULT XUI_FontRenderer::GetCharMetrics( HFONTOBJ hFont, WCHAR wch, XUICharMetrics *pCharMetrics )
|
||||
{
|
||||
if (hFont == 0 || pCharMetrics == 0) return E_INVALIDARG;
|
||||
|
||||
XUI_Font *font = (XUI_Font *)hFont;
|
||||
XUI_FontData::SChar sChar = font->m_fontData->getChar(wch);
|
||||
|
||||
pCharMetrics->fMinX = sChar.getMinX() * font->m_fYScaleFactor;
|
||||
pCharMetrics->fMinY = sChar.getMinY() * font->m_fYScaleFactor;
|
||||
pCharMetrics->fMaxX = sChar.getMaxX() * font->m_fYScaleFactor;
|
||||
pCharMetrics->fMaxY = sChar.getMaxY() * font->m_fYScaleFactor;
|
||||
pCharMetrics->fAdvance = sChar.getAdvance() * font->m_fYScaleFactor;
|
||||
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT XUI_FontRenderer::DrawCharToTexture( HFONTOBJ hFont, WCHAR wch, HXUIDC hDC, IXuiTexture * pTexture, UINT x, UINT y, UINT width, UINT height, UINT insetX, UINT insetY )
|
||||
{
|
||||
if( hFont==0 || pTexture==NULL ) return E_INVALIDARG;
|
||||
return( S_OK );
|
||||
}
|
||||
|
||||
HRESULT XUI_FontRenderer::DrawCharsToDevice( HFONTOBJ hFont, CharData * pCharData, DWORD dwCount, RECT *pClipRect, HXUIDC hDC, D3DXMATRIX * pWorldViewProj )
|
||||
{
|
||||
if( hFont == 0 ) return E_INVALIDARG;
|
||||
if( dwCount == 0 ) return( S_OK );
|
||||
|
||||
DWORD RenderStateA[8];
|
||||
DWORD SamplerStateA[5];
|
||||
XMVECTOR vconsts[20];
|
||||
XMVECTOR pconsts[20];
|
||||
XUI_Font *font = (XUI_Font *)hFont;
|
||||
|
||||
// 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())
|
||||
{
|
||||
float fScaleX, fScaleY;
|
||||
font->GetScaleFactors(&fScaleX,&fScaleY);
|
||||
int iScaleX=fScaleX;
|
||||
int iScaleY=fScaleY;
|
||||
|
||||
if(iScaleX%2==0)
|
||||
{
|
||||
int iWorldX=pWorldViewProj->_41;
|
||||
pWorldViewProj->_41 = (float)(iWorldX & -2);
|
||||
}
|
||||
if(iScaleY%2==0)
|
||||
{
|
||||
int iWorldY=pWorldViewProj->_42;
|
||||
pWorldViewProj->_42 = (float)(iWorldY & -2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// make x an even number for 480 4:3
|
||||
int iWorldX=pWorldViewProj->_41;
|
||||
pWorldViewProj->_41 = (float)(iWorldX & -2);
|
||||
|
||||
// 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 iWorldY=pWorldViewProj->_42;
|
||||
if(iWorldY%2==1)
|
||||
{
|
||||
pWorldViewProj->_42-=1.0f/3.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_pD3DDevice->GetVertexShaderConstantF( 0, (float *)vconsts, 20 );
|
||||
g_pD3DDevice->GetPixelShaderConstantF( 0, (float *)pconsts, 20 );
|
||||
g_pD3DDevice->SetRenderState(D3DRS_HALFPIXELOFFSET, TRUE);
|
||||
GetRenderAndSamplerStates(g_pD3DDevice, RenderStateA, SamplerStateA );
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
RenderManager.Set_matrixDirty();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, 1280.0f, 720.0f, 0, 1000, 3000);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glTranslatef(0, 0, -2000);
|
||||
glColor4f(1.0f,1.0f,1.0f,1.0f);
|
||||
float matrixCopy[16];
|
||||
memcpy(matrixCopy, pWorldViewProj, 64);
|
||||
matrixCopy[11] = 0.0f;
|
||||
matrixCopy[12] = floor(matrixCopy[12] + 0.5f);
|
||||
matrixCopy[13] = floor(matrixCopy[13] + 0.5f);
|
||||
matrixCopy[14] = floor(matrixCopy[14] + 0.5f);
|
||||
matrixCopy[15] = 1.0f;
|
||||
glMultMatrixf(matrixCopy);
|
||||
|
||||
|
||||
float lineXPos = 0.0f;
|
||||
float lineYPos = 0.0f;
|
||||
DWORD colour = 0;
|
||||
DWORD style = 0;
|
||||
#if 1
|
||||
for( int i = 0; i < dwCount; i++ )
|
||||
{
|
||||
wstring string;
|
||||
string.push_back(pCharData[i].wch);
|
||||
lineYPos = pCharData[i].y;
|
||||
lineXPos = pCharData[i].x;
|
||||
colour = pCharData[i].dwColor;
|
||||
style = pCharData[i].dwStyle;
|
||||
|
||||
//if(pCharData[i].wch > font->m_fontData->getMaxGlyph())
|
||||
if ( !font->m_fontData->getChar(pCharData[i].wch).hasChar() )
|
||||
{
|
||||
// Can't render this character, fallback to the default renderer
|
||||
app.OverrideFontRenderer(false,false);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
DWORD i = 0;
|
||||
while( i < dwCount )
|
||||
{
|
||||
wstring string;
|
||||
lineYPos = pCharData[i].y;
|
||||
lineXPos = pCharData[i].x;
|
||||
colour = pCharData[i].dwColor;
|
||||
style = pCharData[i].dwStyle;
|
||||
|
||||
while(i < dwCount && pCharData[i].y == lineYPos)
|
||||
{
|
||||
string.push_back(pCharData[i].wch);
|
||||
++i;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool dropShadow = false;
|
||||
if( (style & XUI_FONT_STYLE_DROPSHADOW) == XUI_FONT_STYLE_DROPSHADOW) dropShadow = true;
|
||||
|
||||
//int yPos = (int)pCharData[i].y + (int)(font->m_fontMetrics.fLineHeight - font->m_fontMetrics.fMaxAscent)/2;
|
||||
//if( (pCharData[i].dwStyle & XUI_FONT_STYLE_VERTICAL_CENTER) == XUI_FONT_STYLE_VERTICAL_CENTER)
|
||||
//{
|
||||
// yPos = (pClipRect->bottom - (int)font->m_fontMetrics.fLineHeight) / 2;
|
||||
//}
|
||||
|
||||
if(dropShadow)
|
||||
{
|
||||
DWORD shadowColour;
|
||||
XuiGetTextDropShadowColor(hDC, &shadowColour);
|
||||
// 4J Stu - Shadow colour is currently ignored
|
||||
font->DrawShadowText( lineXPos,lineYPos,colour,shadowColour,string.c_str() );
|
||||
//drawShadow(thisChar, (int)pCharData[i].x, yPos, pCharData[i].dwColor );
|
||||
}
|
||||
else
|
||||
{
|
||||
font->DrawText( lineXPos,lineYPos,colour,string.c_str() );
|
||||
//draw(thisChar, (int)pCharData[i].x, yPos, pCharData[i].dwColor, false );
|
||||
}
|
||||
}
|
||||
|
||||
g_pD3DDevice->SetVertexShaderConstantF( 0, (float *)vconsts, 20 );
|
||||
g_pD3DDevice->SetPixelShaderConstantF( 0, (float *)pconsts, 20 );
|
||||
SetRenderAndSamplerStates(g_pD3DDevice, RenderStateA, SamplerStateA );
|
||||
g_pD3DDevice->SetRenderState(D3DRS_HALFPIXELOFFSET, FALSE);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
XuiRenderRestoreState(hDC);
|
||||
|
||||
return( S_OK );
|
||||
}
|
||||
49
Minecraft.Client/Xbox/Font/XUI_FontRenderer.h
Normal file
49
Minecraft.Client/Xbox/Font/XUI_FontRenderer.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
class XUI_FontData;
|
||||
class XUI_Font;
|
||||
|
||||
// Define this to use this class as the XUI font renderer
|
||||
#define OVERRIDE_XUI_FONT_RENDERER
|
||||
|
||||
//#define USE_SCALING_FONT
|
||||
|
||||
class XUI_FontRenderer : public IXuiFontRenderer
|
||||
{
|
||||
protected:
|
||||
enum eFontData
|
||||
{
|
||||
eFontData_MIN = 0,
|
||||
eFontData_Mojangles_7 = 0,
|
||||
eFontData_Mojangles_11,
|
||||
eFontData_MAX
|
||||
};
|
||||
|
||||
// The font data is the image and size/coords data
|
||||
XUI_FontData *m_loadedFontData[eFontData_MAX];
|
||||
|
||||
// The XUI_Font is a temporary instance that is around as long as XUI needs it, but does the actual rendering
|
||||
// These can be chained
|
||||
unordered_map<float, XUI_Font *> m_loadedFonts[eFontData_MAX];
|
||||
|
||||
public:
|
||||
XUI_FontRenderer();
|
||||
|
||||
// 4J - IXuiFontRenderer interface
|
||||
virtual HRESULT STDMETHODCALLTYPE Init( float fDpi );
|
||||
virtual VOID STDMETHODCALLTYPE Term();
|
||||
virtual HRESULT STDMETHODCALLTYPE GetCaps( DWORD * pdwCaps );
|
||||
virtual HRESULT STDMETHODCALLTYPE CreateFont( const TypefaceDescriptor * pTypefaceDescriptor,
|
||||
float fPointSize, DWORD dwStyle, DWORD dwReserved, HFONTOBJ * phFont );
|
||||
virtual VOID STDMETHODCALLTYPE ReleaseFont( HFONTOBJ hFont );
|
||||
virtual HRESULT STDMETHODCALLTYPE GetFontMetrics( HFONTOBJ hFont, XUIFontMetrics *pFontMetrics );
|
||||
virtual HRESULT STDMETHODCALLTYPE GetCharMetrics( HFONTOBJ hFont, WCHAR wch,
|
||||
XUICharMetrics *pCharMetrics );
|
||||
virtual HRESULT STDMETHODCALLTYPE DrawCharToTexture( HFONTOBJ hFont, WCHAR wch, HXUIDC hDC,
|
||||
IXuiTexture * pTexture, UINT x, UINT y, UINT width, UINT height,
|
||||
UINT insetX, UINT insetY );
|
||||
virtual HRESULT STDMETHODCALLTYPE DrawCharsToDevice( HFONTOBJ hFont, CharData * pCharData,
|
||||
DWORD dwCount, RECT *pClipRect, HXUIDC hDC,
|
||||
D3DXMATRIX * pWorldViewProj );
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user