Merge remote-tracking branch 'origin/gl_swframebuffer' into qzdoom

This commit is contained in:
Magnus Norddahl 2016-10-11 14:54:18 +02:00
commit f5c069c759
9 changed files with 4886 additions and 4 deletions

View file

@ -1194,6 +1194,8 @@ set( FASTMATH_SOURCES
gl/shaders/gl_fxaashader.cpp
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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,498 @@
#ifndef __GL_SWFRAMEBUFFER
#define __GL_SWFRAMEBUFFER
#ifdef _WIN32
#include "win32iface.h"
#include "win32gliface.h"
#endif
#include "SkylineBinPack.h"
#include <memory>
class FGLDebug;
#ifdef _WIN32
class OpenGLSWFrameBuffer : public Win32GLFrameBuffer
{
typedef Win32GLFrameBuffer Super;
DECLARE_CLASS(OpenGLSWFrameBuffer, Win32GLFrameBuffer)
#else
#include "sdlglvideo.h"
class OpenGLFrameBuffer : public SDLGLFB
{
// typedef SDLGLFB Super; //[C]commented, DECLARE_CLASS defines this in linux
DECLARE_CLASS(OpenGLSWFrameBuffer, SDLGLFB)
#endif
public:
explicit OpenGLSWFrameBuffer() {}
OpenGLSWFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen);
~OpenGLSWFrameBuffer();
bool IsValid() override;
bool Lock(bool buffered) override;
void Unlock() override;
void Update() override;
PalEntry *GetPalette() override;
void GetFlashedPalette(PalEntry palette[256]) override;
void UpdatePalette() override;
bool SetGamma(float gamma) override;
bool SetFlash(PalEntry rgb, int amount) override;
void GetFlash(PalEntry &rgb, int &amount) override;
int GetPageCount() override;
bool IsFullscreen() override;
void PaletteChanged() override;
int QueryNewPalette() override;
void Blank() override;
bool PaintToWindow() override;
void SetVSync(bool vsync) override;
void NewRefreshRate() override;
void GetScreenshotBuffer(const uint8_t *&buffer, int &pitch, ESSType &color_type) override;
void ReleaseScreenshotBuffer() override;
void SetBlendingRect(int x1, int y1, int x2, int y2) override;
bool Begin2D(bool copy3d) override;
void DrawBlendingRect() override;
FNativeTexture *CreateTexture(FTexture *gametex, bool wrapping) override;
FNativePalette *CreatePalette(FRemapTable *remap) override;
void DrawTextureParms(FTexture *img, DrawParms &parms) override;
void Clear(int left, int top, int right, int bottom, int palcolor, uint32 color) override;
void Dim(PalEntry color, float amount, int x1, int y1, int w, int h) override;
void FlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin) override;
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 Is8BitMode() override { return false; }
int GetTrueHeight() override { return TrueHeight; }
private:
struct FBVERTEX
{
float x, y, z, rhw;
uint32_t color0, color1;
float tu, tv;
};
struct BURNVERTEX
{
float x, y, z, rhw;
float tu0, tv0;
float tu1, tv1;
};
enum
{
PSCONST_Desaturation,
PSCONST_PaletteMod,
PSCONST_Weights,
PSCONST_Gamma,
PSCONST_ScreenSize,
NumPSCONST
};
struct GammaRamp
{
uint16_t red[256], green[256], blue[256];
};
struct LTRBRect
{
int left, top, right, bottom;
};
class HWTexture
{
public:
HWTexture() { Buffers[0] = 0; Buffers[1] = 0; }
~HWTexture();
int Texture = 0;
int Buffers[2];
int CurrentBuffer = 0;
int WrapS = 0;
int WrapT = 0;
int Format = 0;
};
class HWFrameBuffer
{
public:
~HWFrameBuffer();
int Framebuffer = 0;
HWTexture *Texture = nullptr;
};
class HWVertexBuffer
{
public:
~HWVertexBuffer();
FBVERTEX *Lock();
void Unlock();
int VertexArray = 0;
int Buffer = 0;
int Size = 0;
};
class HWIndexBuffer
{
public:
~HWIndexBuffer();
uint16_t *Lock();
void Unlock();
int Buffer = 0;
int Size = 0;
private:
int LockedOldBinding = 0;
};
class HWPixelShader
{
public:
~HWPixelShader();
int Program = 0;
int VertexShader = 0;
int FragmentShader = 0;
int ConstantLocations[NumPSCONST];
int ImageLocation = -1;
int PaletteLocation = -1;
int NewScreenLocation = -1;
int BurnLocation = -1;
};
bool CreateFrameBuffer(const FString &name, int width, int height, HWFrameBuffer **outFramebuffer);
bool CreatePixelShader(FString vertexsrc, FString fragmentsrc, const FString &defines, HWPixelShader **outShader);
bool CreateVertexBuffer(int size, HWVertexBuffer **outVertexBuffer);
bool CreateIndexBuffer(int size, HWIndexBuffer **outIndexBuffer);
bool CreateTexture(const FString &name, int width, int height, int levels, int format, HWTexture **outTexture);
void SetGammaRamp(const GammaRamp *ramp);
void SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount);
void SetHWPixelShader(HWPixelShader *shader);
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);
void Present();
static uint32_t ColorARGB(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b) & 0xff); }
static uint32_t ColorRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { return ColorARGB(a, r, g, b); }
static uint32_t ColorXRGB(uint32_t r, uint32_t g, uint32_t b) { return ColorARGB(0xff, r, g, b); }
static uint32_t ColorValue(float r, float g, float b, float a) { return ColorRGBA((uint32_t)(r * 255.0f), (uint32_t)(g * 255.0f), (uint32_t)(b * 255.0f), (uint32_t)(a * 255.0f)); }
// The number of points for the vertex buffer.
enum { NUM_VERTS = 10240 };
// The number of indices for the index buffer.
enum { NUM_INDEXES = ((NUM_VERTS * 6) / 4) };
// The number of quads we can batch together.
enum { MAX_QUAD_BATCH = (NUM_INDEXES / 6) };
// The default size for a texture atlas.
enum { DEF_ATLAS_WIDTH = 512 };
enum { DEF_ATLAS_HEIGHT = 512 };
// TYPES -------------------------------------------------------------------
struct Atlas;
struct PackedTexture
{
Atlas *Owner;
PackedTexture **Prev, *Next;
// Pixels this image covers
LTRBRect Area;
// Texture coordinates for this image
float Left, Top, Right, Bottom;
// Texture has extra space on the border?
bool Padded;
};
struct Atlas
{
Atlas(OpenGLSWFrameBuffer *fb, int width, int height, int format);
~Atlas();
PackedTexture *AllocateImage(const Rect &rect, bool padded);
void FreeBox(PackedTexture *box);
SkylineBinPack Packer;
Atlas *Next;
HWTexture *Tex;
int Format;
PackedTexture *UsedList; // Boxes that contain images
int Width, Height;
bool OneUse;
};
class OpenGLTex : public FNativeTexture
{
public:
OpenGLTex(FTexture *tex, OpenGLSWFrameBuffer *fb, bool wrapping);
~OpenGLTex();
FTexture *GameTex;
PackedTexture *Box;
OpenGLTex **Prev;
OpenGLTex *Next;
bool IsGray;
bool Create(OpenGLSWFrameBuffer *fb, bool wrapping);
bool Update();
bool CheckWrapping(bool wrapping);
int GetTexFormat();
FTextureFormat ToTexFmt(int fmt);
};
class OpenGLPal : public FNativePalette
{
public:
OpenGLPal(FRemapTable *remap, OpenGLSWFrameBuffer *fb);
~OpenGLPal();
OpenGLPal **Prev;
OpenGLPal *Next;
HWTexture *Tex;
uint32_t BorderColor;
bool DoColorSkip;
bool Update();
FRemapTable *Remap;
int RoundedPaletteSize;
};
// Flags for a buffered quad
enum
{
BQF_GamePalette = 1,
BQF_CustomPalette = 7,
BQF_Paletted = 7,
BQF_Bilinear = 8,
BQF_WrapUV = 16,
BQF_InvertSource = 32,
BQF_DisableAlphaTest = 64,
BQF_Desaturated = 128,
};
// Shaders for a buffered quad
enum
{
BQS_PalTex,
BQS_Plain,
BQS_RedToAlpha,
BQS_ColorOnly,
BQS_SpecialColormap,
BQS_InGameColormap,
};
struct PackedTexture;
struct Atlas;
struct BufferedTris
{
uint8_t Flags;
uint8_t ShaderNum;
int BlendOp;
int SrcBlend;
int DestBlend;
uint8_t Desat;
OpenGLPal *Palette;
HWTexture *Texture;
uint16_t NumVerts; // Number of _unique_ vertices used by this set.
uint16_t NumTris; // Number of triangles used by this set.
void ClearSetup()
{
Flags = 0;
ShaderNum = 0;
BlendOp = 0;
SrcBlend = 0;
DestBlend = 0;
}
bool IsSameSetup(const BufferedTris &other) const
{
return Flags == other.Flags && ShaderNum == other.ShaderNum && BlendOp == other.BlendOp && SrcBlend == other.SrcBlend && DestBlend == other.DestBlend;
}
};
enum
{
SHADER_NormalColor,
SHADER_NormalColorPal,
SHADER_NormalColorInv,
SHADER_NormalColorPalInv,
SHADER_RedToAlpha,
SHADER_RedToAlphaInv,
SHADER_VertexColor,
SHADER_SpecialColormap,
SHADER_SpecialColormapPal,
SHADER_InGameColormap,
SHADER_InGameColormapDesat,
SHADER_InGameColormapInv,
SHADER_InGameColormapInvDesat,
SHADER_InGameColormapPal,
SHADER_InGameColormapPalDesat,
SHADER_InGameColormapPalInv,
SHADER_InGameColormapPalInvDesat,
SHADER_BurnWipe,
SHADER_GammaCorrection,
NUM_SHADERS
};
static const char *const ShaderDefines[NUM_SHADERS];
void Flip();
void SetInitialState();
bool CreateResources();
void ReleaseResources();
bool LoadShaders();
bool CreateFBTexture();
bool CreatePaletteTexture();
bool CreateVertexes();
void UploadPalette();
void CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, bool can_double, uint32_t color0, uint32_t color1) const;
bool Reset();
HWTexture *CopyCurrentScreen();
void ReleaseDefaultPoolItems();
void KillNativePals();
void KillNativeTexs();
PackedTexture *AllocPackedTexture(int width, int height, bool wrapping, int format);
void DrawPackedTextures(int packnum);
void DrawLetterbox();
void Draw3DPart(bool copy3d);
bool SetStyle(OpenGLTex *tex, DrawParms &parms, uint32_t &color0, uint32_t &color1, BufferedTris &quad);
static int GetStyleAlpha(int type);
static void SetColorOverlay(uint32_t color, float alpha, uint32_t &color0, uint32_t &color1);
void AddColorOnlyQuad(int left, int top, int width, int height, uint32_t color);
void AddColorOnlyRect(int left, int top, int width, int height, uint32_t color);
void CheckQuadBatch(int numtris = 2, int numverts = 4);
void BeginQuadBatch();
void EndQuadBatch();
void BeginLineBatch();
void EndLineBatch();
void EndBatch();
// State
void EnableAlphaTest(bool enabled);
void SetAlphaBlend(int op, int srcblend = 0, int destblend = 0);
void SetConstant(int cnum, float r, float g, float b, float a);
void SetPixelShader(HWPixelShader *shader);
void SetTexture(int tnum, HWTexture *texture);
void SetSamplerWrapS(int tnum, int mode);
void SetSamplerWrapT(int tnum, int mode);
void SetPaletteTexture(HWTexture *texture, int count, uint32_t border_color);
template<typename T> static void SafeRelease(T &x) { if (x != nullptr) { delete x; x = nullptr; } }
std::shared_ptr<FGLDebug> Debug;
std::unique_ptr<HWVertexBuffer> StreamVertexBuffer, StreamVertexBufferBurn;
float ShaderConstants[NumPSCONST * 4];
HWPixelShader *CurrentShader = nullptr;
HWFrameBuffer *OutputFB = nullptr;
bool AlphaTestEnabled = false;
bool AlphaBlendEnabled = false;
int AlphaBlendOp = 0;
int AlphaSrcBlend = 0;
int AlphaDestBlend = 0;
float Constant[3][4];
uint32_t CurBorderColor;
HWPixelShader *CurPixelShader;
HWTexture *Texture[5];
int SamplerWrapS[5], SamplerWrapT[5];
PalEntry SourcePalette[256];
uint32_t BorderColor;
uint32_t FlashColor0, FlashColor1;
PalEntry FlashColor;
int FlashAmount;
int TrueHeight;
int PixelDoubling;
int LBOffsetI;
float LBOffset;
float Gamma;
bool UpdatePending;
bool NeedPalUpdate;
bool NeedGammaUpdate;
int FBWidth, FBHeight;
bool VSync;
LTRBRect BlendingRect;
int In2D;
bool InScene;
bool GatheringWipeScreen;
bool AALines;
uint8_t BlockNum;
OpenGLPal *Palettes = nullptr;
OpenGLTex *Textures = nullptr;
Atlas *Atlases = nullptr;
HWTexture *FBTexture = nullptr;
HWTexture *PaletteTexture = nullptr;
HWTexture *ScreenshotTexture = nullptr;
HWVertexBuffer *VertexBuffer = nullptr;
FBVERTEX *VertexData = nullptr;
HWIndexBuffer *IndexBuffer = nullptr;
uint16_t *IndexData = nullptr;
BufferedTris *QuadExtra = nullptr;
int VertexPos;
int IndexPos;
int QuadBatchPos;
enum { BATCH_None, BATCH_Quads, BATCH_Lines } BatchType;
HWPixelShader *Shaders[NUM_SHADERS];
HWTexture *InitialWipeScreen = nullptr, *FinalWipeScreen = nullptr;
class Wiper
{
public:
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);
};
class Wiper_Melt; friend class Wiper_Melt;
class Wiper_Burn; friend class Wiper_Burn;
class Wiper_Crossfade; friend class Wiper_Crossfade;
Wiper *ScreenWipe;
};
#endif //__GL_SWFRAMEBUFFER

