mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-29 07:12:36 +00:00
Interpolate non-Burn screen wipes
This commit is contained in:
parent
12d1afcc4e
commit
c603494057
1 changed files with 135 additions and 25 deletions
|
@ -43,6 +43,8 @@
|
||||||
#include "s_soundinternal.h"
|
#include "s_soundinternal.h"
|
||||||
#include "i_time.h"
|
#include "i_time.h"
|
||||||
|
|
||||||
|
EXTERN_CVAR(Bool, cl_capfps)
|
||||||
|
|
||||||
class FBurnTexture : public FTexture
|
class FBurnTexture : public FTexture
|
||||||
{
|
{
|
||||||
TArray<uint32_t> WorkBuffer;
|
TArray<uint32_t> WorkBuffer;
|
||||||
|
@ -163,6 +165,8 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual ~Wiper();
|
virtual ~Wiper();
|
||||||
virtual bool Run(int ticks) = 0;
|
virtual bool Run(int ticks) = 0;
|
||||||
|
virtual bool RunInterpolated(double ticks) { return true; };
|
||||||
|
virtual bool Interpolatable() { return false; }
|
||||||
virtual void SetTextures(FGameTexture* startscreen, FGameTexture* endscreen)
|
virtual void SetTextures(FGameTexture* startscreen, FGameTexture* endscreen)
|
||||||
{
|
{
|
||||||
startScreen = startscreen;
|
startScreen = startscreen;
|
||||||
|
@ -177,9 +181,11 @@ class Wiper_Crossfade : public Wiper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool Run(int ticks) override;
|
bool Run(int ticks) override;
|
||||||
|
bool RunInterpolated(double ticks) override;
|
||||||
|
bool Interpolatable() override { return true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int Clock = 0;
|
float Clock = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Wiper_Melt : public Wiper
|
class Wiper_Melt : public Wiper
|
||||||
|
@ -187,10 +193,12 @@ class Wiper_Melt : public Wiper
|
||||||
public:
|
public:
|
||||||
Wiper_Melt();
|
Wiper_Melt();
|
||||||
bool Run(int ticks) override;
|
bool Run(int ticks) override;
|
||||||
|
bool RunInterpolated(double ticks) override;
|
||||||
|
bool Interpolatable() override { return true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum { WIDTH = 320, HEIGHT = 200 };
|
enum { WIDTH = 320, HEIGHT = 200 };
|
||||||
int y[WIDTH];
|
double y[WIDTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
class Wiper_Burn : public Wiper
|
class Wiper_Burn : public Wiper
|
||||||
|
@ -268,7 +276,23 @@ bool Wiper_Crossfade::Run(int ticks)
|
||||||
Clock += ticks;
|
Clock += ticks;
|
||||||
DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE);
|
DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE);
|
||||||
DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE);
|
DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE);
|
||||||
return Clock >= 32;
|
return Clock >= 32.;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// OpenGLFrameBuffer :: Wiper_Crossfade :: Run
|
||||||
|
//
|
||||||
|
// Fades the old screen into the new one over 32 ticks.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool Wiper_Crossfade::RunInterpolated(double ticks)
|
||||||
|
{
|
||||||
|
Clock += ticks;
|
||||||
|
DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE);
|
||||||
|
DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE);
|
||||||
|
return Clock >= 32.;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -282,7 +306,7 @@ Wiper_Melt::Wiper_Melt()
|
||||||
y[0] = -(M_Random() & 15);
|
y[0] = -(M_Random() & 15);
|
||||||
for (int i = 1; i < WIDTH; ++i)
|
for (int i = 1; i < WIDTH; ++i)
|
||||||
{
|
{
|
||||||
y[i] = clamp(y[i-1] + (M_Random() % 3) - 1, -15, 0);
|
y[i] = clamp(y[i-1] + (double)(M_Random() % 3) - 1., -15., 0.);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,25 +331,25 @@ bool Wiper_Melt::Run(int ticks)
|
||||||
{
|
{
|
||||||
if (y[i] < HEIGHT)
|
if (y[i] < HEIGHT)
|
||||||
{
|
{
|
||||||
if (y[i] < 0)
|
if (y[i] < 0.)
|
||||||
y[i]++;
|
y[i] = y[i] + 1.;
|
||||||
else if (y[i] < 16)
|
else if (y[i] < 16.)
|
||||||
y[i] += y[i] + 1;
|
y[i] += y[i] + 1.;
|
||||||
else
|
else
|
||||||
y[i] = min<int>(y[i] + 8, HEIGHT);
|
y[i] = min<double>(y[i] + 8., HEIGHT);
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
if (ticks == 0)
|
if (ticks == 0)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
int32_t x;
|
int32_t x;
|
||||||
int32_t y;
|
double y;
|
||||||
} dpt;
|
} dpt;
|
||||||
struct {
|
struct {
|
||||||
int32_t left;
|
int32_t left;
|
||||||
int32_t top;
|
double top;
|
||||||
int32_t right;
|
int32_t right;
|
||||||
int32_t bottom;
|
double bottom;
|
||||||
} rect;
|
} rect;
|
||||||
|
|
||||||
// Only draw for the final tick.
|
// Only draw for the final tick.
|
||||||
|
@ -333,7 +357,7 @@ bool Wiper_Melt::Run(int ticks)
|
||||||
int w = startScreen->GetTexelWidth();
|
int w = startScreen->GetTexelWidth();
|
||||||
int h = startScreen->GetTexelHeight();
|
int h = startScreen->GetTexelHeight();
|
||||||
dpt.x = i * w / WIDTH;
|
dpt.x = i * w / WIDTH;
|
||||||
dpt.y = max(0, y[i] * h / HEIGHT);
|
dpt.y = max(0., y[i] * (double)h / (double)HEIGHT);
|
||||||
rect.left = dpt.x;
|
rect.left = dpt.x;
|
||||||
rect.top = 0;
|
rect.top = 0;
|
||||||
rect.right = (i + 1) * w / WIDTH;
|
rect.right = (i + 1) * w / WIDTH;
|
||||||
|
@ -348,6 +372,77 @@ bool Wiper_Melt::Run(int ticks)
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Wiper_Melt :: RunInterpolated
|
||||||
|
//
|
||||||
|
// Melts the old screen into the new one over 32 ticks (interpolated).
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool Wiper_Melt::RunInterpolated(double ticks)
|
||||||
|
{
|
||||||
|
bool done = false;
|
||||||
|
DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE);
|
||||||
|
|
||||||
|
// Copy the old screen in vertical strips on top of the new one.
|
||||||
|
while (ticks > 0.)
|
||||||
|
{
|
||||||
|
done = true;
|
||||||
|
for (int i = 0; i < WIDTH; i++)
|
||||||
|
{
|
||||||
|
if (y[i] < (double)HEIGHT)
|
||||||
|
{
|
||||||
|
if (ticks > 0. && ticks < 1.)
|
||||||
|
{
|
||||||
|
if (y[i] < 0)
|
||||||
|
y[i] += ticks;
|
||||||
|
else if (y[i] < 16)
|
||||||
|
y[i] += (y[i] + 1) * ticks;
|
||||||
|
else
|
||||||
|
y[i] = min<double>(y[i] + (8 * ticks), (double)HEIGHT);
|
||||||
|
}
|
||||||
|
else if (y[i] < 0.)
|
||||||
|
y[i] = y[i] + 1.;
|
||||||
|
else if (y[i] < 16.)
|
||||||
|
y[i] += y[i] + 1.;
|
||||||
|
else
|
||||||
|
y[i] = min<double>(y[i] + 8., HEIGHT);
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ticks -= 1.;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < WIDTH; i++)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
int32_t x;
|
||||||
|
double y;
|
||||||
|
} dpt;
|
||||||
|
struct {
|
||||||
|
int32_t left;
|
||||||
|
double top;
|
||||||
|
int32_t right;
|
||||||
|
double bottom;
|
||||||
|
} rect;
|
||||||
|
|
||||||
|
// Only draw for the final tick.
|
||||||
|
int w = startScreen->GetTexelWidth();
|
||||||
|
double h = startScreen->GetTexelHeight();
|
||||||
|
dpt.x = i * w / WIDTH;
|
||||||
|
dpt.y = max(0., y[i] * (double)h / (double)HEIGHT);
|
||||||
|
rect.left = dpt.x;
|
||||||
|
rect.top = 0;
|
||||||
|
rect.right = (i + 1) * w / WIDTH;
|
||||||
|
rect.bottom = h - dpt.y;
|
||||||
|
if (rect.bottom > rect.top)
|
||||||
|
{
|
||||||
|
DrawTexture(twod, startScreen, 0, dpt.y, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, DTA_Masked, false, TAG_DONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// OpenGLFrameBuffer :: Wiper_Burn Constructor
|
// OpenGLFrameBuffer :: Wiper_Burn Constructor
|
||||||
|
@ -423,6 +518,7 @@ void PerformWipe(FTexture* startimg, FTexture* endimg, int wipe_type, bool stops
|
||||||
{
|
{
|
||||||
// wipe update
|
// wipe update
|
||||||
uint64_t wipestart, nowtime, diff;
|
uint64_t wipestart, nowtime, diff;
|
||||||
|
double diff_frac;
|
||||||
bool done;
|
bool done;
|
||||||
|
|
||||||
GSnd->SetSfxPaused(true, 1);
|
GSnd->SetSfxPaused(true, 1);
|
||||||
|
@ -438,20 +534,34 @@ void PerformWipe(FTexture* startimg, FTexture* endimg, int wipe_type, bool stops
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
do
|
if (wiper->Interpolatable() && !cl_capfps)
|
||||||
{
|
{
|
||||||
I_WaitVBL(2);
|
|
||||||
nowtime = I_msTime();
|
nowtime = I_msTime();
|
||||||
diff = (nowtime - wipestart) * 40 / 1000; // Using 35 here feels too slow.
|
diff_frac = (nowtime - wipestart) * 40. / 1000.; // Using 35 here feels too slow.
|
||||||
} while (diff < 1);
|
wipestart = nowtime;
|
||||||
wipestart = nowtime;
|
twod->Begin(screen->GetWidth(), screen->GetHeight());
|
||||||
twod->Begin(screen->GetWidth(), screen->GetHeight());
|
done = wiper->RunInterpolated(diff_frac);
|
||||||
done = wiper->Run(1);
|
if (overlaydrawer) overlaydrawer();
|
||||||
if (overlaydrawer) overlaydrawer();
|
twod->End();
|
||||||
twod->End();
|
screen->Update();
|
||||||
screen->Update();
|
twod->OnFrameDone();
|
||||||
twod->OnFrameDone();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
I_WaitVBL(2);
|
||||||
|
nowtime = I_msTime();
|
||||||
|
diff = (nowtime - wipestart) * 40 / 1000; // Using 35 here feels too slow.
|
||||||
|
} while (diff < 1);
|
||||||
|
wipestart = nowtime;
|
||||||
|
twod->Begin(screen->GetWidth(), screen->GetHeight());
|
||||||
|
done = wiper->Run(1);
|
||||||
|
if (overlaydrawer) overlaydrawer();
|
||||||
|
twod->End();
|
||||||
|
screen->Update();
|
||||||
|
twod->OnFrameDone();
|
||||||
|
}
|
||||||
} while (!done);
|
} while (!done);
|
||||||
delete wiper;
|
delete wiper;
|
||||||
I_FreezeTime(false);
|
I_FreezeTime(false);
|
||||||
|
|
Loading…
Reference in a new issue