- create a second font based on the VGA glyphs that is stylistically more similar to the SmallFont and use that for the option menus.

This commit is contained in:
Christoph Oelckers 2019-03-17 16:22:38 +01:00
parent 2e260c6367
commit 2227c15010
10 changed files with 239 additions and 76 deletions

View file

@ -42,6 +42,51 @@
#include "fontinternals.h"
struct HexDataSource
{
int FirstChar = INT_MAX, LastChar = INT_MIN;
TArray<uint8_t> glyphdata;
unsigned glyphmap[65536] = {};
//==========================================================================
//
// parse a HEX font
//
//==========================================================================
void ParseDefinition(int lumpnum)
{
FScanner sc;
sc.OpenLumpNum(lumpnum);
sc.SetCMode(true);
glyphdata.Push(0); // ensure that index 0 can be used as 'not present'.
while (sc.GetString())
{
int codepoint = (int)strtoull(sc.String, nullptr, 16);
sc.MustGetStringName(":");
sc.MustGetString();
if (codepoint >= 0 && codepoint < 65536 && !sc.Compare("00000000000000000000000000000000")) // don't set up empty glyphs.
{
unsigned size = (unsigned)strlen(sc.String);
unsigned offset = glyphdata.Reserve(size / 2 + 1);
glyphmap[codepoint] = offset;
glyphdata[offset++] = size / 2;
for (unsigned i = 0; i < size; i += 2)
{
char hex[] = { sc.String[i], sc.String[i + 1], 0 };
glyphdata[offset++] = (uint8_t)strtoull(hex, nullptr, 16);
}
if (codepoint < FirstChar) FirstChar = codepoint;
if (codepoint > LastChar) LastChar = codepoint;
}
}
}
};
static HexDataSource hexdata;
// This is a font character that reads RLE compressed data.
class FHexFontChar : public FImageSource
{
@ -113,51 +158,78 @@ TArray<uint8_t> FHexFontChar::CreatePalettedPixels(int)
return Pixels;
}
class FHexFontChar2 : public FHexFontChar
{
public:
FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height);
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
};
//==========================================================================
//
// FHexFontChar :: FHexFontChar
//
// Used by HEX fonts.
//
//==========================================================================
FHexFontChar2::FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height)
: FHexFontChar(sourcedata, swidth, width, height)
{
}
//==========================================================================
//
// FHexFontChar :: Get8BitPixels
//
// The render style has no relevance here.
//
//==========================================================================
TArray<uint8_t> FHexFontChar2::CreatePalettedPixels(int)
{
int destSize = Width * Height;
TArray<uint8_t> Pixels(destSize, true);
uint8_t *dest_p = Pixels.Data();
auto drawLayer = [&](int ix, int iy, int color)
{
const uint8_t *src_p = SourceData;
for (int y = 0; y < Height-2; y++)
{
for (int x = 0; x < SourceWidth; x++)
{
int byte = *src_p++;
uint8_t *pixelstart = dest_p + (ix + 8 * x) * Height + (iy+y);
for (int bit = 0; bit < 8; bit++)
{
if (byte & (128 >> bit))
{
pixelstart[bit*Height] = color;
}
}
}
}
};
memset(dest_p, 0, destSize);
const int darkcolor = 3;
const int brightcolor = 14;
for (int xx=0;xx<3;xx++) for (int yy=0;yy<3;yy++) if (xx !=1 || yy != 1)
drawLayer(xx, yy, darkcolor);
drawLayer(1, 1, brightcolor);
return Pixels;
}
class FHexFont : public FFont
{
TArray<uint8_t> glyphdata;
unsigned glyphmap[65536] = {};
public:
//==========================================================================
//
// parse a HEX font
//
//==========================================================================
void ParseDefinition(int lumpnum)
{
FScanner sc;
FirstChar = INT_MAX;
LastChar = INT_MIN;
sc.OpenLumpNum(lumpnum);
sc.SetCMode(true);
glyphdata.Push(0); // ensure that index 0 can be used as 'not present'.
while (sc.GetString())
{
int codepoint = (int)strtoull(sc.String, nullptr, 16);
sc.MustGetStringName(":");
sc.MustGetString();
if (codepoint >= 0 && codepoint < 65536 && !sc.Compare("00000000000000000000000000000000")) // don't set up empty glyphs.
{
unsigned size = (unsigned)strlen(sc.String);
unsigned offset = glyphdata.Reserve(size/2 + 1);
glyphmap[codepoint] = offset;
glyphdata[offset++] = size / 2;
for(unsigned i = 0; i < size; i+=2)
{
char hex[] = { sc.String[i], sc.String[i+1], 0 };
glyphdata[offset++] = (uint8_t)strtoull(hex, nullptr, 16);
}
if (codepoint < FirstChar) FirstChar = codepoint;
if (codepoint > LastChar) LastChar = codepoint;
}
}
}
//==========================================================================
//
// FHexFont :: FHexFont
@ -173,7 +245,8 @@ public:
FontName = fontname;
ParseDefinition(lump);
FirstChar = hexdata.FirstChar;
LastChar = hexdata.LastChar;
Next = FirstFont;
FirstFont = this;
@ -208,11 +281,11 @@ public:
Chars.Resize(LastChar - FirstChar + 1);
for (int i = FirstChar; i <= LastChar; i++)
{
if (glyphmap[i] > 0)
if (hexdata.glyphmap[i] > 0)
{
auto offset = glyphmap[i];
int size = glyphdata[offset] / 16;
Chars[i - FirstChar].TranslatedPic = new FImageTexture(new FHexFontChar (&glyphdata[offset+1], size, size * 9, 16));
auto offset = hexdata.glyphmap[i];
int size = hexdata.glyphdata[offset] / 16;
Chars[i - FirstChar].TranslatedPic = new FImageTexture(new FHexFontChar (&hexdata.glyphdata[offset+1], size, size * 9, 16));
Chars[i - FirstChar].TranslatedPic->SetUseType(ETextureType::FontChar);
Chars[i - FirstChar].XMove = size * spacing;
TexMan.AddTexture(Chars[i - FirstChar].TranslatedPic);
@ -226,6 +299,79 @@ public:
};
class FHexFont2 : public FFont
{
public:
//==========================================================================
//
// FHexFont :: FHexFont
//
// Loads a HEX font
//
//==========================================================================
FHexFont2(const char *fontname, int lump)
: FFont(lump)
{
assert(lump >= 0);
FontName = fontname;
FirstChar = hexdata.FirstChar;
LastChar = hexdata.LastChar;
Next = FirstFont;
FirstFont = this;
FontHeight = 18;
SpaceWidth = 10;
GlobalKerning = -1;
translateUntranslated = true;
LoadTranslations();
}
//==========================================================================
//
// FHexFont :: LoadTranslations
//
//==========================================================================
void LoadTranslations()
{
const int spacing = 9;
double luminosity[256];
memset(PatchRemap, 0, 256);
for (int i = 0; i < 18; i++)
{
// Create a gradient similar to the old console font.
PatchRemap[i] = i;
luminosity[i] = i / 17.;
}
ActiveColors = 18;
Chars.Resize(LastChar - FirstChar + 1);
for (int i = FirstChar; i <= LastChar; i++)
{
if (hexdata.glyphmap[i] > 0)
{
auto offset = hexdata.glyphmap[i];
int size = hexdata.glyphdata[offset] / 16;
Chars[i - FirstChar].TranslatedPic = new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18));
Chars[i - FirstChar].TranslatedPic->SetUseType(ETextureType::FontChar);
Chars[i - FirstChar].XMove = size * spacing;
TexMan.AddTexture(Chars[i - FirstChar].TranslatedPic);
}
else Chars[i - FirstChar].XMove = spacing;
}
BuildTranslations(luminosity, nullptr, &TranslationParms[0][0], ActiveColors, nullptr);
}
};
//==========================================================================
//
//
@ -234,5 +380,18 @@ public:
FFont *CreateHexLumpFont (const char *fontname, int lump)
{
if (hexdata.FirstChar == INT_MAX) hexdata.ParseDefinition(lump);
return new FHexFont(fontname, lump);
}
//==========================================================================
//
//
//
//==========================================================================
FFont *CreateHexLumpFont2(const char *fontname, int lump)
{
if (hexdata.FirstChar == INT_MAX) hexdata.ParseDefinition(lump);
return new FHexFont2(fontname, lump);
}

View file

@ -1449,10 +1449,12 @@ void V_InitFonts()
V_InitCustomFonts();
FFont *CreateHexLumpFont(const char *fontname, int lump);
FFont *CreateHexLumpFont2(const char *fontname, int lump);
auto lump = Wads.CheckNumForFullName("newconsolefont.hex", 0); // This is always loaded from gzdoom.pk3 to prevent overriding it with incomplete replacements.
if (lump == -1) I_FatalError("newconsolefont.hex not found"); // This font is needed - do not start up without it.
NewConsoleFont = CreateHexLumpFont("NewConsoleFont", lump);
NewSmallFont = CreateHexLumpFont2("NewSmallFont", lump);
CurrentConsoleFont = NewConsoleFont;
// load the heads-up font
@ -1540,6 +1542,6 @@ void V_ClearFonts()
delete FFont::FirstFont;
}
FFont::FirstFont = nullptr;
CurrentConsoleFont = NewConsoleFont = SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = nullptr;
CurrentConsoleFont = NewSmallFont = NewConsoleFont = SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = nullptr;
}

View file

@ -164,7 +164,7 @@ protected:
};
extern FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *CurrentConsoleFont;
extern FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont;
void V_InitFonts();
void V_ClearFonts();

View file

@ -145,7 +145,7 @@ public:
int DisplayWidth, DisplayHeight;
FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *CurrentConsoleFont;
FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont;
uint32_t Col2RGB8[65][256];
uint32_t *Col2RGB8_LessPrecision[65];
@ -908,6 +908,7 @@ DEFINE_GLOBAL(SmallFont2)
DEFINE_GLOBAL(BigFont)
DEFINE_GLOBAL(ConFont)
DEFINE_GLOBAL(NewConsoleFont)
DEFINE_GLOBAL(NewSmallFont)
DEFINE_GLOBAL(IntermissionFont)
DEFINE_GLOBAL(CleanXfac)
DEFINE_GLOBAL(CleanYfac)

View file

@ -23,6 +23,7 @@ struct _ native // These are the global variables, the struct is only here to av
native readonly Font bigfont;
native readonly Font confont;
native readonly Font NewConsoleFont;
native readonly Font NewSmallFont;
native readonly Font intermissionfont;
native readonly int CleanXFac;
native readonly int CleanYFac;

View file

@ -285,7 +285,7 @@ class Menu : Object native ui version("2.4")
static void DrawConText (int color, int x, int y, String str)
{
screen.DrawText (NewConsoleFont, color, x, y, str, DTA_CellX, 9 * CleanXfac_1/2, DTA_CellY, 8 * CleanYfac_1);
screen.DrawText (ConFont, color, x, y, str, DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac);
}
}

View file

@ -451,7 +451,7 @@ class OptionMenu : Menu
}
int ytop = y + mDesc.mScrollTop * 8 * CleanYfac_1;
int lastrow = screen.GetHeight() - NewConsoleFont.GetHeight() * CleanYfac_1;
int lastrow = screen.GetHeight() - NewSmallFont.GetHeight() * CleanYfac_1;
int i;
for (i = 0; i < mDesc.mItems.Size() && y <= lastrow; i++)
@ -519,8 +519,8 @@ class GameplayMenu : OptionMenu
Super.Drawer();
String s = String.Format("dmflags = %d dmflags2 = %d", dmflags, dmflags2);
screen.DrawText (NewConsoleFont, OptionMenuSettings.mFontColorValue,
(screen.GetWidth() - NewConsoleFont.StringWidth (s) * CleanXfac_1) / 2, 0, s,
screen.DrawText (NewSmallFont, OptionMenuSettings.mFontColorValue,
(screen.GetWidth() - NewSmallFont.StringWidth (s) * CleanXfac_1) / 2, 0, s,
DTA_CleanNoMove_1, true);
}
}
@ -532,8 +532,8 @@ class CompatibilityMenu : OptionMenu
Super.Drawer();
String s = String.Format("compatflags = %d compatflags2 = %d", compatflags, compatflags2);
screen.DrawText (NewConsoleFont, OptionMenuSettings.mFontColorValue,
(screen.GetWidth() - NewConsoleFont.StringWidth (s) * CleanXfac_1) / 2, 0, s,
screen.DrawText (NewSmallFont, OptionMenuSettings.mFontColorValue,
(screen.GetWidth() - NewSmallFont.StringWidth (s) * CleanXfac_1) / 2, 0, s,
DTA_CleanNoMove_1, true);
}
}

View file

