- cleaned up the screen job's fade handling, now that the jobs no longer depend on an external timer.

This commit is contained in:
Christoph Oelckers 2021-04-16 21:27:54 +02:00
parent e580407d7d
commit 2942e011bf
6 changed files with 46 additions and 80 deletions

View file

@ -189,8 +189,9 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle)
//
//==========================================================================
int F2DDrawer::AddCommand(const RenderCommand *data)
int F2DDrawer::AddCommand(RenderCommand *data)
{
data->mScreenFade = screenFade;
if (mData.Size() > 0 && data->isCompatible(mData.Last()))
{
// Merge with the last command.

View file

@ -118,6 +118,7 @@ public:
ETexMode mDrawMode;
uint8_t mLightLevel;
uint8_t mFlags;
float mScreenFade;
bool useTransform;
DMatrix3x3 transform;
@ -149,6 +150,7 @@ public:
mLightLevel == other.mLightLevel &&
mColor1.d == other.mColor1.d &&
useTransform == other.useTransform &&
mScreenFade == other.mScreenFade &&
(
!useTransform ||
(
@ -172,7 +174,7 @@ public:
int fullscreenautoaspect = 3;
int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1;
int AddCommand(const RenderCommand *data);
int AddCommand(RenderCommand *data);
void AddIndices(int firstvert, int count, ...);
private:
void AddIndices(int firstvert, TArray<int> &v);

View file

@ -85,7 +85,6 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state)
vb.UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size());
state.SetVertexBuffer(&vb);
state.EnableFog(false);
state.SetScreenFade(drawer->screenFade);
for(auto &cmd : commands)
{
@ -94,6 +93,7 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state)
state.SetRenderStyle(cmd.mRenderStyle);
state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed));
state.EnableFog(2); // Special 2D mode 'fog'.
state.SetScreenFade(cmd.mScreenFade);
state.SetTextureMode(cmd.mDrawMode);

View file

