- reworked font loader to make adding multi-lump fonts easier.

A multi-lump font can be created by putting all characters into a subdirectory of fonts/ with the intended name. Each character needs to be named by its character index as hex number.
So far this is only active for the predefined small fonts
This commit is contained in:
Christoph Oelckers 2019-02-07 13:12:39 +01:00
parent 495298079b
commit 4d2bb11317
83 changed files with 123 additions and 47 deletions

View file

@ -1260,6 +1260,43 @@ FResourceLump *FWadCollection::GetLumpRecord(int lump) const
return LumpInfo[lump].lump; return LumpInfo[lump].lump;
} }
//==========================================================================
//
// GetLumpsInFolder
//
// Gets all lumps within a single folder in the hierarchy.
//
//==========================================================================
static int folderentrycmp(const void *a, const void *b)
{
auto A = (FolderEntry*)a;
auto B = (FolderEntry*)b;
return strcmp(A->name, B->name);
}
unsigned FWadCollection::GetLumpsInFolder(const char *inpath, TArray<FolderEntry> &result) const
{
FString path = inpath;
FixPathSeperator(path);
path.ToLower();
if (path[path.Len() - 1] != '/') path += '/';
result.Clear();
for (unsigned i = 0; i < LumpInfo.Size(); i++)
{
if (LumpInfo[i].lump->FullName.IndexOf(path) == 0)
{
// Only if it hasn't been replaced.
if (Wads.CheckNumForFullName(LumpInfo[i].lump->FullName) == i)
{
result.Push({ LumpInfo[i].lump->FullName.GetChars(), i });
}
}
}
qsort(result.Data(), result.Size(), sizeof(FolderEntry), folderentrycmp);
return result.Size();
}
//========================================================================== //==========================================================================
// //
// W_ReadLump // W_ReadLump

View file

@ -101,6 +101,12 @@ private:
friend class FWadCollection; friend class FWadCollection;
}; };
struct FolderEntry
{
const char *name;
unsigned lumpnum;
};
class FWadCollection class FWadCollection
{ {
public: public:
@ -173,6 +179,7 @@ public:
int GetLumpIndexNum (int lump) const; // Returns the RFF index number for this lump int GetLumpIndexNum (int lump) const; // Returns the RFF index number for this lump
FResourceLump *GetLumpRecord(int lump) const; // Returns the FResourceLump, in case the caller wants to have direct access to the lump cache. FResourceLump *GetLumpRecord(int lump) const; // Returns the FResourceLump, in case the caller wants to have direct access to the lump cache.
bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match
unsigned GetLumpsInFolder(const char *path, TArray<FolderEntry> &result) const;
bool IsEncryptedFile(int lump) const; bool IsEncryptedFile(int lump) const;

View file

@ -987,10 +987,11 @@ FString FStringFormat(VM_ARGS, int offset)
ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments.");
FString argnumstr = fmt_current.Mid(1); FString argnumstr = fmt_current.Mid(1);
if (!argnumstr.IsInt()) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for argument number, got '%s'.", argnumstr.GetChars()); if (!argnumstr.IsInt()) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for argument number, got '%s'.", argnumstr.GetChars());
argnum = argnumstr.ToLong(); auto argnum64 = argnumstr.ToLong();
if (argnum < 1 || argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format (tried to access argument %d, %d total).", argnum, numparam); if (argnum64 < 1 || argnum64 >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format (tried to access argument %d, %d total).", argnum64, numparam);
fmt_current = "%"; fmt_current = "%";
haveargnums = true; haveargnums = true;
argnum = int(argnum64);
} }
else else
{ {

View file

@ -44,7 +44,7 @@ static void CastF2S(FString *a, double b) { a->Format("%.5f", b); }
static void CastV22S(FString *a, double b, double b1) { a->Format("(%.5f, %.5f)", b, b1); } static void CastV22S(FString *a, double b, double b1) { a->Format("(%.5f, %.5f)", b, b1); }
static void CastV32S(FString *a, double b, double b1, double b2) { a->Format("(%.5f, %.5f, %.5f)", b, b1, b2); } static void CastV32S(FString *a, double b, double b1, double b2) { a->Format("(%.5f, %.5f, %.5f)", b, b1, b2); }
static void CastP2S(FString *a, void *b) { if (b == nullptr) *a = "null"; else a->Format("%p", b); } static void CastP2S(FString *a, void *b) { if (b == nullptr) *a = "null"; else a->Format("%p", b); }
static int CastS2I(FString *b) { return (VM_SWORD)b->ToLong(); } static int CastS2I(FString *b) { return (int)b->ToLong(); }
static double CastS2F(FString *b) { return b->ToDouble(); } static double CastS2F(FString *b) { return b->ToDouble(); }
static int CastS2N(FString *b) { return b->Len() == 0 ? FName(NAME_None) : FName(*b); } static int CastS2N(FString *b) { return b->Len() == 0 ? FName(NAME_None) : FName(*b); }
static void CastN2S(FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; } static void CastN2S(FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; }

View file

@ -369,7 +369,7 @@ struct VMValue
} }
if (Type == REGT_STRING) if (Type == REGT_STRING)
{ {
return s().ToLong(); return (int)s().ToLong();
} }
// FIXME // FIXME
return 0; return 0;