592
src/gl/system/gl_swwipe.cpp Normal file
View 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);
}

View file

@ -312,6 +312,7 @@ public:
static void FlipNonSquareBlockRemap (BYTE *blockto, const BYTE *blockfrom, int x, int y, int srcpitch, const BYTE *remap);
friend class D3DTex;
friend class OpenGLSWFrameBuffer;
public:

View file

@ -137,9 +137,13 @@ void I_InitGraphics ()
val.Bool = !!Args->CheckParm ("-devparm");
ticker.SetGenericRepDefault (val, CVAR_Bool);
//currentrenderer = vid_renderer;
if (currentrenderer==1) Video = gl_CreateVideo();
else Video = new Win32Video (0);
//#define USE_D3D9_VIDEO
#ifdef USE_D3D9_VIDEO
if (currentrenderer == 1) Video = gl_CreateVideo();
else Video = new Win32Video(0);
#else
Video = gl_CreateVideo();
#endif
if (Video == NULL)
I_FatalError ("Failed to initialize display");

View file

@ -25,6 +25,7 @@
#include "gl/renderer/gl_renderer.h"
#include "gl/system/gl_framebuffer.h"
#include "gl/system/gl_swframebuffer.h"
extern "C" {
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
@ -387,7 +388,10 @@ DFrameBuffer *Win32GLVideo::CreateFrameBuffer(int width, int height, bool bgra,
//old->GetFlash(flashColor, flashAmount);
delete old;
}
fb = new OpenGLFrameBuffer(m_hMonitor, m_DisplayWidth, m_DisplayHeight, m_DisplayBits, m_DisplayHz, fs);
if (vid_renderer == 1)
fb = new OpenGLFrameBuffer(m_hMonitor, m_DisplayWidth, m_DisplayHeight, m_DisplayBits, m_DisplayHz, fs);
else
fb = new OpenGLSWFrameBuffer(m_hMonitor, m_DisplayWidth, m_DisplayHeight, m_DisplayBits, m_DisplayHz, fs);
return fb;
}

