mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-12-01 08:31:14 +00:00
Add wipes
This commit is contained in:
parent
7911302ad8
commit
3c7d6234cb
5 changed files with 669 additions and 11 deletions
|
@ -1152,6 +1152,7 @@ set( FASTMATH_SOURCES
|
|||
gl/system/gl_interface.cpp
|
||||
gl/system/gl_framebuffer.cpp
|
||||
gl/system/gl_swframebuffer.cpp
|
||||
gl/system/gl_swwipe.cpp
|
||||
gl/system/gl_debug.cpp
|
||||
gl/system/gl_menu.cpp
|
||||
gl/system/gl_wipe.cpp
|
||||
|
|
|
@ -461,6 +461,28 @@ bool OpenGLSWFrameBuffer::CreateTexture(const FString &name, int width, int heig
|
|||
return true;
|
||||
}
|
||||
|
||||
OpenGLSWFrameBuffer::HWTexture *OpenGLSWFrameBuffer::CopyCurrentScreen()
|
||||
{
|
||||
auto obj = std::make_unique<HWTexture>();
|
||||
obj->Format = GL_RGBA16F;
|
||||
|
||||
GLint oldBinding = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
|
||||
|
||||
glGenTextures(1, (GLuint*)&obj->Texture);
|
||||
glBindTexture(GL_TEXTURE_2D, obj->Texture);
|
||||
|
||||
glCopyTexImage2D(GL_TEXTURE_2D, 0, obj->Format, 0, 0, Width, Height, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
FGLDebug::LabelObject(GL_TEXTURE, obj->Texture, "CopyCurrentScreen");
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, oldBinding);
|
||||
|
||||
return obj.release();
|
||||
}
|
||||
|
||||
void OpenGLSWFrameBuffer::SetGammaRamp(const GammaRamp *ramp)
|
||||
{
|
||||
}
|
||||
|
@ -548,6 +570,39 @@ void OpenGLSWFrameBuffer::DrawTriangleFans(int count, const FBVERTEX *vertices)
|
|||
glBindVertexArray(oldBinding);
|
||||
}
|
||||
|
||||
void OpenGLSWFrameBuffer::DrawTriangleFans(int count, const BURNVERTEX *vertices)
|
||||
{
|
||||
count = 2 + count;
|
||||
|
||||
GLint oldBinding = 0;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldBinding);
|
||||
|
||||
if (!StreamVertexBufferBurn)
|
||||
{
|
||||
StreamVertexBufferBurn = std::make_unique<HWVertexBuffer>();
|
||||
glGenVertexArrays(1, (GLuint*)&StreamVertexBufferBurn->VertexArray);
|
||||
glGenBuffers(1, (GLuint*)&StreamVertexBufferBurn->Buffer);
|
||||
glBindVertexArray(StreamVertexBufferBurn->VertexArray);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBufferBurn->Buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, count * sizeof(BURNVERTEX), vertices, GL_STREAM_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(BURNVERTEX), (const GLvoid*)offsetof(BURNVERTEX, x));
|
||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(BURNVERTEX), (const GLvoid*)offsetof(BURNVERTEX, tu0));
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindVertexArray(StreamVertexBufferBurn->VertexArray);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBufferBurn->Buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, count * sizeof(BURNVERTEX), vertices, GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, count);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(oldBinding);
|
||||
}
|
||||
|
||||
void OpenGLSWFrameBuffer::DrawPoints(int count, const FBVERTEX *vertices)
|
||||
{
|
||||
GLint oldBinding = 0;
|
||||
|
@ -600,8 +655,8 @@ void OpenGLSWFrameBuffer::Present()
|
|||
FBVERTEX verts[4];
|
||||
|
||||
CalcFullscreenCoords(verts, false, true, 0, 0xFFFFFFFF);
|
||||
for (int i = 0; i < 4; i++)
|
||||
verts[i].tv = 1.0f - verts[i].tv;
|
||||
//for (int i = 0; i < 4; i++)
|
||||
// verts[i].tv = 1.0f - verts[i].tv;
|
||||
SetTexture(0, OutputFB->Texture);
|
||||
SetPixelShader(Shaders[SHADER_GammaCorrection]);
|
||||
SetAlphaBlend(0);
|
||||
|
|
|
@ -64,19 +64,26 @@ public:
|
|||
void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32 realcolor) override;
|
||||
void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor) override;
|
||||
void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, int lightlevel) override;
|
||||
//bool WipeStartScreen(int type) override;
|
||||
//void WipeEndScreen() override;
|
||||
//bool WipeDo(int ticks) override;
|
||||
//void WipeCleanup() override;
|
||||
bool WipeStartScreen(int type) override;
|
||||
void WipeEndScreen() override;
|
||||
bool WipeDo(int ticks) override;
|
||||
void WipeCleanup() override;
|
||||
bool Is8BitMode() override { return false; }
|
||||
int GetTrueHeight() override { return TrueHeight; }
|
||||
|
||||
private:
|
||||
struct FBVERTEX
|
||||
{
|
||||
FLOAT x, y, z, rhw;
|
||||
float x, y, z, rhw;
|
||||
uint32_t color0, color1;
|
||||
FLOAT tu, tv;
|
||||
float tu, tv;
|
||||
};
|
||||
|
||||
struct BURNVERTEX
|
||||
{
|
||||
float x, y, z, rhw;
|
||||
float tu0, tv0;
|
||||
float tu1, tv1;
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -178,6 +185,7 @@ private:
|
|||
void SetStreamSource(HWVertexBuffer *vertexBuffer);
|
||||
void SetIndices(HWIndexBuffer *indexBuffer);
|
||||
void DrawTriangleFans(int count, const FBVERTEX *vertices);
|
||||
void DrawTriangleFans(int count, const BURNVERTEX *vertices);
|
||||
void DrawPoints(int count, const FBVERTEX *vertices);
|
||||
void DrawLineList(int count);
|
||||
void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount);
|
||||
|
@ -376,7 +384,7 @@ private:
|
|||
void UploadPalette();
|
||||
void CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, bool can_double, uint32_t color0, uint32_t color1) const;
|
||||
bool Reset();
|
||||
HWTexture *GetCurrentScreen();
|
||||
HWTexture *CopyCurrentScreen();
|
||||
void ReleaseDefaultPoolItems();
|
||||
void KillNativePals();
|
||||
void KillNativeTexs();
|
||||
|
@ -410,7 +418,7 @@ private:
|
|||
|
||||
std::shared_ptr<FGLDebug> Debug;
|
||||
|
||||
std::unique_ptr<HWVertexBuffer> StreamVertexBuffer;
|
||||
std::unique_ptr<HWVertexBuffer> StreamVertexBuffer, StreamVertexBufferBurn;
|
||||
float ShaderConstants[NumPSCONST * 4];
|
||||
HWPixelShader *CurrentShader = nullptr;
|
||||
|
||||
|
@ -476,7 +484,7 @@ private:
|
|||
virtual ~Wiper();
|
||||
virtual bool Run(int ticks, OpenGLSWFrameBuffer *fb) = 0;
|
||||
|
||||
//void DrawScreen(OpenGLSWFrameBuffer *fb, HWTexture *tex, int blendop = 0, uint32_t color0 = 0, uint32_t color1 = 0xFFFFFFF);
|
||||
void DrawScreen(OpenGLSWFrameBuffer *fb, HWTexture *tex, int blendop = 0, uint32_t color0 = 0, uint32_t color1 = 0xFFFFFFF);
|
||||
};
|
||||
|
||||
class Wiper_Melt; friend class Wiper_Melt;
|
||||
|
|
592
src/gl/system/gl_swwipe.cpp
Normal file
592
src/gl/system/gl_swwipe.cpp
Normal file
|
@ -0,0 +1,592 @@
|
|||
/*
|
||||
** gl_swwipe.cpp
|
||||
** Implements the different screen wipes using OpenGL calls.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2008 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include "gl/system/gl_system.h"
|
||||
#include "files.h"
|
||||
#include "m_swap.h"
|
||||
#include "v_video.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_png.h"
|
||||
#include "m_crc32.h"
|
||||
#include "vectors.h"
|
||||
#include "v_palette.h"
|
||||
#include "templates.h"
|
||||
|
||||
#include "c_dispatch.h"
|
||||
#include "templates.h"
|
||||
#include "i_system.h"
|
||||
#include "i_video.h"
|
||||
#include "i_input.h"
|
||||
#include "v_pfx.h"
|
||||
#include "stats.h"
|
||||
#include "doomerrors.h"
|
||||
#include "r_main.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "f_wipe.h"
|
||||
#include "sbar.h"
|
||||
#include "w_wad.h"
|
||||
#include "r_data/colormaps.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_swframebuffer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
#include "gl/gl_functions.h"
|
||||
#include "gl_debug.h"
|
||||
#include "m_random.h"
|
||||
|
||||
class OpenGLSWFrameBuffer::Wiper_Crossfade : public OpenGLSWFrameBuffer::Wiper
|
||||
{
|
||||
public:
|
||||
Wiper_Crossfade();
|
||||
bool Run(int ticks, OpenGLSWFrameBuffer *fb);
|
||||
|
||||
private:
|
||||
int Clock;
|
||||
};
|
||||
|
||||
class OpenGLSWFrameBuffer::Wiper_Melt : public OpenGLSWFrameBuffer::Wiper
|
||||
{
|
||||
public:
|
||||
Wiper_Melt();
|
||||
bool Run(int ticks, OpenGLSWFrameBuffer *fb);
|
||||
|
||||
private:
|
||||
// Match the strip sizes that oldschool Doom used.
|
||||
static const int WIDTH = 160, HEIGHT = 200;
|
||||
int y[WIDTH];
|
||||
};
|
||||
|
||||
class OpenGLSWFrameBuffer::Wiper_Burn : public OpenGLSWFrameBuffer::Wiper
|
||||
{
|
||||
public:
|
||||
Wiper_Burn(OpenGLSWFrameBuffer *fb);
|
||||
~Wiper_Burn();
|
||||
bool Run(int ticks, OpenGLSWFrameBuffer *fb);
|
||||
|
||||
private:
|
||||
static const int WIDTH = 64, HEIGHT = 64;
|
||||
uint8_t BurnArray[WIDTH * (HEIGHT + 5)];
|
||||
HWTexture *BurnTexture;
|
||||
int Density;
|
||||
int BurnTime;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: WipeStartScreen
|
||||
//
|
||||
// Called before the current screen has started rendering. This needs to
|
||||
// save what was drawn the previous frame so that it can be animated into
|
||||
// what gets drawn this frame.
|
||||
//
|
||||
// In fullscreen mode, we use GetFrontBufferData() to grab the data that
|
||||
// is visible on screen right now.
|
||||
//
|
||||
// In windowed mode, we can't do that because we'll get the whole desktop.
|
||||
// Instead, we can conveniently use the TempRenderTexture, which is normally
|
||||
// used for gamma-correcting copying the image to the back buffer.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool OpenGLSWFrameBuffer::WipeStartScreen(int type)
|
||||
{
|
||||
if (!Accel2D)
|
||||
{
|
||||
return Super::WipeStartScreen(type);
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case wipe_Melt:
|
||||
ScreenWipe = new Wiper_Melt;
|
||||
break;
|
||||
|
||||
case wipe_Burn:
|
||||
ScreenWipe = new Wiper_Burn(this);
|
||||
break;
|
||||
|
||||
case wipe_Fade:
|
||||
ScreenWipe = new Wiper_Crossfade;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
InitialWipeScreen = CopyCurrentScreen();
|
||||
|
||||
// Make even fullscreen model render to the TempRenderTexture, so
|
||||
// we can have a copy of the new screen readily available.
|
||||
GatheringWipeScreen = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: WipeEndScreen
|
||||
//
|
||||
// The screen we want to animate to has just been drawn. This function is
|
||||
// called in place of Update(), so it has not been Presented yet.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLSWFrameBuffer::WipeEndScreen()
|
||||
{
|
||||
if (!Accel2D)
|
||||
{
|
||||
Super::WipeEndScreen();
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't do anything if there is no starting point.
|
||||
if (InitialWipeScreen == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the whole screen was drawn without 2D accel, get it in to
|
||||
// video memory now.
|
||||
if (!In2D)
|
||||
{
|
||||
Begin2D(true);
|
||||
}
|
||||
|
||||
EndBatch(); // Make sure all batched primitives have been drawn.
|
||||
|
||||
FinalWipeScreen = CopyCurrentScreen();
|
||||
|
||||
// At this point, InitialWipeScreen holds the screen we are wiping from.
|
||||
// FinalWipeScreen holds the screen we are wiping to, which may be the
|
||||
// same texture as TempRenderTexture.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: 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 OpenGLSWFrameBuffer::WipeDo(int ticks)
|
||||
{
|
||||
if (!Accel2D)
|
||||
{
|
||||
return Super::WipeDo(ticks);
|
||||
}
|
||||
|
||||
// Sanity checks.
|
||||
if (InitialWipeScreen == NULL || FinalWipeScreen == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (GatheringWipeScreen)
|
||||
{ // This is the first time we've been called for this wipe.
|
||||
GatheringWipeScreen = false;
|
||||
}
|
||||
else
|
||||
{ // This is the second or later time we've been called for this wipe.
|
||||
InScene = true;
|
||||
}
|
||||
|
||||
In2D = 3;
|
||||
|
||||
EnableAlphaTest(false);
|
||||
bool done = ScreenWipe->Run(ticks, this);
|
||||
DrawLetterbox();
|
||||
return done;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: WipeCleanup
|
||||
//
|
||||
// Release any resources that were specifically created for the wipe.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLSWFrameBuffer::WipeCleanup()
|
||||
{
|
||||
if (ScreenWipe != NULL)
|
||||
{
|
||||
delete ScreenWipe;
|
||||
ScreenWipe = NULL;
|
||||
}
|
||||
SafeRelease( InitialWipeScreen );
|
||||
SafeRelease( FinalWipeScreen );
|
||||
GatheringWipeScreen = false;
|
||||
if (!Accel2D)
|
||||
{
|
||||
Super::WipeCleanup();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLSWFrameBuffer::Wiper::~Wiper()
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper :: DrawScreen
|
||||
//
|
||||
// Draw either the initial or target screen completely to the screen.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLSWFrameBuffer::Wiper::DrawScreen(OpenGLSWFrameBuffer *fb, HWTexture *tex,
|
||||
int blendop, uint32_t color0, uint32_t color1)
|
||||
{
|
||||
FBVERTEX verts[4];
|
||||
|
||||
fb->CalcFullscreenCoords(verts, false, false, color0, color1);
|
||||
fb->SetTexture(0, tex);
|
||||
fb->SetAlphaBlend(blendop, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
fb->SetPixelShader(fb->Shaders[SHADER_NormalColor]);
|
||||
fb->DrawTriangleFans(2, verts);
|
||||
}
|
||||
|
||||
// WIPE: CROSSFADE ---------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper_Crossfade Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLSWFrameBuffer::Wiper_Crossfade::Wiper_Crossfade()
|
||||
: Clock(0)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper_Crossfade :: Run
|
||||
//
|
||||
// Fades the old screen into the new one over 32 ticks.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool OpenGLSWFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLSWFrameBuffer *fb)
|
||||
{
|
||||
Clock += ticks;
|
||||
|
||||
// Put the initial screen back to the buffer.
|
||||
DrawScreen(fb, fb->InitialWipeScreen);
|
||||
|
||||
// Draw the new screen on top of it.
|
||||
DrawScreen(fb, fb->FinalWipeScreen, GL_FUNC_ADD, ColorValue(0,0,0,Clock / 32.f), ColorRGBA(255,255,255,0));
|
||||
|
||||
return Clock >= 32;
|
||||
}
|
||||
|
||||
// WIPE: MELT --------------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper_Melt Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLSWFrameBuffer::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);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper_Melt :: Run
|
||||
//
|
||||
// Fades the old screen into the new one over 32 ticks.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool OpenGLSWFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLSWFrameBuffer *fb)
|
||||
{
|
||||
// Draw the new screen on the bottom.
|
||||
DrawScreen(fb, fb->FinalWipeScreen);
|
||||
|
||||
int i, dy;
|
||||
int fbwidth = fb->Width;
|
||||
int fbheight = fb->Height;
|
||||
bool done = true;
|
||||
|
||||
// Copy the old screen in vertical strips on top of the new one.
|
||||
while (ticks--)
|
||||
{
|
||||
done = true;
|
||||
for (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)
|
||||
{ // Only draw for the final tick.
|
||||
RECT rect;
|
||||
POINT dpt;
|
||||
|
||||
dpt.x = i * fbwidth / WIDTH;
|
||||
dpt.y = MAX(0, y[i] * fbheight / HEIGHT);
|
||||
rect.left = dpt.x;
|
||||
rect.top = 0;
|
||||
rect.right = (i + 1) * fbwidth / WIDTH;
|
||||
rect.bottom = fbheight - dpt.y;
|
||||
if (rect.bottom > rect.top)
|
||||
{
|
||||
fb->CheckQuadBatch();
|
||||
|
||||
BufferedTris *quad = &fb->QuadExtra[fb->QuadBatchPos];
|
||||
FBVERTEX *vert = &fb->VertexData[fb->VertexPos];
|
||||
WORD *index = &fb->IndexData[fb->IndexPos];
|
||||
|
||||
quad->ClearSetup();
|
||||
quad->Flags = BQF_DisableAlphaTest;
|
||||
quad->ShaderNum = BQS_Plain;
|
||||
quad->Palette = NULL;
|
||||
quad->Texture = fb->InitialWipeScreen;
|
||||
quad->NumVerts = 4;
|
||||
quad->NumTris = 2;
|
||||
|
||||
// Fill the vertex buffer.
|
||||
float u0 = rect.left / float(fb->FBWidth);
|
||||
float v0 = 0;
|
||||
float u1 = rect.right / float(fb->FBWidth);
|
||||
float v1 = (rect.bottom - rect.top) / float(fb->FBHeight);
|
||||
|
||||
float x0 = float(rect.left) - 0.5f;
|
||||
float x1 = float(rect.right) - 0.5f;
|
||||
float y0 = float(dpt.y + fb->LBOffsetI) - 0.5f;
|
||||
float y1 = float(fbheight + fb->LBOffsetI) - 0.5f;
|
||||
|
||||
vert[0].x = x0;
|
||||
vert[0].y = y0;
|
||||
vert[0].z = 0;
|
||||
vert[0].rhw = 1;
|
||||
vert[0].color0 = 0;
|
||||
vert[0].color1 = 0xFFFFFFF;
|
||||
vert[0].tu = u0;
|
||||
vert[0].tv = v0;
|
||||
|
||||
vert[1].x = x1;
|
||||
vert[1].y = y0;
|
||||
vert[1].z = 0;
|
||||
vert[1].rhw = 1;
|
||||
vert[1].color0 = 0;
|
||||
vert[1].color1 = 0xFFFFFFF;
|
||||
vert[1].tu = u1;
|
||||
vert[1].tv = v0;
|
||||
|
||||
vert[2].x = x1;
|
||||
vert[2].y = y1;
|
||||
vert[2].z = 0;
|
||||
vert[2].rhw = 1;
|
||||
vert[2].color0 = 0;
|
||||
vert[2].color1 = 0xFFFFFFF;
|
||||
vert[2].tu = u1;
|
||||
vert[2].tv = v1;
|
||||
|
||||
vert[3].x = x0;
|
||||
vert[3].y = y1;
|
||||
vert[3].z = 0;
|
||||
vert[3].rhw = 1;
|
||||
vert[3].color0 = 0;
|
||||
vert[3].color1 = 0xFFFFFFF;
|
||||
vert[3].tu = u0;
|
||||
vert[3].tv = v1;
|
||||
|
||||
// Fill the vertex index buffer.
|
||||
index[0] = fb->VertexPos;
|
||||
index[1] = fb->VertexPos + 1;
|
||||
index[2] = fb->VertexPos + 2;
|
||||
index[3] = fb->VertexPos;
|
||||
index[4] = fb->VertexPos + 2;
|
||||
index[5] = fb->VertexPos + 3;
|
||||
|
||||
// Batch the quad.
|
||||
fb->QuadBatchPos++;
|
||||
fb->VertexPos += 4;
|
||||
fb->IndexPos += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fb->EndQuadBatch();
|
||||
return done;
|
||||
}
|
||||
|
||||
// WIPE: BURN --------------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper_Burn Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLSWFrameBuffer::Wiper_Burn::Wiper_Burn(OpenGLSWFrameBuffer *fb)
|
||||
{
|
||||
Density = 4;
|
||||
BurnTime = 0;
|
||||
memset(BurnArray, 0, sizeof(BurnArray));
|
||||
if (fb->Shaders[SHADER_BurnWipe] == NULL || !fb->CreateTexture("BurnWipe", WIDTH, HEIGHT, 1, GL_R8, &BurnTexture))
|
||||
{
|
||||
BurnTexture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper_Burn Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLSWFrameBuffer::Wiper_Burn::~Wiper_Burn()
|
||||
{
|
||||
SafeRelease( BurnTexture );
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLSWFrameBuffer :: Wiper_Burn :: Run
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool OpenGLSWFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLSWFrameBuffer *fb)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// Update the burn texture with the new burn data
|
||||
|
||||
if (BurnTexture->Buffers[0] == 0)
|
||||
{
|
||||
glGenBuffers(2, (GLuint*)BurnTexture->Buffers);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[0]);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, WIDTH * HEIGHT, nullptr, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[1]);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, WIDTH * HEIGHT, nullptr, GL_STREAM_DRAW);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[BurnTexture->CurrentBuffer]);
|
||||
BurnTexture->CurrentBuffer = (BurnTexture->CurrentBuffer + 1) & 1;
|
||||
}
|
||||
|
||||
uint8_t *dest = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, WIDTH * HEIGHT, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
if (dest)
|
||||
{
|
||||
memcpy(dest, BurnArray, WIDTH * HEIGHT);
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
|
||||
GLint oldBinding = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
|
||||
glBindTexture(GL_TEXTURE_2D, BurnTexture->Texture);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_RED, GL_UNSIGNED_BYTE, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, oldBinding);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
// Put the initial screen back to the buffer.
|
||||
DrawScreen(fb, fb->InitialWipeScreen);
|
||||
|
||||
// Burn the new screen on top of it.
|
||||
float top = fb->LBOffset - 0.5f;
|
||||
float right = float(fb->Width) - 0.5f;
|
||||
float bot = float(fb->Height) + top;
|
||||
float texright = float(fb->Width) / float(fb->FBWidth);
|
||||
float texbot = float(fb->Height) / float(fb->FBHeight);
|
||||
|
||||
BURNVERTEX verts[4] =
|
||||
{
|
||||
{ -0.5f, top, 0.5f, 1.f, 0.f, 0.f, 0, 0 },
|
||||
{ right, top, 0.5f, 1.f, texright, 0.f, 1, 0 },
|
||||
{ right, bot, 0.5f, 1.f, texright, texbot, 1, 1 },
|
||||
{ -0.5f, bot, 0.5f, 1.f, 0.f, texbot, 0, 1 }
|
||||
};
|
||||
|
||||
fb->SetTexture(0, fb->FinalWipeScreen);
|
||||
fb->SetTexture(1, BurnTexture);
|
||||
fb->SetAlphaBlend(GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
fb->SetPixelShader(fb->Shaders[SHADER_BurnWipe]);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
fb->DrawTriangleFans(2, verts);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
// The fire may not always stabilize, so the wipe is forced to end
|
||||
// after an arbitrary maximum time.
|
||||
return done || (BurnTime > 40);
|
||||
}
|
|
@ -13,7 +13,9 @@ uniform vec4 ScreenSize;
|
|||
void main()
|
||||
{
|
||||
gl_Position = vec4(AttrPosition.xy / ScreenSize.xy * 2.0 - 1.0, 1.0, 1.0);
|
||||
#if defined(EGAMMACORRECTION)
|
||||
gl_Position.y = -gl_Position.y;
|
||||
#endif
|
||||
PixelColor0 = AttrColor0.bgra;
|
||||
PixelColor1 = AttrColor1.bgra;
|
||||
PixelTexCoord0 = AttrTexCoord0;
|
||||
|
|
Loading…
Reference in a new issue