- another backend update from GZDoom.

This commit is contained in:
Christoph Oelckers 2022-06-06 15:28:41 +02:00
parent f599040212
commit 998def2487
4 changed files with 100 additions and 75 deletions

View file

@ -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, &param, 1, &ret, 1);
return can;
}
return true;
}
//=============================================================================
//
//

View file

@ -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;

View file

@ -180,29 +180,21 @@ class TObjPtr
DObject *o;
};
public:
TObjPtr() = default;
TObjPtr(const TObjPtr<T> &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<T>& operator=(T q) noexcept
{
pp = q;
return *this;
}
T operator=(std::nullptr_t nul)
constexpr TObjPtr<T>& operator=(std::nullptr_t nul) noexcept
{
o = nullptr;
return *this;
}
// To allow NULL, too.
T operator=(const int val)
TObjPtr<T>& 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<T>& 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<class T>
constexpr TObjPtr<T> 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<T> 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<class T,class U> inline T barrier_cast(TObjPtr<U> &o)

View file

@ -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;
}
}