- backend update from GZDoom.

This commit is contained in:
Christoph Oelckers 2020-10-24 17:30:47 +02:00
parent 8b03abcd00
commit c82d9d2908
28 changed files with 178 additions and 53 deletions

View file

@ -169,7 +169,7 @@ public:
float screenFade = 1.f;
DVector2 offset;
public:
int fullscreenautoaspect = 0;
int fullscreenautoaspect = 3;
int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1;
int AddCommand(const RenderCommand *data);

View file

@ -350,9 +350,9 @@ void CalcFullscreenScale(DrawParms *parms, double srcwidth, double srcheight, in
}
double aspect;
if (srcheight == 200) aspect = srcwidth / 240.;
else if (srcheight == 400) aspect = srcwidth / 480;
else aspect = srcwidth / srcheight;
if (srcheight == 200) srcheight = 240.;
else if (srcheight == 400) srcheight = 480;
aspect = srcwidth / srcheight;
rect.left = rect.top = 0;
auto screenratio = ActiveRatio(GetWidth(), GetHeight());
if (autoaspect == FSMode_ScaleToFit43 || autoaspect == FSMode_ScaleToFit43Top || autoaspect == FSMode_ScaleToFit43Bottom)
@ -366,7 +366,7 @@ void CalcFullscreenScale(DrawParms *parms, double srcwidth, double srcheight, in
double width4_3 = srcheight * (4. / 3.);
rect.width = (double)GetWidth() * srcwidth / width4_3;
rect.height = GetHeight() * screenratio * (3. / 4.); // use 4:3 for the image
rect.left = -(srcwidth - width4_3) / 2;
rect.left = (double)GetWidth() * (-(srcwidth - width4_3) / 2) / width4_3;
switch (oautoaspect)
{
default:
@ -410,7 +410,15 @@ void CalcFullscreenScale(DrawParms *parms, double srcwidth, double srcheight, in
}
}
DEFINE_ACTION_FUNCTION(_Screen, GetFullscreenRect)
void GetFullscreenRect(double width, double height, int fsmode, DoubleRect* rect)
{
DrawParms parms;
parms.viewport.width = twod->GetWidth();
parms.viewport.height = twod->GetHeight();
CalcFullscreenScale(&parms, width, height, fsmode, *rect);
}
DEFINE_ACTION_FUNCTION_NATIVE(_Screen, GetFullscreenRect, GetFullscreenRect)
{
PARAM_PROLOGUE;
PARAM_FLOAT(virtw);

View file

@ -254,6 +254,8 @@ template<class T>
void DrawTextCommon(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double y, const T* string, DrawParms& parms);
bool SetTextureParms(F2DDrawer *drawer, DrawParms* parms, FGameTexture* img, double x, double y);
void GetFullscreenRect(double width, double height, int fsmode, DoubleRect* rect);
void DrawText(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, const char* string, int tag_first, ...);
void DrawText(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, const char32_t* string, int tag_first, ...);
void DrawChar(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, int character, int tag_first, ...);

View file

@ -50,7 +50,7 @@ int eventhead;
int eventtail;
event_t events[MAXEVENTS];
CVAR(Float, m_sensitivity_x, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Float, m_sensitivity_x, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Float, m_sensitivity_y, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)

View file

@ -1247,7 +1247,7 @@ void FScanner::AddSymbol(const char* name, uint64_t value)
Symbol sym;
sym.tokenType = TK_UIntConst;
sym.Number = value;
sym.Float = value;
sym.Float = (double)value;
symbols.Insert(name, sym);
}

View file

@ -87,6 +87,7 @@ class FSingleLumpFont : public FFont
{
public:
FSingleLumpFont (const char *fontname, int lump);
void RecordAllTextureColors(uint32_t* usedcolors) override;
protected:
void CheckFON1Chars (double *luminosity);
@ -649,6 +650,32 @@ void FSingleLumpFont::FixupPalette (uint8_t *identity, double *luminosity, const
}
}
//==========================================================================
//
// RecordAllTextureColors
//
// Given a 256 entry buffer, sets every entry that corresponds to a color
// used by the font.
//
//==========================================================================
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);
for (int i = 0; i < 256; i++)
{
if (identity[i] != 0) usedcolors[identity[i]]++;
}
}
}
FFont *CreateSingleLumpFont (const char *fontname, int lump)
{
return new FSingleLumpFont(fontname, lump);

View file

@ -85,7 +85,8 @@ static int TranslationMapCompare (const void *a, const void *b);
extern int PrintColors[];
// PUBLIC DATA DEFINITIONS -------------------------------------------------
FFont* SmallFont, * SmallFont2, * BigFont, * BigUpper, * ConFont, * IntermissionFont, * NewConsoleFont, * NewSmallFont, * CurrentConsoleFont, * OriginalSmallFont, * AlternativeSmallFont, * OriginalBigFont;
FFont* SmallFont, * SmallFont2, * BigFont, * BigUpper, * ConFont, * IntermissionFont, * NewConsoleFont, * NewSmallFont,
* CurrentConsoleFont, * OriginalSmallFont, * AlternativeSmallFont, * OriginalBigFont, *AlternativeBigFont;
FFont *FFont::FirstFont = nullptr;
int NumTextColors;

View file

@ -127,7 +127,7 @@ public:
void SetCursor(char c) { Cursor = c; }
void SetKerning(int c) { GlobalKerning = c; }
bool NoTranslate() const { return noTranslate; }
void RecordAllTextureColors(uint32_t *usedcolors);
virtual void RecordAllTextureColors(uint32_t *usedcolors);
virtual void SetDefaultTranslation(uint32_t *colors);
void CheckCase();
@ -182,7 +182,7 @@ protected:
};
extern FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont, *OriginalSmallFont, *AlternativeSmallFont, *OriginalBigFont;
extern FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont, *OriginalSmallFont, *AlternativeSmallFont, *OriginalBigFont, *AlternativeBigFont;
void V_InitFonts();
void V_ClearFonts();

