- Untested wipe refactor

# Conflicts:
#	src/gl/renderer/gl_renderer.cpp
#	src/gl/system/gl_wipe.cpp
#	src/hwrenderer/scene/hw_attributebuffer.cpp
This commit is contained in:
Christoph Oelckers 2018-08-28 15:11:35 +02:00
parent ecf6e3f620
commit 9af01c4667
11 changed files with 363 additions and 517 deletions

View file

@ -638,7 +638,8 @@ CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
void D_Display () void D_Display ()
{ {
bool wipe; FTexture *wipe;
int wipe_type;
sector_t *viewsec; sector_t *viewsec;
if (nodrawers || screen == NULL) if (nodrawers || screen == NULL)
@ -703,35 +704,36 @@ void D_Display ()
if (NoWipe) if (NoWipe)
{ {
NoWipe--; NoWipe--;
wipe = false; wipe = nullptr;
wipegamestate = gamestate; wipegamestate = gamestate;
} }
// No wipes when in a stereo3D VR mode // No wipes when in a stereo3D VR mode
else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL && (vr_mode == 0 || vid_rendermode != 4)) else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL && (vr_mode == 0 || vid_rendermode != 4))
{ // save the current screen if about to wipe { // save the current screen if about to wipe
wipe = screen->WipeStartScreen ();
switch (wipegamestate) switch (wipegamestate)
{ {
default: default:
wipe = screen->WipeStartScreen (wipetype); wipe_type = wipetype;
break; break;
case GS_FORCEWIPEFADE: case GS_FORCEWIPEFADE:
wipe = screen->WipeStartScreen (wipe_Fade); wipe_type = wipe_Fade;
break; break;
case GS_FORCEWIPEBURN: case GS_FORCEWIPEBURN:
wipe = screen->WipeStartScreen (wipe_Burn); wipe_type =wipe_Burn;
break; break;
case GS_FORCEWIPEMELT: case GS_FORCEWIPEMELT:
wipe = screen->WipeStartScreen (wipe_Melt); wipe_type = wipe_Melt;
break; break;
} }
wipegamestate = gamestate; wipegamestate = gamestate;
} }
else else
{ {
wipe = false; wipe = nullptr;
} }
screen->FrameTime = I_msTimeFS(); screen->FrameTime = I_msTimeFS();
@ -885,7 +887,7 @@ void D_Display ()
GSnd->SetSfxPaused(true, 1); GSnd->SetSfxPaused(true, 1);
I_FreezeTime(true); I_FreezeTime(true);
screen->End2D(); screen->End2D();
screen->WipeEndScreen (); auto wipend = screen->WipeEndScreen ();
wipestart = I_msTime(); wipestart = I_msTime();
NetUpdate(); // send out any new accumulation NetUpdate(); // send out any new accumulation

View file

