- added a CanPrint function to FFont and used that to handle the statistics display on the automap HUD to only replace the font when actually needed, not based on the language.

This commit is contained in:
Christoph Oelckers 2019-04-22 09:08:43 +02:00
parent 68c33a6e43
commit e0a0be4f7b
8 changed files with 119 additions and 29 deletions

View File

@ -140,20 +140,7 @@ bool CheckFontComplete(FFont *font)
{
// Also check if the SmallFont contains all characters this language needs.
// If not, switch back to the original one.
const uint8_t* checkstr = (const uint8_t*)GStrings["REQUIRED_CHARACTERS"];
bool incomplete = false;
if (!checkstr) return true;
while (int c = GetCharFromString(checkstr))
{
bool redirected;
int cc = font->GetCharCode(c, true);
if (c != cc && (c != 0x1e9e || cc != 0xdf))
{
return false;
}
}
return true;
return font->CanPrint(GStrings["REQUIRED_CHARACTERS"]);
}
void UpdateGenericUI(bool cvar)

View File

@ -597,6 +597,7 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight)
{
auto scale = GetUIScale(hud_scale);
auto font = generic_ui ? NewSmallFont : SmallFont;
auto font2 = font;
auto vwidth = screen->GetWidth() / scale;
auto vheight = screen->GetHeight() / scale;
auto fheight = font->GetHeight();
@ -606,6 +607,11 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight)
int textdist = 4;
int zerowidth = font->GetCharWidth('0');
if (!generic_ui)
{
if (!font->CanPrint(GStrings("AM_MONSTERS")) || !font->CanPrint(GStrings("AM_SECRETS")) || !font->CanPrint(GStrings("AM_ITEMS"))) font2 = OriginalSmallFont;
}
if (am_showtime)
{
sec = Tics2Seconds(primaryLevel->time);
@ -629,14 +635,14 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight)
if (am_showmonsters)
{
textbuffer.Format("%s\34%c %d/%d", GStrings("AM_MONSTERS"), crdefault + 65, primaryLevel->killed_monsters, primaryLevel->total_monsters);
screen->DrawText(font, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);
screen->DrawText(font2, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);
y += fheight;
}
if (am_showsecrets)
{
textbuffer.Format("%s\34%c %d/%d", GStrings("AM_SECRETS"), crdefault + 65, primaryLevel->found_secrets, primaryLevel->total_secrets);
screen->DrawText(font, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);
screen->DrawText(font2, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);
y += fheight;
}
@ -644,7 +650,7 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight)
if (am_showitems)
{
textbuffer.Format("%s\34%c %d/%d", GStrings("AM_ITEMS"), crdefault + 65, primaryLevel->found_items, primaryLevel->total_items);
screen->DrawText(font, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);
screen->DrawText(font2, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);
y += fheight;
}

View File

@ -482,6 +482,51 @@ FFont::~FFont ()
}
}
//==========================================================================
//
// FFont :: CheckCase
//
//==========================================================================
void FFont::CheckCase()
{
int lowercount = 0, uppercount = 0;
for (unsigned i = 0; i < Chars.Size(); i++)
{
unsigned chr = i + FirstChar;
if (lowerforupper[chr] == chr && upperforlower[chr] == chr)
{
continue; // not a letter;
}
if (myislower(chr))
{
if (Chars[i].TranslatedPic != nullptr) lowercount++;
}
else
{
if (Chars[i].TranslatedPic != nullptr) uppercount++;
}
}
if (lowercount == 0) return; // This is an uppercase-only font and we are done.
// The ß needs special treatment because it is far more likely to be supplied lowercase only, even in an uppercase font.
if (Chars[0xdf - FirstChar].TranslatedPic != nullptr)
{
if (LastChar < 0x1e9e)
{
Chars.Resize(0x1e9f - FirstChar);
LastChar = 0x1e9e;
}
if (Chars[0x1e9e - FirstChar].TranslatedPic == nullptr)
{
std::swap(Chars[0xdf - FirstChar], Chars[0x1e9e - FirstChar]);
lowercount--;
uppercount++;
if (lowercount == 0) return;
}
}
}
//==========================================================================
//
// FFont :: FindFont
@ -834,15 +879,6 @@ int FFont::GetCharCode(int code, bool needpic) const
return code;
}
// Special handling for the ß which may only exist as lowercase, so for this we need an additional upper -> lower check for all fonts aside from the generic substitution logic.
if (code == 0x1e9e)
{
if (LastChar <= 0xdf && (!needpic || Chars[0xdf - FirstChar].TranslatedPic != nullptr))
{
return 0xdf;
}
}
// Use different substitution logic based on the fonts content:
// In a font which has both upper and lower case, prefer unaccented small characters over capital ones.
// In a pure upper-case font, do not check for lower case replacements.
@ -975,6 +1011,47 @@ double GetBottomAlignOffset(FFont *font, int c)
return offset;
}
//==========================================================================
//
// Checks if the font contains proper glyphs for all characters in the string
//
//==========================================================================
bool FFont::CanPrint(const uint8_t *string) const
{
while (*string)
{
auto chr = GetCharFromString(string);
if (!MixedCase) chr = upperforlower[chr]; // For uppercase-only fonts we shouldn't check lowercase characters.
if (chr == TEXTCOLOR_ESCAPE)
{
// We do not need to check for UTF-8 in here.
if (*string == '[')
{
while (*string != '\0' && *string != ']')
{
++string;
}
}
if (*string != '\0')
{
++string;
}
continue;
}
else if (chr != '\n')
{
int cc = GetCharCode(chr, true);
if (chr != cc)
{
return false;
}
}
}
return true;
}
//==========================================================================
//
// Find string width using this font

