Rewrite fonticon localized string caching to fix strings being reallocated

This commit is contained in:
Jan 2021-09-22 22:50:22 +02:00
parent e70b329614
commit 70bc28ee7b
2 changed files with 223 additions and 171 deletions

View File

@ -40,17 +40,16 @@ namespace Components
}; };
unsigned(*TextRenderer::currentColorTable)[TEXT_COLOR_COUNT]; unsigned(*TextRenderer::currentColorTable)[TEXT_COLOR_COUNT];
TextRenderer::FontIconAutocompleteContext TextRenderer::autocompleteContextArray[FONT_ICON_ACI_COUNT]{}; TextRenderer::FontIconAutocompleteContext TextRenderer::autocompleteContextArray[FONT_ICON_ACI_COUNT];
std::map<std::string, TextRenderer::FontIconTableEntry> TextRenderer::fontIconLookup; std::map<std::string, TextRenderer::FontIconTableEntry> TextRenderer::fontIconLookup;
std::vector<TextRenderer::FontIconTableEntry> TextRenderer::fontIconList; std::vector<TextRenderer::FontIconTableEntry> TextRenderer::fontIconList;
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_BIG> TextRenderer::stringSearchStartWith; TextRenderer::BufferedLocalizedString TextRenderer::stringHintAutoComplete(REFERENCE_HINT_AUTO_COMPLETE, STRING_BUFFER_SIZE_SMALL);
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringHintAutoComplete; TextRenderer::BufferedLocalizedString TextRenderer::stringHintModifier(REFERENCE_HINT_MODIFIER, STRING_BUFFER_SIZE_SMALL);
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringHintModifier; TextRenderer::BufferedLocalizedString TextRenderer::stringListHeader(REFERENCE_MODIFIER_LIST_HEADER, STRING_BUFFER_SIZE_SMALL);
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_NONE> TextRenderer::stringListHeader; TextRenderer::BufferedLocalizedString TextRenderer::stringListFlipHorizontal(REFERENCE_MODIFIER_LIST_FLIP_HORIZONTAL, STRING_BUFFER_SIZE_SMALL);
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringListFlipHorizontal; TextRenderer::BufferedLocalizedString TextRenderer::stringListFlipVertical(REFERENCE_MODIFIER_LIST_FLIP_VERTICAL, STRING_BUFFER_SIZE_SMALL);
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringListFlipVertical; TextRenderer::BufferedLocalizedString TextRenderer::stringListBig(REFERENCE_MODIFIER_LIST_BIG, STRING_BUFFER_SIZE_SMALL);
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringListBig;
Dvar::Var TextRenderer::cg_newColors; Dvar::Var TextRenderer::cg_newColors;
Dvar::Var TextRenderer::cg_fontIconAutocomplete; Dvar::Var TextRenderer::cg_fontIconAutocomplete;
@ -61,6 +60,77 @@ namespace Components
Game::dvar_t* TextRenderer::g_ColorBlind_EnemyTeam; Game::dvar_t* TextRenderer::g_ColorBlind_EnemyTeam;
Game::dvar_t** TextRenderer::con_inputBoxColor = reinterpret_cast<Game::dvar_t**>(0x9FD4BC); Game::dvar_t** TextRenderer::con_inputBoxColor = reinterpret_cast<Game::dvar_t**>(0x9FD4BC);
TextRenderer::BufferedLocalizedString::BufferedLocalizedString(const char* reference, const size_t bufferSize)
: stringReference(reference),
stringBuffer(std::make_unique<char[]>(bufferSize)),
stringBufferSize(bufferSize),
stringWidth{-1}
{
}
void TextRenderer::BufferedLocalizedString::Cache()
{
const auto* formattingString = Game::UI_SafeTranslateString(stringReference);
if (formattingString != nullptr)
{
strncpy(stringBuffer.get(), formattingString, stringBufferSize);
for (auto& width : stringWidth)
width = -1;
}
}
const char* TextRenderer::BufferedLocalizedString::Format(const char* value)
{
const auto* formattingString = Game::UI_SafeTranslateString(stringReference);
if (formattingString == nullptr)
{
stringBuffer[0] = '\0';
return stringBuffer.get();
}
Game::ConversionArguments conversionArguments{};
conversionArguments.args[conversionArguments.argCount++] = value;
Game::UI_ReplaceConversions(formattingString, &conversionArguments, stringBuffer.get(), stringBufferSize);
for (auto& width : stringWidth)
width = -1;
return stringBuffer.get();
}
const char* TextRenderer::BufferedLocalizedString::GetString() const
{
return stringBuffer.get();
}
int TextRenderer::BufferedLocalizedString::GetWidth(const FontIconAutocompleteInstance autocompleteInstance, Game::Font_s* font)
{
assert(autocompleteInstance < FONT_ICON_ACI_COUNT);
if (stringWidth[autocompleteInstance] < 0)
stringWidth[autocompleteInstance] = Game::R_TextWidth(GetString(), std::numeric_limits<int>::max(), font);
return stringWidth[autocompleteInstance];
}
TextRenderer::FontIconAutocompleteContext::FontIconAutocompleteContext()
: autocompleteActive(false),
inModifiers(false),
userClosed(false),
lastHash(0u),
results{},
resultCount(0u),
hasMoreResults(false),
resultOffset(0u),
lastResultOffset(0u),
selectedOffset(0u),
maxFontIconWidth(0.0f),
maxMaterialNameWidth(0.0f),
stringSearchStartWith(REFERENCE_SEARCH_START_WITH, STRING_BUFFER_SIZE_BIG)
{
}
unsigned TextRenderer::HsvToRgb(HsvColor hsv) unsigned TextRenderer::HsvToRgb(HsvColor hsv)
{ {
unsigned rgb; unsigned rgb;
@ -199,7 +269,7 @@ namespace Components
} }
} }
void TextRenderer::UpdateAutocompleteContext(TextRenderer::FontIconAutocompleteContext& context, const Game::field_t* edit, Game::Font_s* font, const float textXScale) void TextRenderer::UpdateAutocompleteContext(FontIconAutocompleteContext& context, const Game::field_t* edit, Game::Font_s* font, const float textXScale)
{ {
int fontIconStart = -1; int fontIconStart = -1;
auto inModifiers = false; auto inModifiers = false;
@ -283,18 +353,24 @@ namespace Components
context.lastHash = currentFontIconHash; context.lastHash = currentFontIconHash;
} }
// Update results for query and scroll // Update results for query and scroll and update search string
context.lastQuery = std::string(&edit->buffer[fontIconStart], edit->cursor - fontIconStart); context.lastQuery = std::string(&edit->buffer[fontIconStart], edit->cursor - fontIconStart);
stringSearchStartWith.Format(context.lastQuery.c_str()); context.stringSearchStartWith.Format(context.lastQuery.c_str());
UpdateAutocompleteContextResults(context, font, textXScale); UpdateAutocompleteContextResults(context, font, textXScale);
} }
void TextRenderer::DrawAutocompleteModifiers(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font, float textXScale, float textYScale) void TextRenderer::DrawAutocompleteModifiers(const FontIconAutocompleteInstance instance, const float x, const float y, Game::Font_s* font, const float textXScale, const float textYScale)
{ {
const auto textWidth = std::max(std::max(std::max(stringListHeader.GetWidth(font), stringListFlipHorizontal.GetWidth(font)), assert(instance < FONT_ICON_ACI_COUNT);
stringListFlipVertical.GetWidth(font)), const auto& context = autocompleteContextArray[instance];
stringListBig.GetWidth(font));
const auto boxWidth = static_cast<float>(textWidth) * textXScale; // Check which is the longest string to be able to calculate how big the box needs to be
const auto longestStringLength = std::max(std::max(std::max(stringListHeader.GetWidth(instance, font), stringListFlipHorizontal.GetWidth(instance, font)),
stringListFlipVertical.GetWidth(instance, font)),
stringListBig.GetWidth(instance, font));
// Draw background box
const auto boxWidth = static_cast<float>(longestStringLength) * textXScale;
constexpr auto totalLines = 4u; constexpr auto totalLines = 4u;
const auto lineHeight = static_cast<float>(font->pixelHeight) * textYScale; const auto lineHeight = static_cast<float>(font->pixelHeight) * textYScale;
DrawAutocompleteBox(context, DrawAutocompleteBox(context,
@ -306,8 +382,11 @@ namespace Components
auto currentY = y + lineHeight; auto currentY = y + lineHeight;
// Draw header line: "Following modifiers are available:"
Game::R_AddCmdDrawText(stringListHeader.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0); Game::R_AddCmdDrawText(stringListHeader.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
currentY += lineHeight; currentY += lineHeight;
// Draw modifier hints
Game::R_AddCmdDrawText(stringListFlipHorizontal.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0); Game::R_AddCmdDrawText(stringListFlipHorizontal.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
currentY += lineHeight; currentY += lineHeight;
Game::R_AddCmdDrawText(stringListFlipVertical.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0); Game::R_AddCmdDrawText(stringListFlipVertical.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
@ -315,18 +394,23 @@ namespace Components
Game::R_AddCmdDrawText(stringListBig.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0); Game::R_AddCmdDrawText(stringListBig.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
} }
void TextRenderer::DrawAutocompleteResults(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font, const float textXScale, const float textYScale) void TextRenderer::DrawAutocompleteResults(const FontIconAutocompleteInstance instance, const float x, const float y, Game::Font_s* font, const float textXScale, const float textYScale)
{ {
assert(instance < FONT_ICON_ACI_COUNT);
auto& context = autocompleteContextArray[instance];
const auto hintEnabled = cg_fontIconAutocompleteHint.get<bool>(); const auto hintEnabled = cg_fontIconAutocompleteHint.get<bool>();
auto longestStringLength = stringSearchStartWith.GetWidth(font); // Check which is the longest string to be able to calculate how big the box needs to be
auto longestStringLength = context.stringSearchStartWith.GetWidth(instance, font);
if(hintEnabled) if(hintEnabled)
longestStringLength = std::max(std::max(longestStringLength, stringHintAutoComplete.GetWidth(font)), stringHintModifier.GetWidth(font)); longestStringLength = std::max(std::max(longestStringLength, stringHintAutoComplete.GetWidth(instance, font)), stringHintModifier.GetWidth(instance, font));
const auto colSpacing = FONT_ICON_AUTOCOMPLETE_COL_SPACING * textXScale; const auto colSpacing = FONT_ICON_AUTOCOMPLETE_COL_SPACING * textXScale;
const auto boxWidth = std::max(context.maxFontIconWidth + context.maxMaterialNameWidth + colSpacing, static_cast<float>(longestStringLength) * textXScale); const auto boxWidth = std::max(context.maxFontIconWidth + context.maxMaterialNameWidth + colSpacing, static_cast<float>(longestStringLength) * textXScale);
const auto lineHeight = static_cast<float>(font->pixelHeight) * textYScale; const auto lineHeight = static_cast<float>(font->pixelHeight) * textYScale;
// Draw background box
const auto totalLines = 1u + context.resultCount + (hintEnabled ? 2u : 0u); const auto totalLines = 1u + context.resultCount + (hintEnabled ? 2u : 0u);
const auto arrowPadding = context.resultOffset > 0 || context.hasMoreResults ? FONT_ICON_AUTOCOMPLETE_ARROW_SIZE : 0.0f; const auto arrowPadding = context.resultOffset > 0 || context.hasMoreResults ? FONT_ICON_AUTOCOMPLETE_ARROW_SIZE : 0.0f;
DrawAutocompleteBox(context, DrawAutocompleteBox(context,
@ -335,11 +419,13 @@ namespace Components
boxWidth + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2 + arrowPadding, boxWidth + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2 + arrowPadding,
static_cast<float>(totalLines) * lineHeight + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2, static_cast<float>(totalLines) * lineHeight + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2,
(*con_inputBoxColor)->current.vector); (*con_inputBoxColor)->current.vector);
// Draw header line "Search results for: xyz"
auto currentY = y + lineHeight; auto currentY = y + lineHeight;
Game::R_AddCmdDrawText(stringSearchStartWith.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0); Game::R_AddCmdDrawText(context.stringSearchStartWith.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
currentY += lineHeight; currentY += lineHeight;
// Draw search results
const auto selectedIndex = context.selectedOffset - context.resultOffset; const auto selectedIndex = context.selectedOffset - context.resultOffset;
for(auto resultIndex = 0u; resultIndex < context.resultCount; resultIndex++) for(auto resultIndex = 0u; resultIndex < context.resultCount; resultIndex++)
{ {
@ -353,6 +439,7 @@ namespace Components
currentY += lineHeight; currentY += lineHeight;
} }
// Draw extra hint if enabled
if(hintEnabled) if(hintEnabled)
{ {
Game::R_AddCmdDrawText(stringHintAutoComplete.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, HINT_COLOR, 0); Game::R_AddCmdDrawText(stringHintAutoComplete.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, HINT_COLOR, 0);
@ -361,12 +448,15 @@ namespace Components
} }
} }
void TextRenderer::DrawAutocomplete(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font, const float textXScale, const float textYScale) void TextRenderer::DrawAutocomplete(const FontIconAutocompleteInstance instance, const float x, const float y, Game::Font_s* font, const float textXScale, const float textYScale)
{ {
assert(instance < FONT_ICON_ACI_COUNT);
const auto& context = autocompleteContextArray[instance];
if (context.inModifiers) if (context.inModifiers)
DrawAutocompleteModifiers(context, x, y, font, textXScale, textYScale); DrawAutocompleteModifiers(instance, x, y, font, textXScale, textYScale);
else else
DrawAutocompleteResults(context, x, y, font, textXScale, textYScale); DrawAutocompleteResults(instance, x, y, font, textXScale, textYScale);
} }
void TextRenderer::Con_DrawInput_Hk(const int localClientNum) void TextRenderer::Con_DrawInput_Hk(const int localClientNum)
@ -386,7 +476,7 @@ namespace Components
{ {
const auto x = Game::conDrawInputGlob->leftX; const auto x = Game::conDrawInputGlob->leftX;
const auto y = Game::con_screenMin[1] + 6.0f + static_cast<float>(2 * Game::R_TextHeight(Game::cls->consoleFont)); const auto y = Game::con_screenMin[1] + 6.0f + static_cast<float>(2 * Game::R_TextHeight(Game::cls->consoleFont));
DrawAutocomplete(autocompleteContext, x, y, Game::cls->consoleFont, 1.0f, 1.0f); DrawAutocomplete(FONT_ICON_ACI_CONSOLE, x, y, Game::cls->consoleFont, 1.0f, 1.0f);
} }
} }
@ -415,7 +505,7 @@ namespace Components
UpdateAutocompleteContext(autocompleteContext, edit, font, ww); UpdateAutocompleteContext(autocompleteContext, edit, font, ww);
if (autocompleteContext.autocompleteActive) if (autocompleteContext.autocompleteActive)
{ {
DrawAutocomplete(autocompleteContext, std::floor(xx), std::floor(yy), font, ww, hh); DrawAutocomplete(FONT_ICON_ACI_CHAT, std::floor(xx), std::floor(yy), font, ww, hh);
} }
} }
@ -1442,23 +1532,11 @@ namespace Components
void TextRenderer::InitFontIconStrings() void TextRenderer::InitFontIconStrings()
{ {
stringSearchStartWith.Load("FONT_ICON_SEARCH_START_WITH");
stringHintAutoComplete.Load("FONT_ICON_HINT_AUTO_COMPLETE");
stringHintAutoComplete.Format("TAB"); stringHintAutoComplete.Format("TAB");
stringHintModifier.Load("FONT_ICON_HINT_MODIFIER");
stringHintModifier.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_SEPARATOR_CHARACTER)); stringHintModifier.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_SEPARATOR_CHARACTER));
stringListHeader.Cache();
stringListHeader.Load("FONT_ICON_MODIFIER_LIST_HEADER");
stringListFlipHorizontal.Load("FONT_ICON_MODIFIER_LIST_FLIP_HORIZONTAL");
stringListFlipHorizontal.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_FLIP_HORIZONTALLY)); stringListFlipHorizontal.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_FLIP_HORIZONTALLY));
stringListFlipVertical.Load("FONT_ICON_MODIFIER_LIST_FLIP_VERTICAL");
stringListFlipVertical.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_FLIP_VERTICALLY)); stringListFlipVertical.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_FLIP_VERTICALLY));
stringListBig.Load("FONT_ICON_MODIFIER_LIST_BIG");
stringListBig.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_BIG)); stringListBig.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_BIG));
} }