@ -27,6 +27,36 @@
#include "m_random.h" #include "m_random.h"
#include "f_wipe.h" #include "f_wipe.h"
#include "templates.h" #include "templates.h"
#include "textures/bitmap.h"
#include "hwrenderer/textures/hw_material.h"
class FBurnTexture : public FTexture
{
uint32_t *WorkBuffer;
public:
FBurnTexture(int w, int h)
{
Width = w;
Height = h;
WorkBuffer = new uint32_t[w * h];
}
~FBurnTexture()
{
delete [] WorkBuffer;
}
int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override
{
bmp->CopyPixelDataRGB(x, y, (uint8_t*)WorkBuffer, Width, Height, 4, Width*4, rotate, CF_RGBA, inf);
return 0;
}
uint32_t *GetBuffer()
{
return WorkBuffer;
}
};
int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density) int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density)
{ {
@ -112,3 +142,257 @@ int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density)
return -1; return -1;
} }
// TYPES -------------------------------------------------------------------
class Wiper_Crossfade : public Wiper
{
public:
bool Run(int ticks) override;
private:
int Clock = 0;
};
class Wiper_Melt : public Wiper
{
public:
Wiper_Melt();
bool Run(int ticks) override;
private:
static const int WIDTH = 320, HEIGHT = 200;
int y[WIDTH];
};
class Wiper_Burn : public Wiper
{
public:
Wiper_Burn();
~Wiper_Burn();
bool Run(int ticks) override;
void SetTextures(FTexture *startscreen, FTexture *endscreen) override;
private:
static const int WIDTH = 64, HEIGHT = 64;
uint8_t BurnArray[WIDTH * (HEIGHT + 5)] = {0};
FBurnTexture *BurnTexture = nullptr;
int Density = 4;
int BurnTime = 8;
};
//===========================================================================
//
// Screen wipes
//
//===========================================================================
Wiper *Wiper::Create(int type)
{
switch(type)
{
case wipe_Burn:
return new Wiper_Burn;
case wipe_Fade:
return new Wiper_Crossfade;
case wipe_Melt:
return new Wiper_Melt;
default:
return nullptr;
}
}
//==========================================================================
//
// OpenGLFrameBuffer :: WipeCleanup
//
// Release any resources that were specifically created for the wipe.
//
//==========================================================================
Wiper::~Wiper()
{
if (startScreen != nullptr) delete startScreen;
if (endScreen != nullptr) delete endScreen;
}
//==========================================================================
//
// WIPE: CROSSFADE ---------------------------------------------------------
//
//==========================================================================
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Crossfade :: Run
//
// Fades the old screen into the new one over 32 ticks.
//
//==========================================================================
bool Wiper_Crossfade::Run(int ticks)
{
Clock += ticks;
screen->DrawTexture(startScreen, 0, 0, TAG_DONE);
screen->DrawTexture(endScreen, 0, 0, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE);
return Clock >= 32;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Melt Constructor
//
//==========================================================================
Wiper_Melt::Wiper_Melt()
{
int i, r;
// setup initial column positions
// (y<0 => not ready to scroll yet)
y[0] = -(M_Random() & 15);
for (i = 1; i < WIDTH; ++i)
{
r = (M_Random()%3) - 1;
y[i] = clamp(y[i-1] + r, -15, 0);
}
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Melt :: Run
//
// Melts the old screen into the new one over 32 ticks.
//
//==========================================================================
bool Wiper_Melt::Run(int ticks)
{
bool done;
screen->DrawTexture(endScreen, 0, 0, TAG_DONE);
// Copy the old screen in vertical strips on top of the new one.
while (ticks--)
{
done = true;
for (int i = 0; i < WIDTH; i++)
{
if (y[i] < 0)
{
y[i]++;
done = false;
}
else if (y[i] < HEIGHT)
{
int dy = (y[i] < 16) ? y[i] + 1 : 8;
y[i] = MIN(y[i] + dy, HEIGHT);
done = false;
}
if (ticks == 0)
{
struct {
int32_t x;
int32_t y;
} dpt;
struct {
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
} rect;
// Only draw for the final tick.
// No need for optimization. Wipes won't ever be drawn with anything else.
int w = startScreen->GetWidth();
int h = startScreen->GetHeight();
dpt.x = i * h / WIDTH;
dpt.y = MAX(0, y[i] * h / HEIGHT);
rect.left = dpt.x;
rect.top = 0;
rect.right = (i + 1) * w / WIDTH;
rect.bottom = w - dpt.y;
if (rect.bottom > rect.top)
{
screen->DrawTexture(startScreen, 0, rect.top, DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, TAG_DONE);
}
}
}
}
return done;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn Constructor
//
//==========================================================================
void Wiper_Burn::SetTextures(FTexture *startscreen, FTexture *endscreen)
{
startScreen = startscreen;
endScreen = endscreen;
BurnTexture = new FBurnTexture(WIDTH, HEIGHT);
auto mat = FMaterial::ValidateTexture(startscreen, false);
mat->AddTextureLayer(BurnTexture);
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn Destructor
//
//==========================================================================
Wiper_Burn::~Wiper_Burn()
{
if (BurnTexture != nullptr) delete BurnTexture;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn :: Run
//
//==========================================================================
bool Wiper_Burn::Run(int ticks)
{
bool done;
BurnTime += ticks;
ticks *= 2;
// Make the fire burn
done = false;
while (!done && ticks--)
{
Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density);
done = (Density < 0);
}
auto mat = FMaterial::ValidateTexture(BurnTexture, false);
mat->Clean(true);
const uint8_t *src = BurnArray;
uint32_t *dest = (uint32_t *)BurnTexture->GetBuffer();
for (int y = HEIGHT; y != 0; --y)
{
for (int x = WIDTH; x != 0; --x)
{
uint8_t s = clamp<int>((*src++)*2, 0, 255);
*dest++ = MAKEARGB(s,255,255,255);
}
}
screen->DrawTexture(startScreen, 0, 0, TAG_DONE);
screen->DrawTexture(endScreen, 0, 0, DTA_Burn, true, TAG_DONE);
// The fire may not always stabilize, so the wipe is forced to end
// after an arbitrary maximum time.
return done || (BurnTime > 40);
}

View file

@ -26,19 +26,9 @@
#ifndef __F_WIPE_H__ #ifndef __F_WIPE_H__
#define __F_WIPE_H__ #define __F_WIPE_H__
// #include "stdint.h"
// SCREEN WIPE PACKAGE
//
#if 0 class FTexture;
bool wipe_StartScreen (int type);
void wipe_EndScreen (void);
bool wipe_ScreenWipe (int ticks);
void wipe_Cleanup ();
// The buffer must have an additional 5 rows not included in height
// to use for a seeding area.
#endif
int wipe_CalcBurn(uint8_t *buffer, int width, int height, int density); int wipe_CalcBurn(uint8_t *buffer, int width, int height, int density);
enum enum
@ -50,4 +40,21 @@ enum
wipe_NUMWIPES wipe_NUMWIPES
}; };
class Wiper
{
protected:
FTexture *startScreen = nullptr, *endScreen = nullptr;
public:
virtual ~Wiper();
virtual bool Run(int ticks) = 0;
virtual void SetTextures(FTexture *startscreen, FTexture *endscreen)
{
startScreen = startscreen;
endScreen = endscreen;
}
static Wiper *Create(int type);
};
#endif #endif

View file

@ -428,12 +428,6 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
const auto &mScreenViewport = screen->mScreenViewport; const auto &mScreenViewport = screen->mScreenViewport;
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
HWViewpointUniforms matrices;
matrices.SetDefaults();
matrices.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f);
matrices.CalcDependencies();
GLRenderer->mShaderManager->ApplyMatrices(&matrices, NORMAL_PASS);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
// Korshun: ENABLE AUTOMAP ANTIALIASING!!! // Korshun: ENABLE AUTOMAP ANTIALIASING!!!
@ -530,6 +524,10 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
gl_RenderState.mTextureMatrix.translate(0.f, 1.f, 0.0f); gl_RenderState.mTextureMatrix.translate(0.f, 1.f, 0.0f);
gl_RenderState.EnableTextureMatrix(true); gl_RenderState.EnableTextureMatrix(true);
} }
if (cmd.mFlags & F2DDrawer::DTF_Burn)
{
gl_RenderState.SetEffect(EFF_BURN);
}
} }
else else
{ {
@ -555,6 +553,8 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
gl_RenderState.SetObjectColor(0xffffffff); gl_RenderState.SetObjectColor(0xffffffff);
gl_RenderState.SetObjectColor2(0); gl_RenderState.SetObjectColor2(0);
gl_RenderState.EnableTextureMatrix(false); gl_RenderState.EnableTextureMatrix(false);
gl_RenderState.SetEffect(EFF_NONE);
} }
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);