View file

@ -257,7 +257,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToInt, StringToInt)
{ {
PARAM_SELF_STRUCT_PROLOGUE(FString); PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_INT(base); PARAM_INT(base);
ACTION_RETURN_INT(self->ToLong(base)); ACTION_RETURN_INT((int)self->ToLong(base));
} }
static double StringToDbl(FString *self) static double StringToDbl(FString *self)

View file

@ -1130,14 +1130,14 @@ digits = [0-9];
return yych == '\0'; return yych == '\0';
} }
long FString::ToLong (int base) const int64_t FString::ToLong (int base) const
{ {
return (long)strtoll (Chars, NULL, base); return strtoll (Chars, NULL, base);
} }
unsigned long FString::ToULong (int base) const uint64_t FString::ToULong (int base) const
{ {
return (unsigned long)strtoull (Chars, NULL, base); return strtoull (Chars, NULL, base);
} }
double FString::ToDouble () const double FString::ToDouble () const

View file

@ -299,8 +299,8 @@ public:
bool IsInt () const; bool IsInt () const;
bool IsFloat () const; bool IsFloat () const;
long ToLong (int base=0) const; int64_t ToLong (int base=0) const;
unsigned long ToULong (int base=0) const; uint64_t ToULong (int base=0) const;
double ToDouble () const; double ToDouble () const;
size_t Len() const { return Data()->Len; } size_t Len() const { return Data()->Len; }

View file