View file

@ -276,7 +276,18 @@ void UpdateGenericUI(bool cvar)
AlternativeSmallFont = NewSmallFont;
}
// Todo: Do the same for the BigFont
if (CheckFontComplete(BigFont))
{
AlternativeBigFont = BigFont;
}
else if (OriginalBigFont && CheckFontComplete(OriginalBigFont))
{
AlternativeBigFont = OriginalBigFont;
}
else
{
AlternativeBigFont = NewSmallFont;
}
}
}

View file

@ -435,7 +435,7 @@ DObject *PClass::CreateNew()
else
memset (mem, 0, Size);
if (ConstructNative == nullptr)
if (ConstructNative == nullptr || bAbstract)
{
M_Free(mem);
I_Error("Attempt to instantiate abstract class %s.", TypeName.GetChars());

View file

@ -36,8 +36,11 @@ public:
void SetAABBTree(hwrenderer::LevelAABBTree* tree)
{
mAABBTree = tree;
mNewTree = true;
if (mAABBTree != tree)
{
mAABBTree = tree;
mNewTree = true;
}
}
void SetCollectLights(std::function<void()> func)

View file

@ -445,6 +445,7 @@ DEFINE_GLOBAL(ConFont)
DEFINE_GLOBAL(NewConsoleFont)
DEFINE_GLOBAL(NewSmallFont)
DEFINE_GLOBAL(AlternativeSmallFont)
DEFINE_GLOBAL(AlternativeBigFont)
DEFINE_GLOBAL(OriginalSmallFont)
DEFINE_GLOBAL(OriginalBigFont)
DEFINE_GLOBAL(IntermissionFont)

View file

@ -6055,6 +6055,12 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
}
}
if (compileEnvironment.CheckSpecialGlobalIdentifier)
{
auto result = compileEnvironment.CheckSpecialGlobalIdentifier(this, ctx);
if (result != this) return result;
}
if (auto *cvar = FindCVar(Identifier.GetChars(), nullptr))
{
if (cvar->GetFlags() & CVAR_USERINFO)
@ -8540,6 +8546,13 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
if (!result) return nullptr;
}
// [Player701] Catch attempts to call abstract functions directly at compile time
if (NoVirtual && Function->Variants[0].Implementation->VarFlags & VARF_Abstract)
{
ScriptPosition.Message(MSG_ERROR, "Cannot call abstract function %s", Function->Variants[0].Implementation->PrintableName.GetChars());
delete this;
return nullptr;
}
CallingFunction = ctx.Function;
if (ArgList.Size() > 0)

