aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Xbox/Font
diff options
context:
space:
mode:
authordaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
committerdaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
commitb691c43c44ff180d10e7d4a9afc83b98551ff586 (patch)
tree3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Xbox/Font
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.Client/Xbox/Font')
-rw-r--r--Minecraft.Client/Xbox/Font/XUI_Font.cpp503
-rw-r--r--Minecraft.Client/Xbox/Font/XUI_Font.h93
-rw-r--r--Minecraft.Client/Xbox/Font/XUI_FontData.cpp395
-rw-r--r--Minecraft.Client/Xbox/Font/XUI_FontData.h147
-rw-r--r--Minecraft.Client/Xbox/Font/XUI_FontRenderer.cpp307
-rw-r--r--Minecraft.Client/Xbox/Font/XUI_FontRenderer.h49
6 files changed, 1494 insertions, 0 deletions
diff --git a/Minecraft.Client/Xbox/Font/XUI_Font.cpp b/Minecraft.Client/Xbox/Font/XUI_Font.cpp
new file mode 100644
index 00000000..8b1a624b
--- /dev/null
+++ b/Minecraft.Client/Xbox/Font/XUI_Font.cpp
@@ -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();
+} \ No newline at end of file
diff --git a/Minecraft.Client/Xbox/Font/XUI_Font.h b/Minecraft.Client/Xbox/Font/XUI_Font.h
new file mode 100644
index 00000000..1b6278e3
--- /dev/null
+++ b/Minecraft.Client/Xbox/Font/XUI_Font.h
@@ -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();
+}; \ No newline at end of file
diff --git a/Minecraft.Client/Xbox/Font/XUI_FontData.cpp b/Minecraft.Client/Xbox/Font/XUI_FontData.cpp
new file mode 100644
index 00000000..7a70cdfb
--- /dev/null
+++ b/Minecraft.Client/Xbox/Font/XUI_FontData.cpp
@@ -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 );
+}
+*/ \ No newline at end of file
diff --git a/Minecraft.Client/Xbox/Font/XUI_FontData.h b/Minecraft.Client/Xbox/Font/XUI_FontData.h
new file mode 100644
index 00000000..af18c7a6
--- /dev/null
+++ b/Minecraft.Client/Xbox/Font/XUI_FontData.h
@@ -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);
+}; \ No newline at end of file
diff --git a/Minecraft.Client/Xbox/Font/XUI_FontRenderer.cpp b/Minecraft.Client/Xbox/Font/XUI_FontRenderer.cpp
new file mode 100644
index 00000000..48581905
--- /dev/null
+++ b/Minecraft.Client/Xbox/Font/XUI_FontRenderer.cpp
@@ -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 );
+}
diff --git a/Minecraft.Client/Xbox/Font/XUI_FontRenderer.h b/Minecraft.Client/Xbox/Font/XUI_FontRenderer.h
new file mode 100644
index 00000000..cffe2ed1
--- /dev/null
+++ b/Minecraft.Client/Xbox/Font/XUI_FontRenderer.h
@@ -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 );
+
+}; \ No newline at end of file