View file

@ -0,0 +1,146 @@
in vec4 PixelColor0;
in vec4 PixelColor1;
in vec4 PixelTexCoord0;
out vec4 FragColor;
uniform sampler2D Image;
uniform sampler2D Palette;
uniform sampler2D NewScreen;
uniform sampler2D Burn;
uniform vec4 Desaturation; // { Desat, 1 - Desat }
uniform vec4 PaletteMod;
uniform vec4 Weights; // RGB->Gray weighting { 77/256.0, 143/256.0, 37/256.0, 1 }
uniform vec4 Gamma;
vec4 TextureLookup(vec2 tex_coord)
{
#if PALTEX
float index = texture(Image, tex_coord).x;
index = index * PaletteMod.x + PaletteMod.y;
return texture(Palette, vec2(index, 0.5));
#else
return texture(Image, tex_coord);
#endif
}
vec4 Invert(vec4 rgb)
{
#if INVERT
rgb.rgb = Weights.www - rgb.xyz;
#endif
return rgb;
}
float Grayscale(vec4 rgb)
{
return dot(rgb.rgb, Weights.rgb);
}
vec4 SampleTexture(vec2 tex_coord)
{
return Invert(TextureLookup(tex_coord));
}
// Normal color calculation for most drawing modes.
vec4 NormalColor(vec2 tex_coord, vec4 Flash, vec4 InvFlash)
{
return Flash + SampleTexture(tex_coord) * InvFlash;
}
// Copy the red channel to the alpha channel. Pays no attention to palettes.
vec4 RedToAlpha(vec2 tex_coord, vec4 Flash, vec4 InvFlash)
{
vec4 color = Invert(texture(Image, tex_coord));
color.a = color.r;
return Flash + color * InvFlash;
}
// Just return the value of c0.
vec4 VertexColor(vec4 color)
{
return color;
}
// Emulate one of the special colormaps. (Invulnerability, gold, etc.)
vec4 SpecialColormap(vec2 tex_coord, vec4 start, vec4 end)
{
vec4 color = SampleTexture(tex_coord);
vec4 range = end - start;
// We can't store values greater than 1.0 in a color register, so we multiply
// the final result by 2 and expect the caller to divide the start and end by 2.
color.rgb = 2 * (start + Grayscale(color) * range).rgb;
// Duplicate alpha semantics of NormalColor.
color.a = start.a + color.a * end.a;
return color;
}
// In-game colormap effect: fade to a particular color and multiply by another, with
// optional desaturation of the original color. Desaturation is stored in c1.
// Fade level is packed int fade.a. Fade.rgb has been premultiplied by alpha.
// Overall alpha is in color.a.
vec4 InGameColormap(vec2 tex_coord, vec4 color, vec4 fade)
{
vec4 rgb = SampleTexture(tex_coord);
// Desaturate
#if DESAT
vec3 intensity;
intensity.rgb = vec3(Grayscale(rgb) * Desaturation.x);
rgb.rgb = intensity.rgb + rgb.rgb * Desaturation.y;
#endif
// Fade
rgb.rgb = rgb.rgb * fade.aaa + fade.rgb;
// Shade and Alpha
rgb = rgb * color;
return rgb;
}
// Windowed gamma correction.
vec4 GammaCorrection(vec2 tex_coord)
{
vec4 color = texture(Image, tex_coord);
color.rgb = pow(color.rgb, Gamma.rgb);
return color;
}
// The burn wipe effect.
vec4 BurnWipe(vec4 coord)
{
vec4 color = texture(NewScreen, coord.xy);
vec4 alpha = texture(Burn, coord.zw);
color.a = alpha.r * 2;
return color;
}
void main()
{
#if defined(ENORMALCOLOR)
FragColor = NormalColor(PixelTexCoord0.xy, PixelColor0, PixelColor1);
#elif defined(EREDTOALPHA)
FragColor = RedToAlpha(PixelTexCoord0.xy, PixelColor0, PixelColor1);
#elif defined(EVERTEXCOLOR)
FragColor = VertexColor(PixelColor0);
#elif defined(ESPECIALCOLORMAP)
FragColor = SpecialColormap(PixelTexCoord0.xy, PixelColor0, PixelColor1);
#elif defined(EINGAMECOLORMAP)
FragColor = InGameColormap(PixelTexCoord0.xy, PixelColor0, PixelColor1);
#elif defined(EBURNWIPE)
FragColor = BurnWipe(PixelTexCoord0);
#elif defined(EGAMMACORRECTION)
FragColor = GammaCorrection(PixelTexCoord0.xy);
#else
#error Entry point define is missing
#endif
}

View file

@ -0,0 +1,22 @@
in vec4 AttrPosition;
in vec4 AttrColor0;
in vec4 AttrColor1;
in vec4 AttrTexCoord0;
out vec4 PixelColor0;
out vec4 PixelColor1;
out vec4 PixelTexCoord0;
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;
}