- implemented running screen jobs from the main loop.

The entire game now has only one single place where videoNextPage gets called.
This commit is contained in:
Christoph Oelckers 2020-07-19 12:48:31 +02:00
parent e2e9c8ad01
commit f9842fc4a8
6 changed files with 68 additions and 105 deletions

View File

@ -66,6 +66,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "startupinfo.h" #include "startupinfo.h"
#include "mapinfo.h" #include "mapinfo.h"
#include "menustate.h" #include "menustate.h"
#include "screenjob.h"
CVAR(Bool, autoloadlights, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, autoloadlights, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Bool, autoloadbrightmaps, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, autoloadbrightmaps, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
@ -518,6 +519,7 @@ int GameMain()
I_ShowFatalError(err.what()); I_ShowFatalError(err.what());
r = -1; r = -1;
} }
DeleteScreenJob();
M_ClearMenus(true); M_ClearMenus(true);
if (gi) if (gi)
{ {

View File

@ -42,6 +42,7 @@
#include "v_draw.h" #include "v_draw.h"
#include "s_soundinternal.h" #include "s_soundinternal.h"
#include "animtexture.h" #include "animtexture.h"
#include "gamestate.h"
IMPLEMENT_CLASS(DScreenJob, true, false) IMPLEMENT_CLASS(DScreenJob, true, false)
@ -258,6 +259,22 @@ public:
AdvanceJob(false); AdvanceJob(false);
} }
~ScreenJobRunner()
{
DeleteJobs();
}
void DeleteJobs()
{
for (auto& job : jobs)
{
job.job->Destroy();
job.job->ObjectFlags |= OF_YesReallyDelete;
delete job.job;
}
jobs.Clear();
}
void AdvanceJob(bool skip) void AdvanceJob(bool skip)
{ {
index++; index++;
@ -307,12 +324,7 @@ public:
{ {
if (index >= jobs.Size()) if (index >= jobs.Size())
{ {
for (auto& job : jobs) DeleteJobs();
{
job.job->Destroy();
job.job->ObjectFlags |= OF_YesReallyDelete;
delete job.job;
}
twod->SetScreenFade(1); twod->SetScreenFade(1);
if (completion) completion(false); if (completion) completion(false);
return false; return false;
@ -354,102 +366,32 @@ public:
} }
}; };
ScreenJobRunner *runner;
void RunScreenJob(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore) void RunScreenJob(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore)
{ {
ScreenJobRunner runner(jobs, count, completion, clearbefore); assert(completion != nullptr);
if (count)
while (runner.RunFrame())
{ {
videoNextPage(); runner = new ScreenJobRunner(jobs, count, completion, clearbefore);
gamestate = GS_INTERMISSION;
} }
} }
#if 0
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void RunScreenJobSync(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore) void DeleteScreenJob()
{ {
// Release all jobs from the garbage collector - the code as it is cannot deal with them getting collected. if (runner)
for (int i = 0; i < count; i++)
{ {
jobs[i].job->Release(); delete runner;
runner = nullptr;
} }
bool skipped = false;
for (int i = 0; i < count; i++)
{
auto job = jobs[i];
if (job.job != nullptr && (!skipped || !job.ignoreifskipped))
{
skipped = false;
if (clearbefore)
{
twod->ClearScreen();
videoNextPage();
}
auto startTime = I_nsTime();
// Input later needs to be event based so that these screens can do more than be skipped.
inputState.ClearAllInput();
float screenfade = job.job->fadestyle & DScreenJob::fadein ? 0.f : 1.f;
while (true)
{
auto now = I_nsTime();
handleevents();
bool skiprequest = inputState.CheckAllInput();
auto clock = now - startTime;
if (screenfade < 1.f)
{
float ms = (clock / 1'000'000) / job.job->fadetime;
screenfade = clamp(ms, 0.f, 1.f);
twod->SetScreenFade(screenfade);
job.job->fadestate = DScreenJob::fadein;
}
else job.job->fadestate = DScreenJob::visible;
job.job->SetClock(clock);
int state = job.job->Frame(clock, skiprequest);
startTime -= job.job->GetClock() - clock;
// Must lock before displaying.
if (state < 1 && job.job->fadestyle & DScreenJob::fadeout)
twod->Lock();
videoNextPage();
if (state < 1)
{
if (job.job->fadestyle & DScreenJob::fadeout)
{
job.job->fadestate = DScreenJob::fadeout;
startTime = now;
float screenfade2;
do
{
now = I_nsTime();
auto clock = now - startTime;
float ms = (clock / 1'000'000) / job.job->fadetime;
screenfade2 = clamp(screenfade - ms, 0.f, 1.f);
twod->SetScreenFade(screenfade2);
if (screenfade2 <= 0.f) twod->Unlock(); // must unlock before displaying.
videoNextPage();
} while (screenfade2 > 0.f);
}
skipped = state < 0;
job.job->Destroy();
job.job->ObjectFlags |= OF_YesReallyDelete;
delete job.job;
twod->SetScreenFade(1);
break;
}
}
}
if (job.postAction) job.postAction();
}
if (completion) completion(false);
} }
#endif
void RunScreenJobFrame()
{
// we cannot recover from this because we have no completion callback to call.
if (!runner) I_Error("Trying to run a non-existent screen job");
auto res = runner->RunFrame();
if (!res) DeleteScreenJob();
}

View File

@ -14,7 +14,6 @@ class DScreenJob : public DObject
const float fadetime; // in milliseconds const float fadetime; // in milliseconds
int fadestate = fadein; int fadestate = fadein;
friend void RunScreenJob(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore);
friend class ScreenJobRunner; friend class ScreenJobRunner;
public: public:
@ -81,7 +80,8 @@ struct JobDesc
void RunScreenJob(JobDesc *jobs, int count, CompletionFunc completion, bool clearbefore = true); void RunScreenJob(JobDesc *jobs, int count, CompletionFunc completion, bool clearbefore = true);
void RunScreenJobSync(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore = true); void DeleteScreenJob();
void RunScreenJobFrame();
struct AnimSound struct AnimSound
{ {

View File

@ -40,6 +40,7 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
#include "buildtiles.h" #include "buildtiles.h"
#include "mapinfo.h" #include "mapinfo.h"
#include "c_dispatch.h" #include "c_dispatch.h"
#include "gamestate.h"
BEGIN_DUKE_NS BEGIN_DUKE_NS
@ -1077,6 +1078,15 @@ CCMD(testscreen)
C_HideConsole(); C_HideConsole();
FX_StopAllSounds(); FX_StopAllSounds();
Mus_Stop(); Mus_Stop();
auto gs = gamestate;
auto completion = [=](bool)
{
if (gs == GS_LEVEL || gs == GS_DEMOSCREEN) gamestate = gs;
else gamestate = GS_STARTUP;
};
if (argv.argc() > 1) if (argv.argc() > 1)
{ {
int screen = strtol(argv[1], nullptr, 0); int screen = strtol(argv[1], nullptr, 0);
@ -1088,7 +1098,7 @@ CCMD(testscreen)
case 3: case 3:
case 4: case 4:
bonussequence_d(screen, jobs, job); bonussequence_d(screen, jobs, job);
RunScreenJob(jobs, job, nullptr); RunScreenJob(jobs, job, completion);
break; break;
case 5: case 5:
@ -1097,7 +1107,7 @@ CCMD(testscreen)
case 6: case 6:
jobs[job++] = { Create<DDukeMultiplayerBonusScreen>(6) }; jobs[job++] = { Create<DDukeMultiplayerBonusScreen>(6) };
RunScreenJob(jobs, job, nullptr); RunScreenJob(jobs, job, completion);
break; break;
case 7: case 7:
@ -1110,13 +1120,13 @@ CCMD(testscreen)
case 9: case 9:
jobs[job++] = { Create<DDukeLevelSummaryScreen>() }; jobs[job++] = { Create<DDukeLevelSummaryScreen>() };
RunScreenJob(jobs, job, nullptr); RunScreenJob(jobs, job, completion);
break; break;
case 10: case 10:
ud.eog = true; ud.eog = true;
jobs[job++] = { Create<DDukeLevelSummaryScreen>() }; jobs[job++] = { Create<DDukeLevelSummaryScreen>() };
RunScreenJob(jobs, job, nullptr); RunScreenJob(jobs, job, completion);
ud.eog = false; ud.eog = false;
break; break;

View File

@ -38,6 +38,7 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
#include "screenjob.h" #include "screenjob.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "c_dispatch.h" #include "c_dispatch.h"
#include "gamestate.h"
BEGIN_DUKE_NS BEGIN_DUKE_NS
@ -644,6 +645,14 @@ CCMD(testrscreen)
C_HideConsole(); C_HideConsole();
FX_StopAllSounds(); FX_StopAllSounds();
Mus_Stop(); Mus_Stop();
auto gs = gamestate;
auto completion = [=](bool)
{
if (gs == GS_LEVEL || gs == GS_DEMOSCREEN) gamestate = gs;
else gamestate = GS_STARTUP;
};
if (argv.argc() > 1) if (argv.argc() > 1)
{ {
int screen = strtol(argv[1], nullptr, 0); int screen = strtol(argv[1], nullptr, 0);
@ -654,23 +663,23 @@ CCMD(testrscreen)
if (!isRRRA()) if (!isRRRA())
{ {
bonussequence_r(screen, jobs, job); bonussequence_r(screen, jobs, job);
RunScreenJob(jobs, job, nullptr); RunScreenJob(jobs, job, completion);
} }
break; break;
case 2: case 2:
jobs[job++] = { Create<DRRMultiplayerBonusScreen>(6) }; jobs[job++] = { Create<DRRMultiplayerBonusScreen>(6) };
RunScreenJob(jobs, job, nullptr); RunScreenJob(jobs, job, completion);
break; break;
case 3: case 3:
jobs[job++] = { Create<DRRLevelSummaryScreen>() }; jobs[job++] = { Create<DRRLevelSummaryScreen>() };
RunScreenJob(jobs, job, nullptr); RunScreenJob(jobs, job, completion);
break; break;
case 4: case 4:
jobs[job++] = { Create<DRRRAEndOfGame>() }; jobs[job++] = { Create<DRRRAEndOfGame>() };
RunScreenJob(jobs, job, nullptr); RunScreenJob(jobs, job, completion);
break; break;
default: default:

View File

@ -435,7 +435,7 @@ void app_loop()
break; break;
case GS_INTERMISSION: case GS_INTERMISSION:
// todo: run screen jobs here RunScreenJobFrame(); // This handles continuation through its completion callback.
break; break;
} }