mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-15 08:52:00 +00:00
- rewrote the ScreenJob player as a class that can be called by an asynchronous dispatcher.
Works, except for timing issues with ANMs.
This commit is contained in:
parent
2ce612e8ab
commit
31b9995406
9 changed files with 263 additions and 114 deletions
|
@ -67,95 +67,6 @@ int DImageScreen::Frame(uint64_t clock, bool skiprequest)
|
|||
return skiprequest ? -1 : 1;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void RunScreenJob(JobDesc *jobs, int count, CompletionFunc completion, bool clearbefore)
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
jobs[i].job->Release();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
@ -305,3 +216,235 @@ DScreenJob *PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
|||
return nothing();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class ScreenJobRunner
|
||||
{
|
||||
enum
|
||||
{
|
||||
State_Clear,
|
||||
State_Run,
|
||||
State_Fadeout
|
||||
};
|
||||
TArray<JobDesc> jobs;
|
||||
CompletionFunc completion;
|
||||
int index = -1;
|
||||
float screenfade;
|
||||
bool clearbefore;
|
||||
bool skipped = false;
|
||||
uint64_t startTime;
|
||||
int actionState;
|
||||
int terminateState;
|
||||
|
||||
public:
|
||||
ScreenJobRunner(JobDesc* jobs_, int count, CompletionFunc completion_, bool clearbefore_)
|
||||
: completion(std::move(completion_)), clearbefore(clearbefore_)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
jobs[i].job->Release();
|
||||
}
|
||||
AdvanceJob(false);
|
||||
}
|
||||
|
||||
void AdvanceJob(bool skip)
|
||||
{
|
||||
index++;
|
||||
while (index < jobs.Size() && (jobs[index].job == nullptr || (skip && jobs[index].ignoreifskipped))) index++;
|
||||
actionState = clearbefore ? State_Clear : State_Run;
|
||||
if (index < jobs.Size()) screenfade = jobs[index].job->fadestyle & DScreenJob::fadein ? 0.f : 1.f;
|
||||
}
|
||||
|
||||
int DisplayFrame()
|
||||
{
|
||||
auto& job = jobs[index];
|
||||
auto now = I_nsTime();
|
||||
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;
|
||||
return state;
|
||||
}
|
||||
|
||||
int FadeoutFrame()
|
||||
{
|
||||
auto now = I_nsTime();
|
||||
auto clock = now - startTime;
|
||||
float ms = (clock / 1'000'000) / jobs[index].job->fadetime;
|
||||
float screenfade2 = clamp(screenfade - ms, 0.f, 1.f);
|
||||
twod->SetScreenFade(screenfade2);
|
||||
if (screenfade2 <= 0.f)
|
||||
{
|
||||
twod->Unlock(); // must unlock before displaying.
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool RunFrame()
|
||||
{
|
||||
if (index >= jobs.Size())
|
||||
{
|
||||
for (auto& job : jobs)
|
||||
{
|
||||
job.job->Destroy();
|
||||
job.job->ObjectFlags |= OF_YesReallyDelete;
|
||||
delete job.job;
|
||||
}
|
||||
twod->SetScreenFade(1);
|
||||
if (completion) completion(false);
|
||||
return false;
|
||||
}
|
||||
handleevents();
|
||||
if (actionState == State_Clear)
|
||||
{
|
||||
actionState = State_Run;
|
||||
twod->ClearScreen();
|
||||
}
|
||||
else if (actionState == State_Run)
|
||||
{
|
||||
terminateState = DisplayFrame();
|
||||
if (terminateState < 1)
|
||||
{
|
||||
// Must lock before displaying.
|
||||
if (jobs[index].job->fadestyle & DScreenJob::fadeout)
|
||||
{
|
||||
twod->Lock();
|
||||
startTime = I_nsTime();
|
||||
jobs[index].job->fadestate = DScreenJob::fadeout;
|
||||
actionState = State_Fadeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
AdvanceJob(terminateState < 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (actionState == State_Fadeout)
|
||||
{
|
||||
int ended = FadeoutFrame();
|
||||
if (ended < 1)
|
||||
{
|
||||
AdvanceJob(terminateState < 0);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void RunScreenJob(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore)
|
||||
{
|
||||
ScreenJobRunner runner(jobs, count, completion, clearbefore);
|
||||
|
||||
while (runner.RunFrame())
|
||||
{
|
||||
videoNextPage();
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void RunScreenJobSync(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore)
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
jobs[i].job->Release();
|
||||
}
|
||||
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
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
using CompletionFunc = std::function<void(bool)>;
|
||||
struct JobDesc;
|
||||
class ScreenJobRunner;
|
||||
|
||||
class DScreenJob : public DObject
|
||||
{
|
||||
|
@ -14,6 +15,7 @@ class DScreenJob : public DObject
|
|||
int fadestate = fadein;
|
||||
|
||||
friend void RunScreenJob(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore);
|
||||
friend class ScreenJobRunner;
|
||||
|
||||
public:
|
||||
enum
|
||||
|
@ -79,6 +81,7 @@ struct JobDesc
|
|||
|
||||
|
||||
void RunScreenJob(JobDesc *jobs, int count, CompletionFunc completion, bool clearbefore = true);
|
||||
void RunScreenJobSync(JobDesc* jobs, int count, CompletionFunc completion, bool clearbefore = true);
|
||||
|
||||
struct AnimSound
|
||||
{
|
||||
|
|
|
@ -253,7 +253,7 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void Logo_d(CompletionFunc completion)
|
||||
void Logo_d(const CompletionFunc &completion)
|
||||
{
|
||||
Mus_Stop();
|
||||
FX_StopAllSounds(); // JBF 20031228
|
||||
|
@ -636,7 +636,7 @@ static void bonussequence_d(int num, JobDesc *jobs, int &job)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void showtwoscreens(CompletionFunc completion)
|
||||
void showtwoscreens(const CompletionFunc& completion)
|
||||
{
|
||||
JobDesc jobs[2];
|
||||
int job = 0;
|
||||
|
@ -646,7 +646,7 @@ void showtwoscreens(CompletionFunc completion)
|
|||
RunScreenJob(jobs, job, completion);
|
||||
}
|
||||
|
||||
void doorders(CompletionFunc completion)
|
||||
void doorders(const CompletionFunc& completion)
|
||||
{
|
||||
JobDesc jobs[4];
|
||||
int job = 0;
|
||||
|
@ -956,7 +956,7 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void dobonus_d(bool bonusonly, CompletionFunc completion)
|
||||
void dobonus_d(bool bonusonly, const CompletionFunc& completion)
|
||||
{
|
||||
JobDesc jobs[20];
|
||||
int job = 0;
|
||||
|
@ -988,7 +988,7 @@ void dobonus_d(bool bonusonly, CompletionFunc completion)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void e4intro(CompletionFunc completion)
|
||||
void e4intro(const CompletionFunc& completion)
|
||||
{
|
||||
JobDesc jobs[5];
|
||||
int job = 0;
|
||||
|
|
|
@ -164,7 +164,7 @@ static void MiniText(double x, double y, const char* t, int shade, int align = -
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void Logo_r(CompletionFunc completion)
|
||||
void Logo_r(const CompletionFunc& completion)
|
||||
{
|
||||
Mus_Stop();
|
||||
FX_StopAllSounds(); // JBF 20031228
|
||||
|
@ -552,7 +552,7 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void dobonus_r(bool bonusonly, CompletionFunc completion)
|
||||
void dobonus_r(bool bonusonly, const CompletionFunc& completion)
|
||||
{
|
||||
JobDesc jobs[20];
|
||||
int job = 0;
|
||||
|
|
|
@ -114,8 +114,8 @@ void think_r();
|
|||
void animatesprites_d(int x, int y, int a, int smoothratio);
|
||||
void animatesprites_r(int x, int y, int a, int smoothratio);
|
||||
|
||||
void Logo_d(CompletionFunc);
|
||||
void Logo_r(CompletionFunc);
|
||||
void Logo_d(const CompletionFunc&);
|
||||
void Logo_r(const CompletionFunc&);
|
||||
void InitFonts_d();
|
||||
void InitFonts_r();
|
||||
void PrintPaused_d();
|
||||
|
|
|
@ -69,7 +69,7 @@ struct GameInterface : ::GameInterface
|
|||
struct Dispatcher
|
||||
{
|
||||
// global stuff
|
||||
void (*ShowLogo)(CompletionFunc completion);
|
||||
void (*ShowLogo)(const CompletionFunc& completion);
|
||||
void (*InitFonts)();
|
||||
void (*PrintPaused)();
|
||||
|
||||
|
|
|
@ -156,8 +156,8 @@ void setsectinterpolate(int sprnum);
|
|||
int LocateTheLocator(int const tag, int const sectnum);
|
||||
void clearcamera(player_struct* ps);
|
||||
|
||||
void showtwoscreens(CompletionFunc func);
|
||||
void doorders(CompletionFunc func);
|
||||
void showtwoscreens(const CompletionFunc& func);
|
||||
void doorders(const CompletionFunc& func);
|
||||
|
||||
void execute(int s, int p, int d);
|
||||
void makeitfall(int s);
|
||||
|
@ -208,9 +208,9 @@ void drawstatusbar_d(int snum);
|
|||
void drawstatusbar_r(int snum);
|
||||
void drawoverheadmap(int cposx, int cposy, int czoom, int cang);
|
||||
void cameratext(int i);
|
||||
void dobonus(int bonusonly, CompletionFunc completion);
|
||||
void dobonus_d(bool bonusonly, CompletionFunc completion);
|
||||
void dobonus_r(bool bonusonly, CompletionFunc completion);
|
||||
void dobonus(int bonusonly, const CompletionFunc& completion);
|
||||
void dobonus_d(bool bonusonly, const CompletionFunc& completion);
|
||||
void dobonus_r(bool bonusonly, const CompletionFunc& completion);
|
||||
|
||||
void displayrest(int32_t smoothratio);
|
||||
void drawbackground(void);
|
||||
|
@ -221,11 +221,10 @@ void resettimevars();
|
|||
bool setnextmap(bool checksecretexit);
|
||||
void prelevel_d(int g);
|
||||
void prelevel_r(int g);
|
||||
void e4intro(CompletionFunc completion);
|
||||
void e4intro(const CompletionFunc& completion);
|
||||
void clearfrags(void);
|
||||
void exitlevel();
|
||||
int enterlevel(MapRecord* mi, int gm);
|
||||
void newgame(MapRecord* mi, int sk, CompletionFunc completion);
|
||||
void donewgame(MapRecord* map, int sk);
|
||||
void startnewgame(MapRecord* map, int skill);
|
||||
void setlocalplayerinput(player_struct *pp);
|
||||
|
|
|
@ -109,22 +109,25 @@ void setmapfog(int fogtype)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void runbonus(CompletionFunc completion)
|
||||
template<class func>
|
||||
void runbonus(func completion)
|
||||
{
|
||||
// MP scoreboard
|
||||
if (playerswhenstarted > 1 && ps[myconnectindex].gm & MODE_GAME && !ud.coop)
|
||||
{
|
||||
dobonus(1, completion);
|
||||
}
|
||||
else if (completion) completion(false);
|
||||
else completion(false);
|
||||
|
||||
}
|
||||
static void runtwoscreens(CompletionFunc completion)
|
||||
|
||||
template <class func>
|
||||
void runtwoscreens(func completion)
|
||||
{
|
||||
// shareware and TEN screens
|
||||
if (!VOLUMEALL && !isRR())
|
||||
showtwoscreens(completion);
|
||||
else if (completion) completion(false);
|
||||
else completion(false);
|
||||
}
|
||||
|
||||
static void endthegame(bool)
|
||||
|
@ -722,7 +725,7 @@ void cameratext(int i)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void dobonus(int bonusonly, CompletionFunc completion)
|
||||
void dobonus(int bonusonly, const CompletionFunc& completion)
|
||||
{
|
||||
if (isRRRA()) { if (completion) completion(false); }
|
||||
else if (isRR()) dobonus_r(bonusonly, completion);
|
||||
|
|
|
@ -837,7 +837,8 @@ void donewgame(MapRecord* map, int sk)
|
|||
}
|
||||
}
|
||||
|
||||
void newgame(MapRecord* map, int sk, CompletionFunc completion)
|
||||
template<class func>
|
||||
void newgame(MapRecord* map, int sk, func completion)
|
||||
{
|
||||
handleevents();
|
||||
ready2send = 0;
|
||||
|
@ -846,12 +847,12 @@ void newgame(MapRecord* map, int sk, CompletionFunc completion)
|
|||
{
|
||||
if (!isRR() && map->levelNumber == levelnum(3, 0) && (ud.multimode < 2))
|
||||
{
|
||||
e4intro([=](bool) { donewgame(map, sk); if (completion) completion(res); });
|
||||
e4intro([=](bool) { donewgame(map, sk); completion(res); });
|
||||
}
|
||||
else
|
||||
{
|
||||
donewgame(map, sk);
|
||||
if (completion) completion(res);
|
||||
completion(res);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue