diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index b3bb83deb..4f4e8fd0f 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -66,6 +66,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "startupinfo.h" #include "mapinfo.h" #include "menustate.h" +#include "screenjob.h" CVAR(Bool, autoloadlights, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, autoloadbrightmaps, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) @@ -518,6 +519,7 @@ int GameMain() I_ShowFatalError(err.what()); r = -1; } + DeleteScreenJob(); M_ClearMenus(true); if (gi) { diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 35d395906..ef374b9d1 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -42,6 +42,7 @@ #include "v_draw.h" #include "s_soundinternal.h" #include "animtexture.h" +#include "gamestate.h" IMPLEMENT_CLASS(DScreenJob, true, false) @@ -258,6 +259,22 @@ public: 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) { index++; @@ -307,12 +324,7 @@ public: { if (index >= jobs.Size()) { - for (auto& job : jobs) - { - job.job->Destroy(); - job.job->ObjectFlags |= OF_YesReallyDelete; - delete job.job; - } + DeleteJobs(); twod->SetScreenFade(1); if (completion) completion(false); return false; @@ -354,102 +366,32 @@ public: } }; +ScreenJobRunner *runner; + void RunScreenJob(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore) { - ScreenJobRunner runner(jobs, count, completion, clearbefore); - - while (runner.RunFrame()) + assert(completion != nullptr); + if (count) { - 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. - for (int i = 0; i < count; i++) + if (runner) { - 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(); +} diff --git a/source/core/screenjob.h b/source/core/screenjob.h index f8fb89422..77c5afdc3 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -14,7 +14,6 @@ class DScreenJob : public DObject const float fadetime; // in milliseconds int fadestate = fadein; - friend void RunScreenJob(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore); friend class ScreenJobRunner; public: @@ -81,7 +80,8 @@ struct JobDesc 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 { diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index 55df398d9..5ef96a851 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -40,6 +40,7 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) #include "buildtiles.h" #include "mapinfo.h" #include "c_dispatch.h" +#include "gamestate.h" BEGIN_DUKE_NS @@ -1077,6 +1078,15 @@ CCMD(testscreen) C_HideConsole(); FX_StopAllSounds(); 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) { int screen = strtol(argv[1], nullptr, 0); @@ -1088,7 +1098,7 @@ CCMD(testscreen) case 3: case 4: bonussequence_d(screen, jobs, job); - RunScreenJob(jobs, job, nullptr); + RunScreenJob(jobs, job, completion); break; case 5: @@ -1097,7 +1107,7 @@ CCMD(testscreen) case 6: jobs[job++] = { Create(6) }; - RunScreenJob(jobs, job, nullptr); + RunScreenJob(jobs, job, completion); break; case 7: @@ -1110,13 +1120,13 @@ CCMD(testscreen) case 9: jobs[job++] = { Create() }; - RunScreenJob(jobs, job, nullptr); + RunScreenJob(jobs, job, completion); break; case 10: ud.eog = true; jobs[job++] = { Create() }; - RunScreenJob(jobs, job, nullptr); + RunScreenJob(jobs, job, completion); ud.eog = false; break; diff --git a/source/games/duke/src/2d_r.cpp b/source/games/duke/src/2d_r.cpp index b9304fc5b..db0b5e540 100644 --- a/source/games/duke/src/2d_r.cpp +++ b/source/games/duke/src/2d_r.cpp @@ -38,6 +38,7 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms #include "screenjob.h" #include "texturemanager.h" #include "c_dispatch.h" +#include "gamestate.h" BEGIN_DUKE_NS @@ -644,6 +645,14 @@ CCMD(testrscreen) C_HideConsole(); FX_StopAllSounds(); 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) { int screen = strtol(argv[1], nullptr, 0); @@ -654,23 +663,23 @@ CCMD(testrscreen) if (!isRRRA()) { bonussequence_r(screen, jobs, job); - RunScreenJob(jobs, job, nullptr); + RunScreenJob(jobs, job, completion); } break; case 2: jobs[job++] = { Create(6) }; - RunScreenJob(jobs, job, nullptr); + RunScreenJob(jobs, job, completion); break; case 3: jobs[job++] = { Create() }; - RunScreenJob(jobs, job, nullptr); + RunScreenJob(jobs, job, completion); break; case 4: jobs[job++] = { Create() }; - RunScreenJob(jobs, job, nullptr); + RunScreenJob(jobs, job, completion); break; default: diff --git a/source/games/duke/src/gameloop.cpp b/source/games/duke/src/gameloop.cpp index 9bef3c3c2..5dc1cfeaa 100644 --- a/source/games/duke/src/gameloop.cpp +++ b/source/games/duke/src/gameloop.cpp @@ -435,7 +435,7 @@ void app_loop() break; case GS_INTERMISSION: - // todo: run screen jobs here + RunScreenJobFrame(); // This handles continuation through its completion callback. break; }