View file

@ -49,10 +49,6 @@ public:
// points to the last row in the buffer, which will be the first row output. // points to the last row in the buffer, which will be the first row output.
virtual void GetScreenshotBuffer(const uint8_t *&buffer, int &pitch, ESSType &color_type, float &gamma) override; virtual void GetScreenshotBuffer(const uint8_t *&buffer, int &pitch, ESSType &color_type, float &gamma) override;
bool WipeStartScreen(int type);
void WipeEndScreen();
bool WipeDo(int ticks);
void WipeCleanup();
void Swap(); void Swap();
bool IsHWGammaActive() const { return HWGammaActive; } bool IsHWGammaActive() const { return HWGammaActive; }
@ -63,33 +59,11 @@ public:
bool HWGammaActive = false; // Are we using hardware or software gamma? bool HWGammaActive = false; // Are we using hardware or software gamma?
std::shared_ptr<FGLDebug> mDebug; // Debug API std::shared_ptr<FGLDebug> mDebug; // Debug API
FTexture *WipeStartScreen() override;
FTexture *WipeEndScreen() override;
private: private:
int camtexcount = 0; int camtexcount = 0;
class Wiper
{
protected:
FSimpleVertexBuffer *mVertexBuf;
void MakeVBO(OpenGLFrameBuffer *fb);
public:
Wiper();
virtual ~Wiper();
virtual bool Run(int ticks, OpenGLFrameBuffer *fb) = 0;
};
class Wiper_Melt; friend class Wiper_Melt;
class Wiper_Burn; friend class Wiper_Burn;
class Wiper_Crossfade; friend class Wiper_Crossfade;
Wiper *ScreenWipe;
FHardwareTexture *wipestartscreen;
FHardwareTexture *wipeendscreen;
public:
}; };

