Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Core/GameEngine/Include/GameClient/DisplayString.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class DisplayString : public MemoryPoolObject
virtual void draw( Int x, Int y, Color color, Color dropColor, Int xDrop, Int yDrop ) = 0; ///< render text with the drop shadow being at the offsets passed in
virtual void getSize( Int *width, Int *height ) = 0; ///< get render size
virtual Int getWidth( Int charPos = -1 ) = 0; ///< get text with up to charPos characters, 1- = all characters
virtual void setComplexTextEnabled( Bool enabled ) = 0; ///< enable shaped complex text for this string

virtual void setUseHotkey( Bool useHotkey, Color hotKeyColor ) = 0;

Expand Down
5 changes: 5 additions & 0 deletions Core/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2725,6 +2725,11 @@ GameWindow *GameWindowManager::gogoGadgetTextEntry( GameWindow *parent,
data->text = TheDisplayStringManager->newDisplayString();
data->sText = TheDisplayStringManager->newDisplayString();
data->constructText = TheDisplayStringManager->newDisplayString();
// TheSuperHackers @bugfix Omar Aglan 28/08/2026 Keep editable strings on
// the legacy path until shaped caret metrics are supported.
data->text->setComplexTextEnabled(FALSE);
data->sText->setComplexTextEnabled(FALSE);
data->constructText->setComplexTextEnabled(FALSE);

// set the max for the text lengths
// data->text->allocateFixed( ENTRY_TEXT_LEN );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class W3DDisplayString : public DisplayString
virtual void draw( Int x, Int y, Color color, Color dropColor, Int xDrop, Int yDrop ) override; ///< render text with the drop shadow being at the offsets passed in
virtual void getSize( Int *width, Int *height ) override; ///< get render size
virtual Int getWidth( Int charPos = -1) override;
virtual void setComplexTextEnabled( Bool enabled ) override;
virtual void setWordWrap( Int wordWrap ) override; ///< set the word wrap width
virtual void setWordWrapCentered( Bool isCentered ) override; ///< If this is set to true, the text on a new line is centered
virtual void setFont( GameFont *font ) override; ///< set a font for display
Expand All @@ -95,8 +96,9 @@ class W3DDisplayString : public DisplayString

Render2DSentenceClass m_textRenderer; ///< for drawing text
Render2DSentenceClass m_textRendererHotKey; ///< for drawing text
Bool m_textChanged; ///< when contents of string change this is TRUE
Bool m_fontChanged; ///< when font has changed this is TRUE
Bool m_textChanged; ///< when text or font changes this is TRUE
Bool m_sentenceChanged; ///< when the rendered sentence needs new polygons
Bool m_hasComplexTextExtents; ///< cached size uses shaped complex-text metrics
UnicodeString m_hotkey; ///< holds the current hotkey marker.
Bool m_useHotKey;
ICoord2D m_hotKeyPos;
Expand All @@ -113,6 +115,7 @@ class W3DDisplayString : public DisplayString
///////////////////////////////////////////////////////////////////////////////
// INLINING ///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
inline void W3DDisplayString::usingResources( UnsignedInt frame ) { m_lastResourceFrame = frame; }
// TheSuperHackers @bugfix Omar Aglan 10/09/2026 Reserve zero for strings without rendering resources.
inline void W3DDisplayString::usingResources( UnsignedInt frame ) { m_lastResourceFrame = max(frame, 1U); }

// EXTERNALS //////////////////////////////////////////////////////////////////
112 changes: 79 additions & 33 deletions Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
#include "GameClient/Display.h"
#include "GameClient/GameClient.h"
#include "W3DDevice/GameClient/W3DDisplayString.h"
#include "GameClient/HotKey.h"
#include "GameClient/GameFont.h"
#include "GameClient/GlobalLanguage.h"

Expand Down Expand Up @@ -85,7 +84,8 @@ W3DDisplayString::W3DDisplayString()
m_currDropColor = 0;
m_size.x = 0;
m_size.y = 0;
m_fontChanged = FALSE;
m_sentenceChanged = FALSE;
m_hasComplexTextExtents = FALSE;
m_clipRegion.lo.x = 0;
m_clipRegion.lo.y = 0;
m_clipRegion.hi.x = 0;
Expand Down Expand Up @@ -130,6 +130,18 @@ void W3DDisplayString::notifyTextChanged()
}
}