View file

@ -2131,6 +2131,7 @@ struct CompileEnvironment
FxExpression* (*SpecialTypeCast)(FxTypeCast* func, FCompileContext& ctx);
bool (*CheckForCustomAddition)(FxAddSub* func, FCompileContext& ctx);
FxExpression* (*CheckSpecialIdentifier)(FxIdentifier* func, FCompileContext& ctx);
FxExpression* (*CheckSpecialGlobalIdentifier)(FxIdentifier* func, FCompileContext& ctx);
FxExpression* (*ResolveSpecialIdentifier)(FxIdentifier* func, FxExpression*& object, PContainerType* objtype, FCompileContext& ctx);
FxExpression* (*CheckSpecialMember)(FxStructMember* func, FCompileContext& ctx);
FxExpression* (*CheckCustomGlobalFunctions)(FxFunctionCall* func, FCompileContext& ctx);

View file

@ -767,13 +767,16 @@ FFunctionBuildList FunctionBuildList;
VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, const VersionInfo &ver, PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum)
{
auto func = code->GetDirectFunction(functype, ver);
if (func != nullptr)
if (code != nullptr)
{
delete code;
auto func = code->GetDirectFunction(functype, ver);
if (func != nullptr)
{
delete code;
return func;
return func;
}
}
//Printf("Adding %s\n", name.GetChars());
@ -815,6 +818,10 @@ void FFunctionBuildList::Build()
for (auto &item : mItems)
{
// [Player701] Do not emit code for abstract functions
bool isAbstract = item.Func->Variants[0].Implementation->VarFlags & VARF_Abstract;
if (isAbstract) continue;
assert(item.Code != NULL);
// We don't know the return type in advance for anonymous functions.

View file

@ -87,11 +87,12 @@ template<class T> void ArrayDelete(T *self, int index, int count)
template<class T, class U, int fill = 1> void ArrayInsert(T *self, int index, U val)
{
//int oldSize = self->Size();
int oldSize = self->Size();
self->Insert(index, static_cast<typename T::value_type>(val));
// Is this even necessary? All Insert does is inserting one defined element into the array and moving the rest.
// It never creates empty tailing entries. fillcount in the macro will always be 0
//if (fill) { DYNARRAY_FILL_ITEMS_SKIP(1); }
if constexpr (fill)
{
for (unsigned i = oldSize; i < self->Size() - 1; i++) (*self)[i] = 0;
}
}
template<class T> void ArrayShrinkToFit(T *self)
@ -879,8 +880,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Delete, ArrayDelete<FDynArray_Obj>)
void ObjArrayInsert(FDynArray_Obj *self,int index, DObject *obj)
{
int oldSize = self->Size();
GC::WriteBarrier(obj);
self->Insert(index, obj);
for (unsigned i = oldSize; i < self->Size() - 1; i++) (*self)[i] = nullptr;
}
DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Insert, ObjArrayInsert)

View file