@ -51,10 +51,10 @@ class OptionMenuItem : MenuItemBase
int overlay = grayed? Color(96,48,0,0) : 0;
int x;
int w = NewConsoleFont.StringWidth(label) * CleanXfac_1;
int w = NewSmallFont.StringWidth(label) * CleanXfac_1;
if (!mCentered) x = indent - w;
else x = (screen.GetWidth() - w) / 2;
screen.DrawText (NewConsoleFont, color, x, y, label, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
screen.DrawText (NewSmallFont, color, x, y, label, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
return x;
}
@ -71,7 +71,7 @@ class OptionMenuItem : MenuItemBase
override int GetIndent()
{
if (mCentered) return 0;
return NewConsoleFont.StringWidth(Stringtable.Localize(mLabel));
return NewSmallFont.StringWidth(Stringtable.Localize(mLabel));
}
override bool MouseEvent(int type, int x, int y)
@ -140,7 +140,7 @@ class OptionMenuItemLabeledSubmenu : OptionMenuItemSubmenu
String text = mLabelCVar.GetString();
if (text.Length() == 0) text = Stringtable.Localize("$notset");
screen.DrawText (NewConsoleFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true);
screen.DrawText (NewSmallFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true);
return indent;
}
@ -298,7 +298,7 @@ class OptionMenuItemOptionBase : OptionMenuItem
int Selection = GetSelection();
String text = StringTable.Localize(OptionValues.GetText(mValues, Selection));
if (text.Length() == 0) text = "Unknown";
screen.DrawText (NewConsoleFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
screen.DrawText (NewSmallFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
return indent;
}
@ -502,11 +502,11 @@ class OptionMenuItemControlBase : OptionMenuItem
description = KeyBindings.NameKeys (Key1, Key2);
if (description.Length() > 0)
{
Menu.DrawConText(Font.CR_WHITE, indent + CursorSpace(), y + (OptionMenuSettings.mLinespacing-8)*CleanYfac_1, description);
screen.DrawText(NewSmallFont, Font.CR_WHITE, indent + CursorSpace(), y, description, DTA_CleanNoMove_1, true);
}
else
{
screen.DrawText(NewConsoleFont, Font.CR_BLACK, indent + CursorSpace(), y + (OptionMenuSettings.mLinespacing-8)*CleanYfac_1, "---", DTA_CleanNoMove_1, true);
screen.DrawText(NewSmallFont, Font.CR_BLACK, indent + CursorSpace(), y, "---", DTA_CleanNoMove_1, true);
}
return indent;
}
@ -644,9 +644,9 @@ class OptionMenuItemStaticTextSwitchable : OptionMenuItem
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{
String txt = StringTable.Localize(mCurrent? mAltText : mLabel);
int w = NewConsoleFont.StringWidth(txt) * CleanXfac_1;
int w = NewSmallFont.StringWidth(txt) * CleanXfac_1;
int x = (screen.GetWidth() - w) / 2;
screen.DrawText (NewConsoleFont, mColor, x, y, txt, DTA_CleanNoMove_1, true);
screen.DrawText (NewSmallFont, mColor, x, y, txt, DTA_CleanNoMove_1, true);
return -1;
}
@ -723,7 +723,7 @@ class OptionMenuSliderBase : OptionMenuItem
double range;
int maxlen = 0;
int right = x + (12*8 + 4) * CleanXfac_1;
int cy = y + (OptionMenuSettings.mLinespacing-8)*CleanYfac_1;
int cy = y;
range = max - min;
double ccur = clamp(cur, min, max) - min;
@ -731,7 +731,7 @@ class OptionMenuSliderBase : OptionMenuItem
if (fracdigits >= 0)
{
textbuf = String.format(formater, max);
maxlen = NewConsoleFont.StringWidth(textbuf) * CleanXfac_1;
maxlen = NewSmallFont.StringWidth(textbuf) * CleanXfac_1;
}
mSliderShort = right + maxlen > screen.GetWidth();
@ -746,13 +746,13 @@ class OptionMenuSliderBase : OptionMenuItem
// On 320x200 we need a shorter slider
Menu.DrawConText(Font.CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x12");
Menu.DrawConText(Font.FindFontColor(gameinfo.mSliderColor), x + int((5 + ((ccur * 38) / range)) * CleanXfac_1), cy, "\x13");
right -= 5*8*CleanXfac_1;
right -= 5*8*CleanXfac;
}
if (fracdigits >= 0 && right + maxlen <= screen.GetWidth())
{
textbuf = String.format(formater, cur);
screen.DrawText(NewConsoleFont, Font.CR_DARKGRAY, right, y, textbuf, DTA_CleanNoMove_1, true);
screen.DrawText(NewSmallFont, Font.CR_DARKGRAY, right, y, textbuf, DTA_CleanNoMove_1, true);
}
}
@ -973,7 +973,7 @@ class OptionMenuFieldBase : OptionMenuItem
drawLabel(indent, y, selected ? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, grayed);
int overlay = grayed? Color(96, 48, 0, 0) : 0;
screen.DrawText(NewConsoleFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, Represent(), DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
screen.DrawText(NewSmallFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, Represent(), DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
return indent;
}
@ -1022,7 +1022,7 @@ class OptionMenuItemTextField : OptionMenuFieldBase
override String Represent()
{
if (mEnter) return mEnter.GetText() .. NewConsoleFont.GetCursor();
if (mEnter) return mEnter.GetText() .. NewSmallFont.GetCursor();
else return GetCVarString();
}
@ -1032,7 +1032,7 @@ class OptionMenuItemTextField : OptionMenuFieldBase
{
// reposition the text so that the cursor is visible when in entering mode.
String text = Represent();
int tlen = NewConsoleFont.StringWidth(text) * CleanXfac_1;
int tlen = NewSmallFont.StringWidth(text) * CleanXfac_1;
int newindent = screen.GetWidth() - tlen - CursorSpace();
if (newindent < indent) indent = newindent;
}
@ -1044,7 +1044,7 @@ class OptionMenuItemTextField : OptionMenuFieldBase
if (mkey == Menu.MKEY_Enter)
{
Menu.MenuSound("menu/choose");
mEnter = TextEnterMenu.OpenTextEnter(Menu.GetCurrentMenu(), NewConsoleFont, GetCVarString(), -1, fromcontroller);
mEnter = TextEnterMenu.OpenTextEnter(Menu.GetCurrentMenu(), NewSmallFont, GetCVarString(), -1, fromcontroller);
mEnter.ActivateMenu();
return true;
}
@ -1156,7 +1156,7 @@ class OptionMenuItemScaleSlider : OptionMenuItemSlider
if ((Selection == 0 || Selection == -1) && mClickVal <= 0)
{
String text = Selection == 0? TextZero : Selection == -1? TextNegOne : "";
screen.DrawText (NewConsoleFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true);
screen.DrawText (NewSmallFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true);
}
else
{

View file

@ -132,7 +132,7 @@ class OptionMenuItemReverbSelect : OptionMenuItemSubMenu
int x = drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor);
String text = ReverbEdit.GetSelectedEnvironment();
screen.DrawText (NewConsoleFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true);
screen.DrawText (NewSmallFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true);
return indent;
}
@ -210,7 +210,7 @@ class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase
virtual String Represent()
{
return mEnter.GetText() .. NewConsoleFont.GetCursor();
return mEnter.GetText() .. NewSmallFont.GetCursor();
}
//=============================================================================
@ -221,7 +221,7 @@ class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase
mDrawX = indent + CursorSpace();
if (mEnter)
{
screen.DrawText(NewConsoleFont, OptionMenuSettings.mFontColorValue, mDrawX, y, Represent(), DTA_CleanNoMove_1, true);
screen.DrawText(NewSmallFont, OptionMenuSettings.mFontColorValue, mDrawX, y, Represent(), DTA_CleanNoMove_1, true);
}
else
{
@ -235,7 +235,7 @@ class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase
if (mkey == Menu.MKEY_Enter)
{
Menu.MenuSound("menu/choose");
mEnter = TextEnterMenu.OpenTextEnter(Menu.GetCurrentMenu(), NewConsoleFont, String.Format("%.3f", GetSliderValue()), -1, fromcontroller);
mEnter = TextEnterMenu.OpenTextEnter(Menu.GetCurrentMenu(), NewSmallFont, String.Format("%.3f", GetSliderValue()), -1, fromcontroller);
mEnter.ActivateMenu();
return true;
}

View file

@ -84,7 +84,7 @@ class TextEnterMenu : Menu
deprecated("3.8") static TextEnterMenu Open(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid = false, bool allowcolors = false)
{
let me = new("TextEnterMenu");
me.Init(parent, NewConsoleFont, textbuffer, maxlen*8, showgrid, allowcolors);
me.Init(parent, NewSmallFont, textbuffer, maxlen*8, showgrid, allowcolors);
return me;
}