From 531c68edfe7d6c377a1ce737b660bb6df681e71e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Apr 2020 22:51:53 +0200 Subject: [PATCH] - use GZDoom's font code to fix the crash issues and moved around some files in the PK3. This pulls in a lot of Doom specific font setup, this can be sorted out later as it won't get into the way. # Conflicts: # source/CMakeLists.txt # Conflicts: # source/glbackend/hw_draw2d.cpp # Conflicts: # source/CMakeLists.txt # Conflicts: # source/glbackend/gl_texture.cpp # Conflicts: # source/CMakeLists.txt # Conflicts: # source/build/src/palette.cpp # source/core/gamecontrol.cpp --- source/CMakeLists.txt | 18 +- source/build/include/palette.h | 2 +- source/build/src/palette.cpp | 6 +- source/common/engine/palettecontainer.cpp | 5 +- source/common/engine/palettecontainer.h | 7 + source/{core => common}/fonts/font.cpp | 480 +++++++++++++++++- source/{core => common}/fonts/fontinternals.h | 6 - source/{core => common}/fonts/hexfont.cpp | 28 +- source/{core => common}/fonts/myiswalpha.h | 0 .../{core => common}/fonts/singlelumpfont.cpp | 71 ++- source/common/fonts/singlepicfont.cpp | 128 +++++ source/common/fonts/specialfont.cpp | 223 ++++++++ source/{core => common}/fonts/v_font.cpp | 368 +++++++++----- source/{core => common}/fonts/v_font.h | 22 +- source/common/fonts/v_text.cpp | 2 +- source/common/textures/textures.h | 2 +- source/core/console/c_console.cpp | 10 +- source/core/gamecontrol.cpp | 1 + source/glbackend/gl_texture.cpp | 2 +- source/glbackend/hw_draw2d.cpp | 3 +- wadsrc/static/engine/Roboto-Regular.ttf | Bin 171676 -> 0 bytes wadsrc/static/engine/confont.lmp | Bin 10239 -> 0 bytes wadsrc/static/{engine => }/newconsolefont.hex | 0 wadsrc/static/{engine => }/textcolors.txt | 0 24 files changed, 1154 insertions(+), 230 deletions(-) rename source/{core => common}/fonts/font.cpp (63%) rename source/{core => common}/fonts/fontinternals.h (81%) rename source/{core => common}/fonts/hexfont.cpp (95%) rename source/{core => common}/fonts/myiswalpha.h (100%) rename source/{core => common}/fonts/singlelumpfont.cpp (89%) create mode 100644 source/common/fonts/singlepicfont.cpp create mode 100644 source/common/fonts/specialfont.cpp rename source/{core => common}/fonts/v_font.cpp (68%) rename source/{core => common}/fonts/v_font.h (90%) delete mode 100644 wadsrc/static/engine/Roboto-Regular.ttf delete mode 100644 wadsrc/static/engine/confont.lmp rename wadsrc/static/{engine => }/newconsolefont.hex (100%) rename wadsrc/static/{engine => }/textcolors.txt (100%) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 9a1487747..658b4b001 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -605,7 +605,6 @@ file( GLOB HEADER_FILES libxmp-lite/src/*.h core/*.h core/2d/*.h - core/fonts/*.h core/utility/*.h core/utility/rapidjson/*.h core/console/*.h @@ -626,6 +625,7 @@ file( GLOB HEADER_FILES common/console/*.h common/utility/*.h common/engine/*.h + common/fonts/*.h common/objects/*.h common/filesystem/*.h common/textures/*.h @@ -756,11 +756,6 @@ set (PCH_SOURCES core/2d/v_drawtext.cpp core/2d/screentext.cpp - core/fonts/font.cpp - core/fonts/hexfont.cpp - core/fonts/singlelumpfont.cpp - core/fonts/v_font.cpp - core/console/c_console.cpp core/console/d_event.cpp @@ -774,8 +769,12 @@ set (PCH_SOURCES common/audio/music/i_soundfont.cpp common/audio/music/music_config.cpp common/thirdparty/sfmt/SFMT.cpp - common/textures/texture.cpp - common/textures/animtexture.cpp + common/fonts/singlelumpfont.cpp + common/fonts/singlepicfont.cpp + common/fonts/specialfont.cpp + common/fonts/font.cpp + common/fonts/hexfont.cpp + common/fonts/v_font.cpp common/textures/hw_ihwtexture.cpp common/textures/hw_material.cpp common/fonts/v_text.cpp @@ -787,6 +786,7 @@ set (PCH_SOURCES common/textures/texturemanager.cpp common/textures/multipatchtexturebuilder.cpp common/textures/skyboxtexture.cpp + common/textures/animtexture.cpp common/textures/formats/automaptexture.cpp common/textures/formats/brightmaptexture.cpp common/textures/formats/buildtexture.cpp @@ -1019,6 +1019,7 @@ include_directories( common/utility common/console common/engine + common/fonts common/objects common/rendering common/rendering/gl_load @@ -1123,7 +1124,6 @@ source_group("Core\\Textures\\Formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOUR source_group("Core\\Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/utility/.+") source_group("Core\\2D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/2d/.+") source_group("Core\\Console" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/console/.+") -source_group("Core\\Fonts" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/fonts/.+") source_group("Core\\DObject" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/dobject/.+") source_group("Core\\Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/menu/.+") source_group("Core\\Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/rendering/.+") diff --git a/source/build/include/palette.h b/source/build/include/palette.h index c9d0db980..8c0827167 100644 --- a/source/build/include/palette.h +++ b/source/build/include/palette.h @@ -49,7 +49,7 @@ inline void paletteClearLookupTable(int num) enum { - Translation_BasePalettes, + Translation_BasePalettes = 1, Translation_Remap, }; diff --git a/source/build/src/palette.cpp b/source/build/src/palette.cpp index f1a25ee83..e0ea263ca 100644 --- a/source/build/src/palette.cpp +++ b/source/build/src/palette.cpp @@ -21,6 +21,7 @@ #include "colormatcher.h" #include "m_swap.h" #include "v_colortables.h" +#include "v_font.h" #include "../../glbackend/glbackend.h" // FString is a nice and convenient way to have automatically managed shared storage. @@ -40,6 +41,7 @@ palette_t palookupfog[MAXPALOOKUPS]; // NOTE: g_noFloorPal[0] is irrelevant as it's never checked. int8_t g_noFloorPal[MAXPALOOKUPS]; + //========================================================================== // // Adds a palette to the global list of base palettes @@ -262,7 +264,7 @@ void palettePostLoadLookups(void) remap.Palette[j] = palette->Palette[remap.Remap[j]]; } remap.NumEntries = 256; - GPalette.UpdateTranslation(TRANSLATION(i + 1, l), &remap); + GPalette.UpdateTranslation(TRANSLATION(i + Translation_Remap, l), &remap); } if (palette != basepalette) palette->Inactive = false; // clear the marker flag } @@ -287,7 +289,7 @@ void palettePostLoadLookups(void) for (auto remap : GPalette.uniqueRemaps) { - colorswap(remap); + if (!remap->ForFont) colorswap(remap); } colorswap(&GPalette.GlobalBrightmap); std::swap(GPalette.BaseColors[0], GPalette.BaseColors[255]); diff --git a/source/common/engine/palettecontainer.cpp b/source/common/engine/palettecontainer.cpp index 1f8732db9..a4ee23b82 100644 --- a/source/common/engine/palettecontainer.cpp +++ b/source/common/engine/palettecontainer.cpp @@ -53,14 +53,15 @@ extern uint8_t IcePalette[16][3]; void PaletteContainer::Init(int numslots) // This cannot be a constructor!!! { + if (numslots < 1) numslots = 1; Clear(); HasGlobalBrightmap = false; // Make sure that index 0 is always the identity translation. FRemapTable remap; remap.MakeIdentity(); remap.Inactive = true; - AddRemap(&remap); TranslationTables.Resize(numslots); + StoreTranslation(0, &remap); // make sure that translation ID 0 is the identity. ColorMatcher.SetPalette(BaseColors); } @@ -263,7 +264,7 @@ FRemapTable *PaletteContainer::TranslationToTable(int translation) unsigned int type = GetTranslationType(translation); unsigned int index = GetTranslationIndex(translation); - if (type <= 0 || type >= TranslationTables.Size() || index >= NumTranslations(type)) + if (type < 0 || type >= TranslationTables.Size() || index >= NumTranslations(type)) { return uniqueRemaps[0]; // this is the identity table. } diff --git a/source/common/engine/palettecontainer.h b/source/common/engine/palettecontainer.h index fa9d010dc..c8c5499d3 100644 --- a/source/common/engine/palettecontainer.h +++ b/source/common/engine/palettecontainer.h @@ -6,6 +6,12 @@ class FileReader; +enum +{ + TRANSLATION_Internal = 0 +}; + + struct FRemapTable { FRemapTable(int count = 256) { NumEntries = count; } @@ -28,6 +34,7 @@ struct FRemapTable int Index; int NumEntries; // # of elements in this table (usually 256) bool Inactive = false; // This table is inactive and should be treated as if it was passed as NULL + bool ForFont = false; // Mark font translations because they may require different handling than the ones for sprites- private: }; diff --git a/source/core/fonts/font.cpp b/source/common/fonts/font.cpp similarity index 63% rename from source/core/fonts/font.cpp rename to source/common/fonts/font.cpp index f2215c7cb..4f38b4794 100644 --- a/source/core/fonts/font.cpp +++ b/source/common/fonts/font.cpp @@ -38,28 +38,441 @@ #include #include #include -#include #include #include "templates.h" #include "m_swap.h" #include "v_font.h" +#include "printf.h" +#include "textures.h" +#include "filesystem.h" #include "cmdlib.h" #include "sc_man.h" -#include "v_text.h" +#include "gstrings.h" #include "image.h" #include "utf8.h" #include "myiswalpha.h" #include "fontchars.h" -#include "imagehelpers.h" -#include "glbackend/glbackend.h" -#include "palettecontainer.h" -#include "textures.h" +#include "multipatchtexture.h" +#include "texturemanager.h" #include "fontinternals.h" +//========================================================================== +// +// FFont :: FFont +// +// Loads a multi-texture font. +// +//========================================================================== + +FFont::FFont (const char *name, const char *nametemplate, const char *filetemplate, int lfirst, int lcount, int start, int fdlump, int spacewidth, bool notranslate, bool iwadonly, bool doomtemplate) +{ + int i; + FTextureID lump; + char buffer[12]; + int maxyoffs; + DVector2 Scale = { 1, 1 }; + + noTranslate = notranslate; + Lump = fdlump; + GlobalKerning = false; + FontName = name; + Next = FirstFont; + FirstFont = this; + Cursor = '_'; + ActiveColors = 0; + SpaceWidth = 0; + FontHeight = 0; + uint8_t pp = 0; + for (auto &p : PatchRemap) p = pp++; + translateUntranslated = false; + int FixedWidth = 0; + + maxyoffs = 0; + + TMap charMap; + int minchar = INT_MAX; + int maxchar = INT_MIN; + + // Read the font's configuration. + // This will not be done for the default fonts, because they are not atomic and the default content does not need it. + + TArray folderdata; + if (filetemplate != nullptr) + { + FStringf path("fonts/%s/", filetemplate); + // If a name template is given, collect data from all resource files. + // For anything else, each folder is being treated as an atomic, self-contained unit and mixing from different glyph sets is blocked. + fileSystem.GetFilesInFolder(path, folderdata, nametemplate == nullptr); + + //if (nametemplate == nullptr) + { + FStringf infpath("fonts/%s/font.inf", filetemplate); + + unsigned index = folderdata.FindEx([=](const FolderEntry &entry) + { + return infpath.CompareNoCase(entry.name) == 0; + }); + + if (index < folderdata.Size()) + { + FScanner sc; + sc.OpenLumpNum(folderdata[index].lumpnum); + while (sc.GetToken()) + { + sc.TokenMustBe(TK_Identifier); + if (sc.Compare("Kerning")) + { + sc.MustGetValue(false); + GlobalKerning = sc.Number; + } + else if (sc.Compare("Scale")) + { + sc.MustGetValue(true); + Scale.Y = Scale.X = sc.Float; + if (sc.CheckToken(',')) + { + sc.MustGetValue(true); + Scale.Y = sc.Float; + } + } + else if (sc.Compare("SpaceWidth")) + { + sc.MustGetValue(false); + SpaceWidth = sc.Number; + } + else if (sc.Compare("FontHeight")) + { + sc.MustGetValue(false); + 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")) + { + sc.MustGetToken(TK_Identifier); + if (sc.Compare("console")) + { + TranslationType = 1; + } + else if (sc.Compare("standard")) + { + TranslationType = 0; + } + else + { + sc.ScriptError("Unknown translation type %s", sc.String); + } + } + } + } + } + } + + if (FixedWidth > 0) + { + ReadSheetFont(folderdata, FixedWidth, FontHeight, Scale); + Type = Folder; + } + else + { + if (nametemplate != nullptr) + { + if (!iwadonly) + { + for (i = 0; i < lcount; i++) + { + int position = lfirst + 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'. + FStringf c120("%s120", nametemplate); + FStringf c122("%s122", nametemplate); + if (!TexMan.CheckForTexture(c120, ETextureType::MiscPatch).isValid() || + !TexMan.CheckForTexture(c122, ETextureType::MiscPatch).isValid()) + { + // insert the incorrectly named '|' graphic in its correct position. + position = 124; + } + } + if (lump.isValid()) + { + Type = Multilump; + if (position < minchar) minchar = position; + if (position > maxchar) maxchar = position; + charMap.Insert(position, TexMan.GetTexture(lump)); + } + } + } + else + { + FTexture *texs[256] = {}; + if (lcount > 256 - start) lcount = 256 - start; + for (i = 0; i < lcount; i++) + { + TArray array; + mysnprintf(buffer, countof(buffer), nametemplate, i + start); + + TexMan.ListTextures(buffer, array, true); + for (auto entry : array) + { + FTexture *tex = TexMan.GetTexture(entry, false); + if (tex && tex->GetSourceLump() >= 0 && fileSystem.GetFileContainer(tex->GetSourceLump()) <= fileSystem.GetMaxIwadNum() && tex->GetUseType() == ETextureType::MiscPatch) + { + texs[i] = tex; + } + } + } + if (doomtemplate) + { + // Handle the misplaced '|'. + if (texs[121 - '!'] && !texs[120 - '!'] && !texs[122 - '!'] && !texs[124 - '!']) + { + texs[124 - '!'] = texs[121 - '!']; + texs[121 - '!'] = nullptr; + } + } + + for (i = 0; i < lcount; i++) + { + if (texs[i]) + { + int position = lfirst + i; + Type = Multilump; + if (position < minchar) minchar = position; + if (position > maxchar) maxchar = position; + charMap.Insert(position, texs[i]); + } + } + } + } + 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); + Type = Folder; + } + } + } + } + FirstChar = minchar; + LastChar = maxchar; + auto count = maxchar - minchar + 1; + Chars.Resize(count); + int fontheight = 0; + int asciiheight = 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; + } + if (height > asciiheight && FirstChar + 1 < 128) + { + asciiheight = height; + } + } + + Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); + Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); + Chars[i].OriginalPic->CopySize(pic); + TexMan.AddTexture(Chars[i].OriginalPic); + + if (!noTranslate) + { + 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 = Chars[i].OriginalPic; + } + + 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; + if (AsciiHeight == 0) AsciiHeight = asciiheight; + + FixXMoves(); + } + + if (!noTranslate) LoadTranslations(); + + +} + +void FFont::ReadSheetFont(TArray &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 part(1, true); + TMap 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->GetTexelWidth() / width; + int numtex_y = tex->GetTexelHeight() / 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(int(position) + x + y * numtex_x, tex); + } + } + } + } + } + + + 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; + auto count = maxchar - minchar + 1; + Chars.Resize(count); + int fontheight = 0; + + for (int i = 0; i < count; i++) + { + auto lump = charMap.CheckKey(FirstChar + i); + if (lump != nullptr) + { + FTexture *pic = *lump; + + auto b = pic->Get8BitPixels(false); + + Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); + Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); + Chars[i].OriginalPic->CopySize(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].OriginalPic); + TexMan.AddTexture(Chars[i].TranslatedPic); + } + Chars[i].XMove = width; + } + + if (map1252) + { + // Move the Windows-1252 characters to their proper place. + for (int i = 0x80; i < 0xa0; i++) + { + if (win1252map[i - 0x80] != i && Chars[i - minchar].TranslatedPic != nullptr && Chars[win1252map[i - 0x80] - minchar].TranslatedPic == nullptr) + { + std::swap(Chars[i - minchar], Chars[win1252map[i - 0x80] - minchar]); + } + } + } + + SpaceWidth = width; +} + //========================================================================== // // FFont :: ~FFont @@ -224,6 +637,7 @@ void FFont::SetDefaultTranslation(uint32_t *othercolors) FRemapTable remap(ActiveColors); remap.Remap[0] = 0; remap.Palette[0] = 0; + remap.ForFont = true; for (unsigned l = 1; l < myluminosity.Size(); l++) { @@ -251,7 +665,7 @@ void FFont::SetDefaultTranslation(uint32_t *othercolors) } } } - Ranges[CR_UNTRANSLATED] = GLInterface.GetPaletteIndex(remap.Palette); + Translations[CR_UNTRANSLATED] = GPalette.StoreTranslation(TRANSLATION_Internal, &remap); forceremap = true; } @@ -354,44 +768,49 @@ int FFont::SimpleTranslation (uint32_t *colorsused, uint8_t *translation, uint8_ //========================================================================== void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity, - const void *ranges, int total_colors, const PalEntry *palette) + const void *ranges, int total_colors, const PalEntry *palette, std::function post) { int i, j; const TranslationParm *parmstart = (const TranslationParm *)ranges; - FRemapTable remap; + FRemapTable remap(total_colors); + remap.ForFont = true; // Create different translations for different color ranges - Ranges.Clear(); + Translations.Clear(); for (i = 0; i < NumTextColors; i++) { if (i == CR_UNTRANSLATED) { if (identity != nullptr) { + memcpy(remap.Remap, identity, ActiveColors); if (palette != nullptr) { - memcpy (remap.Palette, palette, ActiveColors*sizeof(PalEntry)); + memcpy(remap.Palette, palette, ActiveColors * sizeof(PalEntry)); } else { - remap.Palette[0] = GPalette.BaseColors[identity[0]] & MAKEARGB(0,255,255,255); + remap.Palette[0] = GPalette.BaseColors[identity[0]] & MAKEARGB(0, 255, 255, 255); for (j = 1; j < ActiveColors; ++j) { - remap.Palette[j] = GPalette.BaseColors[identity[j]] | MAKEARGB(255,0,0,0); + remap.Palette[j] = GPalette.BaseColors[identity[j]] | MAKEARGB(255, 0, 0, 0); } } + Translations.Push(GPalette.StoreTranslation(TRANSLATION_Internal, &remap)); } else { + Translations.Push(Translations[0]); } - Ranges.Push(GLInterface.GetPaletteIndex(remap.Palette)); continue; } assert(parmstart->RangeStart >= 0); + remap.Remap[0] = 0; remap.Palette[0] = 0; + remap.ForFont = true; for (j = 1; j < ActiveColors; j++) { @@ -415,10 +834,11 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity r = clamp(r, 0, 255); g = clamp(g, 0, 255); b = clamp(b, 0, 255); + remap.Remap[j] = ColorMatcher.Pick(r, g, b); remap.Palette[j] = PalEntry(255,r,g,b); } - - Ranges.Push(GLInterface.GetPaletteIndex(remap.Palette)); + if (post) post(&remap); + Translations.Push(GPalette.StoreTranslation(TRANSLATION_Internal, &remap)); // Advance to the next color range. while (parmstart[1].RangeStart > parmstart[0].RangeEnd) @@ -452,7 +872,7 @@ int FFont::GetColorTranslation (EColorRange range, PalEntry *color) const else if (range >= NumTextColors) range = CR_UNTRANSLATED; //if (range == CR_UNTRANSLATED && !translateUntranslated) return nullptr; - return Ranges[range]; + return Translations[range]; } //========================================================================== @@ -581,11 +1001,11 @@ FTexture *FFont::GetChar (int code, int translation, int *const width, bool *red //========================================================================== // -// FFont :: CharWidth +// FFont :: GetCharWidth // //========================================================================== -int FFont::CharWidth (int code) const +int FFont::GetCharWidth (int code) const { code = GetCharCode(code, true); if (code >= 0) return Chars[code - FirstChar].XMove; @@ -641,7 +1061,7 @@ bool FFont::CanPrint(const uint8_t *string) const else if (chr != '\n') { int cc = GetCharCode(chr, true); - if (chr != cc && myiswalpha(chr))// && cc != getAlternative(chr)) + if (chr != cc && myiswalpha(chr) && cc != getAlternative(chr)) { return false; } @@ -689,11 +1109,11 @@ int FFont::StringWidth(const uint8_t *string) const } else { - w += CharWidth(chr) + GlobalKerning; + w += GetCharWidth(chr) + GlobalKerning; } } - return std::max(maxw, w); + return MAX(maxw, w); } //========================================================================== @@ -786,8 +1206,9 @@ void FFont::LoadTranslations() // //========================================================================== -FFont::FFont () +FFont::FFont (int lump) { + Lump = lump; FontName = NAME_None; Cursor = '_'; noTranslate = false; @@ -807,6 +1228,19 @@ FFont::FFont () void FFont::FixXMoves() { + if (FirstChar < 'a' && LastChar >= 'z') + { + MixedCase = true; + // First check if this is a mixed case font. + // For this the basic Latin small characters all need to be present. + for (int i = 'a'; i <= 'z'; i++) + if (Chars[i - FirstChar].OriginalPic == nullptr) + { + MixedCase = false; + break; + } + } + for (int i = 0; i <= LastChar - FirstChar; ++i) { if (Chars[i].XMove == INT_MIN) diff --git a/source/core/fonts/fontinternals.h b/source/common/fonts/fontinternals.h similarity index 81% rename from source/core/fonts/fontinternals.h rename to source/common/fonts/fontinternals.h index 6d68c6aa8..dc942319e 100644 --- a/source/core/fonts/fontinternals.h +++ b/source/common/fonts/fontinternals.h @@ -34,13 +34,7 @@ struct TranslationMap extern TArray TranslationParms[2]; extern TArray TranslationLookup; extern TArray TranslationColors; -extern uint16_t lowerforupper[65536]; -extern uint16_t upperforlower[65536]; class FImageSource; void RecordTextureColors (FImageSource *pic, uint32_t *usedcolors); -bool myislower(int code); -bool myisupper(int code); -int stripaccent(int code); -int getAlternative(int code); diff --git a/source/core/fonts/hexfont.cpp b/source/common/fonts/hexfont.cpp similarity index 95% rename from source/core/fonts/hexfont.cpp rename to source/common/fonts/hexfont.cpp index 2ddf48c3b..1b3bca2e4 100644 --- a/source/core/fonts/hexfont.cpp +++ b/source/common/fonts/hexfont.cpp @@ -32,15 +32,13 @@ ** */ +#include "engineerrors.h" #include "textures.h" #include "image.h" #include "v_font.h" +#include "filesystem.h" #include "utf8.h" #include "sc_man.h" -#include "imagehelpers.h" -#include "v_draw.h" -#include "glbackend/glbackend.h" -#include "palettecontainer.h" #include "texturemanager.h" #include "fontinternals.h" @@ -58,10 +56,11 @@ struct HexDataSource // //========================================================================== - void ParseDefinition(const char *fname) + void ParseDefinition(int lumpnum) { FScanner sc; - sc.Open(fname); + + sc.OpenLumpNum(lumpnum); sc.SetCMode(true); glyphdata.Push(0); // ensure that index 0 can be used as 'not present'. while (sc.GetString()) @@ -243,8 +242,11 @@ public: // //========================================================================== - FHexFont (const char *fontname, const char *lump) + FHexFont (const char *fontname, int lump) + : FFont(lump) { + assert(lump >= 0); + FontName = fontname; FirstChar = hexdata.FirstChar; @@ -313,9 +315,10 @@ public: // //========================================================================== - FHexFont2(const char *fontname, const char *lump) + FHexFont2(const char *fontname, int lump) + : FFont(lump) { - assert(lump != nullptr); + assert(lump >= 0); FontName = fontname; @@ -388,6 +391,7 @@ public: FRemapTable remap(ActiveColors); remap.Remap[0] = 0; remap.Palette[0] = 0; + remap.ForFont = true; for (unsigned l = 1; l < 18; l++) { @@ -415,8 +419,8 @@ public: } } } + Translations[CR_UNTRANSLATED] = GPalette.StoreTranslation(TRANSLATION_Internal, &remap); forceremap = true; - Ranges[CR_UNTRANSLATED] = GLInterface.GetPaletteIndex(remap.Palette); } @@ -429,7 +433,7 @@ public: // //========================================================================== -FFont *CreateHexLumpFont (const char *fontname, const char * lump) +FFont *CreateHexLumpFont (const char *fontname, int lump) { if (hexdata.FirstChar == INT_MAX) hexdata.ParseDefinition(lump); return new FHexFont(fontname, lump); @@ -441,7 +445,7 @@ FFont *CreateHexLumpFont (const char *fontname, const char * lump) // //========================================================================== -FFont *CreateHexLumpFont2(const char *fontname, const char* lump) +FFont *CreateHexLumpFont2(const char *fontname, int lump) { if (hexdata.FirstChar == INT_MAX) hexdata.ParseDefinition(lump); return new FHexFont2(fontname, lump); diff --git a/source/core/fonts/myiswalpha.h b/source/common/fonts/myiswalpha.h similarity index 100% rename from source/core/fonts/myiswalpha.h rename to source/common/fonts/myiswalpha.h diff --git a/source/core/fonts/singlelumpfont.cpp b/source/common/fonts/singlelumpfont.cpp similarity index 89% rename from source/core/fonts/singlelumpfont.cpp rename to source/common/fonts/singlelumpfont.cpp index bbf4df705..4b4fc3d9a 100644 --- a/source/core/fonts/singlelumpfont.cpp +++ b/source/common/fonts/singlelumpfont.cpp @@ -33,16 +33,14 @@ ** */ +#include "engineerrors.h" #include "textures.h" #include "image.h" #include "v_font.h" +#include "filesystem.h" #include "utf8.h" #include "fontchars.h" #include "texturemanager.h" -#include "printf.h" -#include "imagehelpers.h" -#include "filesystem.h" -#include "colormatcher.h" #include "fontinternals.h" @@ -88,7 +86,7 @@ The FON2 header is followed by variable length data: class FSingleLumpFont : public FFont { public: - FSingleLumpFont (const char *fontname, const char * lump); + FSingleLumpFont (const char *fontname, int lump); protected: void CheckFON1Chars (double *luminosity); @@ -96,9 +94,10 @@ protected: void FixupPalette (uint8_t *identity, double *luminosity, const uint8_t *palette, bool rescale, PalEntry *out_palette); void LoadTranslations (); - void LoadFON1 (const char * lump, const uint8_t *data); - void LoadFON2 (const char* lump, const uint8_t *data); - void LoadBMF (const char* lump, const uint8_t *data); + void LoadFON1 (int lump, const uint8_t *data); + void LoadFON2 (int lump, const uint8_t *data); + void LoadBMF (int lump, const uint8_t *data); + void CreateFontFromPic (FTextureID picnum); static int BMFCompare(const void *a, const void *b); @@ -121,18 +120,18 @@ protected: // //========================================================================== -FSingleLumpFont::FSingleLumpFont (const char *name, const char * lump) +FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump) { - assert(lump != nullptr); + assert(lump >= 0); FontName = name; - rawData = fileSystem.LoadFile(lump, 0); - auto& data = rawData; + FileData data1 = fileSystem.ReadFile (lump); + const uint8_t *data = (const uint8_t *)data1.GetMem(); if (data[0] == 0xE1 && data[1] == 0xE6 && data[2] == 0xD5 && data[3] == 0x1A) { - LoadBMF(name, data.Data()); + LoadBMF(lump, data); Type = BMF; } else if (data[0] != 'F' || data[1] != 'O' || data[2] != 'N' || @@ -145,12 +144,12 @@ FSingleLumpFont::FSingleLumpFont (const char *name, const char * lump) switch (data[3]) { case '1': - LoadFON1 (name, data.Data()); + LoadFON1 (lump, data); Type = Fon1; break; case '2': - LoadFON2 (name, data.Data()); + LoadFON2 (lump, data); Type = Fon2; break; } @@ -160,6 +159,28 @@ FSingleLumpFont::FSingleLumpFont (const char *name, const char * lump) FirstFont = this; } +//========================================================================== +// +// FSingleLumpFont :: CreateFontFromPic +// +//========================================================================== + +void FSingleLumpFont::CreateFontFromPic (FTextureID picnum) +{ + FTexture *pic = TexMan.GetTexture(picnum); + + FontHeight = pic->GetDisplayHeight (); + SpaceWidth = pic->GetDisplayWidth (); + GlobalKerning = 0; + + FirstChar = LastChar = 'A'; + Chars.Resize(1); + Chars[0].TranslatedPic = pic; + + // Only one color range. Don't bother with the others. + ActiveColors = 0; +} + //========================================================================== // // FSingleLumpFont :: LoadTranslations @@ -215,7 +236,7 @@ void FSingleLumpFont::LoadTranslations() // //========================================================================== -void FSingleLumpFont::LoadFON1 (const char * lump, const uint8_t *data) +void FSingleLumpFont::LoadFON1 (int lump, const uint8_t *data) { int w, h; @@ -256,7 +277,7 @@ void FSingleLumpFont::LoadFON1 (const char * lump, const uint8_t *data) // //========================================================================== -void FSingleLumpFont::LoadFON2 (const char * lump, const uint8_t *data) +void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data) { int count, i, totalwidth; uint16_t *widths; @@ -332,7 +353,7 @@ void FSingleLumpFont::LoadFON2 (const char * lump, const uint8_t *data) } else { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (fileSystem.FindFile(lump), int(data_p - data), widths2[i], FontHeight)); + Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)); Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); TexMan.AddTexture(Chars[i].TranslatedPic); do @@ -369,7 +390,7 @@ void FSingleLumpFont::LoadFON2 (const char * lump, const uint8_t *data) // //========================================================================== -void FSingleLumpFont::LoadBMF(const char *lump, const uint8_t *data) +void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data) { const uint8_t *chardata; int numchars, count, totalwidth, nwidth; @@ -462,7 +483,7 @@ void FSingleLumpFont::LoadBMF(const char *lump, const uint8_t *data) { // Empty character: skip it. continue; } - auto tex = new FImageTexture(new FFontChar2(fileSystem.FindFile(lump), int(chardata + chari + 6 - data), + auto tex = new FImageTexture(new FFontChar2(lump, int(chardata + chari + 6 - data), chardata[chari+1], // width chardata[chari+2], // height -(int8_t)chardata[chari+3], // x offset @@ -519,15 +540,15 @@ int FSingleLumpFont::BMFCompare(const void *a, const void *b) void FSingleLumpFont::CheckFON1Chars (double *luminosity) { - auto &data = rawData; - if (data.Size() < 8) return; + FileData memLump = fileSystem.ReadFile(Lump); + const uint8_t* data = (const uint8_t*) memLump.GetMem(); uint8_t used[256], reverse[256]; const uint8_t *data_p; int i, j; memset (used, 0, 256); - data_p = data.Data() + 8; + data_p = data + 8; for (i = 0; i < 256; ++i) { @@ -535,7 +556,7 @@ void FSingleLumpFont::CheckFON1Chars (double *luminosity) if(!Chars[i].TranslatedPic) { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (0, int(data_p - data.Data()), SpaceWidth, FontHeight)); + Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight)); Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); Chars[i].XMove = SpaceWidth; TexMan.AddTexture(Chars[i].TranslatedPic); @@ -630,7 +651,7 @@ void FSingleLumpFont::FixupPalette (uint8_t *identity, double *luminosity, const } } -FFont *CreateSingleLumpFont (const char *fontname, const char * lump) +FFont *CreateSingleLumpFont (const char *fontname, int lump) { return new FSingleLumpFont(fontname, lump); } diff --git a/source/common/fonts/singlepicfont.cpp b/source/common/fonts/singlepicfont.cpp new file mode 100644 index 000000000..8d289944d --- /dev/null +++ b/source/common/fonts/singlepicfont.cpp @@ -0,0 +1,128 @@ +/* +** v_font.cpp +** Font management +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "engineerrors.h" +#include "textures.h" +#include "v_font.h" +#include "filesystem.h" +#include "texturemanager.h" + +class FSinglePicFont : public FFont +{ +public: + FSinglePicFont(const char *picname); + + // FFont interface + FTexture *GetChar(int code, int translation, int *const width, bool *redirected = nullptr) const override; + int GetCharWidth (int code) const; + +protected: + FTextureID PicNum; +}; + +//========================================================================== +// +// FSinglePicFont :: FSinglePicFont +// +// Creates a font to wrap a texture so that you can use hudmessage as if it +// were a hudpic command. It does not support translation, but animation +// is supported, unlike all the real fonts. +// +//========================================================================== + +FSinglePicFont::FSinglePicFont(const char *picname) : + FFont(-1) // Since lump is only needed for priority information we don't need to worry about this here. +{ + FTextureID picnum = TexMan.CheckForTexture (picname, ETextureType::Any); + + if (!picnum.isValid()) + { + I_FatalError ("%s is not a font or texture", picname); + } + + FTexture *pic = TexMan.GetTexture(picnum); + + FontName = picname; + FontHeight = pic->GetDisplayHeight(); + SpaceWidth = pic->GetDisplayWidth(); + GlobalKerning = 0; + FirstChar = LastChar = 'A'; + ActiveColors = 0; + PicNum = picnum; + + Next = FirstFont; + FirstFont = this; +} + +//========================================================================== +// +// FSinglePicFont :: GetChar +// +// Returns the texture if code is 'a' or 'A', otherwise nullptr. +// +//========================================================================== + +FTexture *FSinglePicFont::GetChar (int code, int translation, int *const width, bool *redirected) const +{ + *width = SpaceWidth; + if (redirected) *redirected = false; + if (code == 'a' || code == 'A') + { + return TexMan.GetPalettedTexture(PicNum, true); + } + else + { + return nullptr; + } +} + +//========================================================================== +// +// FSinglePicFont :: GetCharWidth +// +// Don't expect the text functions to work properly if I actually allowed +// the character width to vary depending on the animation frame. +// +//========================================================================== + +int FSinglePicFont::GetCharWidth (int code) const +{ + return SpaceWidth; +} + +FFont *CreateSinglePicFont(const char *picname) +{ + return new FSinglePicFont(picname); +} diff --git a/source/common/fonts/specialfont.cpp b/source/common/fonts/specialfont.cpp new file mode 100644 index 000000000..519ccf8dd --- /dev/null +++ b/source/common/fonts/specialfont.cpp @@ -0,0 +1,223 @@ +/* +** v_font.cpp +** Font management +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "v_font.h" +#include "textures.h" +#include "image.h" +#include "fontchars.h" +#include "texturemanager.h" + +#include "fontinternals.h" + +// Essentially a normal multilump font but with an explicit list of character patches +class FSpecialFont : public FFont +{ +public: + FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); + + void LoadTranslations(); + +protected: + bool notranslate[256]; +}; + + +//========================================================================== +// +// FSpecialFont :: FSpecialFont +// +//========================================================================== + +FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) + : FFont(lump) +{ + int i; + TArray charlumps(count, true); + int maxyoffs; + FTexture *pic; + + memcpy(this->notranslate, notranslate, 256*sizeof(bool)); + + noTranslate = donttranslate; + FontName = name; + Chars.Resize(count); + FirstChar = first; + LastChar = first + count - 1; + FontHeight = 0; + GlobalKerning = false; + Next = FirstFont; + FirstFont = this; + + maxyoffs = 0; + + for (i = 0; i < count; i++) + { + pic = charlumps[i] = lumplist[i]; + if (pic != nullptr) + { + int height = pic->GetDisplayHeight(); + int yoffs = pic->GetDisplayTopOffset(); + + if (yoffs > maxyoffs) + { + maxyoffs = yoffs; + } + height += abs (yoffs); + if (height > FontHeight) + { + FontHeight = height; + } + } + + if (charlumps[i] != nullptr) + { + auto pic = charlumps[i]; + Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); + Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); + Chars[i].OriginalPic->CopySize(pic); + TexMan.AddTexture(Chars[i].OriginalPic); + + if (!noTranslate) + { + Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (charlumps[i]->GetImage()), ""); + Chars[i].TranslatedPic->CopySize(charlumps[i]); + Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); + TexMan.AddTexture(Chars[i].TranslatedPic); + } + else Chars[i].TranslatedPic = Chars[i].OriginalPic; + Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); + } + else + { + Chars[i].TranslatedPic = nullptr; + Chars[i].XMove = INT_MIN; + } + } + + // Special fonts normally don't have all characters so be careful here! + if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].TranslatedPic != nullptr) + { + SpaceWidth = (Chars['N' - first].XMove + 1) / 2; + } + else + { + SpaceWidth = 4; + } + + FixXMoves(); + + if (noTranslate) + { + ActiveColors = 0; + } + else + { + LoadTranslations(); + } +} + +//========================================================================== +// +// FSpecialFont :: LoadTranslations +// +//========================================================================== + +void FSpecialFont::LoadTranslations() +{ + int count = LastChar - FirstChar + 1; + uint32_t usedcolors[256] = {}; + uint8_t identity[256]; + TArray Luminosity; + int TotalColors; + int i; + + for (i = 0; i < count; i++) + { + if (Chars[i].TranslatedPic) + { + FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); + if (pic) + { + pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture + RecordTextureColors(pic, usedcolors); + } + } + } + + // exclude the non-translated colors from the translation calculation + for (i = 0; i < 256; i++) + if (notranslate[i]) + usedcolors[i] = false; + + TotalColors = ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity); + + // Map all untranslated colors into the table of used colors + for (i = 0; i < 256; i++) + { + if (notranslate[i]) + { + PatchRemap[i] = TotalColors; + identity[TotalColors] = i; + TotalColors++; + } + } + + for (i = 0; i < count; i++) + { + if(Chars[i].TranslatedPic) + static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); + } + + BuildTranslations(Luminosity.Data(), identity, &TranslationParms[0][0], TotalColors, nullptr, [=](FRemapTable* remap) + { + // add the untranslated colors to the Ranges tables + if (ActiveColors < TotalColors) + { + for (int j = ActiveColors; j < TotalColors; ++j) + { + remap->Remap[j] = identity[j]; + remap->Palette[j] = GPalette.BaseColors[identity[j]]; + remap->Palette[j].a = 0xff; + } + } + }); + + ActiveColors = TotalColors; +} + +FFont *CreateSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) +{ + return new FSpecialFont(name, first, count, lumplist, notranslate, lump, donttranslate); +} diff --git a/source/core/fonts/v_font.cpp b/source/common/fonts/v_font.cpp similarity index 68% rename from source/core/fonts/v_font.cpp rename to source/common/fonts/v_font.cpp index 20a56d976..8fe004f7f 100644 --- a/source/core/fonts/v_font.cpp +++ b/source/common/fonts/v_font.cpp @@ -42,15 +42,17 @@ #include "templates.h" #include "m_swap.h" #include "v_font.h" +#include "filesystem.h" #include "cmdlib.h" #include "sc_man.h" -#include "v_text.h" +#include "gstrings.h" #include "image.h" #include "utf8.h" - -#include "m_png.h" +#include "fontchars.h" +#include "textures.h" +#include "texturemanager.h" #include "printf.h" -#include "filesystem.h" +#include "palentry.h" #include "fontinternals.h" @@ -58,24 +60,32 @@ #define DEFAULT_LOG_COLOR PalEntry(223,223,223) +// +// Globally visible constants. +// +#define HU_FONTSTART uint8_t('!') // the first font characters +#define HU_FONTEND uint8_t('\377') // the last font characters + +// Calculate # of glyphs in font. +#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) + + // TYPES ------------------------------------------------------------------- -int V_GetColor(const char* cstr); // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- -FFont* SmallFont, * SmallFont2, * BigFont, * BigUpper, * ConFont, * IntermissionFont, * NewConsoleFont, * NewSmallFont, * CurrentConsoleFont, * OriginalSmallFont, * AlternativeSmallFont, * OriginalBigFont; // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static int TranslationMapCompare (const void *a, const void *b); -//void UpdateGenericUI(bool cvar); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern int PrintColors[]; // PUBLIC DATA DEFINITIONS ------------------------------------------------- +FFont* SmallFont, * SmallFont2, * BigFont, * BigUpper, * ConFont, * IntermissionFont, * NewConsoleFont, * NewSmallFont, * CurrentConsoleFont, * OriginalSmallFont, * AlternativeSmallFont, * OriginalBigFont; FFont *FFont::FirstFont = nullptr; int NumTextColors; @@ -90,19 +100,60 @@ TArray TranslationColors; FFont *V_GetFont(const char *name, const char *fontlumpname) { + if (!stricmp(name, "DBIGFONT")) name = "BigFont"; + else if (!stricmp(name, "CONFONT")) name = "ConsoleFont"; // several mods have used the name CONFONT directly and effectively duplicated the font. FFont *font = FFont::FindFont (name); if (font == nullptr) { - auto lumpy = fileSystem.OpenFileReader(fontlumpname); - if (!lumpy.isOpen()) return nullptr; - uint32_t head; - lumpy.Read (&head, 4); - if ((head & MAKE_ID(255,255,255,0)) == MAKE_ID('F','O','N',0) || - head == MAKE_ID(0xE1,0xE6,0xD5,0x1A)) + if (!stricmp(name, "BIGUPPER")) { - FFont *CreateSingleLumpFont (const char *fontname, const char *lump); - lumpy.Close(); - return CreateSingleLumpFont (name, fontlumpname); + font = FFont::FindFont("BIGFONT"); + if (font) return font; + } + + int lump = -1; + int folderfile = -1; + + TArray folderdata; + FStringf path("fonts/%s/", name); + + // Use a folder-based font only if it comes from a later file than the single lump version. + if (fileSystem.GetFilesInFolder(path, folderdata, true)) + { + // This assumes that any custom font comes in one piece and not distributed across multiple resource files. + folderfile = fileSystem.GetFileContainer(folderdata[0].lumpnum); + } + + + lump = fileSystem.CheckNumForFullName(fontlumpname? fontlumpname : name, true); + + if (lump != -1 && fileSystem.GetFileContainer(lump) >= folderfile) + { + uint32_t head; + { + auto lumpy = fileSystem.OpenFileReader (lump); + lumpy.Read (&head, 4); + } + if ((head & MAKE_ID(255,255,255,0)) == MAKE_ID('F','O','N',0) || + head == MAKE_ID(0xE1,0xE6,0xD5,0x1A)) + { + FFont *CreateSingleLumpFont (const char *fontname, int lump); + return CreateSingleLumpFont (name, lump); + } + } + FTextureID picnum = TexMan.CheckForTexture (name, ETextureType::Any); + if (picnum.isValid()) + { + FTexture *tex = TexMan.GetTexture(picnum); + if (tex && tex->GetSourceLump() >= folderfile) + { + FFont *CreateSinglePicFont(const char *name); + return CreateSinglePicFont (name); + } + } + if (folderdata.Size() > 0) + { + return new FFont(name, nullptr, name, HU_FONTSTART, HU_FONTSIZE, 1, -1); } } return font; @@ -118,7 +169,6 @@ FFont *V_GetFont(const char *name, const char *fontlumpname) void V_InitCustomFonts() { -#if 0 FScanner sc; FTexture *lumplist[256]; bool notranslate[256]; @@ -134,7 +184,7 @@ void V_InitCustomFonts() int kerning; char cursor = '_'; - while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1) + while ((llump = fileSystem.FindLump ("FONTDEFS", &lastlump)) != -1) { sc.OpenLumpNum(llump); while (sc.GetString()) @@ -223,7 +273,7 @@ void V_InitCustomFonts() { *p = TexMan.GetTexture(texid); } - else if (Wads.GetLumpFile(sc.LumpNum) >= Wads.GetIwadNum()) + else if (fileSystem.GetFileContainer(sc.LumpNum) >= fileSystem.GetIwadNum()) { // Print a message only if this isn't in zdoom.pk3 sc.ScriptMessage("%s: Unable to find texture in font definition for %s", sc.String, namebuffer.GetChars()); @@ -271,107 +321,6 @@ void V_InitCustomFonts() wrong: sc.ScriptError ("Invalid combination of properties in font '%s'", namebuffer.GetChars()); -#endif -} - -//========================================================================== -// -// V_GetColorFromString -// -// Passed a string of the form "#RGB", "#RRGGBB", "R G B", or "RR GG BB", -// returns a number representing that color. If palette is non-NULL, the -// index of the best match in the palette is returned, otherwise the -// RRGGBB value is returned directly. -// -//========================================================================== - -int V_GetColor(const char* cstr) -{ - int c[3], i, p; - char val[3]; - - val[2] = '\0'; - - // Check for HTML-style #RRGGBB or #RGB color string - if (cstr[0] == '#') - { - size_t len = strlen(cstr); - - if (len == 7) - { - // Extract each eight-bit component into c[]. - for (i = 0; i < 3; ++i) - { - val[0] = cstr[1 + i * 2]; - val[1] = cstr[2 + i * 2]; - c[i] = ParseHex(val, nullptr); - } - } - else if (len == 4) - { - // Extract each four-bit component into c[], expanding to eight bits. - for (i = 0; i < 3; ++i) - { - val[1] = val[0] = cstr[1 + i]; - c[i] = ParseHex(val, nullptr); - } - } - else - { - // Bad HTML-style; pretend it's black. - c[2] = c[1] = c[0] = 0; - } - } - else - { - if (strlen(cstr) == 6) - { - char* p; - int color = strtol(cstr, &p, 16); - if (*p == 0) - { - // RRGGBB string - c[0] = (color & 0xff0000) >> 16; - c[1] = (color & 0xff00) >> 8; - c[2] = (color & 0xff); - } - else goto normal; - } - else - { - normal: - // Treat it as a space-delimited hexadecimal string - for (i = 0; i < 3; ++i) - { - // Skip leading whitespace - while (*cstr <= ' ' && *cstr != '\0') - { - cstr++; - } - // Extract a component and convert it to eight-bit - for (p = 0; *cstr > ' '; ++p, ++cstr) - { - if (p < 2) - { - val[p] = *cstr; - } - } - if (p == 0) - { - c[i] = 0; - } - else - { - if (p == 1) - { - val[1] = val[0]; - } - c[i] = ParseHex(val, nullptr); - } - } - } - } - return MAKERGB(c[0], c[1], c[2]); } //========================================================================== @@ -404,7 +353,7 @@ void V_InitFontColors () TranslationLookup.Clear(); TranslationColors.Clear(); - while ((lump = fileSystem.FindLumpFullName("engine/textcolors.txt", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("TEXTCOLO", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString()) @@ -447,19 +396,19 @@ void V_InitFontColors () else if (sc.Compare ("Flat:")) { sc.MustGetString(); - logcolor = V_GetColor (sc.String); + logcolor = V_GetColor (nullptr, sc); } else { // Get first color - c = V_GetColor (sc.String); + c = V_GetColor (nullptr, sc); tparm.Start[0] = RPART(c); tparm.Start[1] = GPART(c); tparm.Start[2] = BPART(c); // Get second color sc.MustGetString(); - c = V_GetColor (sc.String); + c = V_GetColor (nullptr, sc); tparm.End[0] = RPART(c); tparm.End[1] = GPART(c); tparm.End[2] = BPART(c); @@ -670,6 +619,14 @@ EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int { newcolor = boldcolor; } + else if (newcolor == '!') // Team chat + { + newcolor = PrintColors[PRINT_TEAMCHAT]; + } + else if (newcolor == '*') // Chat + { + newcolor = PrintColors[PRINT_CHAT]; + } else if (newcolor == '[') // Named { const uint8_t *namestart = ch; @@ -705,23 +662,170 @@ EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int // // V_InitFonts // +// Fixme: This really needs to be a bit more flexible +// and less rigidly tied to the original game data. +// //========================================================================== void V_InitFonts() { V_InitCustomFonts(); - FFont *CreateHexLumpFont(const char *fontname, const char* lump); - FFont *CreateHexLumpFont2(const char *fontname, const char * lump); + FFont *CreateHexLumpFont(const char *fontname, int lump); + FFont *CreateHexLumpFont2(const char *fontname, int lump); - if (fileSystem.FindFile("engine/newconsolefont.hex") < 0) - I_Error("newconsolefont.hex not found"); // This font is needed - do not start up without it. - NewConsoleFont = CreateHexLumpFont("NewConsoleFont", "engine/newconsolefont.hex"); - NewSmallFont = CreateHexLumpFont2("NewSmallFont", "engine/newconsolefont.hex"); + auto lump = fileSystem.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; - ConFont = V_GetFont("ConsoleFont", "engine/confont.lmp"); // The con font is needed for the slider graphics - SmallFont = ConFont; // This is so that it doesn't crash and that it immediately gets seen as a proble. The SmallFont should later be mapped to the small game font. + // load the heads-up font + if (!(SmallFont = V_GetFont("SmallFont", "SMALLFNT"))) + { + if (fileSystem.CheckNumForName("FONTA_S") >= 0) + { + int wadfile = -1; + auto a = fileSystem.CheckNumForName("FONTA33", ns_graphics); + if (a != -1) wadfile = fileSystem.GetFileContainer(a); + if (wadfile > fileSystem.GetIwadNum()) + { + // The font has been replaced, so we need to create a copy of the original as well. + SmallFont = new FFont("SmallFont", "FONTA%02u", nullptr, HU_FONTSTART, HU_FONTSIZE, 1, -1); + SmallFont->SetCursor('['); + } + else + { + SmallFont = new FFont("SmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1); + SmallFont->SetCursor('['); + } + } + else if (fileSystem.CheckNumForName("STCFN033", ns_graphics) >= 0) + { + int wadfile = -1; + auto a = fileSystem.CheckNumForName("STCFN065", ns_graphics); + if (a != -1) wadfile = fileSystem.GetFileContainer(a); + if (wadfile > fileSystem.GetIwadNum()) + { + // The font has been replaced, so we need to create a copy of the original as well. + SmallFont = new FFont("SmallFont", "STCFN%.3d", nullptr, HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, false, true); + } + else + { + SmallFont = new FFont("SmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, false, true); + } + } + } + + // Create the original small font as a fallback for incomplete definitions. + if (fileSystem.CheckNumForName("FONTA_S") >= 0) + { + OriginalSmallFont = new FFont("OriginalSmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); + OriginalSmallFont->SetCursor('['); + } + else if (fileSystem.CheckNumForName("STCFN033", ns_graphics) >= 0) + { + OriginalSmallFont = new FFont("OriginalSmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, true); + } + + if (SmallFont) + { + uint32_t colors[256] = {}; + SmallFont->RecordAllTextureColors(colors); + if (OriginalSmallFont != nullptr) OriginalSmallFont->SetDefaultTranslation(colors); + NewSmallFont->SetDefaultTranslation(colors); + } + + if (!(SmallFont2 = V_GetFont("SmallFont2"))) // Only used by Strife + { + if (fileSystem.CheckNumForName("STBFN033", ns_graphics) >= 0) + { + SmallFont2 = new FFont("SmallFont2", "STBFN%.3d", "defsmallfont2", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); + } + } + + //This must be read before BigFont so that it can be properly substituted. + BigUpper = V_GetFont("BigUpper"); + + if (!(BigFont = V_GetFont("BigFont"))) + { + if (fileSystem.CheckNumForName("FONTB_S") >= 0) + { + BigFont = new FFont("BigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1); + } + } + + if (!BigFont) + { + // Load the generic fallback if no BigFont is found. + BigFont = V_GetFont("BigFont", "ZBIGFONT"); + } + + if (fileSystem.CheckNumForName("FONTB_S") >= 0) + { + OriginalBigFont = new FFont("OriginalBigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); + } + else + { + OriginalBigFont = new FFont("OriginalBigFont", nullptr, "bigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); + } + + if (BigFont) + { + uint32_t colors[256] = {}; + BigFont->RecordAllTextureColors(colors); + if (OriginalBigFont != nullptr) OriginalBigFont->SetDefaultTranslation(colors); + } + + // let PWAD BIGFONTs override the stock BIGUPPER font. (This check needs to be made smarter.) + if (BigUpper && BigFont->Type != FFont::Folder && BigUpper->Type == FFont::Folder) + { + delete BigUpper; + BigUpper = BigFont; + } + + if (BigUpper == nullptr) + { + BigUpper = BigFont; + } + if (!(ConFont = V_GetFont("ConsoleFont", "CONFONT"))) + { + ConFont = SmallFont; + } + if (!(IntermissionFont = FFont::FindFont("IntermissionFont"))) + { + if (fileSystem.CheckNumForName("WINUM0") >= 0) + { + IntermissionFont = FFont::FindFont("IntermissionFont_Doom"); + } + if (IntermissionFont == nullptr) + { + IntermissionFont = BigFont; + } + } + // This can only happen if gzdoom.pk3 is corrupted. ConFont should always be present. + if (ConFont == nullptr) + { + I_FatalError("Console font not found."); + } + // SmallFont and SmallFont2 have no default provided by the engine. BigFont only has in non-Raven games. + if (OriginalSmallFont == nullptr) + { + OriginalSmallFont = ConFont; + } + if (SmallFont == nullptr) + { + SmallFont = OriginalSmallFont; + } + if (SmallFont2 == nullptr) + { + SmallFont2 = SmallFont; + } + if (BigFont == nullptr) + { + BigFont = OriginalBigFont; + } + AlternativeSmallFont = OriginalSmallFont; } void V_ClearFonts() diff --git a/source/core/fonts/v_font.h b/source/common/fonts/v_font.h similarity index 90% rename from source/core/fonts/v_font.h rename to source/common/fonts/v_font.h index 21264a266..74d47d3da 100644 --- a/source/core/fonts/v_font.h +++ b/source/common/fonts/v_font.h @@ -34,15 +34,14 @@ #ifndef __V_FONT_H__ #define __V_FONT_H__ +#include "filesystem.h" #include "vectors.h" -#include "name.h" #include "palentry.h" -#include "tarray.h" -#include "zstring.h" +#include "name.h" class DCanvas; -struct FRemapTable; class FTexture; +struct FRemapTable; enum EColorRange : int { @@ -95,11 +94,13 @@ public: Custom }; + FFont (const char *fontname, const char *nametemplate, const char *filetemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false, bool iwadonly = false, bool doomtemplate = false); virtual ~FFont (); virtual FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const; - virtual int CharWidth (int code) const; + virtual int GetCharWidth (int code) const; int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; + int GetLump() const { return Lump; } int GetSpaceWidth () const { return SpaceWidth; } int GetHeight () const { return FontHeight; } int GetDefaultKerning () const { return GlobalKerning; } @@ -134,15 +135,17 @@ public: protected: - FFont (); + FFont (int lump); void BuildTranslations (const double *luminosity, const uint8_t *identity, - const void *ranges, int total_colors, const PalEntry *palette); + const void *ranges, int total_colors, const PalEntry *palette, std::function post = nullptr); void FixXMoves(); static int SimpleTranslation (uint32_t *colorsused, uint8_t *translation, uint8_t *identity, TArray &Luminosity); + void ReadSheetFont(TArray &folderdata, int width, int height, const DVector2 &Scale); + EFontType Type = EFontType::Unknown; int FirstChar, LastChar; int SpaceWidth; @@ -164,11 +167,11 @@ protected: }; TArray Chars; int ActiveColors; - TArray Ranges; + TArray Translations; uint8_t PatchRemap[256]; + int Lump; FName FontName = NAME_None; - TArray rawData; FFont *Next; static FFont *FirstFont; @@ -190,4 +193,5 @@ FFont *V_GetFont(const char *fontname, const char *fontlumpname = nullptr); void V_InitFontColors(); char* CleanseString(char* str); + #endif //__V_FONT_H__ diff --git a/source/common/fonts/v_text.cpp b/source/common/fonts/v_text.cpp index f4c7ddc0c..375e2d67b 100644 --- a/source/common/fonts/v_text.cpp +++ b/source/common/fonts/v_text.cpp @@ -119,7 +119,7 @@ TArray V_BreakLines (FFont *font, int maxwidth, const uint8_t *str lastWasSpace = false; } - nw = font->CharWidth (c); + nw = font->GetCharWidth (c); if ((w > 0 && w + nw > maxwidth) || c == '\n') { // Time to break the line diff --git a/source/common/textures/textures.h b/source/common/textures/textures.h index 9dc891fdb..a4cb09e82 100644 --- a/source/common/textures/textures.h +++ b/source/common/textures/textures.h @@ -432,7 +432,7 @@ protected: uint16_t Width, Height; int16_t _LeftOffset[2], _TopOffset[2]; - FTexture(const char *name = NULL, int lumpnum = -1); + FTexture (const char *name = NULL, int lumpnum = -1); public: FTextureBuffer CreateTexBuffer(int translation, int flags = 0); diff --git a/source/core/console/c_console.cpp b/source/core/console/c_console.cpp index 17141589e..3da41fdfc 100644 --- a/source/core/console/c_console.cpp +++ b/source/core/console/c_console.cpp @@ -202,13 +202,13 @@ public: if (scale == 1) { DrawChar(twod, CurrentConsoleFont, CR_ORANGE, x, y, '\x1c', TAG_DONE); - DrawText(twod, CurrentConsoleFont, CR_ORANGE, x + CurrentConsoleFont->CharWidth(0x1c), y, + DrawText(twod, CurrentConsoleFont, CR_ORANGE, x + CurrentConsoleFont->GetCharWidth(0x1c), y, &Text[StartPos], TAG_DONE); if (cursor) { DrawChar(twod, CurrentConsoleFont, CR_YELLOW, - x + CurrentConsoleFont->CharWidth(0x1c) + (CursorPosCells - StartPosCells) * CurrentConsoleFont->CharWidth(0xb), + x + CurrentConsoleFont->GetCharWidth(0x1c) + (CursorPosCells - StartPosCells) * CurrentConsoleFont->GetCharWidth(0xb), y, '\xb', TAG_DONE); } } @@ -219,7 +219,7 @@ public: DTA_VirtualHeight, screen->GetHeight() / scale, DTA_KeepRatio, true, TAG_DONE); - DrawText(twod, CurrentConsoleFont, CR_ORANGE, x + CurrentConsoleFont->CharWidth(0x1c), y, + DrawText(twod, CurrentConsoleFont, CR_ORANGE, x + CurrentConsoleFont->GetCharWidth(0x1c), y, &Text[StartPos], DTA_VirtualWidth, screen->GetWidth() / scale, DTA_VirtualHeight, screen->GetHeight() / scale, @@ -228,7 +228,7 @@ public: if (cursor) { DrawChar(twod, CurrentConsoleFont, CR_YELLOW, - x + CurrentConsoleFont->CharWidth(0x1c) + (CursorPosCells - StartPosCells) * CurrentConsoleFont->CharWidth(0xb), + x + CurrentConsoleFont->GetCharWidth(0x1c) + (CursorPosCells - StartPosCells) * CurrentConsoleFont->GetCharWidth(0xb), y, '\xb', DTA_VirtualWidth, screen->GetWidth() / scale, DTA_VirtualHeight, screen->GetHeight() / scale, @@ -612,7 +612,7 @@ void C_InitConsole (int width, int height, bool ingame) vidactive = ingame; if (CurrentConsoleFont != NULL) { - cwidth = CurrentConsoleFont->CharWidth ('M'); + cwidth = CurrentConsoleFont->GetCharWidth ('M'); cheight = CurrentConsoleFont->GetHeight(); } else diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index bc24e6847..d787c6d20 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -712,6 +712,7 @@ int RunGame() { playername = userConfig.CommandName; } + GPalette.Init(MAXPALOOKUPS + 2); // one slot for each translation, plus a separate one for the base palettes and the internal one TexMan.Init([]() {}, [](BuildInfo &) {}); V_InitFonts(); TileFiles.Init(); diff --git a/source/glbackend/gl_texture.cpp b/source/glbackend/gl_texture.cpp index 7598cdb0c..eaa614574 100644 --- a/source/glbackend/gl_texture.cpp +++ b/source/glbackend/gl_texture.cpp @@ -255,7 +255,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int applytint = true; if (!(h.f & HICTINT_APPLYOVERPALSWAP)) usepalswap = 0; } - lookuppal = palmanager.LookupPalette(usepalette, usepalswap, false, 0); + lookuppal = TRANSLATION(usepalette + Translation_Remap, usepalswap); } } diff --git a/source/glbackend/hw_draw2d.cpp b/source/glbackend/hw_draw2d.cpp index 2aaae3603..4af19143d 100644 --- a/source/glbackend/hw_draw2d.cpp +++ b/source/glbackend/hw_draw2d.cpp @@ -177,7 +177,8 @@ void GLInstance::Draw2D(F2DDrawer *drawer) auto saved = curbasepal; // screw Build's dependencies on global state variables. We only need to change this for the following SetTexture call. curbasepal = (cmd.mRemapIndex >> 8) & 0xff; auto savedf = globalflags; - if (curbasepal > 0) globalflags |= GLOBAL_NO_GL_FULLBRIGHT; // temp. hack to disable brightmaps. + if (curbasepal > 0) + globalflags |= GLOBAL_NO_GL_FULLBRIGHT; // temp. hack to disable brightmaps. SetTexture(-1, tex, cmd.mRemapIndex & 0xff, 4/*DAMETH_CLAMPED*/, cmd.mFlags & F2DDrawer::DTF_Wrap ? SamplerRepeat : SamplerClampXY); curbasepal = saved; globalflags = savedf; diff --git a/wadsrc/static/engine/Roboto-Regular.ttf b/wadsrc/static/engine/Roboto-Regular.ttf deleted file mode 100644 index 2c97eeadffe1a34bd67d3ff1c3887fd53e22c2ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171676 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 ZcAgz$Pp~K2ZnnEU$(~HkLK9l*e*jr~ZsGs{ diff --git a/wadsrc/static/engine/confont.lmp b/wadsrc/static/engine/confont.lmp deleted file mode 100644 index 3d46a3ca4cd3acd1046a9e82360df64403285e36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10239 zcmcJUO^74udB>ku(sa$&?)0u;ZCBwjN`)Xg<7j#j=+Hf6p_#zMkj-IX<`S5L=dhT8 zy#${^`jYG+U_lb_WkDDWa|!5{tJqs^vJVMP4l6s5>~4s+cM^N1^;MPM|0$J9-P0d) z39YJO?wAvmelvV-QGO8*6k%pYd=ZSUdG+&!L&C`Z!yR}-L#dYtxk6u z9fz&$C`4g9+&cJPZ@;&1*6Vb7orA6|(!3YC=`yLOy|kI7wItnNCO6U~{a%~pk~Hls zlaMA^`um+;H%*b9cDg+1HrqYEYc1|G5G6Rb(q`Jx@NK`(fM(L`GCWO=!y8f}3h1G~ zXogxrceWSdX7SA*hV3j|DZbT`PIr;M_|#yoGexZQ!1;y$sWEyVJ#3K6iUP zKAm2=-{lYIOQCLZoYs4H@21&)=xk?E9TT>9)6RY;?R46m-X4DGq`iX=di&i@(&_c~ zQXX~piR3=N_xBF=JDnEO?_Te;EZPpuW@7fj>?d=}{(5Qo)0#bf`kRg44St&)+x)L` zju34A_d0!|(@%B!hgvY3hhuB}#Q0mfoW@h*?^QWdtEKn9yRb(3;fH^AKeOxUqeuE? zT$lHQrP=*F-HI(uznjLH<*CIBdujQzYoGl1M<1I#`}l_+F0FpSC4W}e&||yu@sED| z$+KsS{_uw%pLe;bXJ*Av@_^-94U5}*f0(^r=ko5d9mnl=+wC}t;?|vZyVYz)t#354njXHN)S^RbqI&mwBBYwBIf2R|5vNjOV?^pw&gzwL-_Wg$|O1RUG zlemd#Ev`v3iV`lm#w-&hT$$F=@0f+MsL@X1xRXVBe5Dh2wxg&PB`o|0OhKcBCAgB^ zTsv``Al+b^O;a>JKQ-qngx*7|nbVnRq5Bo*SQO$4H-$#7;h|JPNF zV!mf_Es0{1BF5M(y6IXnw9Sz$qY!T&N7j51WfmUq&MiFM#mSF9dT$quJpRE4yP0i2 z{^-%8_jb)5|KQQ14|eVGM~goWyYJ0*rym8r|LHAm6;F7iky$ZQ0+6#<3D*6WwmgJg z|JK67@}K(oAN~AK7BXA@n}ww<$(*mP7IyAs55mDt_P`FZd;FU3XJ>QuYx9)N0-cGRWUR~e*XXls%{FFq_`z$)}g@%3}6(o-mlNn^61M>W^ zW`~D>tbZf)`{*zj1U}pduu=FG*`D_s*6*XifZ@YN7!E_2jrcyk5yoTEeliJsG^NfI zUwB~)AH86a<%k7CKF)11(V|zv(GkO@2+r&+)?_^$fyt7Mpi!>#ShH?OysyDytwBm0 zLQefWSRaBJ_?_VvQ*AT~8B_D|RxmU(%O*8c%Pezae#5N7Bg`M>3P$+C_|J#c|AmOO1;m4PyW@T@|qU-?FUo_tya zI=5fD^Q%Bg+X{SVHpzh!A#?-QeL&>sR8m( z0mG&HQ9fFPhQl=*zU7eBN$Z_jv>>^>f7MA&r`fQE$pm85Tu*Qx=~OUWg&S5rm3);h zxhFi>859ivwv0DdrZk>di5N1}5{;v`$M=dDKA5OU?CjVbJNIB{T_JNYgAKZ^GinGr zKm&86iw2I(;PDy-A_E6HX6QUC%p1!_x2!U+n2`Gfxe`VhdXQ(Mx`r>u+dhRE@`$5H zvDR1t_*?FHog9~EJAM-!!deZ-h?=B%<-;nTuO%3N9ih-^+24`VPvBU_>R72?Aq#&G zS)S+5sGiC^9dd|{H2@X>HzQX{9F{@4rSY2LDXc3>h4V_1+Y~^10IgoD;BuA>xKP8!>f{REt>jnF z>Ix_ZVXRhQ0+qPoSjB*y00gtLt!kTpeHUaV9 zh>}CkW5J@K+3Yv2c(V!ri3Rhs`A;=fQcniHWWKNImPuK$9&y%j0qYfm!K>22MJ`8M za?m-9SGo~@TwG!{BPvLgO;}a4Hbq_YnD}Wy!lOwj2dW*bIyQ;=#u{A;g~x;xCngmH zUTyD-zHTnh;9*a_Gb6Sci+3)eug$TvtD973OXsb!z0KJq6~NkF0}Cgg%U9)Sg=9-J zl*}tgteHx-mrS*(3QXnT6^6hvijeDYf)XLen{oo*hW>OthIVbDmhHDz@P*2A(POJK zU@i;>mrOV$6<(oMDvbwzJ_W|jBsfMQ8+Z6;hD3Cs&yZfK0okNz1z;*RP+M&J*wlrr zzuL5A;TNlRzff1(k(_3p^Qt@i$})OKT769OEgj}kDO^pnPwihAKeI65WJu5+5}IiZ0l|FK1UYUYLUPqA|FR?Z_9Av4$5bFro&g9>^53d;Lm87;Z=xLLn1N z1}J-?veQCEAn=y#mBC&SkWbr1)K0&sC?}DmgROOYR$7Rtu`;Sa6x(*tSKy4hEA;Vg zMQs{cQY5M1xh0+{EEQeyedMxf1^B*>-8!M%*FQ7b58ht&`}Fnwd~h2`;(EnT7Rgs) zeF6wX$<8_Nf|%jX5-ym>npe5!A(sZAR_)w#-%Ec>XjnZ{uJK{4XF7hJ)IbDRf3Y-S zDrT`vnBnn}7x6y^hT(CK<)ctm>odFW?iCyQZ~RWis{tQ_1BRh5C{;o2mX{u)7+M{5L{ z>nOnn-@{`@a5mSX9J(~bH;2fi78teDVlfjR=O$1@7U_>GluQ>(^o+jMMwwlc5BbV;agK0Hm0)Ef&3~s4F>r^O{xSA(U`Z`bu{iELWARPOp=`4f zhQMslHaK4B*CFM*k6(*AuNS>)@Xvprqga5MzUtNM&(TJy))%*B=+CnLO8MfIz!({E z6Zb0>IPm7{&&Gp?zAC|ZeN77-HCRl^mkq9KRi}!Jb$!W3{syq}3dwkinI$47NmIj77zy*1OIG9u@X0*k8{Tr8{dTGhOqz2*uy zrxTJC1;$F?lJF}9mA)kGuuR^w$2$3yoTWrPfB4Djz}QQ~Z@$GTSPXQGZk8mb%5T+% z_!~u+v;jcUUTp5&7;0U-o7;$9Rp*G}1ux$#SE)|%3%+(eFPu|Gw(J}(pHt-4jm_Lz z4w3@vP61-|O=btXsvmmoank49drdvdenK2YyT>ma-N4P9%9MMDoO|8tKXLBF3|3GyNIqm7+ zRZ%G-zp9B|*H0BiY2?0E;{&C86>X^X;vW;m>%kztbFx#RD7~x(;&sNCfL3$j^nJ++ z1)Q}x=&wtKR)@kbnYmde*t=dby7>18?S2S&Hye6+z_I69UcQ9!*G@y;6s`9bVnOg^n^EWmXh=l>w0FIFp``FL;gF6s_My@LW zJ(uI>+|lc-^6kNIFOVw~Rxc9tcA|;z37$u<>|l+c;O>Iwa{7-~L6zAS#a(?;Hi}9@ z%2v4NeL#tOw`83r@VO@Bkrf_*ln7jM@$NQU|AJ;&*PT`z!6LCYon1u???8Z%CM@O4&s zshyb`S$Mx_4ht+?P%X|s<+lg|Fq^KREqG= G7XE)78R{4S diff --git a/wadsrc/static/engine/newconsolefont.hex b/wadsrc/static/newconsolefont.hex similarity index 100% rename from wadsrc/static/engine/newconsolefont.hex rename to wadsrc/static/newconsolefont.hex diff --git a/wadsrc/static/engine/textcolors.txt b/wadsrc/static/textcolors.txt similarity index 100% rename from wadsrc/static/engine/textcolors.txt rename to wadsrc/static/textcolors.txt