@ -1042,7 +1042,7 @@ PName::PName()
{
mDescriptiveName = "Name";
Flags |= TYPE_IntNotInt;
assert(sizeof(FName) == alignof(FName));
static_assert(sizeof(FName) == alignof(FName), "Name not properly aligned");
}
//==========================================================================
@ -1172,7 +1172,7 @@ PTextureID::PTextureID()
{
mDescriptiveName = "TextureID";
Flags |= TYPE_IntNotInt;
assert(sizeof(FTextureID) == alignof(FTextureID));
static_assert(sizeof(FTextureID) == alignof(FTextureID), "TextureID not properly aligned");
}
//==========================================================================
@ -1214,7 +1214,7 @@ PSound::PSound()
{
mDescriptiveName = "Sound";
Flags |= TYPE_IntNotInt;
assert(sizeof(FSoundID) == alignof(FSoundID));
static_assert(sizeof(FSoundID) == alignof(FSoundID), "SoundID not properly aligned");
}
//==========================================================================
@ -1263,7 +1263,7 @@ PColor::PColor()
{
mDescriptiveName = "Color";
Flags |= TYPE_IntNotInt;
assert(sizeof(PalEntry) == alignof(PalEntry));
static_assert(sizeof(PalEntry) == alignof(PalEntry), "PalEntry not properly aligned");
}
/* PStateLabel *****************************************************************/

View file

@ -36,6 +36,7 @@ enum
VARF_Play = (1<<21), // [ZZ] play: object is playsim-scope only (can't access ui)
VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only)
VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data.
VARF_Abstract = (1<<24), // [Player701] Function does not have a body and must be overridden in subclasses
};
// Basic information shared by all types ------------------------------------

View file

@ -1214,6 +1214,7 @@ decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc
decl_flag(X) ::= INTERNAL(T). { X.Int = ZCC_Internal; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= OVERRIDE(T). { X.Int = ZCC_Override; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= ABSTRACT(T). { X.Int = ZCC_Abstract; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= VARARG(T). { X.Int = ZCC_VarArg; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= UI(T). { X.Int = ZCC_UIFlag; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= PLAY(T). { X.Int = ZCC_Play; X.SourceLoc = T.SourceLoc; }

View file

@ -2042,7 +2042,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
} while (t != f->Type);
}
int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_Abstract | ZCC_Internal;
int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_Internal;
if (f->Flags & notallowed)
{
@ -2088,6 +2088,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated;
if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual;
if (f->Flags & ZCC_Override) varflags |= VARF_Override;
if (f->Flags & ZCC_Abstract) varflags |= VARF_Abstract;
if (f->Flags & ZCC_VarArg) varflags |= VARF_VarArg;
if (f->Flags & ZCC_FuncConst) varflags |= VARF_ReadOnly; // FuncConst method is internally marked as VARF_ReadOnly
if (mVersion >= MakeVersion(2, 4, 0))
@ -2131,7 +2132,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'.
// Only one of these flags may be used.
static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static };
static int exclude[] = { ZCC_Abstract, ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static };
int excludeflags = 0;
int fc = 0;
for (size_t i = 0; i < countof(exclude); i++)
@ -2147,7 +2148,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
Error(f, "Invalid combination of qualifiers %s on function %s", FlagsToString(excludeflags).GetChars(), FName(f->Name).GetChars());
varflags |= VARF_Method;
}
if (varflags & VARF_Override) varflags |= VARF_Virtual; // Now that the flags are checked, make all override functions virtual as well.
if (varflags & (VARF_Override | VARF_Abstract)) varflags |= VARF_Virtual; // Now that the flags are checked, make all override and abstract functions virtual as well.
// [ZZ] this doesn't make sense either.
if ((varflags&(VARF_ReadOnly | VARF_Method)) == VARF_ReadOnly) // non-method const function
@ -2180,6 +2181,12 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (f->Flags & ZCC_Native)
{
if (varflags & VARF_Abstract)
{
Error(f, "Native functions cannot be abstract");
return;
}
varflags |= VARF_Native;
afd = FindFunction(c->Type(), FName(f->Name).GetChars());
if (afd == nullptr)
@ -2371,19 +2378,20 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (!(f->Flags & ZCC_Native))
{
if (f->Body == nullptr)
if (f->Body != nullptr && (varflags & VARF_Abstract))
{
Error(f, "Abstract function %s cannot have a body", FName(f->Name).GetChars());
return;
}
if (f->Body == nullptr && !(varflags & VARF_Abstract))
{
Error(f, "Empty function %s", FName(f->Name).GetChars());
return;
}
else
{
auto code = ConvertAST(c->Type(), f->Body);
if (code != nullptr)
{
newfunc = FunctionBuildList.AddFunction(OutNamespace, mVersion, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump);
}
}
FxExpression* code = f->Body != nullptr ? ConvertAST(c->Type(), f->Body) : nullptr;
newfunc = FunctionBuildList.AddFunction(OutNamespace, mVersion, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump);
}
if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time.
{
@ -2408,6 +2416,12 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (forclass)
{
if ((varflags & VARF_Abstract) && !clstype->bAbstract)
{
Error(f, "Abstract functions can only be defined in abstract classes");
return;
}
auto parentfunc = clstype->ParentClass? dyn_cast<PFunction>(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)) : nullptr;
int vindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], parentfunc, exactReturnType);
@ -2526,6 +2540,18 @@ void ZCCCompiler::InitFunctions()
{
CompileFunction(c, f, true);
}
// [Player701] Make sure all abstract functions are overridden
if (!c->ClassType()->bAbstract)
{
for (auto v : c->ClassType()->Virtuals)
{
if (v->VarFlags & VARF_Abstract)
{
Error(c->cls, "Non-abstract class %s must override abstract function %s", c->Type()->TypeName.GetChars(), v->PrintableName.GetChars());
}
}
}
}
}

View file

@ -284,6 +284,13 @@ static bool CanJit(VMScriptFunction *func)
int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret)
{
// [Player701] Check that we aren't trying to call an abstract function.
// This shouldn't happen normally, but if it does, let's catch this explicitly
// rather than let GZDoom crash.
if (func->VarFlags & VARF_Abstract)
{
ThrowAbortException(X_OTHER, "attempt to call abstract function %s.", func->PrintableName.GetChars());
}
#ifdef HAVE_VM_JIT
if (vm_jit && CanJit(static_cast<VMScriptFunction*>(func)))
{
@ -654,7 +661,11 @@ CVMAbortException::CVMAbortException(EVMAbortException reason, const char *morei
}
if (moreinfo != nullptr)
{
AppendMessage(" ");
// [Player701] avoid double space
if (reason != X_OTHER)
{
AppendMessage(" ");
}
size_t len = strlen(m_Message);
myvsnprintf(m_Message + len, MAX_ERRORTEXT - len, moreinfo, ap);
}

View file

@ -157,6 +157,7 @@ struct _ native // These are the global variables, the struct is only here to av
native readonly Font NewConsoleFont;
native readonly Font NewSmallFont;
native readonly Font AlternativeSmallFont;
native readonly Font AlternativeBigFont;
native readonly Font OriginalSmallFont;
native readonly Font OriginalBigFont;
native readonly Font intermissionfont;

View file

@ -147,7 +147,7 @@ class ListMenu : Menu
override bool MenuEvent (int mkey, bool fromcontroller)
{
int oldSelect = mDesc.mSelectedItem;
int startedAt = mDesc.mSelectedItem;
int startedAt = max(0, mDesc.mSelectedItem);
switch (mkey)
{

View file

@ -293,13 +293,13 @@ class ListMenuItemTextItem : ListMenuItemSelectable
override void Draw(bool selected, ListMenuDescriptor desc)
{
let font = generic_ui ? NewSmallFont : mFont;
let font = menuDelegate.PickFont(mFont);
DrawText(desc, font, selected ? mColorSelected : mColor, mXpos, mYpos, mText);
}
override int GetWidth()
{
let font = generic_ui? NewSmallFont : mFont;
let font = menuDelegate.PickFont(mFont);
return max(1, font.StringWidth(StringTable.Localize(mText)));
}
}
@ -360,7 +360,7 @@ class ListMenuItemCaptionItem : ListMenuItem
override void Draw(bool selected, ListMenuDescriptor desc)
{
let font = generic_ui || !desc.mFont ? NewSmallFont : desc.mFont;
let font = menuDelegate.PickFont(desc.mFont);
if (font && mText.Length() > 0)
{
menuDelegate.DrawCaption(mText, font, 0, true);

View file

@ -129,7 +129,7 @@ class LoadSaveMenu : ListMenu
double wScale = Width43 / 640.;
savepicLeft = Left43 + int(20 * wScale);
savepicTop = mDesc.mYpos * screen.GetHeight() / 200 ;
savepicTop = int(mDesc.mYpos * screen.GetHeight() / 200);
savepicWidth = int(240 * wScale);
savepicHeight = int(180 * wScale);

View file

@ -4,7 +4,7 @@ class MenuDelegateBase ui
{
virtual int DrawCaption(String title, Font fnt, int y, bool drawit)
{
screen.DrawText(fnt, OptionMenuSettings.mTitleColor, (screen.GetWidth() - fnt.StringWidth(title) * CleanXfac_1) / 2, 10 * CleanYfac_1, title, DTA_CleanNoMove_1, true);
if (drawit) screen.DrawText(fnt, OptionMenuSettings.mTitleColor, (screen.GetWidth() - fnt.StringWidth(title) * CleanXfac_1) / 2, 10 * CleanYfac_1, title, DTA_CleanNoMove_1, true);
return (y + fnt.GetHeight()) * CleanYfac_1; // return is spacing in screen pixels.
}
@ -22,4 +22,11 @@ class MenuDelegateBase ui
// overriding this allows to execute special actions when the menu closes
}
virtual Font PickFont(Font fnt)
{
if (generic_ui || !fnt) return NewSmallFont;
if (fnt == SmallFont) return AlternativeSmallFont;
if (fnt == BigFont) return AlternativeBigFont;
return fnt;
}
}

View file

@ -89,7 +89,7 @@ class MessageBoxMenu : Menu
int mr2 = destWidth/2 + 10 + textFont.StringWidth(Stringtable.Localize("$TXT_NO"));
mMouseRight = MAX(mr1, mr2);
mParentMenu = parent;
mMessage = textFont.BreakLines(Stringtable.Localize(message), 300/NotifyFontScale);
mMessage = textFont.BreakLines(Stringtable.Localize(message), int(300/NotifyFontScale));
mMessageMode = messagemode;
if (playsound)
{
@ -106,8 +106,9 @@ class MessageBoxMenu : Menu
override void Drawer ()
{
int i, y;
int fontheight = textFont.GetHeight() * NotifyFontScale;
int i;
double y;
let fontheight = textFont.GetHeight() * NotifyFontScale;
y = destHeight / 2;
@ -124,7 +125,7 @@ class MessageBoxMenu : Menu
if (mMessageMode == 0)
{
y += fontheight;
mMouseY = y;
mMouseY = int(y);
screen.DrawText(textFont, messageSelection == 0? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, destWidth / 2, y, Stringtable.Localize("$TXT_YES"), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true, DTA_ScaleX, NotifyFontScale, DTA_ScaleY, NotifyFontScale);
screen.DrawText(textFont, messageSelection == 1? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, destWidth / 2, y + fontheight, Stringtable.Localize("$TXT_NO"), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true, DTA_ScaleX, NotifyFontScale, DTA_ScaleY, NotifyFontScale);

View file

@ -239,7 +239,7 @@ class OptionMenu : Menu
if (y <= 0)
{
y = DrawCaption(mDesc.mTitle, y, false);
y = DrawCaption(mDesc.mTitle, -y, false);
}
y *= CleanYfac_1;
int rowheight = OptionMenuSettings.mLinespacing * CleanYfac_1;
@ -430,7 +430,7 @@ class OptionMenu : Menu
virtual int DrawCaption(String title, int y, bool drawit)
{
let font = generic_ui || !mDesc.mFont ? NewSmallFont : mDesc.mFont;
let font = menuDelegate.PickFont(mDesc.mFont);
if (font && mDesc.mTitle.Length() > 0)
{
return menuDelegate.DrawCaption(title, font, y, drawit);