- reworked console font loading to use the glyph sheets directly and allowing to load more than one per font.

This commit is contained in:
Christoph Oelckers 2019-02-17 19:15:57 +01:00
parent 95e62e91bb
commit 45d75745f0
7 changed files with 239 additions and 117 deletions

View File

@ -55,6 +55,7 @@
#include "image.h" #include "image.h"
#include "utf8.h" #include "utf8.h"
#include "textures/formats/fontchars.h" #include "textures/formats/fontchars.h"
#include "textures/formats/multipatchtexture.h"
#include "fontinternals.h" #include "fontinternals.h"
@ -91,6 +92,7 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
uint8_t pp = 0; uint8_t pp = 0;
for (auto &p : PatchRemap) p = pp++; for (auto &p : PatchRemap) p = pp++;
translateUntranslated = false; translateUntranslated = false;
int FixedWidth = 0;
maxyoffs = 0; maxyoffs = 0;
@ -151,6 +153,14 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
sc.MustGetValue(false); sc.MustGetValue(false);
FontHeight = sc.Number; FontHeight = sc.Number;
} }
else if (sc.Compare("CellSize"))
{
sc.MustGetValue(false);
FixedWidth = sc.Number;
sc.MustGetToken(',');
sc.MustGetValue(false);
FontHeight = sc.Number;
}
else if (sc.Compare("Translationtype")) else if (sc.Compare("Translationtype"))
{ {
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
@ -172,130 +182,236 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
} }
} }
if (FixedWidth > 0)
if (nametemplate != nullptr)
{ {
for (i = 0; i < lcount; i++) ReadSheetFont(folderdata, FixedWidth, FontHeight, Scale);
{
int position = '!' + i;
mysnprintf(buffer, countof(buffer), nametemplate, i + start);
lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch);
if (doomtemplate && lump.isValid() && i + start == 121)
{ // HACKHACK: Don't load STCFN121 in doom(2), because
// it's not really a lower-case 'y' but a '|'.
// Because a lot of wads with their own font seem to foolishly
// copy STCFN121 and make it a '|' themselves, wads must
// provide STCFN120 (x) and STCFN122 (z) for STCFN121 to load as a 'y'.
if (!TexMan.CheckForTexture("STCFN120", ETextureType::MiscPatch).isValid() ||
!TexMan.CheckForTexture("STCFN122", ETextureType::MiscPatch).isValid())
{
// insert the incorrectly named '|' graphic in its correct position.
position = 124;
}
}
if (lump.isValid())
{
if (position < minchar) minchar = position;
if (position > maxchar) maxchar = position;
charMap.Insert(position, TexMan.GetTexture(lump));
}
}
} }
if (folderdata.Size() > 0) else
{ {
// all valid lumps must be named with a hex number that represents its Unicode character index. if (nametemplate != nullptr)
for (auto &entry : folderdata)
{ {
char *endp; for (i = 0; i < lcount; i++)
auto base = ExtractFileBase(entry.name);
auto position = strtoll(base.GetChars(), &endp, 16);
if ((*endp == 0 || (*endp == '.' && position >= '!' && position < 0xffff)))
{ {
auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); int position = '!' + i;
mysnprintf(buffer, countof(buffer), nametemplate, i + start);
lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch);
if (doomtemplate && lump.isValid() && i + start == 121)
{ // HACKHACK: Don't load STCFN121 in doom(2), because
// it's not really a lower-case 'y' but a '|'.
// Because a lot of wads with their own font seem to foolishly
// copy STCFN121 and make it a '|' themselves, wads must
// provide STCFN120 (x) and STCFN122 (z) for STCFN121 to load as a 'y'.
if (!TexMan.CheckForTexture("STCFN120", ETextureType::MiscPatch).isValid() ||
!TexMan.CheckForTexture("STCFN122", ETextureType::MiscPatch).isValid())
{
// insert the incorrectly named '|' graphic in its correct position.
position = 124;
}
}
if (lump.isValid()) if (lump.isValid())
{ {
if ((int)position < minchar) minchar = (int)position; if (position < minchar) minchar = position;
if ((int)position > maxchar) maxchar = (int)position; if (position > maxchar) maxchar = position;
auto tex = TexMan.GetTexture(lump); charMap.Insert(position, TexMan.GetTexture(lump));
tex->SetScale(Scale); }
charMap.Insert((int)position, tex); }
}
if (folderdata.Size() > 0)
{
// all valid lumps must be named with a hex number that represents its Unicode character index.
for (auto &entry : folderdata)
{
char *endp;
auto base = ExtractFileBase(entry.name);
auto position = strtoll(base.GetChars(), &endp, 16);
if ((*endp == 0 || (*endp == '.' && position >= '!' && position < 0xffff)))
{
auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch);
if (lump.isValid())
{
if ((int)position < minchar) minchar = (int)position;
if ((int)position > maxchar) maxchar = (int)position;
auto tex = TexMan.GetTexture(lump);
tex->SetScale(Scale);
charMap.Insert((int)position, tex);
}
}
}
}
FirstChar = minchar;
LastChar = maxchar;
auto count = maxchar - minchar + 1;
Chars.Resize(count);
int fontheight = 0;
for (i = 0; i < count; i++)
{
auto lump = charMap.CheckKey(FirstChar + i);
if (lump != nullptr)
{
FTexture *pic = *lump;
if (pic != nullptr)
{
int height = pic->GetDisplayHeight();
int yoffs = pic->GetDisplayTopOffset();
if (yoffs > maxyoffs)
{
maxyoffs = yoffs;
}
height += abs(yoffs);
if (height > fontheight)
{
fontheight = height;
}
}
pic->SetUseType(ETextureType::FontChar);
if (!noTranslate)
{
Chars[i].OriginalPic = pic;
Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), "");
Chars[i].TranslatedPic->CopySize(pic);
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar);
TexMan.AddTexture(Chars[i].TranslatedPic);
}
else
{
Chars[i].TranslatedPic = pic;
}
Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth();
}
else
{
Chars[i].TranslatedPic = nullptr;
Chars[i].XMove = INT_MIN;
}
}
if (SpaceWidth == 0) // An explicit override from the .inf file must always take precedence
{
if (spacewidth != -1)
{
SpaceWidth = spacewidth;
}
else if ('N' - FirstChar >= 0 && 'N' - FirstChar < count && Chars['N' - FirstChar].TranslatedPic != nullptr)
{
SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2;
}
else
{
SpaceWidth = 4;
}
}
if (FontHeight == 0) FontHeight = fontheight;
FixXMoves();
}
if (!noTranslate) LoadTranslations();
}
void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height, const DVector2 &Scale)
{
// all valid lumps must be named with a hex number that represents the Unicode character index for its first character,
TArray<TexPart> part(1, true);
TMap<int, FTexture*> charMap;
int minchar = INT_MAX;
int maxchar = INT_MIN;
for (auto &entry : folderdata)
{
char *endp;
auto base = ExtractFileBase(entry.name);
auto position = strtoll(base.GetChars(), &endp, 16);
if ((*endp == 0 || (*endp == '.' && position >= 0 && position < 0xffff))) // Sheet fonts may fill in the low control chars.
{
auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch);
if (lump.isValid())
{
auto tex = TexMan.GetTexture(lump);
int numtex_x = tex->GetWidth() / width;
int numtex_y = tex->GetHeight() / height;
int maxinsheet = int(position) + numtex_x * numtex_y - 1;
if (minchar > position) minchar = int(position);
if (maxchar < maxinsheet) maxchar = maxinsheet;
for (int y = 0; y < numtex_y; y++)
{
for (int x = 0; x < numtex_x; x++)
{
part[0].OriginX = -width * x;
part[0].OriginY = -height * y;
part[0].Image = tex->GetImage();
FMultiPatchTexture *image = new FMultiPatchTexture(width, height, part, false, false);
FImageTexture *tex = new FImageTexture(image, "");
tex->SetUseType(ETextureType::FontChar);
tex->bMultiPatch = true;
tex->Width = width;
tex->Height = height;
tex->_LeftOffset[0] =
tex->_LeftOffset[1] =
tex->_TopOffset[0] =
tex->_TopOffset[1] = 0;
tex->Scale = Scale;
tex->bMasked = true;
tex->bTranslucent = -1;
tex->bWorldPanning = true;
tex->bNoDecals = false;
tex->SourceLump = -1; // We do not really care.
TexMan.AddTexture(tex);
charMap.Insert(position + x + y * numtex_x, tex);
}
} }
} }
} }
} }
FirstChar = minchar; FirstChar = minchar;
bool map1252 = false;
if (minchar < 0x80 && maxchar >= 0xa0) // should be a settable option, but that'd probably cause more problems than it'd solve.
{
if (maxchar < 0x2122) maxchar = 0x2122;
map1252 = true;
}
LastChar = maxchar; LastChar = maxchar;
auto count = maxchar - minchar + 1; auto count = maxchar - minchar + 1;
Chars.Resize(count); Chars.Resize(count);
int fontheight = 0; int fontheight = 0;
for (i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
auto lump = charMap.CheckKey(FirstChar + i); auto lump = charMap.CheckKey(FirstChar + i);
if (lump != nullptr) if (lump != nullptr)
{ {
FTexture *pic = *lump; FTexture *pic = *lump;
if (pic != nullptr)
{
int height = pic->GetDisplayHeight();
int yoffs = pic->GetDisplayTopOffset();
if (yoffs > maxyoffs) auto b = pic->Get8BitPixels(false);
{
maxyoffs = yoffs;
}
height += abs(yoffs);
if (height > fontheight)
{
fontheight = height;
}
}
pic->SetUseType(ETextureType::FontChar); Chars[i].OriginalPic = pic;
if (!noTranslate) Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), "");
{ Chars[i].TranslatedPic->CopySize(pic);
Chars[i].OriginalPic = pic; Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar);
Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (pic->GetImage()), ""); TexMan.AddTexture(Chars[i].TranslatedPic);
Chars[i].TranslatedPic->CopySize(pic);
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar);
TexMan.AddTexture(Chars[i].TranslatedPic);
}
else
{
Chars[i].TranslatedPic = pic;
}
Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth();
} }
else Chars[i].XMove = width;
}
if (map1252)
{
// Move the Windows-1252 characters to their proper place.
for (int i = 0x80; i < 0xa0; i++)
{ {
Chars[i].TranslatedPic = nullptr; if (win1252map[i - 0x80] != i && Chars[i - minchar].TranslatedPic != nullptr && Chars[win1252map[i - 0x80] - minchar].TranslatedPic == nullptr)
Chars[i].XMove = INT_MIN; {
std::swap(Chars[i - minchar], Chars[win1252map[i - 0x80] - minchar]);
}
} }
} }
if (SpaceWidth == 0) // An explicit override from the .inf file must always take precedence
{
if (spacewidth != -1)
{
SpaceWidth = spacewidth;
}
else if ('N'-FirstChar >= 0 && 'N'-FirstChar < count && Chars['N' - FirstChar].TranslatedPic != nullptr)
{
SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2;
}
else
{
SpaceWidth = 4;
}
}
if (FontHeight == 0) FontHeight = fontheight;
FixXMoves(); SpaceWidth = width;
if (!noTranslate) LoadTranslations();
} }
//========================================================================== //==========================================================================