View file

@ -40,49 +40,21 @@
#include "gl/data/gl_vertexbuffer.h" #include "gl/data/gl_vertexbuffer.h"
//=========================================================================== class FGLWipeTexture : public FTexture
//
// Screen wipes
//
//===========================================================================
// TYPES -------------------------------------------------------------------
class OpenGLFrameBuffer::Wiper_Crossfade : public OpenGLFrameBuffer::Wiper
{ {
public: public:
Wiper_Crossfade();
bool Run(int ticks, OpenGLFrameBuffer *fb);
private: FGLWipeTexture(int w, int h)
int Clock; {
}; Width = w;
Height = h;
WidthBits = 4;
UseType = ETextureType::SWCanvas;
bNoCompress = true;
SystemTexture[0] = screen->CreateHardwareTexture(this);
}
class OpenGLFrameBuffer::Wiper_Melt : public OpenGLFrameBuffer::Wiper // This is just a wrapper around the hardware texture being extracted below so that it can be passed to the 2D code.
{
public:
Wiper_Melt();
int MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done);
bool Run(int ticks, OpenGLFrameBuffer *fb);
private:
static const int WIDTH = 320, HEIGHT = 200;
int y[WIDTH];
};
class OpenGLFrameBuffer::Wiper_Burn : public OpenGLFrameBuffer::Wiper
{
public:
Wiper_Burn();
~Wiper_Burn();
bool Run(int ticks, OpenGLFrameBuffer *fb);
private:
static const int WIDTH = 64, HEIGHT = 64;
uint8_t BurnArray[WIDTH * (HEIGHT + 5)];
FHardwareTexture *BurnTexture;
int Density;
int BurnTime;
}; };
//========================================================================== //==========================================================================
@ -95,46 +67,18 @@ private:
// //
//========================================================================== //==========================================================================
bool OpenGLFrameBuffer::WipeStartScreen(int type) FTexture *OpenGLFrameBuffer::WipeStartScreen()
{ {
switch (type)
{
case wipe_Burn:
ScreenWipe = new Wiper_Burn;
break;
case wipe_Fade:
ScreenWipe = new Wiper_Crossfade;
break;
case wipe_Melt:
ScreenWipe = new Wiper_Melt;
break;
default:
return false;
}
const auto &viewport = screen->mScreenViewport; const auto &viewport = screen->mScreenViewport;
wipestartscreen = new FHardwareTexture(true);
wipestartscreen->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen");
GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1);
GLRenderer->mSamplerManager->Bind(1, CLAMP_NONE, -1);
glFinish();
wipestartscreen->Bind(0, false, false);
const auto copyPixels = [&viewport]() FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height);
{ tex->SystemTexture[0]->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen");
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); glFinish();
}; static_cast<FHardwareTexture*>(tex->SystemTexture[0])->Bind(0, false, false);
GLRenderer->mBuffers->BindCurrentFB(); GLRenderer->mBuffers->BindCurrentFB();
copyPixels(); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
return tex;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return true;
} }
//========================================================================== //==========================================================================
@ -145,392 +89,16 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type)
// //
//========================================================================== //==========================================================================
void OpenGLFrameBuffer::WipeEndScreen() FTexture *OpenGLFrameBuffer::WipeEndScreen()
{ {
GLRenderer->Flush(); GLRenderer->Flush();
const auto &viewport = screen->mScreenViewport; const auto &viewport = screen->mScreenViewport;
wipeendscreen = new FHardwareTexture(true); FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height);
wipeendscreen->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); tex->SystemTexture[0]->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen");
GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1);
glFinish(); glFinish();
wipeendscreen->Bind(0, false, false); static_cast<FHardwareTexture*>(tex->SystemTexture[0])->Bind(0, false, false);
GLRenderer->mBuffers->BindCurrentFB(); GLRenderer->mBuffers->BindCurrentFB();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); return tex;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} }
//==========================================================================
//
// OpenGLFrameBuffer :: WipeDo
//
// Perform the actual wipe animation. The number of tics since the last
// time this function was called is passed in. Returns true when the wipe
// is over. The first time this function has been called, the screen is
// still locked from before and EndScene() still has not been called.
// Successive times need to call BeginScene().
//
//==========================================================================
bool OpenGLFrameBuffer::WipeDo(int ticks)
{
bool done = true;
// Sanity checks.
if (wipestartscreen != nullptr && wipeendscreen != nullptr)
{
gl_RenderState.EnableTexture(true);
gl_RenderState.EnableFog(false);
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
GLRenderer->mBuffers->BindCurrentFB();
const auto &bounds = screen->mScreenViewport;
glViewport(bounds.left, bounds.top, bounds.width, bounds.height);
done = ScreenWipe->Run(ticks, this);
glDepthMask(true);
}
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
return done;
}
//==========================================================================
//
// OpenGLFrameBuffer :: WipeCleanup
//
// Release any resources that were specifically created for the wipe.
//
//==========================================================================
void OpenGLFrameBuffer::WipeCleanup()
{
if (ScreenWipe != NULL)
{
delete ScreenWipe;
ScreenWipe = NULL;
}
if (wipestartscreen != NULL)
{
delete wipestartscreen;
wipestartscreen = NULL;
}
if (wipeendscreen != NULL)
{
delete wipeendscreen;
wipeendscreen = NULL;
}
gl_RenderState.ClearLastMaterial();
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper Constructor
//
//==========================================================================
OpenGLFrameBuffer::Wiper::Wiper()
{
mVertexBuf = new FSimpleVertexBuffer;
}
OpenGLFrameBuffer::Wiper::~Wiper()
{
delete mVertexBuf;
}
void OpenGLFrameBuffer::Wiper::MakeVBO(OpenGLFrameBuffer *fb)
{
FSimpleVertex make[4];
FSimpleVertex *ptr = make;
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
ptr->Set(0, 0, 0, 0, vb);
ptr++;
ptr->Set(0, fb->GetHeight(), 0, 0, 0);
ptr++;
ptr->Set(fb->GetWidth(), 0, 0, ur, vb);
ptr++;
ptr->Set(fb->GetWidth(), fb->GetHeight(), 0, ur, 0);
mVertexBuf->set(make, 4);
}
// WIPE: CROSSFADE ---------------------------------------------------------
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Crossfade Constructor
//
//==========================================================================
OpenGLFrameBuffer::Wiper_Crossfade::Wiper_Crossfade()
: Clock(0)
{
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Crossfade :: Run
//
// Fades the old screen into the new one over 32 ticks.
//
//==========================================================================
bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb)
{
Clock += ticks;
MakeVBO(fb);
gl_RenderState.SetTextureMode(TM_OPAQUE);
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipestartscreen->Bind(0, 0, false);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
float a = clamp(Clock / 32.f, 0.f, 1.f);
gl_RenderState.SetColorAlpha(0xffffff, a);
gl_RenderState.Apply();
fb->wipeendscreen->Bind(0, 0, false);
mVertexBuf->EnableColorArray(false);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f);
gl_RenderState.SetTextureMode(TM_MODULATE);
return Clock >= 32;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Melt Constructor
//
//==========================================================================
OpenGLFrameBuffer::Wiper_Melt::Wiper_Melt()
{
int i, r;
// setup initial column positions
// (y<0 => not ready to scroll yet)
y[0] = -(M_Random() & 15);
for (i = 1; i < WIDTH; ++i)
{
r = (M_Random()%3) - 1;
y[i] = clamp(y[i-1] + r, -15, 0);
}
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Melt :: Run
//
// Fades the old screen into the new one over 32 ticks.
//
//==========================================================================
int OpenGLFrameBuffer::Wiper_Melt::MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done)
{
FSimpleVertex *make = new FSimpleVertex[321*4];
FSimpleVertex *ptr = make;
int dy;
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
ptr->Set(0, 0, 0, 0, vb);
ptr++;
ptr->Set(0, fb->GetHeight(), 0, 0, 0);
ptr++;
ptr->Set(fb->GetWidth(), 0, 0, ur, vb);
ptr++;
ptr->Set(fb->GetWidth(), fb->GetHeight(), 0, ur, 0);
ptr++;
// Copy the old screen in vertical strips on top of the new one.
while (ticks--)
{
done = true;
for (int i = 0; i < WIDTH; i++)
{
if (y[i] < 0)
{
y[i]++;
done = false;
}
else if (y[i] < HEIGHT)
{
dy = (y[i] < 16) ? y[i] + 1 : 8;
y[i] = MIN(y[i] + dy, HEIGHT);
done = false;
}
if (ticks == 0)
{
struct {
int32_t x;
int32_t y;
} dpt;
struct {
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
} rect;
// Only draw for the final tick.
// No need for optimization. Wipes won't ever be drawn with anything else.
dpt.x = i * fb->GetWidth() / WIDTH;
dpt.y = MAX(0, y[i] * fb->GetHeight() / HEIGHT);
rect.left = dpt.x;
rect.top = 0;
rect.right = (i + 1) * fb->GetWidth() / WIDTH;
rect.bottom = fb->GetHeight() - dpt.y;
if (rect.bottom > rect.top)
{
float tw = (float)FHardwareTexture::GetTexDimension(fb->GetWidth());
float th = (float)FHardwareTexture::GetTexDimension(fb->GetHeight());
rect.bottom = fb->GetHeight() - rect.bottom;
rect.top = fb->GetHeight() - rect.top;
ptr->Set(rect.left, rect.bottom, 0, rect.left / tw, rect.top / th);
ptr++;
ptr->Set(rect.left, rect.top, 0, rect.left / tw, rect.bottom / th);
ptr++;
ptr->Set(rect.right, rect.bottom, 0, rect.right / tw, rect.top / th);
ptr++;
ptr->Set(rect.right, rect.top, 0, rect.right / tw, rect.bottom / th);
ptr++;
}
}
}
}
int numverts = int(ptr - make);
mVertexBuf->set(make, numverts);
delete[] make;
return numverts;
}
bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
{
bool done = false;
int maxvert = MakeVBO(ticks, fb, done);
// Draw the new screen on the bottom.
gl_RenderState.SetTextureMode(TM_OPAQUE);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipeendscreen->Bind(0, 0, false);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
fb->wipestartscreen->Bind(0, 0, false);
gl_RenderState.SetTextureMode(TM_MODULATE);
for (int i = 4; i < maxvert; i += 4)
{
glDrawArrays(GL_TRIANGLE_STRIP, i, 4);
}
return done;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn Constructor
//
//==========================================================================
OpenGLFrameBuffer::Wiper_Burn::Wiper_Burn()
{
Density = 4;
BurnTime = 0;
memset(BurnArray, 0, sizeof(BurnArray));
BurnTexture = NULL;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn Destructor
//
//==========================================================================
OpenGLFrameBuffer::Wiper_Burn::~Wiper_Burn()
{
if (BurnTexture != NULL)
{
delete BurnTexture;
BurnTexture = NULL;
}
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn :: Run
//
//==========================================================================
bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb)
{
bool done;
MakeVBO(fb);
BurnTime += ticks;
ticks *= 2;
// Make the fire burn
done = false;
while (!done && ticks--)
{
Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density);
done = (Density < 0);
}
if (BurnTexture != NULL) delete BurnTexture;
BurnTexture = new FHardwareTexture(true);
// Update the burn texture with the new burn data
uint8_t rgb_buffer[WIDTH*HEIGHT*4];
const uint8_t *src = BurnArray;
uint32_t *dest = (uint32_t *)rgb_buffer;
for (int y = HEIGHT; y != 0; --y)
{
for (int x = WIDTH; x != 0; --x)
{
uint8_t s = clamp<int>((*src++)*2, 0, 255);
*dest++ = MAKEARGB(s,255,255,255);
}
}
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
// Put the initial screen back to the buffer.
gl_RenderState.SetTextureMode(TM_OPAQUE);
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipestartscreen->Bind(0, 0, false);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
gl_RenderState.SetTextureMode(TM_MODULATE);
gl_RenderState.SetEffect(EFF_BURN);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
// Burn the new screen on top of it.
fb->wipeendscreen->Bind(0, 0, false);
BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0, "BurnTexture");
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
gl_RenderState.SetEffect(EFF_NONE);
// The fire may not always stabilize, so the wipe is forced to end
// after an arbitrary maximum time.
return done || (BurnTime > 40);
}

View file

@ -242,6 +242,7 @@ bool F2DDrawer::SetStyle(FTexture *tex, DrawParms &parms, PalEntry &vertexcolor,
else if (quad.mDrawMode == DTM_Invert) quad.mDrawMode = DTM_InvertOpaque; else if (quad.mDrawMode == DTM_Invert) quad.mDrawMode = DTM_InvertOpaque;
} }
quad.mRenderStyle = parms.style; // this contains the blend mode and blend equation settings. quad.mRenderStyle = parms.style; // this contains the blend mode and blend equation settings.
if (parms.burn) quad.mFlags |= DTF_Burn;
return true; return true;
} }