@ -125,11 +125,10 @@ class ScreenJobRunner
int index = -1;
float screenfade;
bool clearbefore;
int64_t startTime = -1;
int64_t lastTime = -1;
int actionState;
int terminateState;
uint64_t clock = 0;
int fadeticks = 0;
int last_M_Active_Tic = -1;
public:
ScreenJobRunner(JobDesc* jobs_, int count, CompletionFunc completion_, bool clearbefore_)
@ -174,73 +173,39 @@ public:
index++;
}
actionState = clearbefore ? State_Clear : State_Run;
if (index < jobs.Size()) screenfade = jobs[index].job->fadestyle & DScreenJob::fadein ? 0.f : 1.f;
lastTime= startTime = -1;
clock = 0;
if (index < jobs.Size())
{
jobs[index].job->fadestate = jobs[index].job->fadestyle & DScreenJob::fadein? DScreenJob::fadein : DScreenJob::visible;
}
inputState.ClearAllInput();
}
int DisplayFrame()
int DisplayFrame(double smoothratio)
{
auto& job = jobs[index];
auto now = I_GetTimeNS();
bool processed = job.job->ProcessInput();
if (startTime == -1)
{
lastTime = startTime = now;
}
else if (!M_Active())
{
clock += now - lastTime;
if (clock == 0) clock = 1;
}
bool skiprequest = clock > 100'000'000 && inputState.CheckAllInput() && !processed && job.job->fadestate != DScreenJob::fadeout;
lastTime = now;
if (screenfade < 1.f && !M_Active())
if (job.job->fadestate == DScreenJob::fadein)
{
float ms = (clock / 1'000'000) / job.job->fadetime;
screenfade = clamp(ms, 0.f, 1.f);
double ms = (job.job->ticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime;
float screenfade = (float)clamp(ms, 0., 1.);
twod->SetScreenFade(screenfade);
if (job.job->fadestate != DScreenJob::fadeout)
job.job->fadestate = DScreenJob::fadein;
if (screenfade == 1.f) job.job->fadestate = DScreenJob::visible;
}
else
{
job.job->fadestate = DScreenJob::visible;
screenfade = 1.f;
}
job.job->SetClock(clock);
int state = job.job->Frame(clock, skiprequest, M_Active()? 1. : I_GetTimeFrac());
clock = job.job->GetClock();
if (clock == 0) clock = 1;
int state = job.job->DrawFrame(smoothratio);
twod->SetScreenFade(1.f);
return state;
}
int FadeoutFrame()
int FadeoutFrame(double smoothratio)
{
auto now = I_GetTimeNS();
if (startTime == -1)
{
lastTime = startTime = now;
}
else if (!M_Active())
{
clock += now - lastTime;
if (clock == 0) clock = 1;
}
lastTime = now;
float ms = (clock / 1'000'000) / jobs[index].job->fadetime;
float screenfade2 = clamp(screenfade - ms, 0.f, 1.f);
if (!M_Active()) twod->SetScreenFade(screenfade2);
if (screenfade2 <= 0.f)
{
twod->Unlock(); // must unlock before displaying.
return 0;
}
return 1;
auto& job = jobs[index];
double ms = (job.job->ticks + 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)
@ -268,9 +233,15 @@ public:
}
else
{
if (jobs[index].job->state != DScreenJob::running) return;
jobs[index].job->ticks++;
jobs[index].job->OnTick();
if (jobs[index].job->state == DScreenJob::running)
{
jobs[index].job->ticks++;
jobs[index].job->OnTick();
}
else if (jobs[index].job->state == DScreenJob::stopping)
{
fadeticks++;
}
}
}
@ -284,6 +255,13 @@ public:
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 = M_Active();
if (menuon) last_M_Active_Tic = jobs[index].job->ticks;
else if (last_M_Active_Tic == jobs[index].job->ticks) menuon = true;
double smoothratio = menuon ? 1. : I_GetTimeFrac();
if (actionState == State_Clear)
{
actionState = State_Run;
@ -291,18 +269,14 @@ public:
}
else if (actionState == State_Run)
{
terminateState = DisplayFrame();
terminateState = DisplayFrame(smoothratio);
if (terminateState < 1)
{
// Must lock before displaying.
if (jobs[index].job->fadestyle & DScreenJob::fadeout)
{
twod->Lock();
startTime = -1;
clock = 0;
jobs[index].job->fadestate = DScreenJob::fadeout;
jobs[index].job->state = DScreenJob::stopping;
gamestate = GS_INTRO; // block menu and console during fadeout - this can cause timing problems.
actionState = State_Fadeout;
}
else
@ -313,7 +287,7 @@ public:
}
else if (actionState == State_Fadeout)
{
int ended = FadeoutFrame();
int ended = FadeoutFrame(smoothratio);
if (ended < 1)
{
jobs[index].job->state = DScreenJob::stopped;

View file

@ -11,7 +11,6 @@ class ScreenJobRunner;
class DScreenJob : public DObject
{
DECLARE_CLASS(DScreenJob, DObject)
int64_t now;
const int fadestyle;
const float fadetime; // in milliseconds
int fadestate = fadein;
@ -45,21 +44,11 @@ public:
return false;
}
void SetClock(int64_t nsnow)
{
now = nsnow;
}
int64_t GetClock() const
{
return now;
}
virtual bool OnEvent(event_t* evt) { return false; }
virtual void OnTick() { /*state = finished;*/ }
virtual void Draw(double smoothratio) {}
int Frame(uint64_t clock, bool skiprequest, double smoothratio)
int DrawFrame(double smoothratio)
{
if (state != running) smoothratio = 1; // this is necessary because the ticker won't be incremented anymore to avoid having a negative time span.
Draw(smoothratio);

View file

@ -526,7 +526,7 @@ class DEpisode4Text : public DSkippableScreenJob
public:
DEpisode4Text() : DSkippableScreenJob(fadein | fadeout) {}
void Draw(double)
void Draw(double) override
{
twod->ClearScreen();
BigText(160, 60, GStrings("Thanks to all our"));