From 805b91b721ef6a0da3934f3f3fada04d5fe62d20 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 22 Apr 2021 00:35:48 +0200 Subject: [PATCH] - put ScreenJobRunner declaration into header. --- source/core/screenjob.cpp | 371 ++++++++++++++++++++------------------ source/core/screenjob.h | 43 ++++- 2 files changed, 233 insertions(+), 181 deletions(-) diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 40d1c0963..5a9991e51 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -117,208 +117,223 @@ void DImageScreen::Draw(double smoothratio) // //--------------------------------------------------------------------------- -class ScreenJobRunner +ScreenJobRunner::ScreenJobRunner(JobDesc* jobs_, int count, CompletionFunc completion_, bool clearbefore_, bool skipall_) + : completion(std::move(completion_)), clearbefore(clearbefore_), skipall(skipall_) { - enum + jobs.Resize(count); + memcpy(jobs.Data(), jobs_, count * sizeof(JobDesc)); + // Release all jobs from the garbage collector - the code as it is cannot deal with them getting collected. This should be removed later once the GC is working. + for (int i = 0; i < count; i++) { - State_Clear, - State_Run, - State_Fadeout - }; - TArray jobs; - CompletionFunc completion; - int index = -1; - float screenfade; - bool clearbefore; - bool skipall; - int actionState; - int terminateState; - int fadeticks = 0; - int last_paused_tic = -1; + jobs[i].job->Release(); + } + AdvanceJob(false); +} -public: - ScreenJobRunner(JobDesc* jobs_, int count, CompletionFunc completion_, bool clearbefore_, bool skipall_) - : completion(std::move(completion_)), clearbefore(clearbefore_), skipall(skipall_) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +ScreenJobRunner::~ScreenJobRunner() +{ + DeleteJobs(); +} + +void ScreenJobRunner::DeleteJobs() +{ + for (auto& job : jobs) { - jobs.Resize(count); - memcpy(jobs.Data(), jobs_, count * sizeof(JobDesc)); - // Release all jobs from the garbage collector - the code as it is cannot deal with them getting collected. This should be removed later once the GC is working. - for (int i = 0; i < count; i++) + job.job->ObjectFlags |= OF_YesReallyDelete; + delete job.job; + } + jobs.Clear(); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ScreenJobRunner::AdvanceJob(bool skip) +{ + if (index >= 0) + { + //if (jobs[index].postAction) jobs[index].postAction(); + jobs[index].job->Destroy(); + } + index++; + while (index < jobs.Size() && (jobs[index].job == nullptr || (skip && skipall))) + { + if (jobs[index].job != nullptr) jobs[index].job->Destroy(); + index++; + } + actionState = clearbefore ? State_Clear : State_Run; + if (index < jobs.Size()) + { + jobs[index].job->fadestate = !paused && jobs[index].job->flags & DScreenJob::fadein? DScreenJob::fadein : DScreenJob::visible; + jobs[index].job->Start(); + } + inputState.ClearAllInput(); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int ScreenJobRunner::DisplayFrame(double smoothratio) +{ + auto& job = jobs[index]; + auto now = I_GetTimeNS(); + bool processed = job.job->ProcessInput(); + + if (job.job->fadestate == DScreenJob::fadein) + { + double ms = (job.job->ticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime; + float screenfade = (float)clamp(ms, 0., 1.); + twod->SetScreenFade(screenfade); + if (screenfade == 1.f) job.job->fadestate = DScreenJob::visible; + } + int state = job.job->DrawFrame(smoothratio); + twod->SetScreenFade(1.f); + return state; +} + +int ScreenJobRunner::FadeoutFrame(double smoothratio) +{ + auto& job = jobs[index]; + double ms = (fadeticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime; + float screenfade = 1.f - (float)clamp(ms, 0., 1.); + twod->SetScreenFade(screenfade); + job.job->DrawFrame(1.); + return (screenfade > 0.f); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool ScreenJobRunner::OnEvent(event_t* ev) +{ + if (paused || index >= jobs.Size()) return false; + + if (ev->type == EV_KeyDown) + { + // We never reach the key binding checks in G_Responder, so for the console we have to check for ourselves here. + auto binding = Bindings.GetBinding(ev->data1); + if (binding.CompareNoCase("toggleconsole") == 0) { - jobs[i].job->Release(); + C_ToggleConsole(); + return true; } - AdvanceJob(false); } - ~ScreenJobRunner() + if (jobs[index].job->state != DScreenJob::running) return false; + + return jobs[index].job->OnEvent(ev); +} + +void ScreenJobRunner::OnFinished() +{ + if (completion) completion(false); + completion = nullptr; // only finish once. +} + +void ScreenJobRunner::OnTick() +{ + if (paused) return; + if (index >= jobs.Size()) + { + //DeleteJobs(); + //twod->SetScreenFade(1); + //twod->ClearScreen(); // This must not leave the 2d buffer empty. + //if (gamestate == GS_INTRO) OnFinished(); + //else Net_WriteByte(DEM_ENDSCREENJOB); // intermissions must be terminated synchronously. + } + else + { + if (jobs[index].job->state == DScreenJob::running) + { + jobs[index].job->ticks++; + jobs[index].job->OnTick(); + } + else if (jobs[index].job->state == DScreenJob::stopping) + { + fadeticks++; + } + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool ScreenJobRunner::RunFrame() +{ + if (index >= jobs.Size()) { DeleteJobs(); - } - - void DeleteJobs() - { - for (auto& job : jobs) - { - job.job->ObjectFlags |= OF_YesReallyDelete; - delete job.job; - } - jobs.Clear(); - } - - void AdvanceJob(bool skip) - { - if (index >= 0) - { - //if (jobs[index].postAction) jobs[index].postAction(); - jobs[index].job->Destroy(); - } - index++; - while (index < jobs.Size() && (jobs[index].job == nullptr || (skip && skipall))) - { - if (jobs[index].job != nullptr) jobs[index].job->Destroy(); - index++; - } - actionState = clearbefore ? State_Clear : State_Run; - if (index < jobs.Size()) - { - jobs[index].job->fadestate = !paused && jobs[index].job->flags & DScreenJob::fadein? DScreenJob::fadein : DScreenJob::visible; - jobs[index].job->Start(); - } - inputState.ClearAllInput(); - } - - int DisplayFrame(double smoothratio) - { - auto& job = jobs[index]; - auto now = I_GetTimeNS(); - bool processed = job.job->ProcessInput(); - - if (job.job->fadestate == DScreenJob::fadein) - { - double ms = (job.job->ticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime; - float screenfade = (float)clamp(ms, 0., 1.); - twod->SetScreenFade(screenfade); - if (screenfade == 1.f) job.job->fadestate = DScreenJob::visible; - } - int state = job.job->DrawFrame(smoothratio); - twod->SetScreenFade(1.f); - return state; - } - - int FadeoutFrame(double smoothratio) - { - auto& job = jobs[index]; - double ms = (fadeticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime; - float screenfade = 1.f - (float)clamp(ms, 0., 1.); - twod->SetScreenFade(screenfade); - job.job->DrawFrame(1.); - return (screenfade > 0.f); - } - - bool OnEvent(event_t* ev) - { - if (paused || index >= jobs.Size()) return false; - - if (ev->type == EV_KeyDown) - { - // We never reach the key binding checks in G_Responder, so for the console we have to check for ourselves here. - auto binding = Bindings.GetBinding(ev->data1); - if (binding.CompareNoCase("toggleconsole") == 0) - { - C_ToggleConsole(); - return true; - } - } - - if (jobs[index].job->state != DScreenJob::running) return false; - - return jobs[index].job->OnEvent(ev); - } - - void OnFinished() - { + twod->SetScreenFade(1); + twod->ClearScreen(); // This must not leave the 2d buffer empty. if (completion) completion(false); - completion = nullptr; // only finish once. + return false; } - void OnTick() + // ensure that we won't go back in time if the menu is dismissed without advancing our ticker + bool menuon = paused; + if (menuon) last_paused_tic = jobs[index].job->ticks; + else if (last_paused_tic == jobs[index].job->ticks) menuon = true; + double smoothratio = menuon ? 1. : I_GetTimeFrac(); + + if (actionState == State_Clear) { - if (paused) return; - if (index >= jobs.Size()) - { - //DeleteJobs(); - //twod->SetScreenFade(1); - //twod->ClearScreen(); // This must not leave the 2d buffer empty. - //if (gamestate == GS_INTRO) OnFinished(); - //else Net_WriteByte(DEM_ENDSCREENJOB); // intermissions must be terminated synchronously. - } - else - { - if (jobs[index].job->state == DScreenJob::running) - { - jobs[index].job->ticks++; - jobs[index].job->OnTick(); - } - else if (jobs[index].job->state == DScreenJob::stopping) - { - fadeticks++; - } - } + actionState = State_Run; + twod->ClearScreen(); } - - bool RunFrame() + else if (actionState == State_Run) { - if (index >= jobs.Size()) + terminateState = DisplayFrame(smoothratio); + if (terminateState < 1) { - DeleteJobs(); - twod->SetScreenFade(1); - twod->ClearScreen(); // This must not leave the 2d buffer empty. - if (completion) completion(false); - return false; - } - - // ensure that we won't go back in time if the menu is dismissed without advancing our ticker - bool menuon = paused; - if (menuon) last_paused_tic = jobs[index].job->ticks; - else if (last_paused_tic == jobs[index].job->ticks) menuon = true; - double smoothratio = menuon ? 1. : I_GetTimeFrac(); - - if (actionState == State_Clear) - { - actionState = State_Run; - twod->ClearScreen(); - } - else if (actionState == State_Run) - { - terminateState = DisplayFrame(smoothratio); - if (terminateState < 1) + // Must lock before displaying. + if (jobs[index].job->flags & DScreenJob::fadeout) { - // Must lock before displaying. - if (jobs[index].job->flags & DScreenJob::fadeout) - { - jobs[index].job->fadestate = DScreenJob::fadeout; - jobs[index].job->state = DScreenJob::stopping; - actionState = State_Fadeout; - fadeticks = 0; - } - else - { - AdvanceJob(terminateState < 0); - } + jobs[index].job->fadestate = DScreenJob::fadeout; + jobs[index].job->state = DScreenJob::stopping; + actionState = State_Fadeout; + fadeticks = 0; } - } - else if (actionState == State_Fadeout) - { - int ended = FadeoutFrame(smoothratio); - if (ended < 1) + else { - jobs[index].job->state = DScreenJob::stopped; AdvanceJob(terminateState < 0); } } - return true; } -}; + else if (actionState == State_Fadeout) + { + int ended = FadeoutFrame(smoothratio); + if (ended < 1) + { + jobs[index].job->state = DScreenJob::stopped; + AdvanceJob(terminateState < 0); + } + } + return true; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- ScreenJobRunner *runner; diff --git a/source/core/screenjob.h b/source/core/screenjob.h index 3eed95e10..4dd35dd56 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -132,15 +132,52 @@ public: void Draw(double smooth) override; }; - - +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- struct JobDesc { DScreenJob* job; - //void (*postAction)(); }; + +class ScreenJobRunner +{ + enum + { + State_Clear, + State_Run, + State_Fadeout + }; + TArray jobs; + CompletionFunc completion; + int index = -1; + float screenfade; + bool clearbefore; + bool skipall; + int actionState; + int terminateState; + int fadeticks = 0; + int last_paused_tic = -1; + +public: + ScreenJobRunner(JobDesc* jobs_, int count, CompletionFunc completion_, bool clearbefore_, bool skipall_); + ~ScreenJobRunner(); + void DeleteJobs(); + void AdvanceJob(bool skip); + int DisplayFrame(double smoothratio); + int FadeoutFrame(double smoothratio); + bool OnEvent(event_t* ev); + void OnFinished(); + void OnTick(); + bool RunFrame(); +}; + + + enum { SJ_DONTCLEAR = 1,