View File

@ -1415,50 +1415,50 @@ EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int
void V_InitFonts() void V_InitFonts()
{ {
InitLowerUpper(); InitLowerUpper();
V_InitCustomFonts (); V_InitCustomFonts();
// load the heads-up font // load the heads-up font
if (!(SmallFont = V_GetFont("SmallFont", "SMALLFNT"))) if (!(SmallFont = V_GetFont("SmallFont", "SMALLFNT")))
{ {
if (Wads.CheckNumForName ("FONTA_S") >= 0) if (Wads.CheckNumForName("FONTA_S") >= 0)
{ {
SmallFont = new FFont ("SmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1); SmallFont = new FFont("SmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
SmallFont->SetCursor('['); SmallFont->SetCursor('[');
} }
else if (Wads.CheckNumForName ("STCFN033", ns_graphics) >= 0) else if (Wads.CheckNumForName("STCFN033", ns_graphics) >= 0)
{ {
SmallFont = new FFont ("SmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); SmallFont = new FFont("SmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
} }
} }
if (!(SmallFont2 = V_GetFont("SmallFont2"))) // Only used by Strife if (!(SmallFont2 = V_GetFont("SmallFont2"))) // Only used by Strife
{ {
if (Wads.CheckNumForName ("STBFN033", ns_graphics) >= 0) if (Wads.CheckNumForName("STBFN033", ns_graphics) >= 0)
{ {
SmallFont2 = new FFont ("SmallFont2", "STBFN%.3d", "defsmallfont2", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); SmallFont2 = new FFont("SmallFont2", "STBFN%.3d", "defsmallfont2", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
}
} }
}
if (!(BigFont = V_GetFont("BigFont"))) if (!(BigFont = V_GetFont("BigFont")))
{ {
if (gameinfo.gametype & GAME_Raven) if (gameinfo.gametype & GAME_Raven)
{ {
BigFont = new FFont ("BigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1); BigFont = new FFont("BigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
}
} }
}
if (!(ConFont = V_GetFont("ConsoleFont", "CONFONT"))) if (!(ConFont = V_GetFont("ConsoleFont", "CONFONT")))
{ {
ConFont = SmallFont; ConFont = SmallFont;
} }
if (!(IntermissionFont = FFont::FindFont("IntermissionFont"))) if (!(IntermissionFont = FFont::FindFont("IntermissionFont")))
{ {
if (gameinfo.gametype & GAME_DoomChex) if (gameinfo.gametype & GAME_DoomChex)
{ {
IntermissionFont = FFont::FindFont("IntermissionFont_Doom"); IntermissionFont = FFont::FindFont("IntermissionFont_Doom");
}
if (IntermissionFont == nullptr)
{
IntermissionFont = BigFont;
}
} }
if (IntermissionFont == nullptr)
{
IntermissionFont = BigFont;
}
}
// This can only happen if gzdoom.pk3 is corrupted. ConFont should always be present. // This can only happen if gzdoom.pk3 is corrupted. ConFont should always be present.
if (ConFont == nullptr) if (ConFont == nullptr)
{ {
@ -1472,12 +1472,11 @@ void V_InitFonts()
if (SmallFont2 == nullptr) if (SmallFont2 == nullptr)
{ {
SmallFont2 = SmallFont; SmallFont2 = SmallFont;
} }
if (BigFont == nullptr) if (BigFont == nullptr)
{ {
BigFont = SmallFont; BigFont = SmallFont;
} }
} }
void V_ClearFonts() void V_ClearFonts()

View File

@ -35,6 +35,8 @@
#define __V_FONT_H__ #define __V_FONT_H__
#include "doomtype.h" #include "doomtype.h"
#include "w_wad.h"
#include "vectors.h"
class DCanvas; class DCanvas;
struct FRemapTable; struct FRemapTable;
@ -114,6 +116,8 @@ protected:
static int SimpleTranslation (uint8_t *colorsused, uint8_t *translation, static int SimpleTranslation (uint8_t *colorsused, uint8_t *translation,
uint8_t *identity, TArray<double> &Luminosity); uint8_t *identity, TArray<double> &Luminosity);
void ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height, const DVector2 &Scale);
int FirstChar, LastChar; int FirstChar, LastChar;
int SpaceWidth; int SpaceWidth;
int FontHeight; int FontHeight;

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,3 @@
TranslationType Console
CellSize 8, 8 // This implies font sheets