From 998def24875b3d5b752c19cb231419b55d402ced Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 6 Jun 2022 15:28:41 +0200 Subject: [PATCH] - another backend update from GZDoom. --- source/common/cutscenes/screenjob.cpp | 77 ++++++++++++++++----------- source/common/cutscenes/screenjob.h | 13 +++-- source/common/objects/dobjgc.h | 41 +++++++------- source/core/screenjob.cpp | 44 +++++++-------- 4 files changed, 100 insertions(+), 75 deletions(-) diff --git a/source/common/cutscenes/screenjob.cpp b/source/common/cutscenes/screenjob.cpp index 840b9f55e..901cf5f7d 100644 --- a/source/common/cutscenes/screenjob.cpp +++ b/source/common/cutscenes/screenjob.cpp @@ -54,10 +54,7 @@ CVAR(Bool, inter_subtitles, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); -DObject* runner; -PClass* runnerclass; -PType* runnerclasstype; -CompletionFunc completion; +CutsceneState cutscene; static int ticks; //============================================================================= @@ -72,11 +69,11 @@ void Job_Init() if (!done) { done = true; - GC::AddMarkerFunc([] { GC::Mark(runner); }); + GC::AddMarkerFunc([] { GC::Mark(cutscene.runner); }); } - runnerclass = PClass::FindClass("ScreenJobRunner"); - if (!runnerclass) I_FatalError("ScreenJobRunner not defined"); - runnerclasstype = NewPointer(runnerclass); + cutscene.runnerclass = PClass::FindClass("ScreenJobRunner"); + if (!cutscene.runnerclass) I_FatalError("ScreenJobRunner not defined"); + cutscene.runnerclasstype = NewPointer(cutscene.runnerclass); } //============================================================================= @@ -115,7 +112,7 @@ void CallCreateFunction(const char* qname, DObject* runner) { auto func = LookupFunction(qname); if (func->Proto->ArgumentTypes.Size() != 1) I_Error("Bad cutscene function %s. Must receive precisely one argument.", qname); - if (func->Proto->ArgumentTypes[0] != runnerclasstype) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner reference.", qname); + if (func->Proto->ArgumentTypes[0] != cutscene.runnerclasstype) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner reference.", qname); VMValue val = runner; VMCall(func, &val, 1, nullptr, 0); } @@ -128,7 +125,7 @@ void CallCreateFunction(const char* qname, DObject* runner) DObject* CreateRunner(bool clearbefore) { - auto obj = runnerclass->CreateNew(); + auto obj = cutscene.runnerclass->CreateNew(); auto func = LookupFunction("ScreenJobRunner.Init", false); VMValue val[3] = { obj, clearbefore, false }; VMCall(func, val, 3, nullptr, 0); @@ -182,15 +179,15 @@ void CutsceneDef::Create(DObject* runner) void DeleteScreenJob() { - if (runner) runner->Destroy(); - runner = nullptr; + if (cutscene.runner) cutscene.runner->Destroy(); + cutscene.runner = nullptr; } void EndScreenJob() { DeleteScreenJob(); - if (completion) completion(false); - completion = nullptr; + if (cutscene.completion) cutscene.completion(false); + cutscene.completion = nullptr; } @@ -213,12 +210,12 @@ bool ScreenJobResponder(event_t* ev) } } FInputEvent evt = ev; - if (runner) + if (cutscene.runner) { - IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, OnEvent) + IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, OnEvent) { int result = 0; - VMValue parm[] = { runner, &evt }; + VMValue parm[] = { cutscene.runner, &evt }; VMReturn ret(&result); VMCall(func, parm, 2, &ret, 1); return result; @@ -236,12 +233,12 @@ bool ScreenJobResponder(event_t* ev) bool ScreenJobTick() { ticks++; - if (runner) + if (cutscene.runner) { - IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, OnTick) + IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, OnTick) { int result = 0; - VMValue parm[] = { runner }; + VMValue parm[] = { cutscene.runner }; VMReturn ret(&result); VMCall(func, parm, 1, &ret, 1); return result; @@ -260,12 +257,12 @@ void ScreenJobDraw() { double smoothratio = I_GetTimeFrac(); - if (runner) + if (cutscene.runner) { twod->ClearScreen(); - IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, RunFrame) + IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, RunFrame) { - VMValue parm[] = { runner, smoothratio }; + VMValue parm[] = { cutscene.runner, smoothratio }; VMCall(func, parm, 2, nullptr, 0); } } @@ -279,12 +276,12 @@ void ScreenJobDraw() bool ScreenJobValidate() { - if (runner) + if (cutscene.runner) { - IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, Validate) + IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, Validate) { int res; - VMValue parm[] = { runner }; + VMValue parm[] = { cutscene.runner }; VMReturn ret(&res); VMCall(func, parm, 1, &ret, 1); I_ResetFrameTime(); @@ -304,12 +301,12 @@ bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion_ { if ((cs.function.IsNotEmpty() || cs.video.IsNotEmpty()) && cs.function.CompareNoCase("none") != 0) { - completion = completion_; - runner = CreateRunner(); - GC::WriteBarrier(runner); + cutscene.completion = completion_; + cutscene.runner = CreateRunner(); + GC::WriteBarrier(cutscene.runner); try { - cs.Create(runner); + cs.Create(cutscene.runner); if (!ScreenJobValidate()) { DeleteScreenJob(); @@ -349,6 +346,26 @@ DEFINE_ACTION_FUNCTION(DScreenJobRunner, setTransition) return 0; } +//============================================================================= +// +// to block wipes on cutscenes that cannot handle it +// +//============================================================================= + +bool CanWipe() +{ + if (cutscene.runner == nullptr) return true; + IFVM(ScreenJobRunner, CanWipe) + { + int can; + VMReturn ret(&can); + VMValue param = cutscene.runner; + VMCall(func, ¶m, 1, &ret, 1); + return can; + } + return true; +} + //============================================================================= // // diff --git a/source/common/cutscenes/screenjob.h b/source/common/cutscenes/screenjob.h index 92cb766e8..dce55e3b0 100644 --- a/source/common/cutscenes/screenjob.h +++ b/source/common/cutscenes/screenjob.h @@ -43,14 +43,19 @@ bool ScreenJobValidate(); struct CutsceneDef; bool StartCutscene(const char* s, int flags, const CompletionFunc& completion); bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion_); +bool CanWipe(); VMFunction* LookupFunction(const char* qname, bool validate = true); void CallCreateFunction(const char* qname, DObject* runner); DObject* CreateRunner(bool clearbefore = true); void AddGenericVideo(DObject* runner, const FString& fn, int soundid, int fps); +struct CutsceneState +{ + DObject* runner; + PClass* runnerclass; + PType* runnerclasstype; + CompletionFunc completion; +}; -extern DObject* runner; -extern PClass* runnerclass; -extern PType* runnerclasstype; -extern CompletionFunc completion; +extern CutsceneState cutscene; diff --git a/source/common/objects/dobjgc.h b/source/common/objects/dobjgc.h index 8be9d56a3..a1695b8ef 100644 --- a/source/common/objects/dobjgc.h +++ b/source/common/objects/dobjgc.h @@ -180,29 +180,21 @@ class TObjPtr DObject *o; }; public: - TObjPtr() = default; - TObjPtr(const TObjPtr &q) = default; -#if 0 // Courtesy of GCC being stupid and not fully recognizing TobjPtr as trivial. GZDoom needs this constructor, but it breaks compilation in Raze, but only with GCC. - TObjPtr(T q) noexcept - : pp(q) - { - } -#endif - T operator=(T q) + constexpr TObjPtr& operator=(T q) noexcept { pp = q; return *this; } - T operator=(std::nullptr_t nul) + constexpr TObjPtr& operator=(std::nullptr_t nul) noexcept { o = nullptr; return *this; } // To allow NULL, too. - T operator=(const int val) + TObjPtr& operator=(const int val) noexcept { assert(val == 0); o = nullptr; @@ -210,42 +202,42 @@ public: } // To allow NULL, too. In Clang NULL is a long. - T operator=(const long val) + TObjPtr& operator=(const long val) noexcept { assert(val == 0); o = nullptr; return *this; } - T Get() noexcept + constexpr T Get() noexcept { return GC::ReadBarrier(pp); } - T ForceGet() noexcept //for situations where the read barrier needs to be skipped. + constexpr T ForceGet() noexcept //for situations where the read barrier needs to be skipped. { return pp; } - operator T() noexcept + constexpr operator T() noexcept { return GC::ReadBarrier(pp); } - T &operator*() noexcept + constexpr T &operator*() noexcept { T q = GC::ReadBarrier(pp); assert(q != NULL); return *q; } - T operator->() noexcept + constexpr T operator->() noexcept { return GC::ReadBarrier(pp); } - bool operator!=(T u) noexcept + constexpr bool operator!=(T u) noexcept { return GC::ReadBarrier(o) != u; } - bool operator==(T u) noexcept + constexpr bool operator==(T u) noexcept { return GC::ReadBarrier(o) == u; } @@ -257,6 +249,17 @@ public: friend class DObject; }; +// This is only needed because some parts of GCC do not treat a class with any constructor as trivial. +// TObjPtr needs to be fully trivial, though - some parts in the engine depend on it. +template +constexpr TObjPtr MakeObjPtr(T t) noexcept +{ + // since this exists to replace the constructor we cannot initialize in the declaration as this would require the constructor we want to avoid. + TObjPtr tt; + tt = t; + return tt; +} + // Use barrier_cast instead of static_cast when you need to cast // the contents of a TObjPtr to a related type. template inline T barrier_cast(TObjPtr &o) diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 45735146c..a148983ba 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -77,7 +77,7 @@ static void CallCreateMapFunction(const char* qname, DObject* runner, MapRecord* auto func = LookupFunction(qname); if (func->Proto->ArgumentTypes.Size() == 1) return CallCreateFunction(qname, runner); // accept functions without map parameter as well here. if (func->Proto->ArgumentTypes.Size() != 2) I_Error("Bad map-cutscene function %s. Must receive precisely two arguments.", qname); - if (func->Proto->ArgumentTypes[0] != runnerclasstype && func->Proto->ArgumentTypes[1] != maprecordtype) + if (func->Proto->ArgumentTypes[0] != cutscene.runnerclasstype && func->Proto->ArgumentTypes[1] != maprecordtype) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner and MapRecord reference.", qname); VMValue val[2] = { runner, map }; VMCall(func, val, 2, nullptr, 0); @@ -96,7 +96,7 @@ void CallCreateSummaryFunction(const char* qname, DObject* runner, MapRecord* ma auto s = func->Proto->ArgumentTypes.Size(); auto at = func->Proto->ArgumentTypes.Data(); if (s != 3 && s != 4) I_Error("Bad map-cutscene function %s. Must receive precisely three or four arguments.", qname); - if (at[0] != runnerclasstype && at[1] != maprecordtype && at[2] != summaryinfotype && (s == 3 || at[3] == maprecordtype)) + if (at[0] != cutscene.runnerclasstype && at[1] != maprecordtype && at[2] != summaryinfotype && (s == 3 || at[3] == maprecordtype)) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner, MapRecord and SummaryInfo reference,", qname); if (info) summaryinfo = *info; // must be copied to a persistent location. else summaryinfo = {}; @@ -158,24 +158,24 @@ void PlayLogos(gameaction_t complete_ga, gameaction_t def_ga, bool stopmusic) void ShowScoreboard(int numplayers, const CompletionFunc& completion_) { - completion = completion_; - runner = CreateRunner(); - Printf("Created runner at %p\n", runner); - GC::WriteBarrier(runner); + cutscene.completion = completion_; + cutscene.runner = CreateRunner(); + Printf("Created runner at %p\n", cutscene.runner); + GC::WriteBarrier(cutscene.runner); const char* qname = globalCutscenes.MPSummaryScreen; auto func = LookupFunction(qname); if (func->Proto->ArgumentTypes.Size() != 2) I_Error("Bad map-cutscene function %s. Must receive precisely two arguments.", qname); - if (func->Proto->ArgumentTypes[0] != runnerclasstype && func->Proto->ArgumentTypes[1] != TypeSInt32) + if (func->Proto->ArgumentTypes[0] != cutscene.runnerclasstype && func->Proto->ArgumentTypes[1] != TypeSInt32) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner reference and integer.", qname); - VMValue val[2] = { runner, numplayers }; + VMValue val[2] = { cutscene.runner, numplayers }; VMCall(func, val, 2, nullptr, 0); if (!ScreenJobValidate()) { - runner->Destroy(); - runner = nullptr; - if (completion) completion(false); - completion = nullptr; + cutscene.runner->Destroy(); + cutscene.runner = nullptr; + if (cutscene.completion) cutscene.completion(false); + cutscene.completion = nullptr; return; } gameaction = ga_intermission; @@ -189,7 +189,7 @@ void ShowScoreboard(int numplayers, const CompletionFunc& completion_) void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, CompletionFunc completion_) { - if (runner != nullptr) + if (cutscene.runner != nullptr) return; // protection against double exits. if (fromMap == toMap) { @@ -200,17 +200,17 @@ void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, C bool bossexit = g_bossexit; g_bossexit = false; - completion = completion_; - runner = CreateRunner(); - GC::WriteBarrier(runner); + cutscene.completion = completion_; + cutscene.runner = CreateRunner(); + GC::WriteBarrier(cutscene.runner); - // retrieve cluster relations for cluster-based cutscenes. + // retrieve cluster relations for cluster-based cutscene. ClusterDef* fromcluster = nullptr, *tocluster = nullptr; if (fromMap) fromcluster = FindCluster(fromMap->cluster); if (toMap) tocluster = FindCluster(toMap->cluster); if (fromcluster == tocluster) fromcluster = tocluster = nullptr; - + auto runner = cutscene.runner; try { if (fromMap && (!(fromMap->gameflags & LEVEL_BOSSONLYCUTSCENE) || bossexit)) @@ -245,9 +245,9 @@ void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, C if (!ScreenJobValidate()) { runner->Destroy(); - runner = nullptr; - if (completion) completion(false); - completion = nullptr; + cutscene.runner = nullptr; + if (cutscene.completion) cutscene.completion(false); + cutscene.completion = nullptr; return; } gameaction = ga_intermission; @@ -255,7 +255,7 @@ void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, C catch (...) { if (runner) runner->Destroy(); - runner = nullptr; + cutscene.runner = nullptr; throw; } }