@ -305,21 +305,16 @@ FFont *V_GetFont(const char *name)
// //
//========================================================================== //==========================================================================
FFont::FFont (const char *name, const char *nametemplate, int first, int count, int start, int fdlump, int spacewidth, bool notranslate) FFont::FFont (const char *name, const char *nametemplate, const char *filetemplate, int lfirst, int lcount, int start, int fdlump, int spacewidth, bool notranslate)
{ {
int i; int i;
FTextureID lump; FTextureID lump;
char buffer[12]; char buffer[12];
TArray<FTexture*> charLumps(count, true);
int maxyoffs; int maxyoffs;
bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false; bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false;
bool stcfn121 = false;
noTranslate = notranslate; noTranslate = notranslate;
Lump = fdlump; Lump = fdlump;
Chars.Resize(count);
FirstChar = first;
LastChar = first + count - 1;
FontHeight = 0; FontHeight = 0;
GlobalKerning = false; GlobalKerning = false;
FontName = name; FontName = name;
@ -333,9 +328,12 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
maxyoffs = 0; maxyoffs = 0;
for (i = 0; i < count; i++) TMap<int, FTexture*> charMap;
int minchar = INT_MAX;
int maxchar = INT_MIN;
for (i = 0; i < lcount; i++)
{ {
charLumps[i] = nullptr; int position = '!' + i;
mysnprintf(buffer, countof(buffer), nametemplate, i + start); mysnprintf(buffer, countof(buffer), nametemplate, i + start);
lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch); lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch);
@ -349,21 +347,55 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
!TexMan.CheckForTexture("STCFN122", ETextureType::MiscPatch).isValid()) !TexMan.CheckForTexture("STCFN122", ETextureType::MiscPatch).isValid())
{ {
// insert the incorrectly named '|' graphic in its correct position. // insert the incorrectly named '|' graphic in its correct position.
if (count > 124-start) charLumps[124-start] = TexMan.GetTexture(lump); position = 124;
lump.SetInvalid();
stcfn121 = true;
} }
} }
if (lump.isValid()) if (lump.isValid())
{ {
FTexture *pic = TexMan.GetTexture(lump); if (position < minchar) minchar = position;
if (position > maxchar) maxchar = position;
charMap.Insert(position, TexMan.GetTexture(lump));
}
}
if (filetemplate != nullptr)
{
TArray<FolderEntry> folderdata;
FStringf path("fonts/%s/", filetemplate);
if (Wads.GetLumpsInFolder(path, folderdata))
{
// 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;
charMap.Insert((int)position, TexMan.GetTexture(lump));
}
}
}
}
}
FirstChar = minchar;
LastChar = maxchar;
auto count = maxchar - minchar + 1;
Chars.Resize(count);
for (i = 0; i < count; i++)
{
auto lump = charMap.CheckKey(FirstChar + i);
if (lump != nullptr)
{
FTexture *pic = *lump;
if (pic != nullptr) if (pic != nullptr)
{ {
// set the lump here only if it represents a valid texture
if (i != 124-start || !stcfn121)
charLumps[i] = pic;
int height = pic->GetDisplayHeight(); int height = pic->GetDisplayHeight();
int yoffs = pic->GetDisplayTopOffset(); int yoffs = pic->GetDisplayTopOffset();
@ -377,21 +409,20 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
FontHeight = height; FontHeight = height;
} }
} }
}
if (charLumps[i] != nullptr)
{
charLumps[i]->SetUseType(ETextureType::FontChar);
pic->SetUseType(ETextureType::FontChar);
if (!noTranslate) if (!noTranslate)
{ {
Chars[i].OriginalPic = charLumps[i]; Chars[i].OriginalPic = pic;
Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (charLumps[i]->GetImage()), ""); Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (pic->GetImage()), "");
Chars[i].TranslatedPic->Scale = charLumps[i]->Scale; Chars[i].TranslatedPic->Scale = pic->Scale;
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar);
TexMan.AddTexture(Chars[i].TranslatedPic); TexMan.AddTexture(Chars[i].TranslatedPic);
} }
else Chars[i].TranslatedPic = charLumps[i]; else
{
Chars[i].TranslatedPic = pic;
}
Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth();
} }
@ -406,9 +437,9 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
{ {
SpaceWidth = spacewidth; SpaceWidth = spacewidth;
} }
else if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].TranslatedPic != nullptr) else if ('N'-FirstChar >= 0 && 'N'-FirstChar < count && Chars['N' - FirstChar].TranslatedPic != nullptr)
{ {
SpaceWidth = (Chars['N' - first].XMove + 1) / 2; SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2;
} }
else else
{ {
@ -1826,7 +1857,7 @@ void V_InitCustomFonts()
} }
if (format == 1) if (format == 1)
{ {
FFont *fnt = new FFont (namebuffer, templatebuf, first, count, start, llump, spacewidth, donttranslate); FFont *fnt = new FFont (namebuffer, templatebuf, nullptr, first, count, start, llump, spacewidth, donttranslate);
fnt->SetCursor(cursor); fnt->SetCursor(cursor);
} }
else if (format == 2) else if (format == 2)
@ -2228,19 +2259,19 @@ void V_InitFonts()
} }
else if (Wads.CheckNumForName ("FONTA_S") >= 0) else if (Wads.CheckNumForName ("FONTA_S") >= 0)
{ {
SmallFont = new FFont ("SmallFont", "FONTA%02u", HU_FONTSTART, HU_FONTSIZE, 1, -1); SmallFont = new FFont ("SmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
SmallFont->SetCursor('['); SmallFont->SetCursor('[');
} }
else else
{ {
SmallFont = new FFont ("SmallFont", "STCFN%.3d", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); SmallFont = new FFont ("SmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
} }
} }
if (!(SmallFont2 = FFont::FindFont("SmallFont2"))) // Only used by Strife if (!(SmallFont2 = FFont::FindFont("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", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); SmallFont2 = new FFont ("SmallFont2", "STBFN%.3d", "defsmallfont2", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
} }
else else
{ {
@ -2271,7 +2302,7 @@ void V_InitFonts()
} }
else else
{ {
BigFont = new FFont ("BigFont", "FONTB%02u", HU_FONTSTART, HU_FONTSIZE, 1, -1); BigFont = new FFont ("BigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
} }
} }
} }

View file

@ -79,7 +79,7 @@ extern int NumTextColors;
class FFont class FFont
{ {
public: public:
FFont (const char *fontname, const char *nametemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false); FFont (const char *fontname, const char *nametemplate, const char *filetemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false);
virtual ~FFont (); virtual ~FFont ();
virtual FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const; virtual FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const;