diff --git a/src/d_main.cpp b/src/d_main.cpp index a08ce7ae1..163ef9d64 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -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 diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 31edce0fd..1f94c29df 100644 --- a/src/f_wipe.cpp +++ b/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((*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); +} diff --git a/src/f_wipe.h b/src/f_wipe.h index dc4cfb8cc..c639307aa 100644 --- a/src/f_wipe.h +++ b/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 diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 47d82c965..17cd6b6b1 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -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); diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 762cf69cf..44a380b3a 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -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 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: }; diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index ac5b924cd..bf1c6b45a 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -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; -}; - -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; + + FGLWipeTexture(int w, int h) + { + Width = w; + Height = h; + WidthBits = 4; + UseType = ETextureType::SWCanvas; + bNoCompress = true; + SystemTexture[0] = screen->CreateHardwareTexture(this); + } + + // 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); + + FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height); + tex->SystemTexture[0]->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); 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); - }; + static_cast(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(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((*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); -} diff --git a/src/v_2ddrawer.cpp b/src/v_2ddrawer.cpp index a09ecd5fd..2bbdec8ee 100644 --- a/src/v_2ddrawer.cpp +++ b/src/v_2ddrawer.cpp @@ -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; } diff --git a/src/v_2ddrawer.h b/src/v_2ddrawer.h index f60665e9e..5cef4f719 100644 --- a/src/v_2ddrawer.h +++ b/src/v_2ddrawer.h @@ -53,6 +53,7 @@ public: { DTF_Wrap = 1, DTF_Scissor = 2, + DTF_Burn = 4, }; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 765b20003..e3babb060 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -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 @@ -862,6 +863,10 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3 case DTA_CellY: parms->celly = ListGetInt(tags); break; + + case DTA_Burn: + parms->burn = true; + break; } tag = ListGetInt(tags); diff --git a/src/v_framebuffer.cpp b/src/v_framebuffer.cpp index 6debe64e0..d0eb961f6 100644 --- a/src/v_framebuffer.cpp +++ b/src/v_framebuffer.cpp @@ -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; } //========================================================================== diff --git a/src/v_video.h b/src/v_video.h index 29d4a7e39..f0dafa3ae 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -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();