// TheSuperHackers @bugfix Omar Aglan 09/09/2026 Refresh the accelerator before measuring changed text.
m_hotkey.clear();
if (m_useHotKey) {
for (const WideChar *marker = getText().str(); *marker; ++marker) {
if (*marker == L'&' && marker[1] > L' ') {
m_hotkey.concat(marker[1]);
break;
}
}
}
m_textRenderer.Set_Hot_Key_Parse(!m_hotkey.isEmpty());

// get our new text extents
computeExtents();

Expand All @@ -145,6 +157,37 @@ void W3DDisplayString::notifyTextChanged()

}

// W3DDisplayString::checkForChangedTextData ==================================
/** Rebuild the sentence and update its extents when its source data changes */
//=============================================================================
void W3DDisplayString::checkForChangedTextData()
{
if( !m_textChanged )
return;

bool usedComplexText = false;
Vector2 legacyExtents;
m_textRenderer.Build_Sentence(getText().str(),
m_hotkey.isEmpty() ? nullptr : &m_hotKeyPos.x,
m_hotkey.isEmpty() ? nullptr : &m_hotKeyPos.y,
&usedComplexText, &legacyExtents);
if(!m_hotkey.isEmpty())
m_textRendererHotKey.Build_Sentence(m_hotkey.str(), nullptr, nullptr);

// TheSuperHackers @bugfix Omar Aglan 04/09/2026 Resolve renderer fallback before callers position complex text.
if (m_hasComplexTextExtents && !usedComplexText) {
m_size.x = legacyExtents.X;
m_size.y = legacyExtents.Y;
m_hasComplexTextExtents = FALSE;
}

m_textChanged = FALSE;
m_sentenceChanged = TRUE;
// TheSuperHackers @bugfix Omar Aglan 06/09/2026 Track resources created by size queries before the first draw.
if( TheGameClient )
usingResources( TheGameClient->getFrame() );
}

// W3DDisplayString::Draw =====================================================
/** Draw the text at the specified location in in the specified colors
* in the parameters. Since we keep an instance of the rendered text
Expand All @@ -159,35 +202,13 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor )
}
void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDrop, Int yDrop )
{
Bool needNewPolys = FALSE;

// sanity
if( getTextLength() == 0 )
return; // nothing to draw

// if our font or text has changed we need to build a new sentence
if( m_fontChanged || m_textChanged )
{
if(m_useHotKey)
{
m_textRenderer.Set_Hot_Key_Parse(TRUE);
m_textRenderer.Build_Sentence( getText().str(), &m_hotKeyPos.x, &m_hotKeyPos.y );
m_hotkey.translate(TheHotKeyManager->searchHotKey(getText()));
if(!m_hotkey.isEmpty())
m_textRendererHotKey.Build_Sentence(m_hotkey.str(), nullptr, nullptr);
else
{
m_useHotKey = FALSE;
m_textRendererHotKey.Reset();
}
}
else
m_textRenderer.Build_Sentence( getText().str(), nullptr, nullptr );
m_fontChanged = FALSE;
m_textChanged = FALSE;
needNewPolys = TRUE;

}
checkForChangedTextData();
Bool needNewPolys = m_sentenceChanged;
m_sentenceChanged = FALSE;

//
// if our position has changed, or our colors have changed, or our
Expand Down Expand Up @@ -217,7 +238,7 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr
m_textRenderer.Set_Location( Vector2( m_textPos.x, m_textPos.y ) );
m_textRenderer.Draw_Sentence( m_currTextColor );

if (m_useHotKey)
if (!m_hotkey.isEmpty())
{
m_textRendererHotKey.Reset_Polys();
m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) );
Expand All @@ -228,7 +249,7 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr

TheDisplay->flush();

if (m_useHotKey)
if (!m_hotkey.isEmpty())
{
m_textRendererHotKey.Render();
}
Expand All @@ -247,6 +268,8 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr
//=============================================================================
void W3DDisplayString::getSize( Int *width, Int *height )
{
if ( m_hasComplexTextExtents )
checkForChangedTextData();

// assign the width and height we have stored to parameters present
if( width )
Expand All @@ -262,6 +285,9 @@ void W3DDisplayString::getSize( Int *width, Int *height )

Int W3DDisplayString::getWidth( Int charPos )
{
if ( charPos == -1 && m_hasComplexTextExtents )
checkForChangedTextData();

FontCharsClass * font;
Int width = 0;
Int count = 0;
Expand All @@ -270,6 +296,9 @@ Int W3DDisplayString::getWidth( Int charPos )

if ( font )
{
if ( charPos == -1 && m_hasComplexTextExtents )
return m_size.x;

const WideChar *text = m_textString.str();
WideChar ch;

Expand All @@ -286,6 +315,17 @@ Int W3DDisplayString::getWidth( Int charPos )
return width;
}

// W3DDisplayString::setComplexTextEnabled ====================================
/** Enable shaped complex text for this display string */
//=============================================================================
void W3DDisplayString::setComplexTextEnabled( Bool enabled )
{
if (m_textRenderer.Set_Complex_Text_Enabled(enabled)) {
m_textRendererHotKey.Set_Complex_Text_Enabled(enabled);
notifyTextChanged();
}
}

