diff options
| author | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
|---|---|---|
| committer | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
| commit | b691c43c44ff180d10e7d4a9afc83b98551ff586 (patch) | |
| tree | 3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Xbox/Font | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.Client/Xbox/Font')
| -rw-r--r-- | Minecraft.Client/Xbox/Font/XUI_Font.cpp | 503 | ||||
| -rw-r--r-- | Minecraft.Client/Xbox/Font/XUI_Font.h | 93 | ||||
| -rw-r--r-- | Minecraft.Client/Xbox/Font/XUI_FontData.cpp | 395 | ||||
| -rw-r--r-- | Minecraft.Client/Xbox/Font/XUI_FontData.h | 147 | ||||
| -rw-r--r-- | Minecraft.Client/Xbox/Font/XUI_FontRenderer.cpp | 307 | ||||
| -rw-r--r-- | Minecraft.Client/Xbox/Font/XUI_FontRenderer.h | 49 |
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 |
