mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 15:02:01 +00:00
- 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:
parent
ecf6e3f620
commit
9af01c4667
11 changed files with 363 additions and 517 deletions
|
@ -638,7 +638,8 @@ CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
|
||||
void D_Display ()
|
||||
{
|
||||
bool wipe;
|
||||
FTexture *wipe;
|
||||
int wipe_type;
|
||||
sector_t *viewsec;
|
||||
|
||||
if (nodrawers || screen == NULL)
|
||||
|
@ -703,35 +704,36 @@ void D_Display ()
|
|||
if (NoWipe)
|
||||
{
|
||||
NoWipe--;
|
||||
wipe = false;
|
||||
wipe = nullptr;
|
||||
wipegamestate = gamestate;
|
||||
}
|
||||
// No wipes when in a stereo3D VR mode
|
||||
else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL && (vr_mode == 0 || vid_rendermode != 4))
|
||||
{ // save the current screen if about to wipe
|
||||
wipe = screen->WipeStartScreen ();
|
||||
switch (wipegamestate)
|
||||
{
|
||||
default:
|
||||
wipe = screen->WipeStartScreen (wipetype);
|
||||
wipe_type = wipetype;
|
||||
break;
|
||||
|
||||
case GS_FORCEWIPEFADE:
|
||||
wipe = screen->WipeStartScreen (wipe_Fade);
|
||||
wipe_type = wipe_Fade;
|
||||
break;
|
||||
|
||||
case GS_FORCEWIPEBURN:
|
||||
wipe = screen->WipeStartScreen (wipe_Burn);
|
||||
wipe_type =wipe_Burn;
|
||||
break;
|
||||
|
||||
case GS_FORCEWIPEMELT:
|
||||
wipe = screen->WipeStartScreen (wipe_Melt);
|
||||
wipe_type = wipe_Melt;
|
||||
break;
|
||||
}
|
||||
wipegamestate = gamestate;
|
||||
}
|
||||
else
|
||||
{
|
||||
wipe = false;
|
||||
wipe = nullptr;
|
||||
}
|
||||
|
||||
screen->FrameTime = I_msTimeFS();
|
||||
|
@ -885,7 +887,7 @@ void D_Display ()
|
|||
GSnd->SetSfxPaused(true, 1);
|
||||
I_FreezeTime(true);
|
||||
screen->End2D();
|
||||
screen->WipeEndScreen ();
|
||||
auto wipend = screen->WipeEndScreen ();
|
||||
|
||||
wipestart = I_msTime();
|
||||
NetUpdate(); // send out any new accumulation
|
||||
|
|
284
src/f_wipe.cpp
284
src/f_wipe.cpp
|
@ -27,6 +27,36 @@
|
|||
#include "m_random.h"
|
||||
#include "f_wipe.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)
|
||||
{
|
||||
|
@ -112,3 +142,257 @@ int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density)
|
|||
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);
|
||||
}
|
||||
|
|
31
src/f_wipe.h
31
src/f_wipe.h
|
@ -26,19 +26,9 @@
|
|||
#ifndef __F_WIPE_H__
|
||||
#define __F_WIPE_H__
|
||||
|
||||
//
|
||||
// SCREEN WIPE PACKAGE
|
||||
//
|
||||
#include "stdint.h"
|
||||
|
||||
#if 0
|
||||
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
|
||||
class FTexture;
|
||||
int wipe_CalcBurn(uint8_t *buffer, int width, int height, int density);
|
||||
|
||||
enum
|
||||
|
@ -50,4 +40,21 @@ enum
|
|||
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
|
||||
|
|
|
@ -428,12 +428,6 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
|
|||
const auto &mScreenViewport = screen->mScreenViewport;
|
||||
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);
|
||||
|
||||
// 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.EnableTextureMatrix(true);
|
||||
}
|
||||
if (cmd.mFlags & F2DDrawer::DTF_Burn)
|
||||
{
|
||||
gl_RenderState.SetEffect(EFF_BURN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -555,6 +553,8 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
|
|||
gl_RenderState.SetObjectColor(0xffffffff);
|
||||
gl_RenderState.SetObjectColor2(0);
|
||||
gl_RenderState.EnableTextureMatrix(false);
|
||||
gl_RenderState.SetEffect(EFF_NONE);
|
||||
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
|
|
|
@ -49,10 +49,6 @@ public:
|
|||
// 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;
|
||||
|
||||
bool WipeStartScreen(int type);
|
||||
void WipeEndScreen();
|
||||
bool WipeDo(int ticks);
|
||||
void WipeCleanup();
|
||||
void Swap();
|
||||
bool IsHWGammaActive() const { return HWGammaActive; }
|
||||
|
||||
|
@ -63,33 +59,11 @@ public:
|
|||
|
||||
bool HWGammaActive = false; // Are we using hardware or software gamma?
|
||||
std::shared_ptr<FGLDebug> mDebug; // Debug API
|
||||
|
||||
FTexture *WipeStartScreen() override;
|
||||
FTexture *WipeEndScreen() override;
|
||||
private:
|
||||
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:
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -40,49 +40,21 @@
|
|||
#include "gl/data/gl_vertexbuffer.h"
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Screen wipes
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
class OpenGLFrameBuffer::Wiper_Crossfade : public OpenGLFrameBuffer::Wiper
|
||||
class FGLWipeTexture : public FTexture
|
||||
{
|
||||
public:
|
||||
Wiper_Crossfade();
|
||||
bool Run(int ticks, OpenGLFrameBuffer *fb);
|
||||
|
||||
private:
|
||||
int Clock;
|
||||
};
|
||||
FGLWipeTexture(int w, int h)
|
||||
{
|
||||
Width = w;
|
||||
Height = h;
|
||||
WidthBits = 4;
|
||||
UseType = ETextureType::SWCanvas;
|
||||
bNoCompress = true;
|
||||
SystemTexture[0] = screen->CreateHardwareTexture(this);
|
||||
}
|
||||
|
||||
class OpenGLFrameBuffer::Wiper_Melt : public OpenGLFrameBuffer::Wiper
|
||||
{
|
||||
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;
|
||||
// This is just a wrapper around the hardware texture being extracted below so that it can be passed to the 2D code.
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -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;
|
||||
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]()
|
||||
{
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
|
||||
};
|
||||
FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height);
|
||||
tex->SystemTexture[0]->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen");
|
||||
glFinish();
|
||||
static_cast<FHardwareTexture*>(tex->SystemTexture[0])->Bind(0, false, false);
|
||||
|
||||
GLRenderer->mBuffers->BindCurrentFB();
|
||||
copyPixels();
|
||||
|
||||
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;
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
|
||||
return tex;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -145,392 +89,16 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::WipeEndScreen()
|
||||
FTexture *OpenGLFrameBuffer::WipeEndScreen()
|
||||
{
|
||||
GLRenderer->Flush();
|
||||
const auto &viewport = screen->mScreenViewport;
|
||||
wipeendscreen = new FHardwareTexture(true);
|
||||
wipeendscreen->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen");
|
||||
GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1);
|
||||
FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height);
|
||||
tex->SystemTexture[0]->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen");
|
||||
glFinish();
|
||||
wipeendscreen->Bind(0, false, false);
|
||||
|
||||
static_cast<FHardwareTexture*>(tex->SystemTexture[0])->Bind(0, false, false);
|
||||
GLRenderer->mBuffers->BindCurrentFB();
|
||||
|
||||
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);
|
||||
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);
|
||||
return tex;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -242,6 +242,7 @@ bool F2DDrawer::SetStyle(FTexture *tex, DrawParms &parms, PalEntry &vertexcolor,
|
|||
else if (quad.mDrawMode == DTM_Invert) quad.mDrawMode = DTM_InvertOpaque;
|
||||
}
|
||||
quad.mRenderStyle = parms.style; // this contains the blend mode and blend equation settings.
|
||||
if (parms.burn) quad.mFlags |= DTF_Burn;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
{
|
||||
DTF_Wrap = 1,
|
||||
DTF_Scissor = 2,
|
||||
DTF_Burn = 4,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -511,6 +511,7 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3
|
|||
parms->srcy = 0.;
|
||||
parms->srcwidth = 1.;
|
||||
parms->srcheight = 1.;
|
||||
parms->burn = false;
|
||||
|
||||
// Parse the tag list for attributes. (For floating point attributes,
|
||||
// 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);
|
||||
break;
|
||||
|
||||
case DTA_Burn:
|
||||
parms->burn = true;
|
||||
break;
|
||||
|
||||
}
|
||||
tag = ListGetInt(tags);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
struct sector_t;
|
||||
class IShaderProgram;
|
||||
class FTexture;
|
||||
|
||||
enum EHWCaps
|
||||
{
|
||||
|
@ -205,6 +206,7 @@ enum
|
|||
DTA_SrcWidth,
|
||||
DTA_SrcHeight,
|
||||
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;
|
||||
double srcx, srcy;
|
||||
double srcwidth, srcheight;
|
||||
bool burn;
|
||||
};
|
||||
|
||||
struct Va_List
|
||||
|
@ -467,8 +470,8 @@ public:
|
|||
virtual sector_t *RenderView(player_t *player) { return nullptr; }
|
||||
|
||||
// Screen wiping
|
||||
virtual bool WipeStartScreen(int type);
|
||||
virtual void WipeEndScreen();
|
||||
virtual FTexture *WipeStartScreen();
|
||||
virtual FTexture *WipeEndScreen();
|
||||
virtual bool WipeDo(int ticks);
|
||||
virtual void WipeCleanup();
|
||||
|
||||
|
|
Loading…
Reference in a new issue