// W3DDisplayString::setFont ==================================================
/** Set the font for this particular display string */
//=============================================================================
Expand Down Expand Up @@ -313,8 +353,8 @@ void W3DDisplayString::setFont( GameFont *font )
// recompute extents for text with new font
computeExtents();

// set flag telling us the font has changed since last render
m_fontChanged = TRUE;
// rebuild the sentence with the new font
m_textChanged = TRUE;

}

Expand Down Expand Up @@ -363,14 +403,17 @@ void W3DDisplayString::computeExtents()

m_size.x = 0;
m_size.y = 0;
m_hasComplexTextExtents = FALSE;

}
else
{

Vector2 extents = m_textRenderer.Get_Formatted_Text_Extents(getText().str()); //Get_Text_Extents( getText().str() );
bool hasComplexTextExtents = false;
Vector2 extents = m_textRenderer.Get_Formatted_Text_Extents(getText().str(), &hasComplexTextExtents);
m_size.x = extents.X;
m_size.y = extents.Y;
m_hasComplexTextExtents = hasComplexTextExtents;

}

Expand All @@ -388,9 +431,12 @@ void W3DDisplayString::setWordWrap( Int wordWrap )

void W3DDisplayString::setUseHotkey( Bool useHotkey, Color hotKeyColor )
{
if (m_useHotKey == useHotkey && m_hotKeyColor == hotKeyColor) {
return;
}

m_useHotKey = useHotkey;
m_hotKeyColor = hotKeyColor;
m_textRenderer.Set_Hot_Key_Parse(useHotkey);
notifyTextChanged();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ void W3DDisplayStringManager::update()
string = static_cast<W3DDisplayString *>(m_currentCheckpoint);
}

UnsignedInt currFrame = TheGameClient->getFrame();
// TheSuperHackers @bugfix Omar Aglan 10/09/2026 Match the nonzero timestamp used for frame-zero resources.
UnsignedInt currFrame = max(TheGameClient->getFrame(), 1U);
const UnsignedInt w3dCleanupTime = 60; /** any string not rendered after
this many frames will have its
render resources freed */
Expand Down
3 changes: 3 additions & 0 deletions Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ set(WW3D2_SRC
#render2d.h
render2dsentence.cpp
render2dsentence.h
complextext.h
unicodebidi.h
supplementarybidi.inl
renderobjectrecycler.cpp
renderobjectrecycler.h
rendobj.cpp
Expand Down
Loading
Loading