mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-27 04:00:42 +00:00
- cleanup of movie player code, migration to event interface.
This commit is contained in:
parent
dbd3e1de44
commit
aad6158288
3 changed files with 188 additions and 66 deletions
|
@ -51,13 +51,22 @@
|
|||
#include "raze_music.h"
|
||||
|
||||
|
||||
class MoviePlayer
|
||||
{
|
||||
public:
|
||||
virtual void Start() {}
|
||||
virtual bool Frame(uint64_t clock) = 0;
|
||||
virtual void Stop() {}
|
||||
virtual ~MoviePlayer() = default;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class DAnmPlayer : public DScreenJob
|
||||
class AnmPlayer : public MoviePlayer
|
||||
{
|
||||
// This doesn't need its own class type
|
||||
anim_t anim;
|
||||
|
@ -74,7 +83,7 @@ class DAnmPlayer : public DScreenJob
|
|||
public:
|
||||
bool isvalid() { return numframes > 0; }
|
||||
|
||||
DAnmPlayer(FileReader& fr, const AnimSound* ans, const int *frameticks, bool nosoundcutoff)
|
||||
AnmPlayer(FileReader& fr, const AnimSound* ans, const int *frameticks, bool nosoundcutoff)
|
||||
: animSnd(ans), frameTicks(frameticks), nostopsound(nosoundcutoff)
|
||||
{
|
||||
buffer = fr.ReadPadded(1);
|
||||
|
@ -94,7 +103,7 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int Frame(uint64_t clock, bool skiprequest) override
|
||||
bool Frame(uint64_t clock) override
|
||||
{
|
||||
int currentclock = int(clock * 120 / 1'000'000'000);
|
||||
|
||||
|
@ -102,8 +111,7 @@ public:
|
|||
{
|
||||
twod->ClearScreen();
|
||||
DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false, TAG_DONE);
|
||||
if (skiprequest && !nostopsound) soundEngine->StopAllChannels();
|
||||
return skiprequest? -1 : 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
animtex.SetFrame(ANIM_GetPalette(&anim), ANIM_DrawFrame(&anim, curframe));
|
||||
|
@ -132,13 +140,18 @@ public:
|
|||
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE);
|
||||
}
|
||||
}
|
||||
if (!skiprequest && !nostopsound && curframe == numframes && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, -1)) return 1;
|
||||
if (!nostopsound && curframe == numframes && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, -1)) return true;
|
||||
curframe++;
|
||||
if (skiprequest && !nostopsound) soundEngine->StopAllChannels();
|
||||
return skiprequest ? -1 : curframe < numframes? 1 : 0;
|
||||
return curframe < numframes;
|
||||
}
|
||||
|
||||
void OnDestroy() override
|
||||
void Stop() override
|
||||
{
|
||||
if (!nostopsound) soundEngine->StopAllChannels();
|
||||
}
|
||||
|
||||
|
||||
~AnmPlayer()
|
||||
{
|
||||
buffer.Reset();
|
||||
animtex.Clean();
|
||||
|
@ -151,7 +164,7 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class DMvePlayer : public DScreenJob
|
||||
class MvePlayer : public MoviePlayer
|
||||
{
|
||||
InterplayDecoder decoder;
|
||||
bool failed = false;
|
||||
|
@ -159,7 +172,7 @@ class DMvePlayer : public DScreenJob
|
|||
public:
|
||||
bool isvalid() { return !failed; }
|
||||
|
||||
DMvePlayer(FileReader& fr) : decoder(SoundEnabled())
|
||||
MvePlayer(FileReader& fr) : decoder(SoundEnabled())
|
||||
{
|
||||
failed = !decoder.Open(fr);
|
||||
}
|
||||
|
@ -170,17 +183,16 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int Frame(uint64_t clock, bool skiprequest) override
|
||||
bool Frame(uint64_t clock) override
|
||||
{
|
||||
if (failed) return -1;
|
||||
if (failed) return false;
|
||||
bool playon = decoder.RunFrame(clock);
|
||||
twod->ClearScreen();
|
||||
DrawTexture(twod, decoder.animTex().GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE);
|
||||
|
||||
return skiprequest ? -1 : playon ? 1 : 0;
|
||||
return playon;
|
||||
}
|
||||
|
||||
void OnDestroy() override
|
||||
~MvePlayer()
|
||||
{
|
||||
decoder.Close();
|
||||
}
|
||||
|
@ -192,7 +204,7 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class DVpxPlayer : public DScreenJob
|
||||
class VpxPlayer : public MoviePlayer
|
||||
{
|
||||
bool failed = false;
|
||||
FileReader fr;
|
||||
|
@ -222,7 +234,7 @@ public:
|
|||
public:
|
||||
bool isvalid() { return !failed; }
|
||||
|
||||
DVpxPlayer(FileReader& fr_, const AnimSound* animSnd_, int origframedelay)
|
||||
VpxPlayer(FileReader& fr_, const AnimSound* animSnd_, int origframedelay, FString& error)
|
||||
{
|
||||
fr = std::move(fr_);
|
||||
animSnd = animSnd_;
|
||||
|
@ -230,7 +242,7 @@ public:
|
|||
if (!ReadIVFHeader(origframedelay))
|
||||
{
|
||||
// We should never get here, because any file failing this has been eliminated before this constructor got called.
|
||||
Printf(PRINT_BOLD, "Failed reading IVF header\n");
|
||||
error.Format("Failed reading IVF header\n");
|
||||
failed = true;
|
||||
}
|
||||
|
||||
|
@ -241,7 +253,7 @@ public:
|
|||
vpx_codec_dec_cfg_t cfg = { 1, width, height };
|
||||
if (vpx_codec_dec_init(&codec, &vpx_codec_vp8_dx_algo, &cfg, 0))
|
||||
{
|
||||
Printf(PRINT_BOLD, "Error initializing VPX codec.\n");
|
||||
error.Format("Error initializing VPX codec.\n");
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
@ -387,16 +399,23 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int Frame(uint64_t clock, bool skiprequest) override
|
||||
void Start() override
|
||||
{
|
||||
if (clock == 0)
|
||||
if (soundtrack > 0)
|
||||
{
|
||||
if (soundtrack > 0)
|
||||
{
|
||||
Mus_Play(nullptr, fileSystem.GetFileFullName(soundtrack, false), false);
|
||||
}
|
||||
animtex.SetSize(AnimTexture::YUV, width, height);
|
||||
Mus_Play(nullptr, fileSystem.GetFileFullName(soundtrack, false), false);
|
||||
}
|
||||
animtex.SetSize(AnimTexture::YUV, width, height);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool Frame(uint64_t clock) override
|
||||
{
|
||||
bool stop = false;
|
||||
if (clock > nextframetime)
|
||||
{
|
||||
|
@ -432,14 +451,18 @@ public:
|
|||
}
|
||||
}
|
||||
DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit, TAG_DONE);
|
||||
if (stop || skiprequest) Mus_Stop();
|
||||
if (stop) return 0;
|
||||
return skiprequest ? -1 : 1;
|
||||
return !stop;
|
||||
}
|
||||
|
||||
void OnDestroy() override
|
||||
void Stop()
|
||||
{
|
||||
Mus_Stop();
|
||||
}
|
||||
|
||||
~VpxPlayer()
|
||||
{
|
||||
vpx_codec_destroy(&codec);
|
||||
animtex.Clean();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -460,7 +483,7 @@ struct AudioData
|
|||
int nRead;
|
||||
};
|
||||
|
||||
class DSmkPlayer : public DScreenJob
|
||||
class SmkPlayer : public MoviePlayer
|
||||
{
|
||||
SmackerHandle hSMK{};
|
||||
int numAudioTracks;
|
||||
|
@ -484,7 +507,7 @@ public:
|
|||
|
||||
static bool StreamCallbackFunc(SoundStream* stream, void* buff, int len, void* userdata)
|
||||
{
|
||||
DSmkPlayer* pId = (DSmkPlayer*)userdata;
|
||||
SmkPlayer* pId = (SmkPlayer*)userdata;
|
||||
memcpy(buff, &pId->adata.samples[pId->adata.nRead], len);
|
||||
pId->adata.nRead += len / 2;
|
||||
if (pId->adata.nRead >= countof(pId->adata.samples)) pId->adata.nRead = 0;
|
||||
|
@ -511,7 +534,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
DSmkPlayer(const char *fn, const AnimSound* ans, bool fixedviewport)
|
||||
SmkPlayer(const char *fn, const AnimSound* ans, bool fixedviewport)
|
||||
{
|
||||
hSMK = Smacker_Open(fn);
|
||||
if (!hSMK.isValid)
|
||||
|
@ -551,23 +574,32 @@ public:
|
|||
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void Start() override
|
||||
{
|
||||
animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int Frame(uint64_t clock, bool skiprequest) override
|
||||
bool Frame(uint64_t clock) override
|
||||
{
|
||||
int frame = clock / nFrameNs;
|
||||
|
||||
if (clock == 0)
|
||||
{
|
||||
animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight);
|
||||
}
|
||||
twod->ClearScreen();
|
||||
Printf("clock = %llu, frame = %d\n", clock, frame);
|
||||
if (frame > nFrame)
|
||||
{
|
||||
Printf("Updating\n");
|
||||
Smacker_GetPalette(hSMK, palette);
|
||||
Smacker_GetFrame(hSMK, pFrame.Data());
|
||||
animtex.SetFrame(palette, pFrame.Data());
|
||||
|
@ -607,10 +639,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
return skiprequest ? -1 : nFrame < nFrames ? 1 : 0;
|
||||
return nFrame < nFrames;
|
||||
}
|
||||
|
||||
void OnDestroy() override
|
||||
~SmkPlayer()
|
||||
{
|
||||
Smacker_Close(hSMK);
|
||||
if (stream) S_StopCustomStream(stream);
|
||||
|
@ -625,13 +657,56 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff)
|
||||
class DMoviePlayer : public DSkippableScreenJob
|
||||
{
|
||||
auto nothing = []()->DScreenJob* { return Create<DScreenJob>(); };
|
||||
if (!filename)
|
||||
MoviePlayer* player;
|
||||
bool started = false;
|
||||
|
||||
public:
|
||||
DMoviePlayer(MoviePlayer* mp)
|
||||
{
|
||||
return nothing();
|
||||
player = mp;
|
||||
}
|
||||
|
||||
void Draw(double smoothratio) override
|
||||
{
|
||||
if (!player)
|
||||
{
|
||||
state = stopped;
|
||||
return;
|
||||
}
|
||||
if (!started)
|
||||
{
|
||||
started = true;
|
||||
player->Start();
|
||||
}
|
||||
uint64_t clock = (ticks + smoothratio) * 1'000'000'000. / GameTicRate;
|
||||
if (state == running && !player->Frame(clock))
|
||||
{
|
||||
state = finished;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy() override
|
||||
{
|
||||
if (player)
|
||||
{
|
||||
player->Stop();
|
||||
delete player;
|
||||
}
|
||||
player = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
MoviePlayer* OpenMovie(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff, FString& error)
|
||||
{
|
||||
FileReader fr;
|
||||
// first try as .ivf - but only if sounds are provided - the decoder is video only.
|
||||
if (ans)
|
||||
|
@ -653,8 +728,8 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
|||
}
|
||||
if (!fr.isOpen())
|
||||
{
|
||||
Printf(PRINT_BOLD, "%s: Unable to open video\n", filename);
|
||||
return nothing();
|
||||
error.Format("%s: Unable to open video\n", filename);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
char id[20] = {};
|
||||
|
@ -664,44 +739,44 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
|||
|
||||
if (!memcmp(id, "LPF ", 4))
|
||||
{
|
||||
auto anm = Create<DAnmPlayer>(fr, ans, frameticks, nosoundcutoff);
|
||||
auto anm = new AnmPlayer(fr, ans, frameticks, nosoundcutoff);
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
Printf(PRINT_BOLD, "%s: invalid ANM file.\n", filename);
|
||||
anm->Destroy();
|
||||
return nothing();
|
||||
error.Format("%s: invalid ANM file.\n", filename);
|
||||
delete anm;
|
||||
return nullptr;
|
||||
}
|
||||
return anm;
|
||||
}
|
||||
else if (!memcmp(id, "SMK2", 4))
|
||||
{
|
||||
fr.Close();
|
||||
auto anm = Create<DSmkPlayer>(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently.
|
||||
auto anm = new SmkPlayer(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently.
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
Printf(PRINT_BOLD, "%s: invalid SMK file.\n", filename);
|
||||
anm->Destroy();
|
||||
return nothing();
|
||||
error.Format("%s: invalid SMK file.\n", filename);
|
||||
delete anm;
|
||||
return nullptr;
|
||||
}
|
||||
return anm;
|
||||
}
|
||||
else if (!memcmp(id, "Interplay MVE File", 18))
|
||||
{
|
||||
auto anm = Create<DMvePlayer>(fr);
|
||||
auto anm = new MvePlayer(fr);
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
anm->Destroy();
|
||||
return nothing();
|
||||
delete anm;
|
||||
return nullptr;
|
||||
}
|
||||
return anm;
|
||||
}
|
||||
else if (!memcmp(id, "DKIF\0\0 \0VP80", 12))
|
||||
{
|
||||
auto anm = Create<DVpxPlayer>(fr, ans, frameticks? frameticks[1] : 0 );
|
||||
auto anm = new VpxPlayer(fr, ans, frameticks ? frameticks[1] : 0, error);
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
anm->Destroy();
|
||||
return nothing();
|
||||
delete anm;
|
||||
return nullptr;
|
||||
}
|
||||
anm->soundtrack = LookupMusic(filename, true);
|
||||
return anm;
|
||||
|
@ -709,9 +784,31 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
|||
// add more formats here.
|
||||
else
|
||||
{
|
||||
Printf(PRINT_BOLD, "%s: Unknown video format\n", filename);
|
||||
error.Format("%s: Unknown video format\n", filename);
|
||||
return nullptr;
|
||||
}
|
||||
return nothing();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff)
|
||||
{
|
||||
if (!filename)
|
||||
{
|
||||
return Create<DScreenJob>();
|
||||
}
|
||||
FString error;
|
||||
auto movie = OpenMovie(filename, ans, frameticks, nosoundcutoff, error);
|
||||
if (!movie)
|
||||
{
|
||||
Printf(TEXTCOLOR_YELLOW, "%s", error.GetChars());
|
||||
return Create<DScreenJob>();
|
||||
}
|
||||
return Create<DMoviePlayer>(movie);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -57,6 +57,13 @@ IMPLEMENT_CLASS(DScreenJob, true, false)
|
|||
IMPLEMENT_CLASS(DImageScreen, true, false)
|
||||
|
||||
|
||||
bool DSkippableScreenJob::OnEvent(event_t* evt)
|
||||
{
|
||||
if (evt->type == EV_GUI_KeyDown) state = skipped;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int DBlackScreen::Frame(uint64_t clock, bool skiprequest)
|
||||
{
|
||||
int span = int(clock / 1'000'000);
|
||||
|
@ -193,7 +200,7 @@ public:
|
|||
screenfade = 1.f;
|
||||
}
|
||||
job.job->SetClock(clock);
|
||||
int state = job.job->Frame(clock, skiprequest, 0);
|
||||
int state = job.job->Frame(clock, skiprequest, I_GetTimeFrac());
|
||||
clock = job.job->GetClock();
|
||||
if (clock == 0) clock = 1;
|
||||
return state;
|
||||
|
@ -227,7 +234,8 @@ public:
|
|||
|
||||
bool OnEvent(event_t* ev)
|
||||
{
|
||||
if (jobs[index].job->state == DScreenJob::stopping) return false;
|
||||
if (index >= jobs.Size()) return false;
|
||||
if (jobs[index].job->state != DScreenJob::running) return false;
|
||||
return jobs[index].job->OnEvent(ev);
|
||||
}
|
||||
|
||||
|
@ -249,7 +257,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
if (jobs[index].job->state == DScreenJob::stopping) return;
|
||||
if (jobs[index].job->state != DScreenJob::running) return;
|
||||
jobs[index].job->ticks++;
|
||||
jobs[index].job->OnTick();
|
||||
}
|
||||
|
@ -282,6 +290,7 @@ public:
|
|||
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;
|
||||
}
|
||||
|
@ -296,6 +305,7 @@ public:
|
|||
int ended = FadeoutFrame();
|
||||
if (ended < 1)
|
||||
{
|
||||
jobs[index].job->state = DScreenJob::stopped;
|
||||
AdvanceJob(terminateState < 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,21 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class DSkippableScreenJob : public DScreenJob
|
||||
{
|
||||
protected:
|
||||
DSkippableScreenJob(int fade = 0, float fadet = 250.f) : DScreenJob(fade, fadet)
|
||||
{}
|
||||
|
||||
bool OnEvent(event_t* evt) override;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class DBlackScreen : public DScreenJob
|
||||
{
|
||||
int wait;
|
||||
|
|
Loading…
Reference in a new issue