- 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;
}
//==========================================================================
//
// 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

View file

@ -101,6 +101,12 @@ private:
friend class FWadCollection;
};
struct FolderEntry
{
const char *name;
unsigned lumpnum;
};
class FWadCollection
{
public:
@ -173,6 +179,7 @@ public:
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.
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;

View file

@ -987,10 +987,11 @@ FString FStringFormat(VM_ARGS, int offset)
ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments.");
FString argnumstr = fmt_current.Mid(1);
if (!argnumstr.IsInt()) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for argument number, got '%s'.", argnumstr.GetChars());
argnum = 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);
auto argnum64 = argnumstr.ToLong();
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 = "%";
haveargnums = true;
argnum = int(argnum64);
}
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 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 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 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() : ""; }

View file

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

View file

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

View file

@ -1130,14 +1130,14 @@ digits = [0-9];
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

View file

@ -299,8 +299,8 @@ public:
bool IsInt () const;
bool IsFloat () const;
long ToLong (int base=0) const;
unsigned long ToULong (int base=0) const;
int64_t ToLong (int base=0) const;
uint64_t ToULong (int base=0) const;
double ToDouble () const;
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;
FTextureID lump;
char buffer[12];
TArray<FTexture*> charLumps(count, true);
int maxyoffs;
bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false;
bool stcfn121 = false;
noTranslate = notranslate;
Lump = fdlump;
Chars.Resize(count);
FirstChar = first;
LastChar = first + count - 1;
FontHeight = 0;
GlobalKerning = false;
FontName = name;
@ -333,9 +328,12 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
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);
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())
{
// insert the incorrectly named '|' graphic in its correct position.
if (count > 124-start) charLumps[124-start] = TexMan.GetTexture(lump);
lump.SetInvalid();
stcfn121 = true;
position = 124;
}
}
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)
{
// set the lump here only if it represents a valid texture
if (i != 124-start || !stcfn121)
charLumps[i] = pic;
int height = pic->GetDisplayHeight();
int yoffs = pic->GetDisplayTopOffset();
@ -377,21 +409,20 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
FontHeight = height;
}
}
}
if (charLumps[i] != nullptr)
{
charLumps[i]->SetUseType(ETextureType::FontChar);
pic->SetUseType(ETextureType::FontChar);
if (!noTranslate)
{
Chars[i].OriginalPic = charLumps[i];
Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (charLumps[i]->GetImage()), "");
Chars[i].TranslatedPic->Scale = charLumps[i]->Scale;
Chars[i].OriginalPic = pic;
Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (pic->GetImage()), "");
Chars[i].TranslatedPic->Scale = pic->Scale;
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar);
TexMan.AddTexture(Chars[i].TranslatedPic);
}
else Chars[i].TranslatedPic = charLumps[i];
else
{
Chars[i].TranslatedPic = pic;
}
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;
}
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
{
@ -1826,7 +1857,7 @@ void V_InitCustomFonts()
}
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);
}
else if (format == 2)
@ -2228,19 +2259,19 @@ void V_InitFonts()
}
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('[');
}
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 (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
{
@ -2271,7 +2302,7 @@ void V_InitFonts()
}
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
{
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 FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const;