View File

@ -849,7 +849,7 @@ int stripaccent(int code)
else if (code == 0x171) code = 0xfc;
else
{
static const char accentless[] = "AaAaAaCcCcCcCcDdDdEeEeEeEeEeGgGgGgGgHhHhIiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnnNnOoOoOoOoRrRrRrSsSsSsSsTtTtTtUuUuUuUuUuUuWwYyYZzZzZz ";
static const char accentless[] = "AaAaAaCcCcCcCcDdDdEeEeEeEeEeGgGgGgGgHhHhIiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnnNnOoOoOoOoRrRrRrSsSsSsSsTtTtTtUuUuUuUuUuUuWwYyYZzZzZzs";
return accentless[code - 0x100];
}
}
@ -908,7 +908,7 @@ int stripaccent(int code)
}
// skip the rest of Latin characters because none of them are relevant for modern languages.
// skip the rest of Latin characters because none of them are relevant for modern languages, except Vietnamese which cannot be represented with the tiny bitmap fonts anyway.
return code;
}

View File

@ -113,6 +113,11 @@ public:
inline int StringWidth (const char *str) const { return StringWidth ((const uint8_t *)str); }
inline int StringWidth (const FString &str) const { return StringWidth ((const uint8_t *)str.GetChars()); }
// Checks if the font contains all characters to print this text.
bool CanPrint(const uint8_t *str) const;
inline bool CanPrint(const char *str) const { return CanPrint((const uint8_t *)str); }
inline bool CanPrint(const FString &str) const { return CanPrint((const uint8_t *)str.GetChars()); }
int GetCharCode(int code, bool needpic) const;
char GetCursor() const { return Cursor; }
void SetCursor(char c) { Cursor = c; }
@ -120,6 +125,7 @@ public:
bool NoTranslate() const { return noTranslate; }
void RecordAllTextureColors(uint32_t *usedcolors);
virtual void SetDefaultTranslation(uint32_t *colors);
void CheckCase();
protected:
FFont (int lump);

View File

@ -2021,6 +2021,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, StringWidth, StringWidth)
ACTION_RETURN_INT(StringWidth(self, str));
}
static int CanPrint(FFont *font, const FString &str)
{
const char *txt = str[0] == '$' ? GStrings(&str[1]) : str.GetChars();
return font->CanPrint(txt);
}
DEFINE_ACTION_FUNCTION_NATIVE(FFont, CanPrint, CanPrint)
{
PARAM_SELF_STRUCT_PROLOGUE(FFont);
PARAM_STRING(str);
ACTION_RETURN_INT(CanPrint(self, str));
}
static int FindFontColor(int name)
{
return V_FindFontColor(ENamedName(name));

View File

@ -308,6 +308,7 @@ struct Font native
native int GetCharWidth(int code);
native int StringWidth(String code);
native bool CanPrint(String code);
native int GetHeight();
native String GetCursor();

View File

@ -828,7 +828,7 @@ class BaseStatusBar native ui
// automap HUD common drawer
// This is not called directly to give a status bar the opportunity to
// change the text colors. If you want to do something different,
// override DrawAutomap directly.
// override DrawAutomapHUD directly.
//
//============================================================================