From 4ff4fa643bcea6a19a6cce5f06dd436c454b88f3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 24 May 2021 20:29:22 +0200 Subject: [PATCH] - rewrote the default translation handling to be compatible with luminosity translations. --- source/common/engine/palettecontainer.h | 2 +- source/common/fonts/font.cpp | 123 ++++-------------------- source/common/fonts/hexfont.cpp | 52 ---------- source/common/fonts/singlelumpfont.cpp | 3 +- source/common/fonts/singlepicfont.cpp | 1 - source/common/fonts/specialfont.cpp | 5 - source/common/fonts/v_font.cpp | 105 ++++++++++++++++++-- source/common/fonts/v_font.h | 6 +- source/core/statusbar2.cpp | 9 -- 9 files changed, 121 insertions(+), 185 deletions(-) diff --git a/source/common/engine/palettecontainer.h b/source/common/engine/palettecontainer.h index c284ae7f830..1103f5c343b 100644 --- a/source/common/engine/palettecontainer.h +++ b/source/common/engine/palettecontainer.h @@ -32,7 +32,7 @@ struct FRemapTable PalEntry Palette[256]; // The ideal palette this maps to int crc32; int Index; - int NumEntries; // # of elements in this table (usually 256), if this is -1 it is a luminosity translation. + 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 TwodOnly = false; // Only used for 2D rendering bool ForFont = false; // Mark font translations because they may require different handling than the ones for sprites- diff --git a/source/common/fonts/font.cpp b/source/common/fonts/font.cpp index e4ae656cf4a..8421ab92b6e 100644 --- a/source/common/fonts/font.cpp +++ b/source/common/fonts/font.cpp @@ -83,7 +83,6 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla Next = FirstFont; FirstFont = this; Cursor = '_'; - ActiveColors = 0; SpaceWidth = 0; FontHeight = 0; uint8_t pp = 0; @@ -590,61 +589,6 @@ void FFont::RecordAllTextureColors(uint32_t *usedcolors) } } -//========================================================================== -// -// SetDefaultTranslation -// -// Builds a translation to map the stock font to a mod provided replacement. -// -//========================================================================== - -void FFont::SetDefaultTranslation(uint32_t *othercolors) -{ - uint32_t mycolors[256] = {}; - RecordAllTextureColors(mycolors); - - uint8_t mytranslation[256], othertranslation[256], myreverse[256], otherreverse[256]; - TArray myluminosity, otherluminosity; - - SimpleTranslation(mycolors, mytranslation, myreverse, myluminosity); - SimpleTranslation(othercolors, othertranslation, otherreverse, otherluminosity); - - FRemapTable remap(ActiveColors); - remap.Remap[0] = 0; - remap.Palette[0] = 0; - remap.ForFont = true; - - for (unsigned l = 1; l < myluminosity.Size(); l++) - { - for (unsigned o = 1; o < otherluminosity.Size()-1; o++) // luminosity[0] is for the transparent color - { - if (myluminosity[l] >= otherluminosity[o] && myluminosity[l] <= otherluminosity[o+1]) - { - PalEntry color1 = GPalette.BaseColors[otherreverse[o]]; - PalEntry color2 = GPalette.BaseColors[otherreverse[o+1]]; - double weight = 0; - if (otherluminosity[o] != otherluminosity[o + 1]) - { - weight = (myluminosity[l] - otherluminosity[o]) / (otherluminosity[o + 1] - otherluminosity[o]); - } - int r = int(color1.r + weight * (color2.r - color1.r)); - int g = int(color1.g + weight * (color2.g - color1.g)); - int b = int(color1.b + weight * (color2.b - color1.b)); - - r = clamp(r, 0, 255); - g = clamp(g, 0, 255); - b = clamp(b, 0, 255); - remap.Remap[l] = ColorMatcher.Pick(r, g, b); - remap.Palette[l] = PalEntry(255, r, g, b); - break; - } - } - } - Translations[CR_UNTRANSLATED] = GPalette.StoreTranslation(TRANSLATION_Internal, &remap); - forceremap = true; -} - - //========================================================================== // // compare @@ -668,66 +612,40 @@ static int compare (const void *arg1, const void *arg2) //========================================================================== // -// FFont :: SimpleTranslation -// -// Colorsused, translation, and reverse must all be 256 entry buffers. -// Colorsused must already be filled out. -// Translation be set to remap the source colors to a new range of -// consecutive colors based at 1 (0 is transparent). -// Reverse will be just the opposite of translation: It maps the new color -// range to the original colors. -// *Luminosity will be an array just large enough to hold the brightness -// levels of all the used colors, in consecutive order. It is sorted from -// darkest to lightest and scaled such that the darkest color is 0.0 and -// the brightest color is 1.0. -// The return value is the number of used colors and thus the number of -// entries in *luminosity. +// FFont :: GetLuminosity // //========================================================================== -int FFont::SimpleTranslation (uint32_t *colorsused, uint8_t *translation, uint8_t *reverse, TArray &Luminosity, int* minlum, int* maxlum) +int FFont::GetLuminosity (uint32_t *colorsused, TArray &Luminosity, int* minlum, int* maxlum) { double min, max, diver; - int i, j; - memset (translation, 0, 256); - - reverse[0] = 0; - for (i = 1, j = 1; i < 256; i++) - { - if (colorsused[i]) - { - reverse[j++] = i; - } - } - - qsort (reverse+1, j-1, 1, compare); - - Luminosity.Resize(j); + Luminosity.Resize(256); Luminosity[0] = 0.0; // [BL] Prevent uninitalized memory max = 0.0; min = 100000000.0; - for (i = 1; i < j; i++) + for (int i = 1; i < 256; i++) { - translation[reverse[i]] = i; - - Luminosity[i] = RPART(GPalette.BaseColors[reverse[i]]) * 0.299 + - GPART(GPalette.BaseColors[reverse[i]]) * 0.587 + - BPART(GPalette.BaseColors[reverse[i]]) * 0.114; - if (Luminosity[i] > max) - max = Luminosity[i]; - if (Luminosity[i] < min) - min = Luminosity[i]; + if (colorsused[i]) + { + Luminosity[i] = GPalette.BaseColors[i].r * 0.299 + GPalette.BaseColors[i].g * 0.587 + GPalette.BaseColors[i].b * 0.114; + if (Luminosity[i] > max) max = Luminosity[i]; + if (Luminosity[i] < min) min = Luminosity[i]; + } + else Luminosity[i] = -1; // this color is not of interest. } diver = 1.0 / (max - min); - for (i = 1; i < j; i++) + for (int i = 1; i < 256; i++) { - Luminosity[i] = (Luminosity[i] - min) * diver; + if (colorsused[i]) + { + Luminosity[i] = (Luminosity[i] - min) * diver; + } } if (minlum) *minlum = int(min); if (maxlum) *maxlum = int(max); - return j; + return 256; } //========================================================================== @@ -748,7 +666,7 @@ int FFont::GetColorTranslation (EColorRange range, PalEntry *color) const } if (color != nullptr) *color = retcolor; } - if (ActiveColors == 0 || range == CR_UNDEFINED) + if (range == CR_UNDEFINED) return -1; else if (range >= NumTextColors) range = CR_UNTRANSLATED; @@ -1046,7 +964,6 @@ void FFont::LoadTranslations() { unsigned int count = LastChar - FirstChar + 1; uint32_t usedcolors[256] = {}; - uint8_t identity[256]; TArray Luminosity; for (unsigned int i = 0; i < count; i++) @@ -1059,7 +976,7 @@ void FFont::LoadTranslations() } int minlum = 0, maxlum = 0; - ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity, &minlum, &maxlum); + GetLuminosity (usedcolors, Luminosity, &minlum, &maxlum); // Here we can set everything to a luminosity translation. @@ -1068,7 +985,7 @@ void FFont::LoadTranslations() for (int i = 0; i < NumTextColors; i++) { if (i == CR_UNTRANSLATED) Translations[i] = 0; - else Translations[i] = LuminosityTranslation(i*2, minlum, maxlum); + else Translations[i] = LuminosityTranslation(i*2 + TranslationType, minlum, maxlum); } } diff --git a/source/common/fonts/hexfont.cpp b/source/common/fonts/hexfont.cpp index 9dd7738c4a3..705195dfd0a 100644 --- a/source/common/fonts/hexfont.cpp +++ b/source/common/fonts/hexfont.cpp @@ -395,58 +395,6 @@ class FHexFont2 : public FFont else Translations[i] = LuminosityTranslation(i * 2, minlum, maxlum); } } - - void SetDefaultTranslation(uint32_t *colors) override - { - double myluminosity[18]; - - myluminosity[0] = 0; - for (int i = 1; i < 18; i++) - { - myluminosity[i] = (i - 1) / 16.; - } - - uint8_t othertranslation[256], otherreverse[256]; - TArray otherluminosity; - - SimpleTranslation(colors, othertranslation, otherreverse, otherluminosity); - - FRemapTable remap(ActiveColors); - remap.Remap[0] = 0; - remap.Palette[0] = 0; - remap.ForFont = true; - - for (unsigned l = 1; l < 18; l++) - { - for (unsigned o = 1; o < otherluminosity.Size() - 1; o++) // luminosity[0] is for the transparent color - { - if (myluminosity[l] >= otherluminosity[o] && myluminosity[l] <= otherluminosity[o + 1]) - { - PalEntry color1 = GPalette.BaseColors[otherreverse[o]]; - PalEntry color2 = GPalette.BaseColors[otherreverse[o + 1]]; - double weight = 0; - if (otherluminosity[o] != otherluminosity[o + 1]) - { - weight = (myluminosity[l] - otherluminosity[o]) / (otherluminosity[o + 1] - otherluminosity[o]); - } - int r = int(color1.r + weight * (color2.r - color1.r)); - int g = int(color1.g + weight * (color2.g - color1.g)); - int b = int(color1.b + weight * (color2.b - color1.b)); - - r = clamp(r, 0, 255); - g = clamp(g, 0, 255); - b = clamp(b, 0, 255); - remap.Remap[l] = ColorMatcher.Pick(r, g, b); - remap.Palette[l] = PalEntry(255, r, g, b); - break; - } - } - } - Translations[CR_UNTRANSLATED] = GPalette.StoreTranslation(TRANSLATION_Internal, &remap); - forceremap = true; - - } - }; diff --git a/source/common/fonts/singlelumpfont.cpp b/source/common/fonts/singlelumpfont.cpp index ce5bb19fcb0..dcded6efa9a 100644 --- a/source/common/fonts/singlelumpfont.cpp +++ b/source/common/fonts/singlelumpfont.cpp @@ -105,6 +105,7 @@ class FSingleLumpFont : public FFont } FontType; PalEntry Palette[256]; bool RescalePalette; + int ActiveColors = -1; }; @@ -468,7 +469,7 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data) // FSingleLumpFont :: CheckFON1Chars // // Scans a FON1 resource for all the color values it uses and sets up -// some tables like SimpleTranslation. Data points to the RLE data for +// some tables. Data points to the RLE data for // the characters. Also sets up the character textures. // //========================================================================== diff --git a/source/common/fonts/singlepicfont.cpp b/source/common/fonts/singlepicfont.cpp index 17dfd26911a..c8d5614ae03 100644 --- a/source/common/fonts/singlepicfont.cpp +++ b/source/common/fonts/singlepicfont.cpp @@ -79,7 +79,6 @@ FSinglePicFont::FSinglePicFont(const char *picname) : SpaceWidth = (int)pic->GetDisplayWidth(); GlobalKerning = 0; FirstChar = LastChar = 'A'; - ActiveColors = 0; PicNum = picnum; Next = FirstFont; diff --git a/source/common/fonts/specialfont.cpp b/source/common/fonts/specialfont.cpp index a8c4d71574b..6ceb38b159a 100644 --- a/source/common/fonts/specialfont.cpp +++ b/source/common/fonts/specialfont.cpp @@ -129,11 +129,6 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture } FixXMoves(); - - if (noTranslate) - { - ActiveColors = 0; - } } //========================================================================== diff --git a/source/common/fonts/v_font.cpp b/source/common/fonts/v_font.cpp index f568de7efc4..280fd585632 100644 --- a/source/common/fonts/v_font.cpp +++ b/source/common/fonts/v_font.cpp @@ -687,6 +687,75 @@ void V_ApplyLuminosityTranslation(int translation, uint8_t* pixel, int size) } } +//========================================================================== +// +// SetDefaultTranslation +// +// Builds a translation to map the stock font to a mod provided replacement. +// This probably won't work that well if the original font is extremely colorful. +// +//========================================================================== + +static void CalcDefaultTranslation(FFont* base, int index) +{ + uint32_t othercolors[256] = {}; + base->RecordAllTextureColors(othercolors); + + TArray otherluminosity; + base->GetLuminosity(othercolors, otherluminosity); + + PalEntry *remap = &paletteptr[index * 256]; + memset(remap, 0, 1024); + + for (unsigned i = 0; i < 256; i++) + { + auto lum = otherluminosity[i]; + if (lum >= 0 && lum <= 1) + { + int index = int(lum * 255); + remap[index] = GPalette.BaseColors[i]; + } + } + + // todo: fill the gaps. + remap[0] = 0; + int lowindex = 0; + int highindex = 1; + + while (lowindex < 255) + { + while (highindex <= 255 && remap[highindex].a == 0) highindex++; + if (lowindex == 0) + { + for (int i = 0; i < highindex; i++) remap[i] = remap[highindex]; + lowindex = highindex++; + } + else if (highindex > 256) + { + for (int i = lowindex + 1; i < highindex; i++) remap[i] = remap[lowindex]; + break; + } + else + { + for (int i = lowindex + 1; i < highindex; i++) + { + PalEntry color1 = remap[lowindex]; + PalEntry color2 = remap[highindex]; + double weight = (i - lowindex) / double(highindex - lowindex); + int r = int(color1.r + weight * (color2.r - color1.r)); + int g = int(color1.g + weight * (color2.g - color1.g)); + int b = int(color1.b + weight * (color2.b - color1.b)); + r = clamp(r, 0, 255); + g = clamp(g, 0, 255); + b = clamp(b, 0, 255); + remap[i] = PalEntry(255, r, g, b); + } + lowindex = highindex++; + } + } + +} + //========================================================================== // // V_LogColorFromColorRange @@ -929,24 +998,44 @@ void V_LoadTranslations() for (auto font = FFont::FirstFont; font; font = font->Next) { if (!font->noTranslate) font->LoadTranslations(); - else font->ActiveColors = 0; } + if (BigFont) { - uint32_t colors[256] = {}; - BigFont->RecordAllTextureColors(colors); - if (OriginalBigFont != nullptr) OriginalBigFont->SetDefaultTranslation(colors); + CalcDefaultTranslation(BigFont, CR_UNTRANSLATED * 2 + 1); + if (OriginalBigFont != nullptr && OriginalBigFont != BigFont) + { + int sometrans = OriginalBigFont->Translations[0]; + sometrans &= ~(0x3fff << 16); + sometrans |= (CR_UNTRANSLATED * 2 + 1) << 16; + OriginalBigFont->Translations[CR_UNTRANSLATED] = sometrans; + OriginalBigFont->forceremap = true; + } } if (SmallFont) { - uint32_t colors[256] = {}; - SmallFont->RecordAllTextureColors(colors); - if (OriginalSmallFont != nullptr) OriginalSmallFont->SetDefaultTranslation(colors); - NewSmallFont->SetDefaultTranslation(colors); + CalcDefaultTranslation(SmallFont, CR_UNTRANSLATED * 2); + if (OriginalSmallFont != nullptr && OriginalSmallFont != SmallFont) + { + int sometrans = OriginalSmallFont->Translations[0]; + sometrans &= ~(0x3fff << 16); + sometrans |= (CR_UNTRANSLATED * 2) << 16; + OriginalSmallFont->Translations[CR_UNTRANSLATED] = sometrans; + OriginalSmallFont->forceremap = true; + } + if (NewSmallFont != nullptr) + { + int sometrans = NewSmallFont->Translations[0]; + sometrans &= ~(0x3fff << 16); + sometrans |= (CR_UNTRANSLATED * 2) << 16; + NewSmallFont->Translations[CR_UNTRANSLATED] = sometrans; + NewSmallFont->forceremap = true; + } } translationsLoaded = true; } + void V_ClearFonts() { while (FFont::FirstFont != nullptr) diff --git a/source/common/fonts/v_font.h b/source/common/fonts/v_font.h index f90b3e5933e..0b17b77e143 100644 --- a/source/common/fonts/v_font.h +++ b/source/common/fonts/v_font.h @@ -128,20 +128,17 @@ class FFont void SetKerning(int c) { GlobalKerning = c; } bool NoTranslate() const { return noTranslate; } virtual void RecordAllTextureColors(uint32_t *usedcolors); - virtual void SetDefaultTranslation(uint32_t *colors); void CheckCase(); int GetDisplacement() const { return Displacement; } + static int GetLuminosity(uint32_t* colorsused, TArray& Luminosity, int* minlum = nullptr, int* maxlum = nullptr); protected: FFont (int lump); void FixXMoves(); - static int SimpleTranslation (uint32_t *colorsused, uint8_t *translation, - uint8_t *identity, TArray &Luminosity, int* minlum = nullptr, int* maxlum = nullptr); - void ReadSheetFont(TArray &folderdata, int width, int height, const DVector2 &Scale); EFontType Type = EFontType::Unknown; @@ -163,7 +160,6 @@ class FFont int XMove = INT_MIN; }; TArray Chars; - int ActiveColors = -1; TArray Translations; uint8_t PatchRemap[256]; diff --git a/source/core/statusbar2.cpp b/source/core/statusbar2.cpp index 9f9fb6b577c..8b90186631d 100644 --- a/source/core/statusbar2.cpp +++ b/source/core/statusbar2.cpp @@ -186,15 +186,6 @@ void UpdateStatusBar(SummaryInfo* info) VMValue params[] = { StatusBar, info }; VMCall(func, params, 2, nullptr, 0); } - -#if 1 // for testing. - for (int i = 0; i < NumTextColors; i++) - { - FStringf buffer("This is font color %d", i); - DrawText(twod, BigFont, i, 340, i * 15, buffer, DTA_FullscreenScale, FSMode_Fit640x400, TAG_DONE); - - } -#endif } void TickStatusBar()