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/XUI_Font.cpp | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.Client/Xbox/Font/XUI_Font.cpp')
| -rw-r--r-- | Minecraft.Client/Xbox/Font/XUI_Font.cpp | 503 |
1 files changed, 503 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 |