View File

@ -42,108 +42,16 @@ namespace Components
class TextRenderer : public Component class TextRenderer : public Component
{ {
public: static constexpr auto STRING_BUFFER_SIZE_BIG = 1024;
enum FontIconAutocompleteInstance : unsigned static constexpr auto STRING_BUFFER_SIZE_SMALL = 128;
{
FONT_ICON_ACI_CONSOLE,
FONT_ICON_ACI_CHAT,
FONT_ICON_ACI_COUNT static constexpr auto REFERENCE_SEARCH_START_WITH = "FONT_ICON_SEARCH_START_WITH";
}; static constexpr auto REFERENCE_HINT_AUTO_COMPLETE = "FONT_ICON_HINT_AUTO_COMPLETE";
static constexpr auto REFERENCE_HINT_MODIFIER = "FONT_ICON_HINT_MODIFIER";
private: static constexpr auto REFERENCE_MODIFIER_LIST_HEADER = "FONT_ICON_MODIFIER_LIST_HEADER";
struct FontIconTableEntry static constexpr auto REFERENCE_MODIFIER_LIST_FLIP_HORIZONTAL = "FONT_ICON_MODIFIER_LIST_FLIP_HORIZONTAL";
{ static constexpr auto REFERENCE_MODIFIER_LIST_FLIP_VERTICAL = "FONT_ICON_MODIFIER_LIST_FLIP_VERTICAL";
std::string iconName; static constexpr auto REFERENCE_MODIFIER_LIST_BIG = "FONT_ICON_MODIFIER_LIST_BIG";
std::string materialName;
Game::Material* material;
};
struct HsvColor
{
unsigned char h;
unsigned char s;
unsigned char v;
};
class FontIconAutocompleteResult
{
public:
std::string fontIconName;
std::string materialName;
};
class FontIconAutocompleteContext
{
public:
static constexpr auto MAX_RESULTS = 10;
bool autocompleteActive;
bool inModifiers;
bool userClosed;
unsigned int lastHash;
std::string lastQuery;
FontIconAutocompleteResult results[MAX_RESULTS];
size_t resultCount;
bool hasMoreResults;
size_t resultOffset;
size_t lastResultOffset;
size_t selectedOffset;
float maxFontIconWidth;
float maxMaterialNameWidth;
};
template<size_t S>
class FormattedStringBuffer
{
public:
FormattedStringBuffer()
: formattingString(nullptr),
stringBuffer{0},
stringWidth(-1)
{
}
void Load(const char* reference)
{
formattingString = Game::UI_SafeTranslateString(reference);
}
const char* Format(const char* value)
{
if (formattingString == nullptr)
return stringBuffer;
Game::ConversionArguments conversionArguments{};
conversionArguments.args[conversionArguments.argCount++] = value;
Game::UI_ReplaceConversions(formattingString, &conversionArguments, stringBuffer, sizeof(stringBuffer));
stringWidth = -1;
return stringBuffer;
}
const char* GetString() const
{
if(stringBuffer[0] != '\0')
return stringBuffer;
if(formattingString)
return formattingString;
return stringBuffer;
}
int GetWidth(Game::Font_s* font)
{
if (stringWidth < 0)
stringWidth = Game::R_TextWidth(GetString(), std::numeric_limits<int>::max(), font);
return stringWidth;
}
private:
const char* formattingString;
char stringBuffer[S];
int stringWidth;
};
static constexpr unsigned MY_ALTCOLOR_TWO = 0x0DCE6FFE6; static constexpr unsigned MY_ALTCOLOR_TWO = 0x0DCE6FFE6;
static constexpr unsigned COLOR_MAP_HASH = 0xA0AB1041; static constexpr unsigned COLOR_MAP_HASH = 0xA0AB1041;
@ -180,6 +88,93 @@ namespace Components
1.0f 1.0f
}; };
public:
static constexpr char FONT_ICON_SEPARATOR_CHARACTER = ':';
static constexpr char FONT_ICON_MODIFIER_SEPARATOR_CHARACTER = '+';
static constexpr char FONT_ICON_MODIFIER_FLIP_HORIZONTALLY = 'h';
static constexpr char FONT_ICON_MODIFIER_FLIP_VERTICALLY = 'v';
static constexpr char FONT_ICON_MODIFIER_BIG = 'b';
static constexpr char COLOR_FIRST_CHAR = '0';
static constexpr char COLOR_LAST_CHAR = CharForColorIndex(TEXT_COLOR_COUNT - 1);
enum FontIconAutocompleteInstance : unsigned
{
FONT_ICON_ACI_CONSOLE,
FONT_ICON_ACI_CHAT,
FONT_ICON_ACI_COUNT
};
struct FontIconInfo
{
Game::Material* material;
bool flipHorizontal;
bool flipVertical;
bool big;
};
private:
struct FontIconTableEntry
{
std::string iconName;
std::string materialName;
Game::Material* material;
};
struct HsvColor
{
unsigned char h;
unsigned char s;
unsigned char v;
};
class FontIconAutocompleteResult
{
public:
std::string fontIconName;
std::string materialName;
};
class BufferedLocalizedString
{
public:
BufferedLocalizedString(const char* reference, size_t bufferSize);
void Cache();
const char* Format(const char* value);
const char* GetString() const;
int GetWidth(FontIconAutocompleteInstance autocompleteInstance, Game::Font_s* font);
private:
const char* stringReference;
std::unique_ptr<char[]> stringBuffer;
size_t stringBufferSize;
int stringWidth[FONT_ICON_ACI_COUNT];
};
class FontIconAutocompleteContext
{
public:
static constexpr auto MAX_RESULTS = 10;
bool autocompleteActive;
bool inModifiers;
bool userClosed;
unsigned int lastHash;
std::string lastQuery;
FontIconAutocompleteResult results[MAX_RESULTS];
size_t resultCount;
bool hasMoreResults;
size_t resultOffset;
size_t lastResultOffset;
size_t selectedOffset;
float maxFontIconWidth;
float maxMaterialNameWidth;
BufferedLocalizedString stringSearchStartWith;
FontIconAutocompleteContext();
};
static unsigned colorTableDefault[TEXT_COLOR_COUNT]; static unsigned colorTableDefault[TEXT_COLOR_COUNT];
static unsigned colorTableNew[TEXT_COLOR_COUNT]; static unsigned colorTableNew[TEXT_COLOR_COUNT];
static unsigned(*currentColorTable)[TEXT_COLOR_COUNT]; static unsigned(*currentColorTable)[TEXT_COLOR_COUNT];
@ -187,16 +182,12 @@ namespace Components
static std::map<std::string, FontIconTableEntry> fontIconLookup; static std::map<std::string, FontIconTableEntry> fontIconLookup;
static std::vector<FontIconTableEntry> fontIconList; static std::vector<FontIconTableEntry> fontIconList;
static constexpr auto STRING_BUFFER_SIZE_BIG = 1024; static BufferedLocalizedString stringHintAutoComplete;
static constexpr auto STRING_BUFFER_SIZE_SMALL = 128; static BufferedLocalizedString stringHintModifier;
static constexpr auto STRING_BUFFER_SIZE_NONE = 1; static BufferedLocalizedString stringListHeader;
static FormattedStringBuffer<STRING_BUFFER_SIZE_BIG> stringSearchStartWith; static BufferedLocalizedString stringListFlipHorizontal;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringHintAutoComplete; static BufferedLocalizedString stringListFlipVertical;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringHintModifier; static BufferedLocalizedString stringListBig;
static FormattedStringBuffer<STRING_BUFFER_SIZE_NONE> stringListHeader;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringListFlipHorizontal;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringListFlipVertical;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringListBig;
static Dvar::Var cg_newColors; static Dvar::Var cg_newColors;
static Dvar::Var cg_fontIconAutocomplete; static Dvar::Var cg_fontIconAutocomplete;
@ -208,23 +199,6 @@ namespace Components
static Game::dvar_t** con_inputBoxColor; static Game::dvar_t** con_inputBoxColor;
public: public:
static constexpr char FONT_ICON_SEPARATOR_CHARACTER = ':';
static constexpr char FONT_ICON_MODIFIER_SEPARATOR_CHARACTER = '+';
static constexpr char FONT_ICON_MODIFIER_FLIP_HORIZONTALLY = 'h';
static constexpr char FONT_ICON_MODIFIER_FLIP_VERTICALLY = 'v';
static constexpr char FONT_ICON_MODIFIER_BIG = 'b';
static constexpr char COLOR_FIRST_CHAR = '0';
static constexpr char COLOR_LAST_CHAR = CharForColorIndex(TEXT_COLOR_COUNT - 1);
struct FontIconInfo
{
Game::Material* material;
bool flipHorizontal;
bool flipVertical;
bool big;
};
static void DrawText2D(const char* text, float x, float y, Game::Font_s* font, float xScale, float yScale, float sinAngle, float cosAngle, Game::GfxColor color, int maxLength, int renderFlags, int cursorPos, char cursorLetter, float padding, Game::GfxColor glowForcedColor, int fxBirthTime, int fxLetterTime, int fxDecayStartTime, int fxDecayDuration, Game::Material* fxMaterial, Game::Material* fxMaterialGlow); static void DrawText2D(const char* text, float x, float y, Game::Font_s* font, float xScale, float yScale, float sinAngle, float cosAngle, Game::GfxColor color, int maxLength, int renderFlags, int cursorPos, char cursorLetter, float padding, Game::GfxColor glowForcedColor, int fxBirthTime, int fxLetterTime, int fxDecayStartTime, int fxDecayDuration, Game::Material* fxMaterial, Game::Material* fxMaterialGlow);
static int R_TextWidth_Hk(const char* text, int maxChars, Game::Font_s* font); static int R_TextWidth_Hk(const char* text, int maxChars, Game::Font_s* font);
static unsigned int ColorIndex(char index); static unsigned int ColorIndex(char index);
@ -247,9 +221,9 @@ namespace Components
static unsigned HsvToRgb(HsvColor hsv); static unsigned HsvToRgb(HsvColor hsv);
static void DrawAutocompleteBox(const FontIconAutocompleteContext& context, float x, float y, float w, float h, const float* color); static void DrawAutocompleteBox(const FontIconAutocompleteContext& context, float x, float y, float w, float h, const float* color);
static void DrawAutocompleteModifiers(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font, float textXScale, float textYScale); static void DrawAutocompleteModifiers(FontIconAutocompleteInstance instance, float x, float y, Game::Font_s* font, float textXScale, float textYScale);
static void DrawAutocompleteResults(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font, float textXScale, float textYScale); static void DrawAutocompleteResults(FontIconAutocompleteInstance instance, float x, float y, Game::Font_s* font, float textXScale, float textYScale);
static void DrawAutocomplete(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font, float textXScale, float textYScale); static void DrawAutocomplete(FontIconAutocompleteInstance instance, float x, float y, Game::Font_s* font, float textXScale, float textYScale);
static void UpdateAutocompleteContextResults(FontIconAutocompleteContext& context, Game::Font_s* font, float textXScale); static void UpdateAutocompleteContextResults(FontIconAutocompleteContext& context, Game::Font_s* font, float textXScale);
static void UpdateAutocompleteContext(FontIconAutocompleteContext& context, const Game::field_t* edit, Game::Font_s* font, const float textXScale); static void UpdateAutocompleteContext(FontIconAutocompleteContext& context, const Game::field_t* edit, Game::Font_s* font, const float textXScale);
static void Field_Draw_Say(int localClientNum, Game::field_t* edit, int x, int y, int horzAlign, int vertAlign); static void Field_Draw_Say(int localClientNum, Game::field_t* edit, int x, int y, int horzAlign, int vertAlign);