mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2025-03-13 20:41:59 +00:00
Re-sync with gzdoom/master and add my latest fixes (#3)
* - Fixed bug with BishopPuff moving in wrong direction * - pull new widepix fix for hexen sprites * - 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. * Force gl_customshader = false, some fixes to shader code. * Delete some unused code * Actually read GL_MAX_TEXTURE_SIZE for max size * - fix for "Return to Phobos (return01.wad) has an ancient bug in map E1M2 where the switch to raise the exit bridge doesn't work in versions of Doom past patch 1.2." * - widepix update * - add missing break statement * - do not calculate translations for empty fonts. FONTDEFS will create some due to lack of game filtering. * - fix DaggerAlert using FindState incorrectly. * Fixed wrong parameter type passed into TryMove here * - fixed: GetColorTranslation did not handle translation-less single pic 'fonts' properly. * - fixed: Actors did not set the position when spawning a dynamic light. It always reused the previous content of the 'Pos' field which was either undefined or an older position where the actor was located when last spawning a light. * - fixed generation of default color range for the option menu font. * - added fallback to the parenthesis glyphs for the braces. * Add 'AddDialogues' in MAPINFO to additively add Strife NPC dialogs without overwriting each other. * Added APROP_SoundClass - Added APROP_SoundClass to GetActorProperty, SetActorProperty, CheckActorProperty * APROP_SoundClass inits a default value and checks for null pointers - Gave default init value to SoundClass as "Player" - Changed SoundClass detection to use the if/else structure - Checked for null pointer in S_FindSkinnedSound when reading the player's sound class * Made S_FindSkinnedSound to use GetSoundClass again - I couldn't simply init SoundClass to NAME_SoundClass, even after converting it to the appropriate type. Probably because NAME_SoundClass hasn't been parsed from decorate yet. Instead, I change it to NAME_SoundClass through GetSoundClass if it's valid and currently "player". - The skin checker code in GetSoundClass now checks if the SoundClass is equal to NAME_SoundClass. This mechanism exists so that way reverting the SoundClass to NAME_SoundClass processes the skin soundclass code. If it's different, the code is not processed. - Just returns sclass. This is never null, so there's no need to check if so. - S_FindSkinnedSound just uses GetSoundClass. This makes sure skins are checked. * Update d_player.h - Deleted some comment fragments I left when trying to get the SoundClass to init to NAME_SoundClass * Sound Class renovations - SoundClass is instantiated to "" by default. Since this property is only used when it is not empty (otherwise GetSoundClass just defaults to player), we can get away with this. - We may want the soundclass to remain the same if we explicitly set it to the same one that is currently used (say, we set SoundClass to "Caleb" so all other skins can use it) - GetActorProperty for APROP_SoundClass just calls GetSoundClass, - CheckActorProperty also just runs GetSoundClass - GetSoundClass is no longer a static method. We needed to access it in other places. - Made renovations to GetSoundClass. First of all, SoundClass is no longer instantiated there. Secondly, skinned sounds are now returned if SoundClass is empty. Thirdly, "sclass" in this method will return the default soundclass of the player pawn or SoundClass, depending on if SoundClass is empty. Finally, sclass will retrieve "player" if it is empty. * APROP_Soundclass update again - Just set init for SoundClass to empty. - Removed code block from SetActorProperty for APROP_Soundclass that does nothing - Lower-cased soundclass in FSerializer - Created a new const char to read the player's soundclass. If the playerpawn returns NAME_None for it's default, then it will set defaultsoundclass to "player". After running the skin code, the function now returns defaultsoundclass or soundclass, depending if soundclass is empty or not. - Renamed GetSoundClass to S_GetSoundClass * - Fixed crash calling ChangeSky() with an invalid texture. * - moved Doom specific font init code out of the backend. * - let dynamic lights call UpdateLocation instead of just setting their position right after being spawned. This ensures that the position is correct and that everything gets set up properly. * - fixed parsing of MAPxx par times in BEX lumps https://forum.zdoom.org/viewtopic.php?t=72458 * - corrected the NUL checks in S_FindSkinnedSound. * Make sprite shadows ignore float bob * - fixed explosive damage radius for clericflame. This was fixed before but must have gotten lost somehow... * - fixed permission validation in OptionMenuItemCommand.DoCommand. This was missing the InMenu check like the other critical menu functions. * - added detection of macOS 12 Monterey * - prevent redundant string copying in Strife conversation parser strifedialogue.cpp:110:22: warning: loop variable 'addd' of type 'const FString' creates a copy from type 'const FString' [-Wrange-loop-analysis] * - Fixed impassable exit line in 007ltsd.wad E4M7 * - fixed initialization of model frames Replaced loop arrays initialization and obvious comments with something more readable, I hope https://forum.zdoom.org/viewtopic.php?t=72523 * - fix missing border flat on heretic shareware * Stop colormap being applied to 2D drawing * - fixed parsing of 2D vectors in OBJ model loader There is no `TVector2<>` constructor that accepts a pointer to float. However, there is such constructor in `TVector3<>`, so `TVector2<>` can be constructed from `float*` implicitly via temporary `TVector3<>` object. * - added `TVector2<>` constructor from `float*` As we seem to do not like explicit constructors, this will make temporary `TVector3<>` object creation much less probable * - fixed bad type in FxFontCast. * - fixed potential crash when sound sequence is destroyed Level can be unset if sound sequence destruction happens after saved game loading failure https://forum.zdoom.org/viewtopic.php?t=72551 * Fix light binding when using pipeline buffer on OpenGL Co-authored-by: Dasperal <Dasperal1@gmail.com> Co-authored-by: Rachael Alexanderson <madame-rachelle@users.noreply.github.com> Co-authored-by: Christoph Oelckers <coelckers@users.noreply.github.com> Co-authored-by: Chronos Ouroboros <doom2.fan@gmail.com> Co-authored-by: nashmuhandes <nashbackslash@gmail.com> Co-authored-by: Zandrewnum <andy.clarke99.ac@gmail.com> Co-authored-by: Shiny Metagross <30511800+ShinyMetagross@users.noreply.github.com> Co-authored-by: drfrag <drfrag666@hotmail.com> Co-authored-by: alexey.lysiuk <alexey.lysiuk@gmail.com> Co-authored-by: emily <minecrafter2010@gmail.com> Co-authored-by: Player701 <player701@player701.ru>
This commit is contained in:
parent
e3ca26482b
commit
0f64dbf61e
50 changed files with 773 additions and 897 deletions
|
@ -173,9 +173,8 @@ void DrawChar(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double
|
|||
|
||||
FGameTexture* pic;
|
||||
int dummy;
|
||||
bool redirected;
|
||||
|
||||
if (NULL != (pic = font->GetChar(character, normalcolor, &dummy, &redirected)))
|
||||
if (NULL != (pic = font->GetChar(character, normalcolor, &dummy)))
|
||||
{
|
||||
DrawParms parms;
|
||||
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);
|
||||
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);
|
||||
drawer->AddTexture(pic, parms);
|
||||
}
|
||||
|
@ -204,9 +203,8 @@ void DrawChar(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double
|
|||
|
||||
FGameTexture *pic;
|
||||
int dummy;
|
||||
bool redirected;
|
||||
|
||||
if (NULL != (pic = font->GetChar(character, normalcolor, &dummy, &redirected)))
|
||||
if (NULL != (pic = font->GetChar(character, normalcolor, &dummy)))
|
||||
{
|
||||
DrawParms parms;
|
||||
uint32_t tag = ListGetInt(args);
|
||||
|
@ -214,7 +212,7 @@ void DrawChar(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double
|
|||
if (!res) return;
|
||||
bool palettetrans = (normalcolor == CR_UNDEFINED && parms.TranslationId != 0);
|
||||
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);
|
||||
drawer->AddTexture(pic, parms);
|
||||
}
|
||||
|
@ -316,11 +314,10 @@ void DrawTextCommon(F2DDrawer *drawer, FFont *font, int normalcolor, double x, d
|
|||
continue;
|
||||
}
|
||||
|
||||
bool redirected = false;
|
||||
if (NULL != (pic = font->GetChar(c, currentcolor, &w, &redirected)))
|
||||
if (NULL != (pic = font->GetChar(c, currentcolor, &w)))
|
||||
{
|
||||
// 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);
|
||||
if (parms.cellx)
|
||||
{
|
||||
|
|
|
@ -70,12 +70,26 @@ inline constexpr uint32_t TRANSLATION(uint8_t a, uint32_t 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)
|
||||
{
|
||||
assert(!IsLuminosityTranslation(trans));
|
||||
return (trans & TRANSLATIONTYPE_MASK) >> TRANSLATION_SHIFT;
|
||||
}
|
||||
|
||||
inline constexpr int GetTranslationIndex(uint32_t trans)
|
||||
{
|
||||
assert(!IsLuminosityTranslation(trans));
|
||||
return (trans & TRANSLATION_MASK);
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,6 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
|
|||
Next = FirstFont;
|
||||
FirstFont = this;
|
||||
Cursor = '_';
|
||||
ActiveColors = 0;
|
||||
SpaceWidth = 0;
|
||||
FontHeight = 0;
|
||||
uint8_t pp = 0;
|
||||
|
@ -333,23 +332,13 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
|
|||
TexMan.AddGameTexture(tex);
|
||||
Chars[i].OriginalPic = tex;
|
||||
|
||||
if (!noTranslate)
|
||||
{
|
||||
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);
|
||||
if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(pic, Chars[i].OriginalPic, Chars[i].OriginalPic);
|
||||
|
||||
Chars[i].XMove = (int)Chars[i].TranslatedPic->GetDisplayWidth();
|
||||
Chars[i].XMove = (int)Chars[i].OriginalPic->GetDisplayWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
Chars[i].TranslatedPic = nullptr;
|
||||
Chars[i].OriginalPic = nullptr;
|
||||
Chars[i].XMove = INT_MIN;
|
||||
}
|
||||
}
|
||||
|
@ -360,7 +349,7 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
@ -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->SetUseType(ETextureType::FontChar);
|
||||
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);
|
||||
TexMan.AddGameTexture(Chars[i].TranslatedPic);
|
||||
}
|
||||
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.
|
||||
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]);
|
||||
}
|
||||
|
@ -509,24 +494,24 @@ void FFont::CheckCase()
|
|||
}
|
||||
if (myislower(chr))
|
||||
{
|
||||
if (Chars[i].TranslatedPic != nullptr) lowercount++;
|
||||
if (Chars[i].OriginalPic != nullptr) lowercount++;
|
||||
}
|
||||
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.
|
||||
|
||||
// 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)
|
||||
{
|
||||
Chars.Resize(0x1e9f - FirstChar);
|
||||
LastChar = 0x1e9e;
|
||||
}
|
||||
if (Chars[0x1e9e - FirstChar].TranslatedPic == nullptr)
|
||||
if (Chars[0x1e9e - FirstChar].OriginalPic == nullptr)
|
||||
{
|
||||
std::swap(Chars[0xdf - FirstChar], Chars[0x1e9e - FirstChar]);
|
||||
lowercount--;
|
||||
|
@ -596,75 +581,14 @@ void FFont::RecordAllTextureColors(uint32_t *usedcolors)
|
|||
{
|
||||
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());
|
||||
if (pic)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
auto pic = Chars[i].OriginalPic->GetTexture()->GetImage();
|
||||
if (pic) RecordTextureColors(pic, usedcolors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SetDefaultTranslation
|
||||
//
|
||||
// Builds a translation to map the stock font to a mod provided replacement.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFont::SetDefaultTranslation(uint32_t *othercolors)
|
||||
{
|
||||
uint32_t mycolors[256] = {};
|
||||
RecordAllTextureColors(mycolors);
|
||||
|
||||
uint8_t mytranslation[256], othertranslation[256], myreverse[256], otherreverse[256];
|
||||
TArray<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
|
||||
|
@ -688,160 +612,40 @@ static int compare (const void *arg1, const void *arg2)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// FFont :: SimpleTranslation
|
||||
//
|
||||
// Colorsused, translation, and reverse must all be 256 entry buffers.
|
||||
// Colorsused must already be filled out.
|
||||
// Translation be set to remap the source colors to a new range of
|
||||
// consecutive colors based at 1 (0 is transparent).
|
||||
// Reverse will be just the opposite of translation: It maps the new color
|
||||
// range to the original colors.
|
||||
// *Luminosity will be an array just large enough to hold the brightness
|
||||
// levels of all the used colors, in consecutive order. It is sorted from
|
||||
// darkest to lightest and scaled such that the darkest color is 0.0 and
|
||||
// the brightest color is 1.0.
|
||||
// The return value is the number of used colors and thus the number of
|
||||
// entries in *luminosity.
|
||||
// FFont :: GetLuminosity
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FFont::SimpleTranslation (uint32_t *colorsused, uint8_t *translation, uint8_t *reverse, TArray<double> &Luminosity)
|
||||
int FFont::GetLuminosity (uint32_t *colorsused, TArray<double> &Luminosity, int* minlum, int* maxlum)
|
||||
{
|
||||
double min, max, diver;
|
||||
int i, j;
|
||||
|
||||
memset (translation, 0, 256);
|
||||
|
||||
reverse[0] = 0;
|
||||
for (i = 1, j = 1; i < 256; i++)
|
||||
{
|
||||
if (colorsused[i])
|
||||
{
|
||||
reverse[j++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
qsort (reverse+1, j-1, 1, compare);
|
||||
|
||||
Luminosity.Resize(j);
|
||||
Luminosity.Resize(256);
|
||||
Luminosity[0] = 0.0; // [BL] Prevent uninitalized memory
|
||||
max = 0.0;
|
||||
min = 100000000.0;
|
||||
for (i = 1; i < j; i++)
|
||||
for (int i = 1; i < 256; i++)
|
||||
{
|
||||
translation[reverse[i]] = i;
|
||||
|
||||
Luminosity[i] = RPART(GPalette.BaseColors[reverse[i]]) * 0.299 +
|
||||
GPART(GPalette.BaseColors[reverse[i]]) * 0.587 +
|
||||
BPART(GPalette.BaseColors[reverse[i]]) * 0.114;
|
||||
if (Luminosity[i] > max)
|
||||
max = Luminosity[i];
|
||||
if (Luminosity[i] < min)
|
||||
min = Luminosity[i];
|
||||
if (colorsused[i])
|
||||
{
|
||||
Luminosity[i] = GPalette.BaseColors[i].r * 0.299 + GPalette.BaseColors[i].g * 0.587 + GPalette.BaseColors[i].b * 0.114;
|
||||
if (Luminosity[i] > max) max = Luminosity[i];
|
||||
if (Luminosity[i] < min) min = Luminosity[i];
|
||||
}
|
||||
else Luminosity[i] = -1; // this color is not of interest.
|
||||
}
|
||||
diver = 1.0 / (max - min);
|
||||
for (i = 1; i < j; i++)
|
||||
for (int i = 1; i < 256; i++)
|
||||
{
|
||||
Luminosity[i] = (Luminosity[i] - min) * diver;
|
||||
if (colorsused[i])
|
||||
{
|
||||
Luminosity[i] = (Luminosity[i] - min) * diver;
|
||||
}
|
||||
}
|
||||
if (minlum) *minlum = int(min);
|
||||
if (maxlum) *maxlum = int(max);
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 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++;
|
||||
}
|
||||
return 256;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -852,6 +656,10 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity
|
|||
|
||||
int FFont::GetColorTranslation (EColorRange range, PalEntry *color) const
|
||||
{
|
||||
// Single pic fonts don not set up their translation table and must always return 0.
|
||||
if (Translations.Size() == 0) return 0;
|
||||
assert(Translations.Size() == NumTextColors);
|
||||
|
||||
if (noTranslate)
|
||||
{
|
||||
PalEntry retcolor = PalEntry(255, 255, 255, 255);
|
||||
|
@ -862,11 +670,10 @@ int FFont::GetColorTranslation (EColorRange range, PalEntry *color) const
|
|||
}
|
||||
if (color != nullptr) *color = retcolor;
|
||||
}
|
||||
if (ActiveColors == 0 || range == CR_UNDEFINED)
|
||||
if (range == CR_UNDEFINED)
|
||||
return -1;
|
||||
else if (range >= NumTextColors)
|
||||
range = CR_UNTRANSLATED;
|
||||
//if (range == CR_UNTRANSLATED && !translateUntranslated) return nullptr;
|
||||
return Translations[range];
|
||||
}
|
||||
|
||||
|
@ -889,7 +696,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
|||
// regular chars turn negative when the 8th bit is set.
|
||||
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;
|
||||
}
|
||||
|
@ -903,7 +710,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
|||
if (myislower(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;
|
||||
}
|
||||
|
@ -912,7 +719,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
|||
while ((newcode = stripaccent(code)) != code)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -926,7 +733,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
|||
while ((newcode = stripaccent(code)) != code)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -944,7 +751,7 @@ int FFont::GetCharCode(int code, bool needpic) const
|
|||
while ((newcode = stripaccent(code)) != code)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -961,7 +768,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);
|
||||
int xmove = SpaceWidth;
|
||||
|
@ -979,19 +786,8 @@ FGameTexture *FFont::GetChar (int code, int translation, int *const width, bool
|
|||
if (code < 0) return nullptr;
|
||||
|
||||
|
||||
if ((translation == CR_UNTRANSLATED || translation == CR_UNDEFINED) && !forceremap)
|
||||
{
|
||||
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;
|
||||
assert(Chars[code].OriginalPic->GetUseType() == ETextureType::FontChar);
|
||||
return Chars[code].OriginalPic;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1172,31 +968,29 @@ void FFont::LoadTranslations()
|
|||
{
|
||||
unsigned int count = LastChar - FirstChar + 1;
|
||||
uint32_t usedcolors[256] = {};
|
||||
uint8_t identity[256];
|
||||
TArray<double> Luminosity;
|
||||
|
||||
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());
|
||||
if (pic)
|
||||
{
|
||||
pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture
|
||||
RecordTextureColors(pic, usedcolors);
|
||||
}
|
||||
auto pic = Chars[i].OriginalPic->GetTexture()->GetImage();
|
||||
if (pic) 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)
|
||||
static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
|
||||
if (i == CR_UNTRANSLATED) Translations[i] = 0;
|
||||
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 "tarray.h"
|
||||
|
||||
// This structure is used by BuildTranslations() to hold color information.
|
||||
struct TranslationParm
|
||||
{
|
||||
short RangeStart; // First level for this range
|
||||
|
|
|
@ -50,6 +50,8 @@ struct HexDataSource
|
|||
TArray<uint8_t> glyphdata;
|
||||
unsigned glyphmap[65536] = {};
|
||||
|
||||
PalEntry ConsolePal[18], SmallPal[18];
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// parse a HEX font
|
||||
|
@ -83,6 +85,17 @@ struct HexDataSource
|
|||
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);
|
||||
|
||||
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
||||
int CopyPixels(FBitmap* bmp, int conversion);
|
||||
|
||||
protected:
|
||||
int SourceWidth;
|
||||
|
@ -159,12 +173,23 @@ TArray<uint8_t> FHexFontChar::CreatePalettedPixels(int)
|
|||
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
|
||||
{
|
||||
public:
|
||||
FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -267,10 +301,9 @@ public:
|
|||
{
|
||||
auto offset = hexdata.glyphmap[i];
|
||||
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 = Chars[i - FirstChar].TranslatedPic;
|
||||
Chars[i - FirstChar].OriginalPic = MakeGameTexture(new FImageTexture(new FHexFontChar(&hexdata.glyphdata[offset + 1], size, size * 9, 16)), nullptr, ETextureType::FontChar);
|
||||
Chars[i - FirstChar].XMove = size * spacing;
|
||||
TexMan.AddGameTexture(Chars[i - FirstChar].TranslatedPic);
|
||||
TexMan.AddGameTexture(Chars[i - FirstChar].OriginalPic);
|
||||
}
|
||||
else Chars[i - FirstChar].XMove = spacing;
|
||||
|
||||
|
@ -285,18 +318,15 @@ public:
|
|||
|
||||
void LoadTranslations()
|
||||
{
|
||||
double luminosity[256];
|
||||
int minlum = hexdata.ConsolePal[1].r;
|
||||
int maxlum = hexdata.ConsolePal[17].r;
|
||||
|
||||
memset (PatchRemap, 0, 256);
|
||||
for (int i = 0; i < 18; i++)
|
||||
{
|
||||
// Create a gradient similar to the old console font.
|
||||
PatchRemap[i] = i;
|
||||
luminosity[i] = i == 1? 0.01 : 0.5 + (i-2) * (0.5 / 17.);
|
||||
Translations.Resize(NumTextColors);
|
||||
for (int i = 0; i < NumTextColors; i++)
|
||||
{
|
||||
if (i == CR_UNTRANSLATED) Translations[i] = 0;
|
||||
else Translations[i] = LuminosityTranslation(i * 2 + 1, minlum, maxlum);
|
||||
}
|
||||
ActiveColors = 18;
|
||||
|
||||
BuildTranslations (luminosity, nullptr, &TranslationParms[1][0], ActiveColors, nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -338,10 +368,9 @@ public:
|
|||
{
|
||||
auto offset = hexdata.glyphmap[i];
|
||||
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 = Chars[i - FirstChar].TranslatedPic;
|
||||
Chars[i - FirstChar].OriginalPic = MakeGameTexture(new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18)), nullptr, ETextureType::FontChar);
|
||||
Chars[i - FirstChar].XMove = size * spacing;
|
||||
TexMan.AddGameTexture(Chars[i - FirstChar].TranslatedPic);
|
||||
TexMan.AddGameTexture(Chars[i - FirstChar].OriginalPic);
|
||||
}
|
||||
else Chars[i - FirstChar].XMove = spacing;
|
||||
|
||||
|
@ -356,71 +385,16 @@ public:
|
|||
|
||||
void LoadTranslations() override
|
||||
{
|
||||
double luminosity[256];
|
||||
int minlum = hexdata.SmallPal[1].r;
|
||||
int maxlum = hexdata.SmallPal[17].r;
|
||||
|
||||
memset(PatchRemap, 0, 256);
|
||||
for (int i = 0; i < 18; i++)
|
||||
Translations.Resize(NumTextColors);
|
||||
for (int i = 0; i < NumTextColors; i++)
|
||||
{
|
||||
// Create a gradient similar to the old console font.
|
||||
PatchRemap[i] = i;
|
||||
luminosity[i] = i / 17.;
|
||||
if (i == CR_UNTRANSLATED) Translations[i] = 0;
|
||||
else Translations[i] = LuminosityTranslation(i * 2, minlum, maxlum);
|
||||
}
|
||||
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;
|
||||
|
||||
protected:
|
||||
void CheckFON1Chars (double *luminosity);
|
||||
void BuildTranslations2 ();
|
||||
void FixupPalette (uint8_t *identity, double *luminosity, const uint8_t *palette,
|
||||
bool rescale, PalEntry *out_palette);
|
||||
void CheckFON1Chars ();
|
||||
void FixupPalette (uint8_t *identity, const PalEntry *palette, int* minlum ,int* maxlum);
|
||||
void LoadTranslations ();
|
||||
void LoadFON1 (int lump, const uint8_t *data);
|
||||
void LoadFON2 (int lump, const uint8_t *data);
|
||||
void LoadBMF (int lump, const uint8_t *data);
|
||||
void CreateFontFromPic (FTextureID picnum);
|
||||
|
||||
static int BMFCompare(const void *a, const void *b);
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
FONT1,
|
||||
FONT2,
|
||||
BMFFONT
|
||||
} FontType;
|
||||
uint8_t PaletteData[768];
|
||||
PalEntry Palette[256];
|
||||
bool RescalePalette;
|
||||
int ActiveColors = -1;
|
||||
};
|
||||
|
||||
|
||||
|
@ -160,29 +156,6 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump)
|
|||
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
|
||||
|
@ -191,28 +164,21 @@ void FSingleLumpFont::CreateFontFromPic (FTextureID picnum)
|
|||
|
||||
void FSingleLumpFont::LoadTranslations()
|
||||
{
|
||||
double luminosity[256];
|
||||
uint8_t identity[256];
|
||||
PalEntry local_palette[256];
|
||||
bool useidentity = true;
|
||||
bool usepalette = false;
|
||||
const void* ranges;
|
||||
unsigned int count = LastChar - FirstChar + 1;
|
||||
int minlum, maxlum;
|
||||
|
||||
switch(FontType)
|
||||
{
|
||||
case FONT1:
|
||||
useidentity = false;
|
||||
ranges = &TranslationParms[1][0];
|
||||
CheckFON1Chars (luminosity);
|
||||
CheckFON1Chars();
|
||||
minlum = 1;
|
||||
maxlum = 255;
|
||||
break;
|
||||
|
||||
case BMFFONT:
|
||||
case FONT2:
|
||||
usepalette = true;
|
||||
FixupPalette (identity, luminosity, PaletteData, RescalePalette, local_palette);
|
||||
|
||||
ranges = &TranslationParms[0][0];
|
||||
FixupPalette (identity, Palette, &minlum, &maxlum);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -223,11 +189,16 @@ void FSingleLumpFont::LoadTranslations()
|
|||
|
||||
for(unsigned int i = 0;i < count;++i)
|
||||
{
|
||||
if(Chars[i].TranslatedPic)
|
||||
static_cast<FFontChar2*>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
|
||||
if(Chars[i].OriginalPic)
|
||||
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.
|
||||
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]]);
|
||||
}
|
||||
}
|
||||
Palette[0] = 0;
|
||||
for (int i = 1; i < 256; i++) Palette[i] = PalEntry(255, i, i, i);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSingleLumpFont :: LoadFON2
|
||||
//
|
||||
// FON2 is used for everything but the console font. The console font should
|
||||
// probably use FON2 as well, but oh well.
|
||||
// FON2 is used for everything but the console font.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -340,7 +312,11 @@ void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data)
|
|||
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;
|
||||
|
||||
|
@ -350,14 +326,12 @@ void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data)
|
|||
Chars[i].XMove = widths2[i];
|
||||
if (destSize <= 0)
|
||||
{
|
||||
Chars[i].TranslatedPic = nullptr;
|
||||
Chars[i].OriginalPic = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Chars[i].TranslatedPic = 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].TranslatedPic);
|
||||
Chars[i].OriginalPic = MakeGameTexture(new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)), nullptr, ETextureType::FontChar);
|
||||
TexMan.AddGameTexture(Chars[i].OriginalPic);
|
||||
do
|
||||
{
|
||||
int8_t code = *data_p++;
|
||||
|
@ -396,8 +370,6 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
|||
int numchars, count, totalwidth, nwidth;
|
||||
int infolen;
|
||||
int i, chari;
|
||||
uint8_t raw_palette[256*3];
|
||||
PalEntry sort_palette[256];
|
||||
|
||||
FontType = BMFFONT;
|
||||
FontHeight = data[5];
|
||||
|
@ -439,31 +411,14 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
|||
count = LastChar - FirstChar + 1;
|
||||
Chars.Resize(count);
|
||||
// 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)
|
||||
{
|
||||
PalEntry *pal = &sort_palette[i];
|
||||
pal->a = i; // Use alpha part to point back to original entry
|
||||
pal->r = raw_palette[i*3 + 0];
|
||||
pal->g = raw_palette[i*3 + 1];
|
||||
pal->b = raw_palette[i*3 + 2];
|
||||
int r = (data[17 + i * 3] << 2) | (data[17 + i * 3] >> 4);
|
||||
int g = (data[18 + i * 3] << 2) | (data[18 + i * 3] >> 4);
|
||||
int b = (data[19 + i * 3] << 2) | (data[19 + i * 3] >> 4);
|
||||
Palette[i + 1] = PalEntry(255, r, g, b); // entry 0 (transparent) is not stored in the font file.
|
||||
}
|
||||
qsort(sort_palette + 1, ActiveColors - 1, sizeof(PalEntry), BMFCompare);
|
||||
|
||||
// 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);
|
||||
ActiveColors++;
|
||||
|
||||
// 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])
|
||||
|
@ -489,7 +444,6 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
|||
-(int8_t)chardata[chari+3], // x offset
|
||||
-(int8_t)chardata[chari+4] // y offset
|
||||
)), nullptr, ETextureType::FontChar);
|
||||
Chars[chardata[chari] - FirstChar].TranslatedPic = tex;
|
||||
Chars[chardata[chari] - FirstChar].OriginalPic = tex;
|
||||
TexMan.AddGameTexture(tex);
|
||||
}
|
||||
|
@ -510,55 +464,33 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
|||
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
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSingleLumpFont::CheckFON1Chars (double *luminosity)
|
||||
void FSingleLumpFont::CheckFON1Chars()
|
||||
{
|
||||
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;
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
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 = Chars[i].TranslatedPic;
|
||||
Chars[i].OriginalPic = MakeGameTexture(new FImageTexture(new FFontChar2(Lump, int(data_p - data), SpaceWidth, FontHeight)), nullptr, ETextureType::FontChar);
|
||||
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.
|
||||
|
@ -567,87 +499,52 @@ void FSingleLumpFont::CheckFON1Chars (double *luminosity)
|
|||
int8_t code = *data_p++;
|
||||
if (code >= 0)
|
||||
{
|
||||
destSize -= code+1;
|
||||
destSize -= code + 1;
|
||||
while (code-- >= 0)
|
||||
{
|
||||
used[*data_p++] = 1;
|
||||
data_p++;
|
||||
}
|
||||
}
|
||||
else if (code != -128)
|
||||
{
|
||||
used[*data_p++] = 1;
|
||||
data_p++;
|
||||
destSize -= 1 - code;
|
||||
}
|
||||
} while (destSize > 0);
|
||||
}
|
||||
|
||||
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;
|
||||
ActiveColors = 256;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSingleLumpFont :: FixupPalette
|
||||
//
|
||||
// Finds the best matches for the colors used by a FON2 font and sets up
|
||||
// some tables like SimpleTranslation.
|
||||
// Finds the best matches for the colors used by a FON2 font and finds thr
|
||||
// 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 minlum = 100000000.0;
|
||||
double diver;
|
||||
|
||||
identity[0] = 0;
|
||||
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 g = palette[1];
|
||||
int b = palette[2];
|
||||
int r = palette->r;
|
||||
int g = palette->g;
|
||||
int b = palette->b;
|
||||
double lum = r*0.299 + g*0.587 + b*0.114;
|
||||
identity[i] = ColorMatcher.Pick(r, g, b);
|
||||
luminosity[i] = lum;
|
||||
out_palette[i].r = r;
|
||||
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;
|
||||
if (lum > maxlum) maxlum = lum;
|
||||
if (lum < minlum) minlum = lum;
|
||||
}
|
||||
out_palette[0] = 0;
|
||||
|
||||
if (rescale)
|
||||
{
|
||||
diver = 1.0 / (maxlum - minlum);
|
||||
}
|
||||
else
|
||||
{
|
||||
diver = 1.0 / 255.0;
|
||||
}
|
||||
for (i = 1; i < ActiveColors; ++i)
|
||||
{
|
||||
luminosity[i] = (luminosity[i] - minlum) * diver;
|
||||
}
|
||||
if (pminlum) *pminlum = int(minlum);
|
||||
if (pmaxlum) *pmaxlum = int(maxlum);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -661,13 +558,11 @@ void FSingleLumpFont::FixupPalette (uint8_t *identity, double *luminosity, const
|
|||
|
||||
void FSingleLumpFont::RecordAllTextureColors(uint32_t* usedcolors)
|
||||
{
|
||||
double luminosity[256];
|
||||
uint8_t identity[256];
|
||||
PalEntry local_palette[256];
|
||||
|
||||
if (FontType == BMFFONT || FontType == FONT2)
|
||||
{
|
||||
FixupPalette(identity, luminosity, PaletteData, RescalePalette, local_palette);
|
||||
FixupPalette(identity, Palette, nullptr, nullptr);
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
if (identity[i] != 0) usedcolors[identity[i]]++;
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
FSinglePicFont(const char *picname);
|
||||
|
||||
// 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;
|
||||
|
||||
protected:
|
||||
|
@ -79,7 +79,6 @@ FSinglePicFont::FSinglePicFont(const char *picname) :
|
|||
SpaceWidth = (int)pic->GetDisplayWidth();
|
||||
GlobalKerning = 0;
|
||||
FirstChar = LastChar = 'A';
|
||||
ActiveColors = 0;
|
||||
PicNum = picnum;
|
||||
|
||||
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;
|
||||
if (redirected) *redirected = false;
|
||||
if (code == 'a' || code == 'A')
|
||||
{
|
||||
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->CopySize(pic, true);
|
||||
TexMan.AddGameTexture(Chars[i].OriginalPic);
|
||||
|
||||
if (!noTranslate)
|
||||
{
|
||||
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);
|
||||
Chars[i].XMove = (int)Chars[i].OriginalPic->GetDisplayWidth();
|
||||
if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(pic, Chars[i].OriginalPic, Chars[i].OriginalPic);
|
||||
}
|
||||
else
|
||||
{
|
||||
Chars[i].TranslatedPic = nullptr;
|
||||
Chars[i].OriginalPic = nullptr;
|
||||
Chars[i].XMove = INT_MIN;
|
||||
}
|
||||
}
|
||||
|
||||
// Special fonts normally don't have all characters so be careful here!
|
||||
if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].TranslatedPic != nullptr)
|
||||
if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].OriginalPic != nullptr)
|
||||
{
|
||||
SpaceWidth = (Chars['N' - first].XMove + 1) / 2;
|
||||
}
|
||||
|
@ -137,11 +129,6 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture
|
|||
}
|
||||
|
||||
FixXMoves();
|
||||
|
||||
if (noTranslate)
|
||||
{
|
||||
ActiveColors = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -152,65 +139,67 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture
|
|||
|
||||
void FSpecialFont::LoadTranslations()
|
||||
{
|
||||
int count = LastChar - FirstChar + 1;
|
||||
uint32_t usedcolors[256] = {};
|
||||
uint8_t identity[256];
|
||||
TArray<double> Luminosity;
|
||||
int TotalColors;
|
||||
int i;
|
||||
FFont::LoadTranslations();
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
bool empty = true;
|
||||
for (auto& c : Chars)
|
||||
{
|
||||
if (Chars[i].TranslatedPic)
|
||||
if (c.OriginalPic != nullptr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty) return; // Font has no characters.
|
||||
|
||||
bool needsnotrans = false;
|
||||
// exclude the non-translated colors from the translation calculation
|
||||
for (i = 0; i < 256; i++)
|
||||
if (notranslate[i])
|
||||
usedcolors[i] = false;
|
||||
|
||||
TotalColors = ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity);
|
||||
|
||||
// Map all untranslated colors into the table of used colors
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
if (notranslate[i])
|
||||
{
|
||||
PatchRemap[i] = TotalColors;
|
||||
identity[TotalColors] = i;
|
||||
TotalColors++;
|
||||
needsnotrans = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
|
||||
return;
|
||||
}
|
||||
|
||||
BuildTranslations(Luminosity.Data(), identity, &TranslationParms[0][0], TotalColors, nullptr, [=](FRemapTable* remap)
|
||||
{
|
||||
// add the untranslated colors to the Ranges tables
|
||||
if (ActiveColors < TotalColors)
|
||||
{
|
||||
for (int j = ActiveColors; j < TotalColors; ++j)
|
||||
{
|
||||
remap->Remap[j] = identity[j];
|
||||
remap->Palette[j] = GPalette.BaseColors[identity[j]];
|
||||
remap->Palette[j].a = 0xff;
|
||||
}
|
||||
}
|
||||
});
|
||||
// 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!
|
||||
for (auto &trans : Translations)
|
||||
{
|
||||
if (!IsLuminosityTranslation(trans)) continue; // this should only happen for CR_UNTRANSLATED.
|
||||
|
||||
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)
|
||||
|
|
|
@ -60,16 +60,6 @@
|
|||
|
||||
#define DEFAULT_LOG_COLOR PalEntry(223,223,223)
|
||||
|
||||
//
|
||||
// Globally visible constants.
|
||||
//
|
||||
#define HU_FONTSTART uint8_t('!') // the first font characters
|
||||
#define HU_FONTEND uint8_t('\377') // the last font characters
|
||||
|
||||
// Calculate # of glyphs in font.
|
||||
#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
|
||||
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
@ -158,7 +148,7 @@ FFont *V_GetFont(const char *name, const char *fontlumpname)
|
|||
}
|
||||
if (folderdata.Size() > 0)
|
||||
{
|
||||
font = new FFont(name, nullptr, name, HU_FONTSTART, HU_FONTSIZE, 1, -1);
|
||||
font = new FFont(name, nullptr, name, 0, 0, 1, -1);
|
||||
if (translationsLoaded) font->LoadTranslations();
|
||||
return font;
|
||||
}
|
||||
|
@ -586,6 +576,179 @@ EColorRange V_FindFontColor (FName name)
|
|||
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];
|
||||
remap[index].a = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// todo: fill the gaps.
|
||||
//remap[0] = 0;
|
||||
int lowindex = 0;
|
||||
while (lowindex < 255 && remap[lowindex].a == 0) lowindex++;
|
||||
lowindex++;
|
||||
int highindex = lowindex + 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
|
||||
|
@ -676,6 +839,7 @@ EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int
|
|||
|
||||
void V_InitFonts()
|
||||
{
|
||||
CreateLuminosityTranslationRanges();
|
||||
V_InitCustomFonts();
|
||||
|
||||
FFont *CreateHexLumpFont(const char *fontname, int lump);
|
||||
|
@ -686,140 +850,7 @@ void V_InitFonts()
|
|||
NewConsoleFont = CreateHexLumpFont("NewConsoleFont", lump);
|
||||
NewSmallFont = CreateHexLumpFont2("NewSmallFont", lump);
|
||||
CurrentConsoleFont = NewConsoleFont;
|
||||
|
||||
// load the heads-up font
|
||||
if (!(SmallFont = V_GetFont("SmallFont", "SMALLFNT")))
|
||||
{
|
||||
if (fileSystem.CheckNumForName("FONTA_S") >= 0)
|
||||
{
|
||||
int wadfile = -1;
|
||||
auto a = fileSystem.CheckNumForName("FONTA33", ns_graphics);
|
||||
if (a != -1) wadfile = fileSystem.GetFileContainer(a);
|
||||
if (wadfile > fileSystem.GetIwadNum())
|
||||
{
|
||||
// The font has been replaced, so we need to create a copy of the original as well.
|
||||
SmallFont = new FFont("SmallFont", "FONTA%02u", nullptr, HU_FONTSTART, HU_FONTSIZE, 1, -1);
|
||||
SmallFont->SetCursor('[');
|
||||
}
|
||||
else
|
||||
{
|
||||
SmallFont = new FFont("SmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
|
||||
SmallFont->SetCursor('[');
|
||||
}
|
||||
}
|
||||
else if (fileSystem.CheckNumForName("STCFN033", ns_graphics) >= 0)
|
||||
{
|
||||
int wadfile = -1;
|
||||
auto a = fileSystem.CheckNumForName("STCFN065", ns_graphics);
|
||||
if (a != -1) wadfile = fileSystem.GetFileContainer(a);
|
||||
if (wadfile > fileSystem.GetIwadNum())
|
||||
{
|
||||
// The font has been replaced, so we need to create a copy of the original as well.
|
||||
SmallFont = new FFont("SmallFont", "STCFN%.3d", nullptr, HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SmallFont = new FFont("SmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the original small font as a fallback for incomplete definitions.
|
||||
if (fileSystem.CheckNumForName("FONTA_S") >= 0)
|
||||
{
|
||||
OriginalSmallFont = new FFont("OriginalSmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true);
|
||||
OriginalSmallFont->SetCursor('[');
|
||||
}
|
||||
else if (fileSystem.CheckNumForName("STCFN033", ns_graphics) >= 0)
|
||||
{
|
||||
OriginalSmallFont = new FFont("OriginalSmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, true);
|
||||
}
|
||||
|
||||
|
||||
if (!(SmallFont2 = V_GetFont("SmallFont2"))) // Only used by Strife
|
||||
{
|
||||
if (fileSystem.CheckNumForName("STBFN033", ns_graphics) >= 0)
|
||||
{
|
||||
SmallFont2 = new FFont("SmallFont2", "STBFN%.3d", "defsmallfont2", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
|
||||
}
|
||||
}
|
||||
|
||||
//This must be read before BigFont so that it can be properly substituted.
|
||||
BigUpper = V_GetFont("BigUpper");
|
||||
|
||||
if (!(BigFont = V_GetFont("BigFont")))
|
||||
{
|
||||
if (fileSystem.CheckNumForName("FONTB_S") >= 0)
|
||||
{
|
||||
BigFont = new FFont("BigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!BigFont)
|
||||
{
|
||||
// Load the generic fallback if no BigFont is found.
|
||||
BigFont = V_GetFont("BigFont", "ZBIGFONT");
|
||||
}
|
||||
|
||||
if (fileSystem.CheckNumForName("FONTB_S") >= 0)
|
||||
{
|
||||
OriginalBigFont = new FFont("OriginalBigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
OriginalBigFont = new FFont("OriginalBigFont", nullptr, "bigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true);
|
||||
}
|
||||
|
||||
// let PWAD BIGFONTs override the stock BIGUPPER font. (This check needs to be made smarter.)
|
||||
if (BigUpper && BigFont->Type != FFont::Folder && BigUpper->Type == FFont::Folder)
|
||||
{
|
||||
delete BigUpper;
|
||||
BigUpper = BigFont;
|
||||
}
|
||||
|
||||
if (BigUpper == nullptr)
|
||||
{
|
||||
BigUpper = BigFont;
|
||||
}
|
||||
if (!(ConFont = V_GetFont("ConsoleFont", "CONFONT")))
|
||||
{
|
||||
ConFont = SmallFont;
|
||||
}
|
||||
if (!(IntermissionFont = FFont::FindFont("IntermissionFont")))
|
||||
{
|
||||
if (TexMan.CheckForTexture("WINUM0", ETextureType::MiscPatch).isValid())
|
||||
{
|
||||
IntermissionFont = FFont::FindFont("IntermissionFont_Doom");
|
||||
}
|
||||
if (IntermissionFont == nullptr)
|
||||
{
|
||||
IntermissionFont = BigFont;
|
||||
}
|
||||
}
|
||||
// This can only happen if gzdoom.pk3 is corrupted. ConFont should always be present.
|
||||
if (ConFont == nullptr)
|
||||
{
|
||||
I_FatalError("Console font not found.");
|
||||
}
|
||||
// SmallFont and SmallFont2 have no default provided by the engine. BigFont only has in non-Raven games.
|
||||
if (OriginalSmallFont == nullptr)
|
||||
{
|
||||
OriginalSmallFont = ConFont;
|
||||
}
|
||||
if (SmallFont == nullptr)
|
||||
{
|
||||
SmallFont = OriginalSmallFont;
|
||||
}
|
||||
if (SmallFont2 == nullptr)
|
||||
{
|
||||
SmallFont2 = SmallFont;
|
||||
}
|
||||
if (BigFont == nullptr)
|
||||
{
|
||||
BigFont = OriginalBigFont;
|
||||
}
|
||||
AlternativeSmallFont = OriginalSmallFont;
|
||||
AlternativeBigFont = OriginalBigFont;
|
||||
ConFont = V_GetFont("ConsoleFont", "CONFONT");
|
||||
}
|
||||
|
||||
void V_LoadTranslations()
|
||||
|
@ -827,24 +858,44 @@ void V_LoadTranslations()
|
|||
for (auto font = FFont::FirstFont; font; font = font->Next)
|
||||
{
|
||||
if (!font->noTranslate) font->LoadTranslations();
|
||||
else font->ActiveColors = 0;
|
||||
}
|
||||
|
||||
if (BigFont)
|
||||
{
|
||||
uint32_t colors[256] = {};
|
||||
BigFont->RecordAllTextureColors(colors);
|
||||
if (OriginalBigFont != nullptr) OriginalBigFont->SetDefaultTranslation(colors);
|
||||
CalcDefaultTranslation(BigFont, CR_UNTRANSLATED * 2 + 1);
|
||||
if (OriginalBigFont != nullptr && OriginalBigFont != BigFont)
|
||||
{
|
||||
int sometrans = OriginalBigFont->Translations[0];
|
||||
sometrans &= ~(0x3fff << 16);
|
||||
sometrans |= (CR_UNTRANSLATED * 2 + 1) << 16;
|
||||
OriginalBigFont->Translations[CR_UNTRANSLATED] = sometrans;
|
||||
OriginalBigFont->forceremap = true;
|
||||
}
|
||||
}
|
||||
if (SmallFont)
|
||||
{
|
||||
uint32_t colors[256] = {};
|
||||
SmallFont->RecordAllTextureColors(colors);
|
||||
if (OriginalSmallFont != nullptr) OriginalSmallFont->SetDefaultTranslation(colors);
|
||||
NewSmallFont->SetDefaultTranslation(colors);
|
||||
CalcDefaultTranslation(SmallFont, CR_UNTRANSLATED * 2);
|
||||
if (OriginalSmallFont != nullptr && OriginalSmallFont != SmallFont)
|
||||
{
|
||||
int sometrans = OriginalSmallFont->Translations[0];
|
||||
sometrans &= ~(0x3fff << 16);
|
||||
sometrans |= (CR_UNTRANSLATED * 2) << 16;
|
||||
OriginalSmallFont->Translations[CR_UNTRANSLATED] = sometrans;
|
||||
OriginalSmallFont->forceremap = true;
|
||||
}
|
||||
if (NewSmallFont != nullptr)
|
||||
{
|
||||
int sometrans = NewSmallFont->Translations[0];
|
||||
sometrans &= ~(0x3fff << 16);
|
||||
sometrans |= (CR_UNTRANSLATED * 2) << 16;
|
||||
NewSmallFont->Translations[CR_UNTRANSLATED] = sometrans;
|
||||
NewSmallFont->forceremap = true;
|
||||
}
|
||||
}
|
||||
translationsLoaded = true;
|
||||
}
|
||||
|
||||
|
||||
void V_ClearFonts()
|
||||
{
|
||||
while (FFont::FirstFont != nullptr)
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const;
|
||||
int GetLump() const { return Lump; }
|
||||
|
@ -128,22 +128,19 @@ public:
|
|||
void SetKerning(int c) { GlobalKerning = c; }
|
||||
bool NoTranslate() const { return noTranslate; }
|
||||
virtual void RecordAllTextureColors(uint32_t *usedcolors);
|
||||
virtual void SetDefaultTranslation(uint32_t *colors);
|
||||
void CheckCase();
|
||||
|
||||
int GetDisplacement() const { return Displacement; }
|
||||
|
||||
static int GetLuminosity(uint32_t* colorsused, TArray<double>& Luminosity, int* minlum = nullptr, int* maxlum = nullptr);
|
||||
EFontType GetType() const { return Type; }
|
||||
|
||||
|
||||
protected:
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
EFontType Type = EFontType::Unknown;
|
||||
|
@ -161,12 +158,10 @@ protected:
|
|||
bool forceremap = false;
|
||||
struct CharData
|
||||
{
|
||||
FGameTexture *TranslatedPic = nullptr; // Texture for use with font translations.
|
||||
FGameTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization.
|
||||
FGameTexture *OriginalPic = nullptr;
|
||||
int XMove = INT_MIN;
|
||||
};
|
||||
TArray<CharData> Chars;
|
||||
int ActiveColors = -1;
|
||||
TArray<int> Translations;
|
||||
uint8_t PatchRemap[256];
|
||||
|
||||
|
@ -192,6 +187,8 @@ EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int
|
|||
FFont *V_GetFont(const char *fontname, const char *fontlumpname = nullptr);
|
||||
void V_InitFontColors();
|
||||
char* CleanseString(char* str);
|
||||
void V_ApplyLuminosityTranslation(int translation, uint8_t* pixel, int size);
|
||||
void V_LoadTranslations();
|
||||
class FBitmap;
|
||||
|
||||
|
||||
|
|
|
@ -240,13 +240,12 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length
|
|||
*/
|
||||
template<typename T, size_t L> void FOBJModel::ParseVector(TArray<T> &array)
|
||||
{
|
||||
float coord[L];
|
||||
for (size_t axis = 0; axis < L; axis++)
|
||||
T vec;
|
||||
for (unsigned axis = 0; axis < L; axis++)
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
coord[axis] = (float)sc.Float;
|
||||
vec[axis] = (float)sc.Float;
|
||||
}
|
||||
T vec(coord);
|
||||
array.Push(vec);
|
||||
}
|
||||
|
||||
|
|
|
@ -101,8 +101,9 @@ void I_DetectOS()
|
|||
|
||||
const char* name = "Unknown version";
|
||||
|
||||
if (10 == version.majorVersion)
|
||||
switch (version.majorVersion)
|
||||
{
|
||||
case 10:
|
||||
switch (version.minorVersion)
|
||||
{
|
||||
case 9: name = "OS X Mavericks"; break;
|
||||
|
@ -114,13 +115,13 @@ void I_DetectOS()
|
|||
case 15: name = "macOS Catalina"; break;
|
||||
case 16: name = "macOS Big Sur"; break;
|
||||
}
|
||||
}
|
||||
else if (11 == version.majorVersion)
|
||||
{
|
||||
switch (version.minorVersion)
|
||||
{
|
||||
case 0: name = "macOS Big Sur"; break;
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
name = "macOS Big Sur";
|
||||
break;
|
||||
case 12:
|
||||
name = "macOS Monterey";
|
||||
break;
|
||||
}
|
||||
|
||||
char release[16] = "unknown";
|
||||
|
|
|
@ -204,7 +204,7 @@ bool FGLRenderState::ApplyShader()
|
|||
size_t start, size;
|
||||
index = screen->mLights->GetBinding(index, &start, &size);
|
||||
|
||||
if (start != mLastMappedLightIndex)
|
||||
if (start != mLastMappedLightIndex || screen->mPipelineNbr > 1) // If multiple buffers always bind
|
||||
{
|
||||
mLastMappedLightIndex = start;
|
||||
static_cast<GLDataBuffer*>(screen->mLights->GetBuffer())->BindRange(nullptr, start, size);
|
||||
|
|
|
@ -1449,7 +1449,7 @@ FxFontCast::FxFontCast(FxExpression *x)
|
|||
: FxExpression(EFX_FontCast, x->ScriptPosition)
|
||||
{
|
||||
basex = x;
|
||||
ValueType = TypeSound;
|
||||
ValueType = TypeFont;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -964,10 +964,16 @@ DEFINE_ACTION_FUNCTION(FKeyBindings, UnbindACommand)
|
|||
// This is only accessible to the special menu item to run CCMDs.
|
||||
DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand)
|
||||
{
|
||||
if (CurrentMenu == nullptr) return 0;
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_STRING(cmd);
|
||||
PARAM_BOOL(unsafe);
|
||||
|
||||
// Only menus are allowed to execute CCMDs.
|
||||
if (DMenu::InMenu == 0)
|
||||
{
|
||||
I_FatalError("Attempt to execute CCMD '%s' outside of menu code", cmd.GetChars());
|
||||
}
|
||||
|
||||
UnsafeExecutionScope scope(unsafe);
|
||||
C_DoCommand(cmd);
|
||||
return 0;
|
||||
|
|
|
@ -198,6 +198,11 @@ public:
|
|||
return Pitch;
|
||||
}
|
||||
|
||||
int GetBufferSize() const
|
||||
{
|
||||
return Pitch * Height;
|
||||
}
|
||||
|
||||
const uint8_t *GetPixels() const
|
||||
{
|
||||
return data;
|
||||
|
|
|
@ -41,48 +41,6 @@
|
|||
#include "fontchars.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
|
||||
|
@ -91,8 +49,8 @@ TArray<uint8_t> FFontChar1::CreatePalettedPixels (int)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs)
|
||||
: SourceLump (sourcelump), SourcePos (sourcepos), SourceRemap(nullptr)
|
||||
FFontChar2::FFontChar2(int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs)
|
||||
: SourceLump(sourcelump), SourcePos(sourcepos)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
|
@ -100,17 +58,6 @@ FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, in
|
|||
TopOffset = topofs;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FFontChar2 :: SetSourceRemap
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFontChar2::SetSourceRemap(const uint8_t *sourceremap)
|
||||
{
|
||||
SourceRemap = sourceremap;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FFontChar2 :: Get8BitPixels
|
||||
|
@ -121,7 +68,7 @@ void FFontChar2::SetSourceRemap(const uint8_t *sourceremap)
|
|||
|
||||
TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
||||
{
|
||||
auto lump = fileSystem.OpenFileReader (SourceLump);
|
||||
auto lump = fileSystem.OpenFileReader(SourceLump);
|
||||
int destSize = Width * Height;
|
||||
uint8_t max = 255;
|
||||
bool rle = true;
|
||||
|
@ -129,23 +76,23 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
|||
// This is to "fix" bad fonts
|
||||
{
|
||||
uint8_t buff[16];
|
||||
lump.Read (buff, 4);
|
||||
lump.Read(buff, 4);
|
||||
if (buff[3] == '2')
|
||||
{
|
||||
lump.Read (buff, 7);
|
||||
lump.Read(buff, 7);
|
||||
max = buff[6];
|
||||
lump.Seek (SourcePos - 11, FileReader::SeekCur);
|
||||
lump.Seek(SourcePos - 11, FileReader::SeekCur);
|
||||
}
|
||||
else if (buff[3] == 0x1A)
|
||||
{
|
||||
lump.Read(buff, 13);
|
||||
max = buff[12] - 1;
|
||||
lump.Seek (SourcePos - 17, FileReader::SeekCur);
|
||||
lump.Seek(SourcePos - 17, FileReader::SeekCur);
|
||||
rle = false;
|
||||
}
|
||||
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;
|
||||
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_rew = destSize - 1;
|
||||
|
||||
|
@ -166,11 +113,7 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
|||
if (runlen != 0)
|
||||
{
|
||||
uint8_t color = lump.ReadUInt8();
|
||||
color = MIN (color, max);
|
||||
if (SourceRemap != nullptr)
|
||||
{
|
||||
color = SourceRemap[color];
|
||||
}
|
||||
color = MIN(color, max);
|
||||
*dest_p = color;
|
||||
dest_p += dest_adv;
|
||||
x--;
|
||||
|
@ -194,11 +137,7 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
|||
{
|
||||
uint8_t color = lump.ReadUInt8();
|
||||
setlen = (-code) + 1;
|
||||
setval = MIN (color, max);
|
||||
if (SourceRemap != nullptr)
|
||||
{
|
||||
setval = SourceRemap[setval];
|
||||
}
|
||||
setval = MIN(color, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -216,10 +155,6 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
|||
{
|
||||
color = max;
|
||||
}
|
||||
if (SourceRemap != nullptr)
|
||||
{
|
||||
color = SourceRemap[color];
|
||||
}
|
||||
*dest_p = color;
|
||||
dest_p += dest_adv;
|
||||
}
|
||||
|
@ -230,10 +165,17 @@ TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
|
|||
if (destSize < 0)
|
||||
{
|
||||
char name[9];
|
||||
fileSystem.GetFileShortName (name, SourceLump);
|
||||
fileSystem.GetFileShortName(name, SourceLump);
|
||||
name[8] = 0;
|
||||
I_FatalError ("The font %s is corrupt", name);
|
||||
I_FatalError("The font %s is corrupt", name);
|
||||
}
|
||||
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.
|
||||
class FFontChar2 : public FImageSource
|
||||
{
|
||||
|
@ -23,10 +7,15 @@ public:
|
|||
FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0);
|
||||
|
||||
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:
|
||||
int SourceLump;
|
||||
int SourcePos;
|
||||
const uint8_t *SourceRemap;
|
||||
const PalEntry *SourceRemap;
|
||||
};
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "c_cvars.h"
|
||||
#include "v_video.h"
|
||||
|
||||
|
||||
CVAR(Bool, gl_customshader, true, 0);
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
if (translation >= 0)
|
||||
{
|
||||
auto remap = GPalette.TranslationToTable(translation);
|
||||
translation = remap == nullptr ? 0 : remap->Index;
|
||||
if (!IsLuminosityTranslation(translation))
|
||||
{
|
||||
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;
|
||||
|
||||
|
|
|
@ -321,6 +321,7 @@ bool FTexture::ProcessData(unsigned char* buffer, int w, int h, bool ispatch)
|
|||
// Initializes the buffer for the texture data
|
||||
//
|
||||
//===========================================================================
|
||||
void V_ApplyLuminosityTranslation(int translation, uint8_t *buffer, int size);
|
||||
|
||||
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];
|
||||
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) translation = remap->Index;
|
||||
FBitmap bmp(buffer, W * 4, W, H);
|
||||
|
@ -364,6 +365,10 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
|
|||
int trans;
|
||||
auto Pixels = GetBgraBitmap(remap ? remap->Palette : nullptr, &trans);
|
||||
bmp.Blit(exx, exx, Pixels);
|
||||
if (IsLuminosityTranslation(translation))
|
||||
{
|
||||
V_ApplyLuminosityTranslation(translation, buffer, W * H);
|
||||
}
|
||||
|
||||
if (remap == nullptr)
|
||||
{
|
||||
|
|
|
@ -354,6 +354,8 @@ int getAlternative(int code)
|
|||
default:
|
||||
return code;
|
||||
|
||||
case '{': return '(';
|
||||
case '}': return ')';
|
||||
case 0x17f: return 's'; // The 'long s' can be safely remapped to the regular variant, not that this gets used in any real text...
|
||||
case 0x218: return 0x15e; // Romanian S with comma below may get remapped to S with cedilla.
|
||||
case 0x219: return 0x15f;
|
||||
|
|
|
@ -82,6 +82,11 @@ struct TVector2
|
|||
{
|
||||
}
|
||||
|
||||
TVector2(vec_t *o)
|
||||
: X(o[0]), Y(o[1])
|
||||
{
|
||||
}
|
||||
|
||||
void Zero()
|
||||
{
|
||||
Y = X = 0;
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
#include "texturemanager.h"
|
||||
#include "hw_clock.h"
|
||||
#include "hwrenderer/scene/hw_drawinfo.h"
|
||||
#include "doomfont.h"
|
||||
|
||||
#ifdef __unix__
|
||||
#include "i_system.h" // for SHARE_DIR
|
||||
|
@ -3409,6 +3410,7 @@ static int D_DoomMain_Internal (void)
|
|||
|
||||
StartScreen->Progress();
|
||||
V_InitFonts();
|
||||
InitDoomFonts();
|
||||
V_LoadTranslations();
|
||||
UpdateGenericUI(false);
|
||||
|
||||
|
|
|
@ -2033,7 +2033,7 @@ static int PatchPars (int dummy)
|
|||
{
|
||||
while ('\0' != *str)
|
||||
{
|
||||
if (isspace((unsigned char)*str))
|
||||
if (*str != '\r' && isspace((unsigned char)*str))
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
|
147
src/gamedata/doomfont.h
Normal file
147
src/gamedata/doomfont.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
//
|
||||
// Globally visible constants.
|
||||
//
|
||||
#define HU_FONTSTART uint8_t('!') // the first font characters
|
||||
#define HU_FONTEND uint8_t('\377') // the last font characters
|
||||
|
||||
// Calculate # of glyphs in font.
|
||||
#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
|
||||
|
||||
|
||||
|
||||
void InitDoomFonts()
|
||||
{
|
||||
// load the heads-up font
|
||||
if (!(SmallFont = V_GetFont("SmallFont", "SMALLFNT")))
|
||||
{
|
||||
if (fileSystem.CheckNumForName("FONTA_S") >= 0)
|
||||
{
|
||||
int wadfile = -1;
|
||||
auto a = fileSystem.CheckNumForName("FONTA33", ns_graphics);
|
||||
if (a != -1) wadfile = fileSystem.GetFileContainer(a);
|
||||
if (wadfile > fileSystem.GetIwadNum())
|
||||
{
|
||||
// The font has been replaced, so we need to create a copy of the original as well.
|
||||
SmallFont = new FFont("SmallFont", "FONTA%02u", nullptr, HU_FONTSTART, HU_FONTSIZE, 1, -1);
|
||||
SmallFont->SetCursor('[');
|
||||
}
|
||||
else
|
||||
{
|
||||
SmallFont = new FFont("SmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
|
||||
SmallFont->SetCursor('[');
|
||||
}
|
||||
}
|
||||
else if (fileSystem.CheckNumForName("STCFN033", ns_graphics) >= 0)
|
||||
{
|
||||
int wadfile = -1;
|
||||
auto a = fileSystem.CheckNumForName("STCFN065", ns_graphics);
|
||||
if (a != -1) wadfile = fileSystem.GetFileContainer(a);
|
||||
if (wadfile > fileSystem.GetIwadNum())
|
||||
{
|
||||
// The font has been replaced, so we need to create a copy of the original as well.
|
||||
SmallFont = new FFont("SmallFont", "STCFN%.3d", nullptr, HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SmallFont = new FFont("SmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the original small font as a fallback for incomplete definitions.
|
||||
if (fileSystem.CheckNumForName("FONTA_S") >= 0)
|
||||
{
|
||||
OriginalSmallFont = new FFont("OriginalSmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true);
|
||||
OriginalSmallFont->SetCursor('[');
|
||||
}
|
||||
else if (fileSystem.CheckNumForName("STCFN033", ns_graphics) >= 0)
|
||||
{
|
||||
OriginalSmallFont = new FFont("OriginalSmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, true);
|
||||
}
|
||||
|
||||
|
||||
if (!(SmallFont2 = V_GetFont("SmallFont2"))) // Only used by Strife
|
||||
{
|
||||
if (fileSystem.CheckNumForName("STBFN033", ns_graphics) >= 0)
|
||||
{
|
||||
SmallFont2 = new FFont("SmallFont2", "STBFN%.3d", "defsmallfont2", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
|
||||
}
|
||||
}
|
||||
|
||||
//This must be read before BigFont so that it can be properly substituted.
|
||||
BigUpper = V_GetFont("BigUpper");
|
||||
|
||||
if (!(BigFont = V_GetFont("BigFont")))
|
||||
{
|
||||
if (fileSystem.CheckNumForName("FONTB_S") >= 0)
|
||||
{
|
||||
BigFont = new FFont("BigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!BigFont)
|
||||
{
|
||||
// Load the generic fallback if no BigFont is found.
|
||||
BigFont = V_GetFont("BigFont", "ZBIGFONT");
|
||||
}
|
||||
|
||||
if (fileSystem.CheckNumForName("FONTB_S") >= 0)
|
||||
{
|
||||
OriginalBigFont = new FFont("OriginalBigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
OriginalBigFont = new FFont("OriginalBigFont", nullptr, "bigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true);
|
||||
}
|
||||
|
||||
// let PWAD BIGFONTs override the stock BIGUPPER font. (This check needs to be made smarter.)
|
||||
if (BigUpper && BigFont->GetType() != FFont::Folder && BigUpper->GetType() == FFont::Folder)
|
||||
{
|
||||
delete BigUpper;
|
||||
BigUpper = BigFont;
|
||||
}
|
||||
|
||||
if (BigUpper == nullptr)
|
||||
{
|
||||
BigUpper = BigFont;
|
||||
}
|
||||
if (!ConFont)
|
||||
{
|
||||
ConFont = SmallFont;
|
||||
}
|
||||
if (!(IntermissionFont = FFont::FindFont("IntermissionFont")))
|
||||
{
|
||||
if (TexMan.CheckForTexture("WINUM0", ETextureType::MiscPatch).isValid())
|
||||
{
|
||||
IntermissionFont = FFont::FindFont("IntermissionFont_Doom");
|
||||
}
|
||||
if (IntermissionFont == nullptr)
|
||||
{
|
||||
IntermissionFont = BigFont;
|
||||
}
|
||||
}
|
||||
// This can only happen if gzdoom.pk3 is corrupted. ConFont should always be present.
|
||||
if (ConFont == nullptr)
|
||||
{
|
||||
I_FatalError("Console font not found.");
|
||||
}
|
||||
// SmallFont and SmallFont2 have no default provided by the engine. BigFont only has in non-Raven games.
|
||||
if (OriginalSmallFont == nullptr)
|
||||
{
|
||||
OriginalSmallFont = ConFont;
|
||||
}
|
||||
if (SmallFont == nullptr)
|
||||
{
|
||||
SmallFont = OriginalSmallFont;
|
||||
}
|
||||
if (SmallFont2 == nullptr)
|
||||
{
|
||||
SmallFont2 = SmallFont;
|
||||
}
|
||||
if (BigFont == nullptr)
|
||||
{
|
||||
BigFont = OriginalBigFont;
|
||||
}
|
||||
AlternativeSmallFont = OriginalSmallFont;
|
||||
AlternativeBigFont = OriginalBigFont;
|
||||
}
|
|
@ -438,6 +438,7 @@ void FMapInfoParser::ParseGameInfo()
|
|||
GAMEINFOKEY_BOOL(norandomplayerclass, "norandomplayerclass")
|
||||
GAMEINFOKEY_BOOL(forcekillscripts, "forcekillscripts") // [JM] Force kill scripts on thing death. (MF7_NOKILLSCRIPTS overrides.)
|
||||
GAMEINFOKEY_STRING(Dialogue, "dialogue")
|
||||
GAMEINFOKEY_STRINGARRAY(AddDialogues, "adddialogues", 0, false)
|
||||
GAMEINFOKEY_STRING(statusscreen_single, "statscreen_single")
|
||||
GAMEINFOKEY_STRING(statusscreen_coop, "statscreen_coop")
|
||||
GAMEINFOKEY_STRING(statusscreen_dm, "statscreen_dm")
|
||||
|
|
|
@ -192,6 +192,7 @@ struct gameinfo_t
|
|||
FString mMapArrow, mCheatMapArrow;
|
||||
FString mEasyKey, mCheatKey;
|
||||
FString Dialogue;
|
||||
TArray<FString> AddDialogues;
|
||||
FGIFont mStatscreenMapNameFont;
|
||||
FGIFont mStatscreenFinishedFont;
|
||||
FGIFont mStatscreenEnteringFont;
|
||||
|
|
|
@ -105,6 +105,20 @@ void MapLoader::LoadStrifeConversations (MapData *map, const char *mapname)
|
|||
}
|
||||
else
|
||||
{
|
||||
// additive dialogues via MAPINFO
|
||||
bool addedDialogues = false;
|
||||
for (const FString &addd : gameinfo.AddDialogues)
|
||||
{
|
||||
if (!LoadScriptFile(addd, true, 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
addedDialogues = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (strnicmp (mapname, "MAP", 3) == 0)
|
||||
{
|
||||
char scriptname_b[9] = { 'S','C','R','I','P','T',mapname[3],mapname[4],0 };
|
||||
|
@ -121,6 +135,10 @@ void MapLoader::LoadStrifeConversations (MapData *map, const char *mapname)
|
|||
{
|
||||
if (LoadScriptFile(gameinfo.Dialogue, false, 0))
|
||||
{
|
||||
if (addedDialogues)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Warning! Dialogue was mixed with AddDialogues! Previous AddDialogues have been overwritten\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -748,6 +748,7 @@ void AActor::AttachLight(unsigned int count, const FLightDefaults *lightdef)
|
|||
AttachedLights.Push(light);
|
||||
}
|
||||
lightdef->ApplyProperties(light);
|
||||
light->UpdateLocation();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -391,6 +391,7 @@ public:
|
|||
float BlendB = 0;
|
||||
float BlendA = 0;
|
||||
|
||||
FString SoundClass;
|
||||
FString LogText; // [RH] Log for Strife
|
||||
FString SubtitleText;
|
||||
int SubtitleCounter;
|
||||
|
|
|
@ -4044,6 +4044,7 @@ enum
|
|||
APROP_MaxStepHeight = 44,
|
||||
APROP_MaxDropOffHeight= 45,
|
||||
APROP_DamageType = 46,
|
||||
APROP_SoundClass = 47,
|
||||
};
|
||||
|
||||
// These are needed for ACS's APROP_RenderStyle
|
||||
|
@ -4307,6 +4308,16 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
|
|||
actor->DamageType = Level->Behaviors.LookupString(value);
|
||||
break;
|
||||
|
||||
case APROP_SoundClass:
|
||||
if (actor->IsKindOf(NAME_PlayerPawn))
|
||||
{
|
||||
if (actor->player != nullptr)
|
||||
{
|
||||
actor->player->SoundClass = Level->Behaviors.LookupString(value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing.
|
||||
break;
|
||||
|
@ -4404,6 +4415,7 @@ int DLevelScript::GetActorProperty (int tid, int property)
|
|||
case APROP_MaxStepHeight: return DoubleToACS(actor->MaxStepHeight);
|
||||
case APROP_MaxDropOffHeight: return DoubleToACS(actor->MaxDropOffHeight);
|
||||
case APROP_DamageType: return GlobalACSStrings.AddString(actor->DamageType.GetChars());
|
||||
case APROP_SoundClass: return GlobalACSStrings.AddString(S_GetSoundClass(actor));
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
|
@ -4477,6 +4489,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value)
|
|||
case APROP_Species: string = actor->GetSpecies().GetChars(); break;
|
||||
case APROP_NameTag: string = actor->GetTag(); break;
|
||||
case APROP_DamageType: string = actor->DamageType.GetChars(); break;
|
||||
case APROP_SoundClass: string = S_GetSoundClass(actor); break;
|
||||
}
|
||||
if (string == NULL) string = "";
|
||||
return (!stricmp(string, Level->Behaviors.LookupString(value)));
|
||||
|
|
|
@ -347,6 +347,7 @@ void player_t::CopyFrom(player_t &p, bool copyPSP)
|
|||
ConversationFaceTalker = p.ConversationFaceTalker;
|
||||
MUSINFOactor = p.MUSINFOactor;
|
||||
MUSINFOtics = p.MUSINFOtics;
|
||||
SoundClass = p.SoundClass;
|
||||
if (copyPSP)
|
||||
{
|
||||
// This needs to transfer ownership completely.
|
||||
|
@ -1696,7 +1697,8 @@ void player_t::Serialize(FSerializer &arc)
|
|||
("settings_controller", settings_controller)
|
||||
("onground", onground)
|
||||
("musinfoactor", MUSINFOactor)
|
||||
("musinfotics", MUSINFOtics);
|
||||
("musinfotics", MUSINFOtics)
|
||||
("soundclass", SoundClass);
|
||||
|
||||
if (arc.isWriting ())
|
||||
{
|
||||
|
@ -1812,6 +1814,7 @@ DEFINE_FIELD_X(PlayerInfo, player_t, original_cmd)
|
|||
DEFINE_FIELD_X(PlayerInfo, player_t, userinfo)
|
||||
DEFINE_FIELD_X(PlayerInfo, player_t, weapons)
|
||||
DEFINE_FIELD_NAMED_X(PlayerInfo, player_t, cmd.ucmd.buttons, buttons)
|
||||
DEFINE_FIELD_X(PlayerInfo, player_t, SoundClass)
|
||||
|
||||
DEFINE_FIELD_X(UserCmd, usercmd_t, buttons)
|
||||
DEFINE_FIELD_X(UserCmd, usercmd_t, pitch)
|
||||
|
|
|
@ -413,25 +413,18 @@ static void ParseModelDefLump(int Lump)
|
|||
{
|
||||
smf.modelsAmount = MIN_MODELS;
|
||||
}
|
||||
//Allocate TArrays
|
||||
smf.modelIDs.Alloc(smf.modelsAmount);
|
||||
smf.skinIDs.Alloc(smf.modelsAmount);
|
||||
smf.surfaceskinIDs.Alloc(smf.modelsAmount * MD3_MAX_SURFACES);
|
||||
smf.modelframes.Alloc(smf.modelsAmount);
|
||||
//Make sure all modelIDs are -1 by default
|
||||
for (auto& modelID : smf.modelIDs)
|
||||
|
||||
const auto initArray = [](auto& array, const unsigned count, const auto value)
|
||||
{
|
||||
modelID = -1;
|
||||
}
|
||||
//Make sure no TArray elements of type FTextureID are null. These elements will have a textureid (FTextureID.texnum) of 0.
|
||||
for (auto& skinID : smf.skinIDs)
|
||||
{
|
||||
skinID = FTextureID(FNullTextureID());
|
||||
}
|
||||
for (auto& surfaceskinID : smf.surfaceskinIDs)
|
||||
{
|
||||
surfaceskinID = FTextureID(FNullTextureID());
|
||||
}
|
||||
array.Alloc(count);
|
||||
std::fill(array.begin(), array.end(), value);
|
||||
};
|
||||
|
||||
initArray(smf.modelIDs, smf.modelsAmount, -1);
|
||||
initArray(smf.skinIDs, smf.modelsAmount, FNullTextureID());
|
||||
initArray(smf.surfaceskinIDs, smf.modelsAmount * MD3_MAX_SURFACES, FNullTextureID());
|
||||
initArray(smf.modelframes, smf.modelsAmount, 0);
|
||||
|
||||
sc.RestorePos(scPos);
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
|
|
|
@ -159,6 +159,9 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
|
|||
|
||||
di->ProcessScene(toscreen);
|
||||
|
||||
// Reset colormap so 2D drawing isn't affected
|
||||
RenderState.SetSpecialColormap(CM_DEFAULT, 1);
|
||||
|
||||
if (mainview)
|
||||
{
|
||||
PostProcess.Clock();
|
||||
|
|
|
@ -800,9 +800,8 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
{
|
||||
z = thing->floorz;
|
||||
}
|
||||
|
||||
// [RH] Make floatbobbing a renderer-only effect.
|
||||
if (thing->flags2 & MF2_FLOATBOB)
|
||||
else if (thing->flags2 & MF2_FLOATBOB)
|
||||
{
|
||||
float fz = thing->GetBobOffset(vp.TicFrac);
|
||||
z += fz;
|
||||
|
|
|
@ -80,14 +80,12 @@ void InitSkyMap(FLevelLocals *Level)
|
|||
Level->skytexture1 = TexMan.GetFrontSkyLayer(Level->skytexture1);
|
||||
}
|
||||
|
||||
|
||||
skytex1 = TexMan.GetGameTexture(Level->skytexture1, false);
|
||||
skytex2 = TexMan.GetGameTexture(Level->skytexture2, false);
|
||||
|
||||
if (skytex1 == nullptr)
|
||||
if (skytex1 == nullptr || skytex2 == nullptr)
|
||||
return;
|
||||
|
||||
|
||||
if ((Level->flags & LEVEL_DOUBLESKY) && skytex1->GetDisplayHeight() != skytex2->GetDisplayHeight())
|
||||
{
|
||||
Printf(TEXTCOLOR_BOLD "Both sky textures must be the same height." TEXTCOLOR_NORMAL "\n");
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace swrenderer
|
|||
auto sskytex1 = GetPalettedSWTexture(Level->skytexture1, true, false, true);
|
||||
auto sskytex2 = GetPalettedSWTexture(Level->skytexture2, true, false, true);
|
||||
|
||||
if (sskytex1 == nullptr)
|
||||
if (sskytex1 == nullptr || sskytex2 == nullptr)
|
||||
return;
|
||||
|
||||
skytexturemid = 0;
|
||||
|
|
|
@ -1608,19 +1608,20 @@ bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
static const char *GetSoundClass(AActor *pp)
|
||||
const char *S_GetSoundClass(AActor *pp)
|
||||
{
|
||||
auto player = pp->player;
|
||||
const char *defaultsoundclass = pp->NameVar(NAME_SoundClass) == NAME_None ? "player" : pp->NameVar(NAME_SoundClass).GetChars();
|
||||
if (player != nullptr &&
|
||||
(player->mo == nullptr || !(player->mo->flags4 &MF4_NOSKIN)) &&
|
||||
(unsigned int)player->userinfo.GetSkin() >= PlayerClasses.Size() &&
|
||||
(unsigned)player->userinfo.GetSkin() < Skins.Size())
|
||||
(unsigned)player->userinfo.GetSkin() < Skins.Size() &&
|
||||
player->SoundClass.IsEmpty())
|
||||
{
|
||||
return Skins[player->userinfo.GetSkin()].Name.GetChars();
|
||||
}
|
||||
auto sclass = player? pp->NameVar(NAME_SoundClass) : NAME_None;
|
||||
|
||||
return sclass != NAME_None ? sclass.GetChars() : "player";
|
||||
|
||||
return player->SoundClass.IsEmpty() ? defaultsoundclass : player->SoundClass.GetChars();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1635,10 +1636,10 @@ int S_FindSkinnedSound (AActor *actor, FSoundID refid)
|
|||
const char *pclass;
|
||||
int gender = 0;
|
||||
|
||||
if (actor != nullptr)
|
||||
if (actor != nullptr && actor->player != nullptr)
|
||||
{
|
||||
pclass = GetSoundClass (actor);
|
||||
if (actor->player != nullptr) gender = actor->player->userinfo.GetGender();
|
||||
pclass = S_GetSoundClass(actor);
|
||||
gender = actor->player->userinfo.GetGender();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1682,7 +1683,7 @@ int S_FindSkinnedSoundEx (AActor *actor, const char *name, const char *extendedn
|
|||
|
||||
void S_MarkPlayerSounds (AActor *player)
|
||||
{
|
||||
const char *playerclass = GetSoundClass(player);
|
||||
const char *playerclass = S_GetSoundClass(player);
|
||||
int classidx = S_FindPlayerClass(playerclass);
|
||||
if (classidx < 0)
|
||||
{
|
||||
|
@ -1696,6 +1697,7 @@ void S_MarkPlayerSounds (AActor *player)
|
|||
PlayerSounds[listidx].MarkUsed();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -395,7 +395,7 @@ void DSeqNode::OnDestroy()
|
|||
m_ParentSeqNode->m_ChildSeqNode = nullptr;
|
||||
m_ParentSeqNode = nullptr;
|
||||
}
|
||||
if (Level->SequenceListHead == this)
|
||||
if (Level && Level->SequenceListHead == this)
|
||||
{
|
||||
Level->SequenceListHead = m_Next;
|
||||
GC::WriteBarrier(m_Next);
|
||||
|
|
|
@ -70,6 +70,7 @@ bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2);
|
|||
bool S_AreSoundsEquivalent (AActor *actor, const char *name1, const char *name2);
|
||||
int S_LookupPlayerSound (const char *playerclass, int gender, const char *logicalname);
|
||||
int S_LookupPlayerSound (const char *playerclass, int gender, FSoundID refid);
|
||||
const char *S_GetSoundClass(AActor *pp);
|
||||
int S_FindSkinnedSound (AActor *actor, FSoundID refid);
|
||||
int S_FindSkinnedSoundEx (AActor *actor, const char *logicalname, const char *extendedname);
|
||||
int S_AddSound (const char *logicalname, const char *lumpname, FScanner *sc=NULL); // Add sound by lumpname
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// MAPINFO for Heretic (Shareware and Retail)
|
||||
// MAPINFO for Heretic (Retail)
|
||||
include "mapinfo/common.txt"
|
||||
|
||||
gameinfo
|
||||
|
|
7
wadsrc/static/mapinfo/hereticshareware.txt
Normal file
7
wadsrc/static/mapinfo/hereticshareware.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
// MAPINFO for Heretic (Shareware)
|
||||
include "mapinfo/heretic.txt"
|
||||
|
||||
gameinfo
|
||||
{
|
||||
borderflat = "FLOOR04"
|
||||
}
|
|
@ -146,7 +146,7 @@ extend class Actor
|
|||
bInCombat = true;
|
||||
|
||||
self.target = target;
|
||||
let painstate = FindState('Pain', 'Dagger');
|
||||
let painstate = FindState('Pain.Dagger');
|
||||
if (painstate != NULL)
|
||||
{
|
||||
SetState(painstate);
|
||||
|
|
|
@ -63,7 +63,7 @@ class Bishop : Actor
|
|||
BISH J 5 BRIGHT A_Explode(random[BishopBoom](25,40));
|
||||
BISH K 5 Bright;
|
||||
BISH LM 4 Bright;
|
||||
BISH N 4 A_SpawnItemEx("BishopPuff", 0,0,40, 0,0,-0.5);
|
||||
BISH N 4 A_SpawnItemEx("BishopPuff", 0,0,40, 0,0,0.5);
|
||||
BISH O 4 A_QueueCorpse;
|
||||
BISH P -1;
|
||||
Stop;
|
||||
|
|
|
@ -185,7 +185,7 @@ class CircleFlame : Actor
|
|||
Stop;
|
||||
Death:
|
||||
CFCF QR 3 Bright;
|
||||
CFCF S 3 Bright A_Explode(20, 20, 0);
|
||||
CFCF S 3 Bright A_Explode(20, 128, 0);
|
||||
CFCF TUVWXYZ 3 Bright;
|
||||
Stop;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ class FastProjectile : Actor
|
|||
tm.ClearLastRipped(); // [RH] Do rip damage each step, like Hexen
|
||||
}
|
||||
|
||||
if (!TryMove (Pos.XY + frac.XY, true, NULL, tm))
|
||||
if (!TryMove (Pos.XY + frac.XY, true, false, tm))
|
||||
{ // Blocked move
|
||||
if (!bSkyExplode)
|
||||
{
|
||||
|
|
|
@ -2112,6 +2112,21 @@ class LevelCompatibility : LevelPostProcessor
|
|||
{
|
||||
SetLineFlags(1461, Line.ML_REPEAT_SPECIAL);
|
||||
SetLineFlags(1468, Line.ML_REPEAT_SPECIAL);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'E0D747B9EE58A0CB74B9AD54423AC15C': // return01.wad e1m2
|
||||
{
|
||||
// fix broken switch to raise the exit bridge
|
||||
SetLineSpecial(1248, Floor_RaiseByValue, 39, 8, 512);
|
||||
break;
|
||||
}
|
||||
|
||||
case '1C35384B22BD805F51B3B2C9D17D62E4': // 007ltsd.wad E4M7
|
||||
{
|
||||
// Fix impassable exit line
|
||||
SetLineFlags(6842, 0, Line.ML_BLOCKING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,7 +264,7 @@ IWad
|
|||
Name = "Heretic Shareware"
|
||||
Game = "Heretic"
|
||||
Config = "Heretic"
|
||||
Mapinfo = "mapinfo/heretic.txt"
|
||||
Mapinfo = "mapinfo/hereticshareware.txt"
|
||||
Compatibility = "Shareware"
|
||||
MustContain = "E1M1", "TITLE", "MUS_E1M1"
|
||||
BannerColors = "fc fc 00", "a8 00 00"
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d458411db4795dfd1420cf1c6456f6d2999b3bad
|
||||
Subproject commit 89dac47dbf874351e2d5a07a0bb33b7d1175ef28
|
Loading…
Reference in a new issue