mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-02-07 16:31:07 +00:00
- font system overhaul.
This eliminates nearly all palette dependencies, most importantly font translation will now be done on True Color data, making translations on True Color font less destructive.
This commit is contained in:
parent
0236271ef6
commit
5f02b92cd0
15 changed files with 479 additions and 699 deletions
|
@ -173,9 +173,8 @@ void DrawChar(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double
|
||||||
|
|
||||||
FGameTexture* pic;
|
FGameTexture* pic;
|
||||||
int dummy;
|
int dummy;
|
||||||
bool redirected;
|
|
||||||
|
|
||||||
if (NULL != (pic = font->GetChar(character, normalcolor, &dummy, &redirected)))
|
if (NULL != (pic = font->GetChar(character, normalcolor, &dummy)))
|
||||||
{
|
{
|
||||||
DrawParms parms;
|
DrawParms parms;
|
||||||
Va_List tags;
|
Va_List tags;
|
||||||
|
@ -188,7 +187,7 @@ void DrawChar(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double
|
||||||
}
|
}
|
||||||
bool palettetrans = (normalcolor == CR_UNDEFINED && parms.TranslationId != 0);
|
bool palettetrans = (normalcolor == CR_UNDEFINED && parms.TranslationId != 0);
|
||||||
PalEntry color = 0xffffffff;
|
PalEntry color = 0xffffffff;
|
||||||
if (!palettetrans) parms.TranslationId = redirected ? -1 : font->GetColorTranslation((EColorRange)normalcolor, &color);
|
if (!palettetrans) parms.TranslationId = font->GetColorTranslation((EColorRange)normalcolor, &color);
|
||||||
parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255);
|
parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255);
|
||||||
drawer->AddTexture(pic, parms);
|
drawer->AddTexture(pic, parms);
|
||||||
}
|
}
|
||||||
|
@ -204,9 +203,8 @@ void DrawChar(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double
|
||||||
|
|
||||||
FGameTexture *pic;
|
FGameTexture *pic;
|
||||||
int dummy;
|
int dummy;
|
||||||
bool redirected;
|
|
||||||
|
|
||||||
if (NULL != (pic = font->GetChar(character, normalcolor, &dummy, &redirected)))
|
if (NULL != (pic = font->GetChar(character, normalcolor, &dummy)))
|
||||||
{
|
{
|
||||||
DrawParms parms;
|
DrawParms parms;
|
||||||
uint32_t tag = ListGetInt(args);
|
uint32_t tag = ListGetInt(args);
|
||||||
|
@ -214,7 +212,7 @@ void DrawChar(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double
|
||||||
if (!res) return;
|
if (!res) return;
|
||||||
bool palettetrans = (normalcolor == CR_UNDEFINED && parms.TranslationId != 0);
|
bool palettetrans = (normalcolor == CR_UNDEFINED && parms.TranslationId != 0);
|
||||||
PalEntry color = 0xffffffff;
|
PalEntry color = 0xffffffff;
|
||||||
if (!palettetrans) parms.TranslationId = redirected ? -1 : font->GetColorTranslation((EColorRange)normalcolor, &color);
|
if (!palettetrans) parms.TranslationId = font->GetColorTranslation((EColorRange)normalcolor, &color);
|
||||||
parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255);
|
parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255);
|
||||||
drawer->AddTexture(pic, parms);
|
drawer->AddTexture(pic, parms);
|
||||||
}
|
}
|
||||||
|
@ -316,11 +314,10 @@ void DrawTextCommon(F2DDrawer *drawer, FFont *font, int normalcolor, double x, d
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool redirected = false;
|
if (NULL != (pic = font->GetChar(c, currentcolor, &w)))
|
||||||
if (NULL != (pic = font->GetChar(c, currentcolor, &w, &redirected)))
|
|
||||||
{
|
{
|
||||||
// if palette translation is used, font colors will be ignored.
|
// if palette translation is used, font colors will be ignored.
|
||||||
if (!palettetrans) parms.TranslationId = redirected? -1 : trans;
|
if (!palettetrans) parms.TranslationId = trans;
|
||||||
SetTextureParms(drawer, &parms, pic, cx, cy);
|
SetTextureParms(drawer, &parms, pic, cx, cy);
|
||||||
if (parms.cellx)
|
if (parms.cellx)
|
||||||
{
|
{
|
||||||
|
|
|
@ -70,12 +70,26 @@ inline constexpr uint32_t TRANSLATION(uint8_t a, uint32_t b)
|
||||||
{
|
{
|
||||||
return (a << TRANSLATION_SHIFT) | b;
|
return (a << TRANSLATION_SHIFT) | b;
|
||||||
}
|
}
|
||||||
|
inline constexpr uint32_t LuminosityTranslation(int range, uint8_t min, uint8_t max)
|
||||||
|
{
|
||||||
|
// ensure that the value remains positive.
|
||||||
|
return ( (1 << 30) | ((range&0x3fff) << 16) | (min << 8) | max );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool IsLuminosityTranslation(int trans)
|
||||||
|
{
|
||||||
|
return trans > 0 && (trans & (1 << 30));
|
||||||
|
}
|
||||||
|
|
||||||
inline constexpr int GetTranslationType(uint32_t trans)
|
inline constexpr int GetTranslationType(uint32_t trans)
|
||||||
{
|
{
|
||||||
|
assert(!IsLuminosityTranslation(trans));
|
||||||
return (trans & TRANSLATIONTYPE_MASK) >> TRANSLATION_SHIFT;
|
return (trans & TRANSLATIONTYPE_MASK) >> TRANSLATION_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr int GetTranslationIndex(uint32_t trans)
|
inline constexpr int GetTranslationIndex(uint32_t trans)
|
||||||
{
|
{
|
||||||
|
assert(!IsLuminosityTranslation(trans));
|
||||||
return (trans & TRANSLATION_MASK);
|
return (trans & TRANSLATION_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,6 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
|
||||||
Next = FirstFont;
|
Next = FirstFont;
|
||||||
FirstFont = this;
|
FirstFont = this;
|
||||||
Cursor = '_';
|
Cursor = '_';
|
||||||
ActiveColors = 0;
|
|
||||||
SpaceWidth = 0;
|
SpaceWidth = 0;
|
||||||
FontHeight = 0;
|
FontHeight = 0;
|
||||||
uint8_t pp = 0;
|
uint8_t pp = 0;
|
||||||
|
@ -333,23 +332,13 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
|
||||||
TexMan.AddGameTexture(tex);
|
TexMan.AddGameTexture(tex);
|
||||||
Chars[i].OriginalPic = tex;
|
Chars[i].OriginalPic = tex;
|
||||||
|
|
||||||
if (!noTranslate)
|
if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(pic, Chars[i].OriginalPic, Chars[i].OriginalPic);
|
||||||
{
|
|
||||||
Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar1(orig->GetImage())), nullptr, ETextureType::FontChar);
|
|
||||||
Chars[i].TranslatedPic->CopySize(pic, true);
|
|
||||||
TexMan.AddGameTexture(Chars[i].TranslatedPic);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Chars[i].TranslatedPic = tex;
|
|
||||||
}
|
|
||||||
if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(pic, Chars[i].OriginalPic, Chars[i].TranslatedPic);
|
|
||||||
|
|
||||||
Chars[i].XMove = (int)Chars[i].TranslatedPic->GetDisplayWidth();
|
Chars[i].XMove = (int)Chars[i].OriginalPic->GetDisplayWidth();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Chars[i].TranslatedPic = nullptr;
|
Chars[i].OriginalPic = nullptr;
|
||||||
Chars[i].XMove = INT_MIN;
|
Chars[i].XMove = INT_MIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +349,7 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
|
||||||
{
|
{
|
||||||
SpaceWidth = spacewidth;
|
SpaceWidth = spacewidth;
|
||||||
}
|
}
|
||||||
else if ('N' - FirstChar >= 0 && 'N' - FirstChar < count && Chars['N' - FirstChar].TranslatedPic != nullptr)
|
else if ('N' - FirstChar >= 0 && 'N' - FirstChar < count && Chars['N' - FirstChar].OriginalPic != nullptr)
|
||||||
{
|
{
|
||||||
SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2;
|
SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2;
|
||||||
}
|
}
|
||||||
|
@ -444,11 +433,7 @@ void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height
|
||||||
Chars[i].OriginalPic = (*lump)->GetUseType() == ETextureType::FontChar? (*lump) : MakeGameTexture(pic, nullptr, ETextureType::FontChar);
|
Chars[i].OriginalPic = (*lump)->GetUseType() == ETextureType::FontChar? (*lump) : MakeGameTexture(pic, nullptr, ETextureType::FontChar);
|
||||||
Chars[i].OriginalPic->SetUseType(ETextureType::FontChar);
|
Chars[i].OriginalPic->SetUseType(ETextureType::FontChar);
|
||||||
Chars[i].OriginalPic->CopySize(*lump, true);
|
Chars[i].OriginalPic->CopySize(*lump, true);
|
||||||
Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar1(pic->GetImage())), nullptr, ETextureType::FontChar);
|
|
||||||
Chars[i].TranslatedPic->CopySize(*lump, true);
|
|
||||||
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar);
|
|
||||||
if (Chars[i].OriginalPic != *lump) TexMan.AddGameTexture(Chars[i].OriginalPic);
|
if (Chars[i].OriginalPic != *lump) TexMan.AddGameTexture(Chars[i].OriginalPic);
|
||||||
TexMan.AddGameTexture(Chars[i].TranslatedPic);
|
|
||||||
}
|
}
|
||||||
Chars[i].XMove = width;
|
Chars[i].XMove = width;
|
||||||
}
|
}
|
||||||
|
@ -458,7 +443,7 @@ void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height
|
||||||
// Move the Windows-1252 characters to their proper place.
|
// Move the Windows-1252 characters to their proper place.
|
||||||
for (int i = 0x80; i < 0xa0; i++)
|
for (int i = 0x80; i < 0xa0; i++)
|
||||||
{
|
{
|
||||||
if (win1252map[i - 0x80] != i && Chars[i - minchar].TranslatedPic != nullptr && Chars[win1252map[i - 0x80] - minchar].TranslatedPic == nullptr)
|
if (win1252map[i - 0x80] != i && Chars[i - minchar].OriginalPic != nullptr && Chars[win1252map[i - 0x80] - minchar].OriginalPic == nullptr)
|
||||||
{
|
{
|
||||||
std::swap(Chars[i - minchar], Chars[win1252map[i - 0x80] - minchar]);
|
std::swap(Chars[i - minchar], Chars[win1252map[i - 0x80] - minchar]);
|
||||||
}
|
}
|
||||||
|
@ -509,24 +494,24 @@ void FFont::CheckCase()
|
||||||
}
|
}
|
||||||
if (myislower(chr))
|
if (myislower(chr))
|
||||||
{
|
{
|
||||||
if (Chars[i].TranslatedPic != nullptr) lowercount++;
|
if (Chars[i].OriginalPic != nullptr) lowercount++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Chars[i].TranslatedPic != nullptr) uppercount++;
|
if (Chars[i].OriginalPic != nullptr) uppercount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lowercount == 0) return; // This is an uppercase-only font and we are done.
|
if (lowercount == 0) return; // This is an uppercase-only font and we are done.
|
||||||
|
|
||||||
// The ß needs special treatment because it is far more likely to be supplied lowercase only, even in an uppercase font.
|
// The ß needs special treatment because it is far more likely to be supplied lowercase only, even in an uppercase font.
|
||||||
if (Chars[0xdf - FirstChar].TranslatedPic != nullptr)
|
if (Chars[0xdf - FirstChar].OriginalPic != nullptr)
|
||||||
{
|
{
|
||||||
if (LastChar < 0x1e9e)
|
if (LastChar < 0x1e9e)
|
||||||
{
|
{
|
||||||
Chars.Resize(0x1e9f - FirstChar);
|
Chars.Resize(0x1e9f - FirstChar);
|
||||||
LastChar = 0x1e9e;
|
LastChar = 0x1e9e;
|
||||||
}
|
}
|
||||||
if (Chars[0x1e9e - FirstChar].TranslatedPic == nullptr)
|
if (Chars[0x1e9e - FirstChar].OriginalPic == nullptr)
|
||||||
{
|
{
|
||||||
std::swap(Chars[0xdf - FirstChar], Chars[0x1e9e - FirstChar]);
|
std::swap(Chars[0xdf - FirstChar], Chars[0x1e9e - FirstChar]);
|
||||||
lowercount--;
|
lowercount--;
|
||||||
|
@ -596,75 +581,14 @@ void FFont::RecordAllTextureColors(uint32_t *usedcolors)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < Chars.Size(); i++)
|
for (unsigned int i = 0; i < Chars.Size(); i++)
|
||||||
{
|
{
|
||||||
if (Chars[i].TranslatedPic)
|
if (Chars[i].OriginalPic)
|
||||||
{
|
{
|
||||||
FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage());
|
auto pic = Chars[i].OriginalPic->GetTexture()->GetImage();
|
||||||
if (pic)
|
if (pic) RecordTextureColors(pic, usedcolors);
|
||||||
{
|
|
||||||
// The remap must be temporarily reset here because this can be called on an initialized font.
|
|
||||||
auto sr = pic->ResetSourceRemap();
|
|
||||||
RecordTextureColors(pic, usedcolors);
|
|
||||||
pic->SetSourceRemap(sr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// 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<double> 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
|
// compare
|
||||||
|
@ -688,160 +612,40 @@ static int compare (const void *arg1, const void *arg2)
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FFont :: SimpleTranslation
|
// FFont :: GetLuminosity
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int FFont::SimpleTranslation (uint32_t *colorsused, uint8_t *translation, uint8_t *reverse, TArray<double> &Luminosity)
|
int FFont::GetLuminosity (uint32_t *colorsused, TArray<double> &Luminosity, int* minlum, int* maxlum)
|
||||||
{
|
{
|
||||||
double min, max, diver;
|
double min, max, diver;
|
||||||
int i, j;
|
|
||||||
|
|
||||||
memset (translation, 0, 256);
|
Luminosity.Resize(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[0] = 0.0; // [BL] Prevent uninitalized memory
|
Luminosity[0] = 0.0; // [BL] Prevent uninitalized memory
|
||||||
max = 0.0;
|
max = 0.0;
|
||||||
min = 100000000.0;
|
min = 100000000.0;
|
||||||
for (i = 1; i < j; i++)
|
for (int i = 1; i < 256; i++)
|
||||||
{
|
{
|
||||||
translation[reverse[i]] = i;
|
if (colorsused[i])
|
||||||
|
{
|
||||||
Luminosity[i] = RPART(GPalette.BaseColors[reverse[i]]) * 0.299 +
|
Luminosity[i] = GPalette.BaseColors[i].r * 0.299 + GPalette.BaseColors[i].g * 0.587 + GPalette.BaseColors[i].b * 0.114;
|
||||||
GPART(GPalette.BaseColors[reverse[i]]) * 0.587 +
|
if (Luminosity[i] > max) max = Luminosity[i];
|
||||||
BPART(GPalette.BaseColors[reverse[i]]) * 0.114;
|
if (Luminosity[i] < min) min = Luminosity[i];
|
||||||
if (Luminosity[i] > max)
|
}
|
||||||
max = Luminosity[i];
|
else Luminosity[i] = -1; // this color is not of interest.
|
||||||
if (Luminosity[i] < min)
|
|
||||||
min = Luminosity[i];
|
|
||||||
}
|
}
|
||||||
diver = 1.0 / (max - min);
|
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;
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FFont :: BuildTranslations
|
|
||||||
//
|
|
||||||
// Build color translations for this font. Luminosity is an array of
|
|
||||||
// brightness levels. The ActiveColors member must be set to indicate how
|
|
||||||
// large this array is. Identity is an array that remaps the colors to
|
|
||||||
// their original values; it is only used for CR_UNTRANSLATED. Ranges
|
|
||||||
// is an array of TranslationParm structs defining the ranges for every
|
|
||||||
// possible color, in order. Palette is the colors to use for the
|
|
||||||
// untranslated version of the font.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity,
|
|
||||||
const void *ranges, int total_colors, const PalEntry *palette, std::function<void(FRemapTable*)> post)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
const TranslationParm *parmstart = (const TranslationParm *)ranges;
|
|
||||||
|
|
||||||
FRemapTable remap(total_colors);
|
|
||||||
remap.ForFont = true;
|
|
||||||
|
|
||||||
// Create different translations for different color ranges
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Translations.Push(GPalette.StoreTranslation(TRANSLATION_Internal, &remap));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Translations.Push(Translations[0]);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(parmstart->RangeStart >= 0);
|
|
||||||
|
|
||||||
remap.Remap[0] = 0;
|
|
||||||
remap.Palette[0] = 0;
|
|
||||||
remap.ForFont = true;
|
|
||||||
|
|
||||||
for (j = 1; j < ActiveColors; j++)
|
|
||||||
{
|
|
||||||
int v = int(luminosity[j] * 256.0);
|
|
||||||
|
|
||||||
// Find the color range that this luminosity value lies within.
|
|
||||||
const TranslationParm *parms = parmstart - 1;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
parms++;
|
|
||||||
if (parms->RangeStart <= v && parms->RangeEnd >= v)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (parms[1].RangeStart > parms[0].RangeEnd);
|
|
||||||
|
|
||||||
// Linearly interpolate to find out which color this luminosity level gets.
|
|
||||||
int rangev = ((v - parms->RangeStart) << 8) / (parms->RangeEnd - parms->RangeStart);
|
|
||||||
int r = ((parms->Start[0] << 8) + rangev * (parms->End[0] - parms->Start[0])) >> 8; // red
|
|
||||||
int g = ((parms->Start[1] << 8) + rangev * (parms->End[1] - parms->Start[1])) >> 8; // green
|
|
||||||
int b = ((parms->Start[2] << 8) + rangev * (parms->End[2] - parms->Start[2])) >> 8; // blue
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (post) post(&remap);
|
|
||||||
Translations.Push(GPalette.StoreTranslation(TRANSLATION_Internal, &remap));
|
|
||||||
|
|
||||||
// Advance to the next color range.
|
|
||||||
while (parmstart[1].RangeStart > parmstart[0].RangeEnd)
|
|
||||||
{
|
|
||||||
parmstart++;
|
|
||||||
}
|
|
||||||
parmstart++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -862,11 +666,10 @@ int FFont::GetColorTranslation (EColorRange range, PalEntry *color) const
|
||||||
}
|
}
|
||||||
if (color != nullptr) *color = retcolor;
|
if (color != nullptr) *color = retcolor;
|
||||||
}
|
}
|
||||||
if (ActiveColors == 0 || range == CR_UNDEFINED)
|
if (range == CR_UNDEFINED)
|
||||||
return -1;
|
return -1;
|
||||||
else if (range >= NumTextColors)
|
else if (range >= NumTextColors)
|
||||||
range = CR_UNTRANSLATED;
|
range = CR_UNTRANSLATED;
|
||||||
//if (range == CR_UNTRANSLATED && !translateUntranslated) return nullptr;
|
|
||||||
return Translations[range];
|
return Translations[range];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,7 +692,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
||||||
// regular chars turn negative when the 8th bit is set.
|
// regular chars turn negative when the 8th bit is set.
|
||||||
code &= 255;
|
code &= 255;
|
||||||
}
|
}
|
||||||
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr))
|
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].OriginalPic != nullptr))
|
||||||
{
|
{
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -903,7 +706,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
||||||
if (myislower(code))
|
if (myislower(code))
|
||||||
{
|
{
|
||||||
code = upperforlower[code];
|
code = upperforlower[code];
|
||||||
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr))
|
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].OriginalPic != nullptr))
|
||||||
{
|
{
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -912,7 +715,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
||||||
while ((newcode = stripaccent(code)) != code)
|
while ((newcode = stripaccent(code)) != code)
|
||||||
{
|
{
|
||||||
code = newcode;
|
code = newcode;
|
||||||
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr))
|
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].OriginalPic != nullptr))
|
||||||
{
|
{
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -926,7 +729,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
||||||
while ((newcode = stripaccent(code)) != code)
|
while ((newcode = stripaccent(code)) != code)
|
||||||
{
|
{
|
||||||
code = newcode;
|
code = newcode;
|
||||||
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr))
|
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].OriginalPic != nullptr))
|
||||||
{
|
{
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -944,7 +747,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
||||||
while ((newcode = stripaccent(code)) != code)
|
while ((newcode = stripaccent(code)) != code)
|
||||||
{
|
{
|
||||||
code = newcode;
|
code = newcode;
|
||||||
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr))
|
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].OriginalPic != nullptr))
|
||||||
{
|
{
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -961,7 +764,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FGameTexture *FFont::GetChar (int code, int translation, int *const width, bool *redirected) const
|
FGameTexture *FFont::GetChar (int code, int translation, int *const width) const
|
||||||
{
|
{
|
||||||
code = GetCharCode(code, true);
|
code = GetCharCode(code, true);
|
||||||
int xmove = SpaceWidth;
|
int xmove = SpaceWidth;
|
||||||
|
@ -979,19 +782,8 @@ FGameTexture *FFont::GetChar (int code, int translation, int *const width, bool
|
||||||
if (code < 0) return nullptr;
|
if (code < 0) return nullptr;
|
||||||
|
|
||||||
|
|
||||||
if ((translation == CR_UNTRANSLATED || translation == CR_UNDEFINED) && !forceremap)
|
assert(Chars[code].OriginalPic->GetUseType() == ETextureType::FontChar);
|
||||||
{
|
return Chars[code].OriginalPic;
|
||||||
bool redirect = Chars[code].OriginalPic && Chars[code].OriginalPic != Chars[code].TranslatedPic;
|
|
||||||
if (redirected) *redirected = redirect;
|
|
||||||
if (redirect)
|
|
||||||
{
|
|
||||||
assert(Chars[code].OriginalPic->GetUseType() == ETextureType::FontChar);
|
|
||||||
return Chars[code].OriginalPic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (redirected) *redirected = false;
|
|
||||||
assert(Chars[code].TranslatedPic->GetUseType() == ETextureType::FontChar);
|
|
||||||
return Chars[code].TranslatedPic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1172,31 +964,29 @@ void FFont::LoadTranslations()
|
||||||
{
|
{
|
||||||
unsigned int count = LastChar - FirstChar + 1;
|
unsigned int count = LastChar - FirstChar + 1;
|
||||||
uint32_t usedcolors[256] = {};
|
uint32_t usedcolors[256] = {};
|
||||||
uint8_t identity[256];
|
|
||||||
TArray<double> Luminosity;
|
TArray<double> Luminosity;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
for (unsigned int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
if (Chars[i].TranslatedPic)
|
if (Chars[i].OriginalPic)
|
||||||
{
|
{
|
||||||
FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage());
|
auto pic = Chars[i].OriginalPic->GetTexture()->GetImage();
|
||||||
if (pic)
|
if (pic) RecordTextureColors(pic, usedcolors);
|
||||||
{
|
|
||||||
pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture
|
|
||||||
RecordTextureColors(pic, usedcolors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity);
|
int minlum = 0, maxlum = 0;
|
||||||
|
GetLuminosity (usedcolors, Luminosity, &minlum, &maxlum);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
// Here we can set everything to a luminosity translation.
|
||||||
|
|
||||||
|
// Create different translations for different color ranges
|
||||||
|
Translations.Resize(NumTextColors);
|
||||||
|
for (int i = 0; i < NumTextColors; i++)
|
||||||
{
|
{
|
||||||
if(Chars[i].TranslatedPic)
|
if (i == CR_UNTRANSLATED) Translations[i] = 0;
|
||||||
static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
|
else Translations[i] = LuminosityTranslation(i*2 + TranslationType, minlum, maxlum);
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildTranslations (Luminosity.Data(), identity, &TranslationParms[TranslationType][0], ActiveColors, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "tarray.h"
|
#include "tarray.h"
|
||||||
|
|
||||||
// This structure is used by BuildTranslations() to hold color information.
|
|
||||||
struct TranslationParm
|
struct TranslationParm
|
||||||
{
|
{
|
||||||
short RangeStart; // First level for this range
|
short RangeStart; // First level for this range
|
||||||
|
|
|
@ -50,6 +50,8 @@ struct HexDataSource
|
||||||
TArray<uint8_t> glyphdata;
|
TArray<uint8_t> glyphdata;
|
||||||
unsigned glyphmap[65536] = {};
|
unsigned glyphmap[65536] = {};
|
||||||
|
|
||||||
|
PalEntry ConsolePal[18], SmallPal[18];
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// parse a HEX font
|
// parse a HEX font
|
||||||
|
@ -83,6 +85,17 @@ struct HexDataSource
|
||||||
if (codepoint > LastChar) LastChar = codepoint;
|
if (codepoint > LastChar) LastChar = codepoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConsolePal[0] = SmallPal[0] = 0;
|
||||||
|
for (int i = 1; i < 18; i++)
|
||||||
|
{
|
||||||
|
double lum = i == 1 ? 0.01 : 0.5 + (i - 2) * (0.5 / 17.);
|
||||||
|
uint8_t lumb = (uint8_t(lum * 255));
|
||||||
|
|
||||||
|
ConsolePal[i] = PalEntry(255, lumb, lumb, lumb);
|
||||||
|
lumb = i * 255 / 17;
|
||||||
|
SmallPal[i] = PalEntry(255, lumb, lumb, lumb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,6 +108,7 @@ public:
|
||||||
FHexFontChar(uint8_t *sourcedata, int swidth, int width, int height);
|
FHexFontChar(uint8_t *sourcedata, int swidth, int width, int height);
|
||||||
|
|
||||||
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
||||||
|
int CopyPixels(FBitmap* bmp, int conversion);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int SourceWidth;
|
int SourceWidth;
|
||||||
|
@ -159,12 +173,23 @@ TArray<uint8_t> FHexFontChar::CreatePalettedPixels(int)
|
||||||
return Pixels;
|
return Pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int FHexFontChar::CopyPixels(FBitmap* bmp, int conversion)
|
||||||
|
{
|
||||||
|
if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source.
|
||||||
|
PalEntry* palette = hexdata.ConsolePal;
|
||||||
|
auto ppix = CreatePalettedPixels(conversion);
|
||||||
|
bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class FHexFontChar2 : public FHexFontChar
|
class FHexFontChar2 : public FHexFontChar
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height);
|
FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height);
|
||||||
|
|
||||||
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
||||||
|
int CopyPixels(FBitmap* bmp, int conversion);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -228,6 +253,15 @@ TArray<uint8_t> FHexFontChar2::CreatePalettedPixels(int)
|
||||||
return Pixels;
|
return Pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int FHexFontChar2::CopyPixels(FBitmap* bmp, int conversion)
|
||||||
|
{
|
||||||
|
if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source.
|
||||||
|
PalEntry* palette = hexdata.SmallPal;
|
||||||
|
auto ppix = CreatePalettedPixels(conversion);
|
||||||
|
bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FHexFont : public FFont
|
class FHexFont : public FFont
|
||||||
|
@ -267,10 +301,9 @@ public:
|
||||||
{
|
{
|
||||||
auto offset = hexdata.glyphmap[i];
|
auto offset = hexdata.glyphmap[i];
|
||||||
int size = hexdata.glyphdata[offset] / 16;
|
int size = hexdata.glyphdata[offset] / 16;
|
||||||
Chars[i - FirstChar].TranslatedPic = MakeGameTexture(new FImageTexture(new FHexFontChar(&hexdata.glyphdata[offset + 1], size, size * 9, 16)), nullptr, ETextureType::FontChar);
|
Chars[i - FirstChar].OriginalPic = MakeGameTexture(new FImageTexture(new FHexFontChar(&hexdata.glyphdata[offset + 1], size, size * 9, 16)), nullptr, ETextureType::FontChar);
|
||||||
Chars[i - FirstChar].OriginalPic = Chars[i - FirstChar].TranslatedPic;
|
|
||||||
Chars[i - FirstChar].XMove = size * spacing;
|
Chars[i - FirstChar].XMove = size * spacing;
|
||||||
TexMan.AddGameTexture(Chars[i - FirstChar].TranslatedPic);
|
TexMan.AddGameTexture(Chars[i - FirstChar].OriginalPic);
|
||||||
}
|
}
|
||||||
else Chars[i - FirstChar].XMove = spacing;
|
else Chars[i - FirstChar].XMove = spacing;
|
||||||
|
|
||||||
|
@ -285,18 +318,15 @@ public:
|
||||||
|
|
||||||
void LoadTranslations()
|
void LoadTranslations()
|
||||||
{
|
{
|
||||||
double luminosity[256];
|
int minlum = hexdata.ConsolePal[1].r;
|
||||||
|
int maxlum = hexdata.ConsolePal[17].r;
|
||||||
|
|
||||||
memset (PatchRemap, 0, 256);
|
Translations.Resize(NumTextColors);
|
||||||
for (int i = 0; i < 18; i++)
|
for (int i = 0; i < NumTextColors; i++)
|
||||||
{
|
{
|
||||||
// Create a gradient similar to the old console font.
|
if (i == CR_UNTRANSLATED) Translations[i] = 0;
|
||||||
PatchRemap[i] = i;
|
else Translations[i] = LuminosityTranslation(i * 2 + 1, minlum, maxlum);
|
||||||
luminosity[i] = i == 1? 0.01 : 0.5 + (i-2) * (0.5 / 17.);
|
|
||||||
}
|
}
|
||||||
ActiveColors = 18;
|
|
||||||
|
|
||||||
BuildTranslations (luminosity, nullptr, &TranslationParms[1][0], ActiveColors, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -338,10 +368,9 @@ public:
|
||||||
{
|
{
|
||||||
auto offset = hexdata.glyphmap[i];
|
auto offset = hexdata.glyphmap[i];
|
||||||
int size = hexdata.glyphdata[offset] / 16;
|
int size = hexdata.glyphdata[offset] / 16;
|
||||||
Chars[i - FirstChar].TranslatedPic = MakeGameTexture(new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18)), nullptr, ETextureType::FontChar);
|
Chars[i - FirstChar].OriginalPic = MakeGameTexture(new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18)), nullptr, ETextureType::FontChar);
|
||||||
Chars[i - FirstChar].OriginalPic = Chars[i - FirstChar].TranslatedPic;
|
|
||||||
Chars[i - FirstChar].XMove = size * spacing;
|
Chars[i - FirstChar].XMove = size * spacing;
|
||||||
TexMan.AddGameTexture(Chars[i - FirstChar].TranslatedPic);
|
TexMan.AddGameTexture(Chars[i - FirstChar].OriginalPic);
|
||||||
}
|
}
|
||||||
else Chars[i - FirstChar].XMove = spacing;
|
else Chars[i - FirstChar].XMove = spacing;
|
||||||
|
|
||||||
|
@ -356,71 +385,16 @@ public:
|
||||||
|
|
||||||
void LoadTranslations() override
|
void LoadTranslations() override
|
||||||
{
|
{
|
||||||
double luminosity[256];
|
int minlum = hexdata.SmallPal[1].r;
|
||||||
|
int maxlum = hexdata.SmallPal[17].r;
|
||||||
|
|
||||||
memset(PatchRemap, 0, 256);
|
Translations.Resize(NumTextColors);
|
||||||
for (int i = 0; i < 18; i++)
|
for (int i = 0; i < NumTextColors; i++)
|
||||||
{
|
{
|
||||||
// Create a gradient similar to the old console font.
|
if (i == CR_UNTRANSLATED) Translations[i] = 0;
|
||||||
PatchRemap[i] = i;
|
else Translations[i] = LuminosityTranslation(i * 2, minlum, maxlum);
|
||||||
luminosity[i] = i / 17.;
|
|
||||||
}
|
}
|
||||||
ActiveColors = 18;
|
|
||||||
|
|
||||||
BuildTranslations(luminosity, nullptr, &TranslationParms[0][0], ActiveColors, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<double> 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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -90,26 +90,22 @@ public:
|
||||||
void RecordAllTextureColors(uint32_t* usedcolors) override;
|
void RecordAllTextureColors(uint32_t* usedcolors) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CheckFON1Chars (double *luminosity);
|
void CheckFON1Chars ();
|
||||||
void BuildTranslations2 ();
|
void FixupPalette (uint8_t *identity, const PalEntry *palette, int* minlum ,int* maxlum);
|
||||||
void FixupPalette (uint8_t *identity, double *luminosity, const uint8_t *palette,
|
|
||||||
bool rescale, PalEntry *out_palette);
|
|
||||||
void LoadTranslations ();
|
void LoadTranslations ();
|
||||||
void LoadFON1 (int lump, const uint8_t *data);
|
void LoadFON1 (int lump, const uint8_t *data);
|
||||||
void LoadFON2 (int lump, const uint8_t *data);
|
void LoadFON2 (int lump, const uint8_t *data);
|
||||||
void LoadBMF (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);
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FONT1,
|
FONT1,
|
||||||
FONT2,
|
FONT2,
|
||||||
BMFFONT
|
BMFFONT
|
||||||
} FontType;
|
} FontType;
|
||||||
uint8_t PaletteData[768];
|
PalEntry Palette[256];
|
||||||
bool RescalePalette;
|
bool RescalePalette;
|
||||||
|
int ActiveColors = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -160,29 +156,6 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump)
|
||||||
FirstFont = this;
|
FirstFont = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FSingleLumpFont :: CreateFontFromPic
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void FSingleLumpFont::CreateFontFromPic (FTextureID picnum)
|
|
||||||
{
|
|
||||||
auto pic = TexMan.GetGameTexture(picnum);
|
|
||||||
|
|
||||||
FontHeight = (int)pic->GetDisplayHeight ();
|
|
||||||
SpaceWidth = (int)pic->GetDisplayWidth ();
|
|
||||||
GlobalKerning = 0;
|
|
||||||
|
|
||||||
FirstChar = LastChar = 'A';
|
|
||||||
Chars.Resize(1);
|
|
||||||
Chars[0].TranslatedPic = pic;
|
|
||||||
Chars[0].OriginalPic = pic;
|
|
||||||
|
|
||||||
// Only one color range. Don't bother with the others.
|
|
||||||
ActiveColors = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FSingleLumpFont :: LoadTranslations
|
// FSingleLumpFont :: LoadTranslations
|
||||||
|
@ -191,28 +164,21 @@ void FSingleLumpFont::CreateFontFromPic (FTextureID picnum)
|
||||||
|
|
||||||
void FSingleLumpFont::LoadTranslations()
|
void FSingleLumpFont::LoadTranslations()
|
||||||
{
|
{
|
||||||
double luminosity[256];
|
|
||||||
uint8_t identity[256];
|
uint8_t identity[256];
|
||||||
PalEntry local_palette[256];
|
|
||||||
bool useidentity = true;
|
|
||||||
bool usepalette = false;
|
|
||||||
const void* ranges;
|
|
||||||
unsigned int count = LastChar - FirstChar + 1;
|
unsigned int count = LastChar - FirstChar + 1;
|
||||||
|
int minlum, maxlum;
|
||||||
|
|
||||||
switch(FontType)
|
switch(FontType)
|
||||||
{
|
{
|
||||||
case FONT1:
|
case FONT1:
|
||||||
useidentity = false;
|
CheckFON1Chars();
|
||||||
ranges = &TranslationParms[1][0];
|
minlum = 1;
|
||||||
CheckFON1Chars (luminosity);
|
maxlum = 255;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BMFFONT:
|
case BMFFONT:
|
||||||
case FONT2:
|
case FONT2:
|
||||||
usepalette = true;
|
FixupPalette (identity, Palette, &minlum, &maxlum);
|
||||||
FixupPalette (identity, luminosity, PaletteData, RescalePalette, local_palette);
|
|
||||||
|
|
||||||
ranges = &TranslationParms[0][0];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -223,11 +189,16 @@ void FSingleLumpFont::LoadTranslations()
|
||||||
|
|
||||||
for(unsigned int i = 0;i < count;++i)
|
for(unsigned int i = 0;i < count;++i)
|
||||||
{
|
{
|
||||||
if(Chars[i].TranslatedPic)
|
if(Chars[i].OriginalPic)
|
||||||
static_cast<FFontChar2*>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
|
static_cast<FFontChar2*>(Chars[i].OriginalPic->GetTexture()->GetImage())->SetSourceRemap(Palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildTranslations (luminosity, useidentity ? identity : nullptr, ranges, ActiveColors, usepalette ? local_palette : nullptr);
|
Translations.Resize(NumTextColors);
|
||||||
|
for (int i = 0; i < NumTextColors; i++)
|
||||||
|
{
|
||||||
|
if (i == CR_UNTRANSLATED) Translations[i] = 0;
|
||||||
|
else Translations[i] = LuminosityTranslation(i * 2 + (FontType == FONT1 ? 1 : 0), minlum, maxlum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -262,19 +233,20 @@ void FSingleLumpFont::LoadFON1 (int lump, const uint8_t *data)
|
||||||
// Move the Windows-1252 characters to their proper place.
|
// Move the Windows-1252 characters to their proper place.
|
||||||
for (int i = 0x80; i < 0xa0; i++)
|
for (int i = 0x80; i < 0xa0; i++)
|
||||||
{
|
{
|
||||||
if (win1252map[i-0x80] != i && Chars[i].TranslatedPic != nullptr && Chars[win1252map[i - 0x80]].TranslatedPic == nullptr)
|
if (win1252map[i-0x80] != i && Chars[i].OriginalPic != nullptr && Chars[win1252map[i - 0x80]].OriginalPic == nullptr)
|
||||||
{
|
{
|
||||||
std::swap(Chars[i], Chars[win1252map[i - 0x80]]);
|
std::swap(Chars[i], Chars[win1252map[i - 0x80]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Palette[0] = 0;
|
||||||
|
for (int i = 1; i < 256; i++) Palette[i] = PalEntry(255, i, i, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FSingleLumpFont :: LoadFON2
|
// FSingleLumpFont :: LoadFON2
|
||||||
//
|
//
|
||||||
// FON2 is used for everything but the console font. The console font should
|
// FON2 is used for everything but the console font.
|
||||||
// probably use FON2 as well, but oh well.
|
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
@ -340,7 +312,11 @@ void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data)
|
||||||
SpaceWidth = totalwidth * 2 / (3 * count);
|
SpaceWidth = totalwidth * 2 / (3 * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(PaletteData, palette, ActiveColors*3);
|
Palette[0] = 0;
|
||||||
|
for (int i = 1; i < ActiveColors; i++)
|
||||||
|
{
|
||||||
|
Palette[i] = PalEntry(255, palette[i * 3], palette[i * 3 + 1], palette[i * 3 + 2]);
|
||||||
|
}
|
||||||
|
|
||||||
data_p = palette + ActiveColors*3;
|
data_p = palette + ActiveColors*3;
|
||||||
|
|
||||||
|
@ -350,14 +326,12 @@ void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data)
|
||||||
Chars[i].XMove = widths2[i];
|
Chars[i].XMove = widths2[i];
|
||||||
if (destSize <= 0)
|
if (destSize <= 0)
|
||||||
{
|
{
|
||||||
Chars[i].TranslatedPic = nullptr;
|
|
||||||
Chars[i].OriginalPic = nullptr;
|
Chars[i].OriginalPic = nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)), nullptr, ETextureType::FontChar);
|
Chars[i].OriginalPic = MakeGameTexture(new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)), nullptr, ETextureType::FontChar);
|
||||||
Chars[i].OriginalPic = Chars[i].TranslatedPic;
|
TexMan.AddGameTexture(Chars[i].OriginalPic);
|
||||||
TexMan.AddGameTexture(Chars[i].TranslatedPic);
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int8_t code = *data_p++;
|
int8_t code = *data_p++;
|
||||||
|
@ -396,8 +370,6 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
||||||
int numchars, count, totalwidth, nwidth;
|
int numchars, count, totalwidth, nwidth;
|
||||||
int infolen;
|
int infolen;
|
||||||
int i, chari;
|
int i, chari;
|
||||||
uint8_t raw_palette[256*3];
|
|
||||||
PalEntry sort_palette[256];
|
|
||||||
|
|
||||||
FontType = BMFFONT;
|
FontType = BMFFONT;
|
||||||
FontHeight = data[5];
|
FontHeight = data[5];
|
||||||
|
@ -439,31 +411,14 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
||||||
count = LastChar - FirstChar + 1;
|
count = LastChar - FirstChar + 1;
|
||||||
Chars.Resize(count);
|
Chars.Resize(count);
|
||||||
// BMF palettes are only six bits per component. Fix that.
|
// BMF palettes are only six bits per component. Fix that.
|
||||||
for (i = 0; i < ActiveColors*3; ++i)
|
|
||||||
{
|
|
||||||
raw_palette[i+3] = (data[17 + i] << 2) | (data[17 + i] >> 4);
|
|
||||||
}
|
|
||||||
ActiveColors++;
|
|
||||||
|
|
||||||
// Sort the palette by increasing brightness
|
|
||||||
for (i = 0; i < ActiveColors; ++i)
|
for (i = 0; i < ActiveColors; ++i)
|
||||||
{
|
{
|
||||||
PalEntry *pal = &sort_palette[i];
|
int r = (data[17 + i * 3] << 2) | (data[17 + i * 3] >> 4);
|
||||||
pal->a = i; // Use alpha part to point back to original entry
|
int g = (data[18 + i * 3] << 2) | (data[18 + i * 3] >> 4);
|
||||||
pal->r = raw_palette[i*3 + 0];
|
int b = (data[19 + i * 3] << 2) | (data[19 + i * 3] >> 4);
|
||||||
pal->g = raw_palette[i*3 + 1];
|
Palette[i + 1] = PalEntry(255, r, g, b); // entry 0 (transparent) is not stored in the font file.
|
||||||
pal->b = raw_palette[i*3 + 2];
|
|
||||||
}
|
}
|
||||||
qsort(sort_palette + 1, ActiveColors - 1, sizeof(PalEntry), BMFCompare);
|
ActiveColors++;
|
||||||
|
|
||||||
// Create the PatchRemap table from the sorted "alpha" values.
|
|
||||||
PatchRemap[0] = 0;
|
|
||||||
for (i = 1; i < ActiveColors; ++i)
|
|
||||||
{
|
|
||||||
PatchRemap[sort_palette[i].a] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(PaletteData, raw_palette, 768);
|
|
||||||
|
|
||||||
// Now scan through the characters again, creating glyphs for each one.
|
// Now scan through the characters again, creating glyphs for each one.
|
||||||
for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2])
|
for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2])
|
||||||
|
@ -489,7 +444,6 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
||||||
-(int8_t)chardata[chari+3], // x offset
|
-(int8_t)chardata[chari+3], // x offset
|
||||||
-(int8_t)chardata[chari+4] // y offset
|
-(int8_t)chardata[chari+4] // y offset
|
||||||
)), nullptr, ETextureType::FontChar);
|
)), nullptr, ETextureType::FontChar);
|
||||||
Chars[chardata[chari] - FirstChar].TranslatedPic = tex;
|
|
||||||
Chars[chardata[chari] - FirstChar].OriginalPic = tex;
|
Chars[chardata[chari] - FirstChar].OriginalPic = tex;
|
||||||
TexMan.AddGameTexture(tex);
|
TexMan.AddGameTexture(tex);
|
||||||
}
|
}
|
||||||
|
@ -510,55 +464,33 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
||||||
FixXMoves();
|
FixXMoves();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FSingleLumpFont :: BMFCompare STATIC
|
|
||||||
//
|
|
||||||
// Helper to sort BMF palettes.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
int FSingleLumpFont::BMFCompare(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const PalEntry *pa = (const PalEntry *)a;
|
|
||||||
const PalEntry *pb = (const PalEntry *)b;
|
|
||||||
|
|
||||||
return (pa->r * 299 + pa->g * 587 + pa->b * 114) -
|
|
||||||
(pb->r * 299 + pb->g * 587 + pb->b * 114);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FSingleLumpFont :: CheckFON1Chars
|
// FSingleLumpFont :: CheckFON1Chars
|
||||||
//
|
//
|
||||||
// Scans a FON1 resource for all the color values it uses and sets up
|
// 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.
|
// the characters. Also sets up the character textures.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void FSingleLumpFont::CheckFON1Chars (double *luminosity)
|
void FSingleLumpFont::CheckFON1Chars()
|
||||||
{
|
{
|
||||||
FileData memLump = fileSystem.ReadFile(Lump);
|
FileData memLump = fileSystem.ReadFile(Lump);
|
||||||
const uint8_t* data = (const uint8_t*) memLump.GetMem();
|
const uint8_t* data = (const uint8_t*)memLump.GetMem();
|
||||||
|
const uint8_t* data_p;
|
||||||
|
|
||||||
uint8_t used[256], reverse[256];
|
|
||||||
const uint8_t *data_p;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
memset (used, 0, 256);
|
|
||||||
data_p = data + 8;
|
data_p = data + 8;
|
||||||
|
|
||||||
for (i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
int destSize = SpaceWidth * FontHeight;
|
int destSize = SpaceWidth * FontHeight;
|
||||||
|
|
||||||
if(!Chars[i].TranslatedPic)
|
if (!Chars[i].OriginalPic)
|
||||||
{
|
{
|
||||||
Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight)), nullptr, ETextureType::FontChar);
|
Chars[i].OriginalPic = MakeGameTexture(new FImageTexture(new FFontChar2(Lump, int(data_p - data), SpaceWidth, FontHeight)), nullptr, ETextureType::FontChar);
|
||||||
Chars[i].OriginalPic = Chars[i].TranslatedPic;
|
|
||||||
Chars[i].XMove = SpaceWidth;
|
Chars[i].XMove = SpaceWidth;
|
||||||
TexMan.AddGameTexture(Chars[i].TranslatedPic);
|
TexMan.AddGameTexture(Chars[i].OriginalPic);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance to next char's data and count the used colors.
|
// Advance to next char's data and count the used colors.
|
||||||
|
@ -567,87 +499,52 @@ void FSingleLumpFont::CheckFON1Chars (double *luminosity)
|
||||||
int8_t code = *data_p++;
|
int8_t code = *data_p++;
|
||||||
if (code >= 0)
|
if (code >= 0)
|
||||||
{
|
{
|
||||||
destSize -= code+1;
|
destSize -= code + 1;
|
||||||
while (code-- >= 0)
|
while (code-- >= 0)
|
||||||
{
|
{
|
||||||
used[*data_p++] = 1;
|
data_p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (code != -128)
|
else if (code != -128)
|
||||||
{
|
{
|
||||||
used[*data_p++] = 1;
|
data_p++;
|
||||||
destSize -= 1 - code;
|
destSize -= 1 - code;
|
||||||
}
|
}
|
||||||
} while (destSize > 0);
|
} while (destSize > 0);
|
||||||
}
|
}
|
||||||
|
ActiveColors = 256;
|
||||||
memset (PatchRemap, 0, 256);
|
|
||||||
reverse[0] = 0;
|
|
||||||
for (i = 1, j = 1; i < 256; ++i)
|
|
||||||
{
|
|
||||||
if (used[i])
|
|
||||||
{
|
|
||||||
reverse[j++] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 1; i < j; ++i)
|
|
||||||
{
|
|
||||||
PatchRemap[reverse[i]] = i;
|
|
||||||
luminosity[i] = (reverse[i] - 1) / 254.0;
|
|
||||||
}
|
|
||||||
ActiveColors = j;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FSingleLumpFont :: FixupPalette
|
// FSingleLumpFont :: FixupPalette
|
||||||
//
|
//
|
||||||
// Finds the best matches for the colors used by a FON2 font and sets up
|
// Finds the best matches for the colors used by a FON2 font and finds thr
|
||||||
// some tables like SimpleTranslation.
|
// used luminosity range
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void FSingleLumpFont::FixupPalette (uint8_t *identity, double *luminosity, const uint8_t *palette, bool rescale, PalEntry *out_palette)
|
void FSingleLumpFont::FixupPalette (uint8_t *identity, const PalEntry *palette, int *pminlum, int *pmaxlum)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
double maxlum = 0.0;
|
double maxlum = 0.0;
|
||||||
double minlum = 100000000.0;
|
double minlum = 100000000.0;
|
||||||
double diver;
|
|
||||||
|
|
||||||
identity[0] = 0;
|
identity[0] = 0;
|
||||||
palette += 3; // Skip the transparent color
|
palette += 3; // Skip the transparent color
|
||||||
|
|
||||||
for (i = 1; i < ActiveColors; ++i, palette += 3)
|
for (int i = 1; i < ActiveColors; ++i, palette ++)
|
||||||
{
|
{
|
||||||
int r = palette[0];
|
int r = palette->r;
|
||||||
int g = palette[1];
|
int g = palette->g;
|
||||||
int b = palette[2];
|
int b = palette->b;
|
||||||
double lum = r*0.299 + g*0.587 + b*0.114;
|
double lum = r*0.299 + g*0.587 + b*0.114;
|
||||||
identity[i] = ColorMatcher.Pick(r, g, b);
|
identity[i] = ColorMatcher.Pick(r, g, b);
|
||||||
luminosity[i] = lum;
|
if (lum > maxlum) maxlum = lum;
|
||||||
out_palette[i].r = r;
|
if (lum < minlum) minlum = lum;
|
||||||
out_palette[i].g = g;
|
|
||||||
out_palette[i].b = b;
|
|
||||||
out_palette[i].a = 255;
|
|
||||||
if (lum > maxlum)
|
|
||||||
maxlum = lum;
|
|
||||||
if (lum < minlum)
|
|
||||||
minlum = lum;
|
|
||||||
}
|
}
|
||||||
out_palette[0] = 0;
|
|
||||||
|
|
||||||
if (rescale)
|
if (pminlum) *pminlum = int(minlum);
|
||||||
{
|
if (pmaxlum) *pmaxlum = int(maxlum);
|
||||||
diver = 1.0 / (maxlum - minlum);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
diver = 1.0 / 255.0;
|
|
||||||
}
|
|
||||||
for (i = 1; i < ActiveColors; ++i)
|
|
||||||
{
|
|
||||||
luminosity[i] = (luminosity[i] - minlum) * diver;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -661,13 +558,11 @@ void FSingleLumpFont::FixupPalette (uint8_t *identity, double *luminosity, const
|
||||||
|
|
||||||
void FSingleLumpFont::RecordAllTextureColors(uint32_t* usedcolors)
|
void FSingleLumpFont::RecordAllTextureColors(uint32_t* usedcolors)
|
||||||
{
|
{
|
||||||
double luminosity[256];
|
|
||||||
uint8_t identity[256];
|
uint8_t identity[256];
|
||||||
PalEntry local_palette[256];
|
|
||||||
|
|
||||||
if (FontType == BMFFONT || FontType == FONT2)
|
if (FontType == BMFFONT || FontType == FONT2)
|
||||||
{
|
{
|
||||||
FixupPalette(identity, luminosity, PaletteData, RescalePalette, local_palette);
|
FixupPalette(identity, Palette, nullptr, nullptr);
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
{
|
{
|
||||||
if (identity[i] != 0) usedcolors[identity[i]]++;
|
if (identity[i] != 0) usedcolors[identity[i]]++;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
FSinglePicFont(const char *picname);
|
FSinglePicFont(const char *picname);
|
||||||
|
|
||||||
// FFont interface
|
// FFont interface
|
||||||
FGameTexture *GetChar(int code, int translation, int *const width, bool *redirected = nullptr) const override;
|
FGameTexture *GetChar(int code, int translation, int *const width) const override;
|
||||||
int GetCharWidth (int code) const override;
|
int GetCharWidth (int code) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -79,7 +79,6 @@ FSinglePicFont::FSinglePicFont(const char *picname) :
|
||||||
SpaceWidth = (int)pic->GetDisplayWidth();
|
SpaceWidth = (int)pic->GetDisplayWidth();
|
||||||
GlobalKerning = 0;
|
GlobalKerning = 0;
|
||||||
FirstChar = LastChar = 'A';
|
FirstChar = LastChar = 'A';
|
||||||
ActiveColors = 0;
|
|
||||||
PicNum = picnum;
|
PicNum = picnum;
|
||||||
|
|
||||||
Next = FirstFont;
|
Next = FirstFont;
|
||||||
|
@ -94,10 +93,9 @@ FSinglePicFont::FSinglePicFont(const char *picname) :
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FGameTexture *FSinglePicFont::GetChar (int code, int translation, int *const width, bool *redirected) const
|
FGameTexture *FSinglePicFont::GetChar (int code, int translation, int *const width) const
|
||||||
{
|
{
|
||||||
*width = SpaceWidth;
|
*width = SpaceWidth;
|
||||||
if (redirected) *redirected = false;
|
|
||||||
if (code == 'a' || code == 'A')
|
if (code == 'a' || code == 'A')
|
||||||
{
|
{
|
||||||
return TexMan.GetGameTexture(PicNum, true);
|
return TexMan.GetGameTexture(PicNum, true);
|
||||||
|
|
|
@ -108,26 +108,18 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture
|
||||||
Chars[i].OriginalPic = MakeGameTexture(pic->GetTexture(), nullptr, ETextureType::FontChar);
|
Chars[i].OriginalPic = MakeGameTexture(pic->GetTexture(), nullptr, ETextureType::FontChar);
|
||||||
Chars[i].OriginalPic->CopySize(pic, true);
|
Chars[i].OriginalPic->CopySize(pic, true);
|
||||||
TexMan.AddGameTexture(Chars[i].OriginalPic);
|
TexMan.AddGameTexture(Chars[i].OriginalPic);
|
||||||
|
Chars[i].XMove = (int)Chars[i].OriginalPic->GetDisplayWidth();
|
||||||
if (!noTranslate)
|
if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(pic, Chars[i].OriginalPic, Chars[i].OriginalPic);
|
||||||
{
|
|
||||||
Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar1 (charlumps[i]->GetTexture()->GetImage())), nullptr, ETextureType::FontChar);
|
|
||||||
Chars[i].TranslatedPic->CopySize(charlumps[i], true);
|
|
||||||
TexMan.AddGameTexture(Chars[i].TranslatedPic);
|
|
||||||
}
|
|
||||||
else Chars[i].TranslatedPic = Chars[i].OriginalPic;
|
|
||||||
Chars[i].XMove = (int)Chars[i].TranslatedPic->GetDisplayWidth();
|
|
||||||
if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(pic, Chars[i].OriginalPic, Chars[i].TranslatedPic);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Chars[i].TranslatedPic = nullptr;
|
Chars[i].OriginalPic = nullptr;
|
||||||
Chars[i].XMove = INT_MIN;
|
Chars[i].XMove = INT_MIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special fonts normally don't have all characters so be careful here!
|
// Special fonts normally don't have all characters so be careful here!
|
||||||
if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].TranslatedPic != nullptr)
|
if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].OriginalPic != nullptr)
|
||||||
{
|
{
|
||||||
SpaceWidth = (Chars['N' - first].XMove + 1) / 2;
|
SpaceWidth = (Chars['N' - first].XMove + 1) / 2;
|
||||||
}
|
}
|
||||||
|
@ -137,11 +129,6 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture
|
||||||
}
|
}
|
||||||
|
|
||||||
FixXMoves();
|
FixXMoves();
|
||||||
|
|
||||||
if (noTranslate)
|
|
||||||
{
|
|
||||||
ActiveColors = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -152,65 +139,56 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture
|
||||||
|
|
||||||
void FSpecialFont::LoadTranslations()
|
void FSpecialFont::LoadTranslations()
|
||||||
{
|
{
|
||||||
int count = LastChar - FirstChar + 1;
|
FFont::LoadTranslations();
|
||||||
uint32_t usedcolors[256] = {};
|
|
||||||
uint8_t identity[256];
|
|
||||||
TArray<double> Luminosity;
|
|
||||||
int TotalColors;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (Chars[i].TranslatedPic)
|
|
||||||
{
|
|
||||||
FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage());
|
|
||||||
if (pic)
|
|
||||||
{
|
|
||||||
pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture
|
|
||||||
RecordTextureColors(pic, usedcolors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool needsnotrans = false;
|
||||||
// exclude the non-translated colors from the translation calculation
|
// exclude the non-translated colors from the translation calculation
|
||||||
for (i = 0; i < 256; i++)
|
for (int 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])
|
if (notranslate[i])
|
||||||
{
|
{
|
||||||
PatchRemap[i] = TotalColors;
|
needsnotrans = true;
|
||||||
identity[TotalColors] = i;
|
break;
|
||||||
TotalColors++;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
// If we have no non-translateable colors, we can use the base data as-is.
|
||||||
|
if (!needsnotrans)
|
||||||
{
|
{
|
||||||
if(Chars[i].TranslatedPic)
|
return;
|
||||||
static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildTranslations(Luminosity.Data(), identity, &TranslationParms[0][0], TotalColors, nullptr, [=](FRemapTable* remap)
|
// we only need to add special handling if there's colors that should not be translated.
|
||||||
{
|
// Obviously 'notranslate' should only be used on data that uses the base palette, otherwise results are undefined!
|
||||||
// add the untranslated colors to the Ranges tables
|
for (auto &trans : Translations)
|
||||||
if (ActiveColors < TotalColors)
|
{
|
||||||
{
|
if (!IsLuminosityTranslation(trans)) continue; // this should only happen for CR_UNTRANSLATED.
|
||||||
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;
|
FRemapTable remap(256);
|
||||||
|
remap.ForFont = true;
|
||||||
|
|
||||||
|
uint8_t workpal[1024];
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
workpal[i * 4 + 0] = GPalette.BaseColors[i].b;
|
||||||
|
workpal[i * 4 + 1] = GPalette.BaseColors[i].g;
|
||||||
|
workpal[i * 4 + 2] = GPalette.BaseColors[i].r;
|
||||||
|
workpal[i * 4 + 3] = GPalette.BaseColors[i].a;
|
||||||
|
}
|
||||||
|
V_ApplyLuminosityTranslation(trans, workpal, 256);
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
if (!notranslate[i])
|
||||||
|
{
|
||||||
|
remap.Palette[i] = PalEntry(workpal[i * 4 + 3], workpal[i * 4 + 2], workpal[i * 4 + 1], workpal[i * 4 + 0]);
|
||||||
|
remap.Remap[i] = ColorMatcher.Pick(remap.Palette[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remap.Palette[i] = GPalette.BaseColors[i];
|
||||||
|
remap.Remap[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trans = GPalette.StoreTranslation(TRANSLATION_Internal, &remap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FFont *CreateSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate)
|
FFont *CreateSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate)
|
||||||
|
|
|
@ -586,6 +586,176 @@ EColorRange V_FindFontColor (FName name)
|
||||||
return CR_UNTRANSLATED;
|
return CR_UNTRANSLATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// CreateLuminosityTranslationRanges
|
||||||
|
//
|
||||||
|
// Create universal remap ranges for hardware rendering.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
static PalEntry* paletteptr;
|
||||||
|
|
||||||
|
static void CreateLuminosityTranslationRanges()
|
||||||
|
{
|
||||||
|
paletteptr = (PalEntry*)ImageArena.Alloc(256 * ((NumTextColors * 2)) * sizeof(PalEntry));
|
||||||
|
for (int l = 0; l < 2; l++)
|
||||||
|
{
|
||||||
|
auto parmstart = &TranslationParms[l][0];
|
||||||
|
// Put the data into the image arena where it gets deleted with the rest of the texture data.
|
||||||
|
for (int p = 0; p < NumTextColors; p++)
|
||||||
|
{
|
||||||
|
// Intended storage order is Range 1, variant 1 - Range 1, variant 2, Range 2, variant 1, and so on.
|
||||||
|
// The storage of the ranges forces us to go through this differently...
|
||||||
|
PalEntry* palette = paletteptr + p * 512 + l * 256;
|
||||||
|
for (int v = 0; v < 256; v++)
|
||||||
|
{
|
||||||
|
palette[v].b = palette[v].g = palette[v].r = (uint8_t)v;
|
||||||
|
}
|
||||||
|
if (p != CR_UNTRANSLATED) // This table skips the untranslated entry. Do I need to say that the stored data format is garbage? >)
|
||||||
|
{
|
||||||
|
for (int v = 0; v < 256; v++)
|
||||||
|
{
|
||||||
|
// Find the color range that this luminosity value lies within.
|
||||||
|
const TranslationParm* parms = parmstart - 1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
parms++;
|
||||||
|
if (parms->RangeStart <= v && parms->RangeEnd >= v)
|
||||||
|
break;
|
||||||
|
} while (parms[1].RangeStart > parms[0].RangeEnd);
|
||||||
|
|
||||||
|
// Linearly interpolate to find out which color this luminosity level gets.
|
||||||
|
int rangev = ((v - parms->RangeStart) << 8) / (parms->RangeEnd - parms->RangeStart);
|
||||||
|
int r = ((parms->Start[0] << 8) + rangev * (parms->End[0] - parms->Start[0])) >> 8; // red
|
||||||
|
int g = ((parms->Start[1] << 8) + rangev * (parms->End[1] - parms->Start[1])) >> 8; // green
|
||||||
|
int b = ((parms->Start[2] << 8) + rangev * (parms->End[2] - parms->Start[2])) >> 8; // blue
|
||||||
|
palette[v].r = (uint8_t)clamp(r, 0, 255);
|
||||||
|
palette[v].g = (uint8_t)clamp(g, 0, 255);
|
||||||
|
palette[v].b = (uint8_t)clamp(b, 0, 255);
|
||||||
|
}
|
||||||
|
// Advance to the next color range.
|
||||||
|
while (parmstart[1].RangeStart > parmstart[0].RangeEnd)
|
||||||
|
{
|
||||||
|
parmstart++;
|
||||||
|
}
|
||||||
|
parmstart++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// V_ApplyLuminosityTranslation
|
||||||
|
//
|
||||||
|
// Applies the translation to a bitmap for texture generation.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void V_ApplyLuminosityTranslation(int translation, uint8_t* pixel, int size)
|
||||||
|
{
|
||||||
|
int colorrange = (translation >> 16) & 0x3fff;
|
||||||
|
if (colorrange >= NumTextColors * 2) return;
|
||||||
|
int lum_min = (translation >> 8) & 0xff;
|
||||||
|
int lum_max = translation & 0xff;
|
||||||
|
int lum_range = (lum_max - lum_min + 1);
|
||||||
|
PalEntry* remap = paletteptr + colorrange * 256;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++, pixel += 4)
|
||||||
|
{
|
||||||
|
// we must also process the transparent pixels here to ensure proper filtering on the characters' edges.
|
||||||
|
int gray = PalEntry(255, pixel[2], pixel[1], pixel[0]).Luminance();
|
||||||
|
int lumadjust = (gray - lum_min) * 255 / lum_range;
|
||||||
|
int index = clamp(lumadjust, 0, 255);
|
||||||
|
PalEntry newcol = remap[index];
|
||||||
|
// extend the range if we find colors outside what initial analysis provided.
|
||||||
|
if (gray < lum_min)
|
||||||
|
{
|
||||||
|
newcol.r = newcol.r * gray / lum_min;
|
||||||
|
newcol.g = newcol.g * gray / lum_min;
|
||||||
|
newcol.b = newcol.b * gray / lum_min;
|
||||||
|
}
|
||||||
|
else if (gray > lum_max)
|
||||||
|
{
|
||||||
|
newcol.r = clamp(newcol.r * gray / lum_max, 0, 255);
|
||||||
|
newcol.g = clamp(newcol.g * gray / lum_max, 0, 255);
|
||||||
|
newcol.b = clamp(newcol.b * gray / lum_max, 0, 255);
|
||||||
|
}
|
||||||
|
pixel[0] = newcol.b;
|
||||||
|
pixel[1] = newcol.g;
|
||||||
|
pixel[2] = newcol.r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// 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<double> 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
|
// V_LogColorFromColorRange
|
||||||
|
@ -676,6 +846,7 @@ EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int
|
||||||
|
|
||||||
void V_InitFonts()
|
void V_InitFonts()
|
||||||
{
|
{
|
||||||
|
CreateLuminosityTranslationRanges();
|
||||||
V_InitCustomFonts();
|
V_InitCustomFonts();
|
||||||
|
|
||||||
FFont *CreateHexLumpFont(const char *fontname, int lump);
|
FFont *CreateHexLumpFont(const char *fontname, int lump);
|
||||||
|
@ -827,24 +998,44 @@ void V_LoadTranslations()
|
||||||
for (auto font = FFont::FirstFont; font; font = font->Next)
|
for (auto font = FFont::FirstFont; font; font = font->Next)
|
||||||
{
|
{
|
||||||
if (!font->noTranslate) font->LoadTranslations();
|
if (!font->noTranslate) font->LoadTranslations();
|
||||||
else font->ActiveColors = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BigFont)
|
if (BigFont)
|
||||||
{
|
{
|
||||||
uint32_t colors[256] = {};
|
CalcDefaultTranslation(BigFont, CR_UNTRANSLATED * 2 + 1);
|
||||||
BigFont->RecordAllTextureColors(colors);
|
if (OriginalBigFont != nullptr && OriginalBigFont != BigFont)
|
||||||
if (OriginalBigFont != nullptr) OriginalBigFont->SetDefaultTranslation(colors);
|
{
|
||||||
|
int sometrans = OriginalBigFont->Translations[0];
|
||||||
|
sometrans &= ~(0x3fff << 16);
|
||||||
|
sometrans |= (CR_UNTRANSLATED * 2 + 1) << 16;
|
||||||
|
OriginalBigFont->Translations[CR_UNTRANSLATED] = sometrans;
|
||||||
|
OriginalBigFont->forceremap = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (SmallFont)
|
if (SmallFont)
|
||||||
{
|
{
|
||||||
uint32_t colors[256] = {};
|
CalcDefaultTranslation(SmallFont, CR_UNTRANSLATED * 2);
|
||||||
SmallFont->RecordAllTextureColors(colors);
|
if (OriginalSmallFont != nullptr && OriginalSmallFont != SmallFont)
|
||||||
if (OriginalSmallFont != nullptr) OriginalSmallFont->SetDefaultTranslation(colors);
|
{
|
||||||
NewSmallFont->SetDefaultTranslation(colors);
|
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;
|
translationsLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void V_ClearFonts()
|
void V_ClearFonts()
|
||||||
{
|
{
|
||||||
while (FFont::FirstFont != nullptr)
|
while (FFont::FirstFont != nullptr)
|
||||||
|
|
|
@ -97,7 +97,7 @@ public:
|
||||||
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, GlyphSet *baseGlpyphs = nullptr);
|
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, GlyphSet *baseGlpyphs = nullptr);
|
||||||
virtual ~FFont ();
|
virtual ~FFont ();
|
||||||
|
|
||||||
virtual FGameTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const;
|
virtual FGameTexture *GetChar (int code, int translation, int *const width) const;
|
||||||
virtual int GetCharWidth (int code) const;
|
virtual int GetCharWidth (int code) const;
|
||||||
int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const;
|
int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const;
|
||||||
int GetLump() const { return Lump; }
|
int GetLump() const { return Lump; }
|
||||||
|
@ -128,22 +128,17 @@ public:
|
||||||
void SetKerning(int c) { GlobalKerning = c; }
|
void SetKerning(int c) { GlobalKerning = c; }
|
||||||
bool NoTranslate() const { return noTranslate; }
|
bool NoTranslate() const { return noTranslate; }
|
||||||
virtual void RecordAllTextureColors(uint32_t *usedcolors);
|
virtual void RecordAllTextureColors(uint32_t *usedcolors);
|
||||||
virtual void SetDefaultTranslation(uint32_t *colors);
|
|
||||||
void CheckCase();
|
void CheckCase();
|
||||||
|
|
||||||
int GetDisplacement() const { return Displacement; }
|
int GetDisplacement() const { return Displacement; }
|
||||||
|
|
||||||
|
static int GetLuminosity(uint32_t* colorsused, TArray<double>& Luminosity, int* minlum = nullptr, int* maxlum = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FFont (int lump);
|
FFont (int lump);
|
||||||
|
|
||||||
void BuildTranslations (const double *luminosity, const uint8_t *identity,
|
|
||||||
const void *ranges, int total_colors, const PalEntry *palette, std::function<void(FRemapTable*)> post = nullptr);
|
|
||||||
void FixXMoves();
|
void FixXMoves();
|
||||||
|
|
||||||
static int SimpleTranslation (uint32_t *colorsused, uint8_t *translation,
|
|
||||||
uint8_t *identity, TArray<double> &Luminosity);
|
|
||||||
|
|
||||||
void ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height, const DVector2 &Scale);
|
void ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height, const DVector2 &Scale);
|
||||||
|
|
||||||
EFontType Type = EFontType::Unknown;
|
EFontType Type = EFontType::Unknown;
|
||||||
|
@ -161,12 +156,10 @@ protected:
|
||||||
bool forceremap = false;
|
bool forceremap = false;
|
||||||
struct CharData
|
struct CharData
|
||||||
{
|
{
|
||||||
FGameTexture *TranslatedPic = nullptr; // Texture for use with font translations.
|
FGameTexture *OriginalPic = nullptr;
|
||||||
FGameTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization.
|
|
||||||
int XMove = INT_MIN;
|
int XMove = INT_MIN;
|
||||||
};
|
};
|
||||||
TArray<CharData> Chars;
|
TArray<CharData> Chars;
|
||||||
int ActiveColors = -1;
|
|
||||||
TArray<int> Translations;
|
TArray<int> Translations;
|
||||||
uint8_t PatchRemap[256];
|
uint8_t PatchRemap[256];
|
||||||
|
|
||||||
|
@ -192,6 +185,8 @@ EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int
|
||||||
FFont *V_GetFont(const char *fontname, const char *fontlumpname = nullptr);
|
FFont *V_GetFont(const char *fontname, const char *fontlumpname = nullptr);
|
||||||
void V_InitFontColors();
|
void V_InitFontColors();
|
||||||
char* CleanseString(char* str);
|
char* CleanseString(char* str);
|
||||||
|
void V_ApplyLuminosityTranslation(int translation, uint8_t* pixel, int size);
|
||||||
void V_LoadTranslations();
|
void V_LoadTranslations();
|
||||||
|
class FBitmap;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -198,6 +198,11 @@ public:
|
||||||
return Pitch;
|
return Pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GetBufferSize() const
|
||||||
|
{
|
||||||
|
return Pitch * Height;
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t *GetPixels() const
|
const uint8_t *GetPixels() const
|
||||||
{
|
{
|
||||||
return data;
|
return data;
|
||||||
|
|
|
@ -41,48 +41,6 @@
|
||||||
#include "fontchars.h"
|
#include "fontchars.h"
|
||||||
#include "engineerrors.h"
|
#include "engineerrors.h"
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FFontChar1 :: FFontChar1
|
|
||||||
//
|
|
||||||
// Used by fonts made from textures.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
FFontChar1::FFontChar1 (FImageSource *sourcelump)
|
|
||||||
: BaseTexture(sourcelump), SourceRemap (nullptr)
|
|
||||||
{
|
|
||||||
// now copy all the properties from the base texture
|
|
||||||
assert(BaseTexture != nullptr);
|
|
||||||
CopySize(*BaseTexture);
|
|
||||||
bUseGamePalette = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FFontChar1 :: GetPixels
|
|
||||||
//
|
|
||||||
// Render style is not relevant for fonts. This must not use it!
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
TArray<uint8_t> FFontChar1::CreatePalettedPixels (int)
|
|
||||||
{
|
|
||||||
// Make the texture as normal, then remap it so that all the colors
|
|
||||||
// are at the low end of the palette
|
|
||||||
// Why? It only creates unnecessary work!
|
|
||||||
auto Pixels = BaseTexture->GetPalettedPixels(normal);
|
|
||||||
|
|
||||||
if (SourceRemap)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < Width*Height; ++x)
|
|
||||||
{
|
|
||||||
Pixels[x] = SourceRemap[Pixels[x]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Pixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FFontChar2 :: FFontChar2
|
// FFontChar2 :: FFontChar2
|
||||||
|
@ -91,8 +49,8 @@ TArray<uint8_t> FFontChar1::CreatePalettedPixels (int)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs)
|
FFontChar2::FFontChar2(int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs)
|
||||||
: SourceLump (sourcelump), SourcePos (sourcepos), SourceRemap(nullptr)
|
: SourceLump(sourcelump), SourcePos(sourcepos)
|
||||||
{
|
{
|
||||||
Width = width;
|
Width = width;
|
||||||
Height = height;
|
Height = height;
|
||||||
|
@ -100,17 +58,6 @@ FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, in
|
||||||
TopOffset = topofs;
|
TopOffset = topofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FFontChar2 :: SetSourceRemap
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void FFontChar2::SetSourceRemap(const uint8_t *sourceremap)
|
|
||||||
{
|
|
||||||
SourceRemap = sourceremap;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FFontChar2 :: Get8BitPixels
|
// FFontChar2 :: Get8BitPixels
|
||||||
|
@ -121,7 +68,7 @@ void FFontChar2::SetSourceRemap(const uint8_t *sourceremap)
|
||||||
|
|
||||||
TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
||||||
{
|
{
|
||||||
auto lump = fileSystem.OpenFileReader (SourceLump);
|
auto lump = fileSystem.OpenFileReader(SourceLump);
|
||||||
int destSize = Width * Height;
|
int destSize = Width * Height;
|
||||||
uint8_t max = 255;
|
uint8_t max = 255;
|
||||||
bool rle = true;
|
bool rle = true;
|
||||||
|
@ -129,23 +76,23 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
||||||
// This is to "fix" bad fonts
|
// This is to "fix" bad fonts
|
||||||
{
|
{
|
||||||
uint8_t buff[16];
|
uint8_t buff[16];
|
||||||
lump.Read (buff, 4);
|
lump.Read(buff, 4);
|
||||||
if (buff[3] == '2')
|
if (buff[3] == '2')
|
||||||
{
|
{
|
||||||
lump.Read (buff, 7);
|
lump.Read(buff, 7);
|
||||||
max = buff[6];
|
max = buff[6];
|
||||||
lump.Seek (SourcePos - 11, FileReader::SeekCur);
|
lump.Seek(SourcePos - 11, FileReader::SeekCur);
|
||||||
}
|
}
|
||||||
else if (buff[3] == 0x1A)
|
else if (buff[3] == 0x1A)
|
||||||
{
|
{
|
||||||
lump.Read(buff, 13);
|
lump.Read(buff, 13);
|
||||||
max = buff[12] - 1;
|
max = buff[12] - 1;
|
||||||
lump.Seek (SourcePos - 17, FileReader::SeekCur);
|
lump.Seek(SourcePos - 17, FileReader::SeekCur);
|
||||||
rle = false;
|
rle = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lump.Seek (SourcePos - 4, FileReader::SeekCur);
|
lump.Seek(SourcePos - 4, FileReader::SeekCur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +100,7 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
||||||
|
|
||||||
int runlen = 0, setlen = 0;
|
int runlen = 0, setlen = 0;
|
||||||
uint8_t setval = 0; // Shut up, GCC!
|
uint8_t setval = 0; // Shut up, GCC!
|
||||||
uint8_t *dest_p = Pixels.Data();
|
uint8_t* dest_p = Pixels.Data();
|
||||||
int dest_adv = Height;
|
int dest_adv = Height;
|
||||||
int dest_rew = destSize - 1;
|
int dest_rew = destSize - 1;
|
||||||
|
|
||||||
|
@ -166,11 +113,7 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
||||||
if (runlen != 0)
|
if (runlen != 0)
|
||||||
{
|
{
|
||||||
uint8_t color = lump.ReadUInt8();
|
uint8_t color = lump.ReadUInt8();
|
||||||
color = MIN (color, max);
|
color = MIN(color, max);
|
||||||
if (SourceRemap != nullptr)
|
|
||||||
{
|
|
||||||
color = SourceRemap[color];
|
|
||||||
}
|
|
||||||
*dest_p = color;
|
*dest_p = color;
|
||||||
dest_p += dest_adv;
|
dest_p += dest_adv;
|
||||||
x--;
|
x--;
|
||||||
|
@ -194,11 +137,7 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
||||||
{
|
{
|
||||||
uint8_t color = lump.ReadUInt8();
|
uint8_t color = lump.ReadUInt8();
|
||||||
setlen = (-code) + 1;
|
setlen = (-code) + 1;
|
||||||
setval = MIN (color, max);
|
setval = MIN(color, max);
|
||||||
if (SourceRemap != nullptr)
|
|
||||||
{
|
|
||||||
setval = SourceRemap[setval];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,10 +155,6 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
||||||
{
|
{
|
||||||
color = max;
|
color = max;
|
||||||
}
|
}
|
||||||
if (SourceRemap != nullptr)
|
|
||||||
{
|
|
||||||
color = SourceRemap[color];
|
|
||||||
}
|
|
||||||
*dest_p = color;
|
*dest_p = color;
|
||||||
dest_p += dest_adv;
|
dest_p += dest_adv;
|
||||||
}
|
}
|
||||||
|
@ -230,10 +165,17 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
||||||
if (destSize < 0)
|
if (destSize < 0)
|
||||||
{
|
{
|
||||||
char name[9];
|
char name[9];
|
||||||
fileSystem.GetFileShortName (name, SourceLump);
|
fileSystem.GetFileShortName(name, SourceLump);
|
||||||
name[8] = 0;
|
name[8] = 0;
|
||||||
I_FatalError ("The font %s is corrupt", name);
|
I_FatalError("The font %s is corrupt", name);
|
||||||
}
|
}
|
||||||
return Pixels;
|
return Pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int FFontChar2::CopyPixels(FBitmap* bmp, int conversion)
|
||||||
|
{
|
||||||
|
if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source.
|
||||||
|
auto ppix = CreatePalettedPixels(conversion);
|
||||||
|
bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, SourceRemap, nullptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,5 @@
|
||||||
|
|
||||||
|
|
||||||
// This is a font character that loads a texture and recolors it.
|
|
||||||
class FFontChar1 : public FImageSource
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FFontChar1 (FImageSource *sourcelump);
|
|
||||||
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
|
||||||
void SetSourceRemap(const uint8_t *sourceremap) { SourceRemap = sourceremap; }
|
|
||||||
const uint8_t *ResetSourceRemap() { auto p = SourceRemap; SourceRemap = nullptr; return p; }
|
|
||||||
FImageSource *GetBase() const { return BaseTexture; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
FImageSource *BaseTexture;
|
|
||||||
const uint8_t *SourceRemap;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is a font character that reads RLE compressed data.
|
// This is a font character that reads RLE compressed data.
|
||||||
class FFontChar2 : public FImageSource
|
class FFontChar2 : public FImageSource
|
||||||
{
|
{
|
||||||
|
@ -23,10 +7,15 @@ public:
|
||||||
FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0);
|
FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0);
|
||||||
|
|
||||||
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
||||||
void SetSourceRemap(const uint8_t *sourceremap);
|
int CopyPixels(FBitmap* bmp, int conversion);
|
||||||
|
|
||||||
|
void SetSourceRemap(const PalEntry* sourceremap)
|
||||||
|
{
|
||||||
|
SourceRemap = sourceremap;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int SourceLump;
|
int SourceLump;
|
||||||
int SourcePos;
|
int SourcePos;
|
||||||
const uint8_t *SourceRemap;
|
const PalEntry *SourceRemap;
|
||||||
};
|
};
|
||||||
|
|
|
@ -65,8 +65,16 @@ private:
|
||||||
// This is needed for allowing the client to allocate slots that aren't matched to a palette, e.g. Build's indexed variants.
|
// This is needed for allowing the client to allocate slots that aren't matched to a palette, e.g. Build's indexed variants.
|
||||||
if (translation >= 0)
|
if (translation >= 0)
|
||||||
{
|
{
|
||||||
auto remap = GPalette.TranslationToTable(translation);
|
if (!IsLuminosityTranslation(translation))
|
||||||
translation = remap == nullptr ? 0 : remap->Index;
|
{
|
||||||
|
auto remap = GPalette.TranslationToTable(translation);
|
||||||
|
translation = remap == nullptr ? 0 : remap->Index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// only needs to preserve the color range plus an identifier for marking this a luminosity translation.
|
||||||
|
translation = ((translation >> 16) & 0x3fff) | 0xff0000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else translation &= ~0x7fffffff;
|
else translation &= ~0x7fffffff;
|
||||||
|
|
||||||
|
|
|
@ -321,6 +321,7 @@ bool FTexture::ProcessData(unsigned char* buffer, int w, int h, bool ispatch)
|
||||||
// Initializes the buffer for the texture data
|
// Initializes the buffer for the texture data
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
void V_ApplyLuminosityTranslation(int translation, uint8_t *buffer, int size);
|
||||||
|
|
||||||
FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
|
FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
|
||||||
{
|
{
|
||||||
|
@ -356,7 +357,7 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
|
||||||
buffer = new unsigned char[W * (H + 1) * 4];
|
buffer = new unsigned char[W * (H + 1) * 4];
|
||||||
memset(buffer, 0, W * (H + 1) * 4);
|
memset(buffer, 0, W * (H + 1) * 4);
|
||||||
|
|
||||||
auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation);
|
auto remap = translation <= 0 || IsLuminosityTranslation(translation) ? nullptr : GPalette.TranslationToTable(translation);
|
||||||
if (remap && remap->Inactive) remap = nullptr;
|
if (remap && remap->Inactive) remap = nullptr;
|
||||||
if (remap) translation = remap->Index;
|
if (remap) translation = remap->Index;
|
||||||
FBitmap bmp(buffer, W * 4, W, H);
|
FBitmap bmp(buffer, W * 4, W, H);
|
||||||
|
@ -364,6 +365,10 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
|
||||||
int trans;
|
int trans;
|
||||||
auto Pixels = GetBgraBitmap(remap ? remap->Palette : nullptr, &trans);
|
auto Pixels = GetBgraBitmap(remap ? remap->Palette : nullptr, &trans);
|
||||||
bmp.Blit(exx, exx, Pixels);
|
bmp.Blit(exx, exx, Pixels);
|
||||||
|
if (IsLuminosityTranslation(translation))
|
||||||
|
{
|
||||||
|
V_ApplyLuminosityTranslation(translation, buffer, W * H);
|
||||||
|
}
|
||||||
|
|
||||||
if (remap == nullptr)
|
if (remap == nullptr)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue