From c82d9d29081a252751e1511a3699c1acadb35b01 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 24 Oct 2020 17:30:47 +0200 Subject: [PATCH] - backend update from GZDoom. --- source/common/2d/v_2ddrawer.h | 2 +- source/common/2d/v_draw.cpp | 18 +++++-- source/common/2d/v_draw.h | 2 + source/common/engine/d_event.cpp | 2 +- source/common/engine/sc_man.cpp | 2 +- source/common/fonts/singlelumpfont.cpp | 27 ++++++++++ source/common/fonts/v_font.cpp | 3 +- source/common/fonts/v_font.h | 4 +- source/common/fonts/v_text.cpp | 13 ++++- source/common/objects/dobjtype.cpp | 2 +- .../rendering/hwrenderer/data/hw_shadowmap.h | 7 ++- source/common/rendering/v_video.cpp | 1 + source/common/scripting/backend/codegen.cpp | 13 +++++ source/common/scripting/backend/codegen.h | 1 + source/common/scripting/backend/vmbuilder.cpp | 15 ++++-- source/common/scripting/core/dynarrays.cpp | 11 ++-- source/common/scripting/core/types.cpp | 8 +-- source/common/scripting/core/types.h | 1 + .../common/scripting/frontend/zcc-parse.lemon | 1 + .../common/scripting/frontend/zcc_compile.cpp | 50 ++++++++++++++----- source/common/scripting/vm/vmframe.cpp | 13 ++++- wadsrc/static/zscript/base.zs | 1 + wadsrc/static/zscript/ui/menu/listmenu.zs | 2 +- .../static/zscript/ui/menu/listmenuitems.zs | 8 +-- wadsrc/static/zscript/ui/menu/loadsavemenu.zs | 2 +- .../static/zscript/ui/menu/menucustomize.zs | 9 +++- wadsrc/static/zscript/ui/menu/messagebox.zs | 9 ++-- wadsrc/static/zscript/ui/menu/optionmenu.zs | 4 +- 28 files changed, 178 insertions(+), 53 deletions(-) diff --git a/source/common/2d/v_2ddrawer.h b/source/common/2d/v_2ddrawer.h index 9fc5227e7..1087ec63e 100644 --- a/source/common/2d/v_2ddrawer.h +++ b/source/common/2d/v_2ddrawer.h @@ -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); diff --git a/source/common/2d/v_draw.cpp b/source/common/2d/v_draw.cpp index ef34bbb57..6a02f0a32 100644 --- a/source/common/2d/v_draw.cpp +++ b/source/common/2d/v_draw.cpp @@ -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); diff --git a/source/common/2d/v_draw.h b/source/common/2d/v_draw.h index b7eafbbec..49ca81ed3 100644 --- a/source/common/2d/v_draw.h +++ b/source/common/2d/v_draw.h @@ -254,6 +254,8 @@ template 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, ...); diff --git a/source/common/engine/d_event.cpp b/source/common/engine/d_event.cpp index effb5dc3a..b42915c7b 100644 --- a/source/common/engine/d_event.cpp +++ b/source/common/engine/d_event.cpp @@ -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) diff --git a/source/common/engine/sc_man.cpp b/source/common/engine/sc_man.cpp index 495ef2493..fa9a2f6c4 100644 --- a/source/common/engine/sc_man.cpp +++ b/source/common/engine/sc_man.cpp @@ -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); } diff --git a/source/common/fonts/singlelumpfont.cpp b/source/common/fonts/singlelumpfont.cpp index a9cd6ee04..3678ee441 100644 --- a/source/common/fonts/singlelumpfont.cpp +++ b/source/common/fonts/singlelumpfont.cpp @@ -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); diff --git a/source/common/fonts/v_font.cpp b/source/common/fonts/v_font.cpp index 1d75d9f18..b90a74866 100644 --- a/source/common/fonts/v_font.cpp +++ b/source/common/fonts/v_font.cpp @@ -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; diff --git a/source/common/fonts/v_font.h b/source/common/fonts/v_font.h index 6de1dae86..37bf049a3 100644 --- a/source/common/fonts/v_font.h +++ b/source/common/fonts/v_font.h @@ -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(); diff --git a/source/common/fonts/v_text.cpp b/source/common/fonts/v_text.cpp index 742a99e6f..59d843496 100644 --- a/source/common/fonts/v_text.cpp +++ b/source/common/fonts/v_text.cpp @@ -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; + } } } diff --git a/source/common/objects/dobjtype.cpp b/source/common/objects/dobjtype.cpp index 7ef11b7c5..08c0a5692 100644 --- a/source/common/objects/dobjtype.cpp +++ b/source/common/objects/dobjtype.cpp @@ -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()); diff --git a/source/common/rendering/hwrenderer/data/hw_shadowmap.h b/source/common/rendering/hwrenderer/data/hw_shadowmap.h index 5a65e7620..f82e368b2 100644 --- a/source/common/rendering/hwrenderer/data/hw_shadowmap.h +++ b/source/common/rendering/hwrenderer/data/hw_shadowmap.h @@ -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 func) diff --git a/source/common/rendering/v_video.cpp b/source/common/rendering/v_video.cpp index 3cf9f7bb1..815b73a6b 100644 --- a/source/common/rendering/v_video.cpp +++ b/source/common/rendering/v_video.cpp @@ -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) diff --git a/source/common/scripting/backend/codegen.cpp b/source/common/scripting/backend/codegen.cpp index fe3d8e938..cb9642a64 100644 --- a/source/common/scripting/backend/codegen.cpp +++ b/source/common/scripting/backend/codegen.cpp @@ -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) diff --git a/source/common/scripting/backend/codegen.h b/source/common/scripting/backend/codegen.h index bcadae39d..59037929c 100644 --- a/source/common/scripting/backend/codegen.h +++ b/source/common/scripting/backend/codegen.h @@ -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); diff --git a/source/common/scripting/backend/vmbuilder.cpp b/source/common/scripting/backend/vmbuilder.cpp index 4eeae8b66..4c1401e8e 100644 --- a/source/common/scripting/backend/vmbuilder.cpp +++ b/source/common/scripting/backend/vmbuilder.cpp @@ -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. diff --git a/source/common/scripting/core/dynarrays.cpp b/source/common/scripting/core/dynarrays.cpp index eebb97da8..3d8e87e85 100644 --- a/source/common/scripting/core/dynarrays.cpp +++ b/source/common/scripting/core/dynarrays.cpp @@ -87,11 +87,12 @@ template void ArrayDelete(T *self, int index, int count) template void ArrayInsert(T *self, int index, U val) { - //int oldSize = self->Size(); + int oldSize = self->Size(); self->Insert(index, static_cast(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 void ArrayShrinkToFit(T *self) @@ -879,8 +880,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Delete, ArrayDelete) 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) diff --git a/source/common/scripting/core/types.cpp b/source/common/scripting/core/types.cpp index 447af4601..3b7057acb 100644 --- a/source/common/scripting/core/types.cpp +++ b/source/common/scripting/core/types.cpp @@ -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 *****************************************************************/ diff --git a/source/common/scripting/core/types.h b/source/common/scripting/core/types.h index 0d6c6546e..ae423af9d 100644 --- a/source/common/scripting/core/types.h +++ b/source/common/scripting/core/types.h @@ -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 ------------------------------------ diff --git a/source/common/scripting/frontend/zcc-parse.lemon b/source/common/scripting/frontend/zcc-parse.lemon index 79e52d831..6765defa1 100644 --- a/source/common/scripting/frontend/zcc-parse.lemon +++ b/source/common/scripting/frontend/zcc-parse.lemon @@ -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; } diff --git a/source/common/scripting/frontend/zcc_compile.cpp b/source/common/scripting/frontend/zcc_compile.cpp index ac22942fd..47696089e 100644 --- a/source/common/scripting/frontend/zcc_compile.cpp +++ b/source/common/scripting/frontend/zcc_compile.cpp @@ -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(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()); + } + } + } } } diff --git a/source/common/scripting/vm/vmframe.cpp b/source/common/scripting/vm/vmframe.cpp index ff193320f..bc6b344e5 100644 --- a/source/common/scripting/vm/vmframe.cpp +++ b/source/common/scripting/vm/vmframe.cpp @@ -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(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); } diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs index 223ac495f..4f0e64f9a 100644 --- a/wadsrc/static/zscript/base.zs +++ b/wadsrc/static/zscript/base.zs @@ -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; diff --git a/wadsrc/static/zscript/ui/menu/listmenu.zs b/wadsrc/static/zscript/ui/menu/listmenu.zs index c10256518..c8ba63eb1 100644 --- a/wadsrc/static/zscript/ui/menu/listmenu.zs +++ b/wadsrc/static/zscript/ui/menu/listmenu.zs @@ -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) { diff --git a/wadsrc/static/zscript/ui/menu/listmenuitems.zs b/wadsrc/static/zscript/ui/menu/listmenuitems.zs index 13d96281c..8b47d288c 100644 --- a/wadsrc/static/zscript/ui/menu/listmenuitems.zs +++ b/wadsrc/static/zscript/ui/menu/listmenuitems.zs @@ -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); diff --git a/wadsrc/static/zscript/ui/menu/loadsavemenu.zs b/wadsrc/static/zscript/ui/menu/loadsavemenu.zs index 786dfa675..3fac8bf40 100644 --- a/wadsrc/static/zscript/ui/menu/loadsavemenu.zs +++ b/wadsrc/static/zscript/ui/menu/loadsavemenu.zs @@ -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); diff --git a/wadsrc/static/zscript/ui/menu/menucustomize.zs b/wadsrc/static/zscript/ui/menu/menucustomize.zs index 3d3ee1431..75b114e54 100644 --- a/wadsrc/static/zscript/ui/menu/menucustomize.zs +++ b/wadsrc/static/zscript/ui/menu/menucustomize.zs @@ -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; + } } diff --git a/wadsrc/static/zscript/ui/menu/messagebox.zs b/wadsrc/static/zscript/ui/menu/messagebox.zs index 3bae3c27a..94f8a38fd 100644 --- a/wadsrc/static/zscript/ui/menu/messagebox.zs +++ b/wadsrc/static/zscript/ui/menu/messagebox.zs @@ -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); diff --git a/wadsrc/static/zscript/ui/menu/optionmenu.zs b/wadsrc/static/zscript/ui/menu/optionmenu.zs index 6392adf3f..da1d67cda 100644 --- a/wadsrc/static/zscript/ui/menu/optionmenu.zs +++ b/wadsrc/static/zscript/ui/menu/optionmenu.zs @@ -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);