View file

@ -53,6 +53,7 @@ public:
{ {
DTF_Wrap = 1, DTF_Wrap = 1,
DTF_Scissor = 2, DTF_Scissor = 2,
DTF_Burn = 4,
}; };

View file

@ -511,6 +511,7 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3
parms->srcy = 0.; parms->srcy = 0.;
parms->srcwidth = 1.; parms->srcwidth = 1.;
parms->srcheight = 1.; parms->srcheight = 1.;
parms->burn = false;
// Parse the tag list for attributes. (For floating point attributes, // Parse the tag list for attributes. (For floating point attributes,
// consider that the C ABI dictates that all floats be promoted to // consider that the C ABI dictates that all floats be promoted to
@ -863,6 +864,10 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3
parms->celly = ListGetInt(tags); parms->celly = ListGetInt(tags);
break; break;
case DTA_Burn:
parms->burn = true;
break;
} }
tag = ListGetInt(tags); tag = ListGetInt(tags);
} }

View file

@ -320,9 +320,9 @@ void DFrameBuffer::SetVSync (bool vsync)
// //
//========================================================================== //==========================================================================
bool DFrameBuffer::WipeStartScreen(int type) FTexture *DFrameBuffer::WipeStartScreen()
{ {
return false; return nullptr;
} }
//========================================================================== //==========================================================================
@ -334,8 +334,9 @@ bool DFrameBuffer::WipeStartScreen(int type)
// //
//========================================================================== //==========================================================================
void DFrameBuffer::WipeEndScreen() FTexture *DFrameBuffer::WipeEndScreen()
{ {
return nullptr;
} }
//========================================================================== //==========================================================================

View file

@ -47,6 +47,7 @@
struct sector_t; struct sector_t;
class IShaderProgram; class IShaderProgram;
class FTexture;
enum EHWCaps enum EHWCaps
{ {
@ -205,6 +206,7 @@ enum
DTA_SrcWidth, DTA_SrcWidth,
DTA_SrcHeight, DTA_SrcHeight,
DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle
DTA_Burn, // activates the burn shader for this element
}; };
@ -261,6 +263,7 @@ struct DrawParms
bool virtBottom; bool virtBottom;
double srcx, srcy; double srcx, srcy;
double srcwidth, srcheight; double srcwidth, srcheight;
bool burn;
}; };
struct Va_List struct Va_List
@ -467,8 +470,8 @@ public:
virtual sector_t *RenderView(player_t *player) { return nullptr; } virtual sector_t *RenderView(player_t *player) { return nullptr; }
// Screen wiping // Screen wiping
virtual bool WipeStartScreen(int type); virtual FTexture *WipeStartScreen();
virtual void WipeEndScreen(); virtual FTexture *WipeEndScreen();
virtual bool WipeDo(int ticks); virtual bool WipeDo(int ticks);
virtual void WipeCleanup(); virtual void WipeCleanup();