mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2025-02-07 07:21:01 +00:00
Merge remote-tracking branch 'origin/gl_swframebuffer' into qzdoom
This commit is contained in:
commit
f5c069c759
9 changed files with 4886 additions and 4 deletions
|
@ -1194,6 +1194,8 @@ set( FASTMATH_SOURCES
|
||||||
gl/shaders/gl_fxaashader.cpp
|
gl/shaders/gl_fxaashader.cpp
|
||||||
gl/system/gl_interface.cpp
|
gl/system/gl_interface.cpp
|
||||||
gl/system/gl_framebuffer.cpp
|
gl/system/gl_framebuffer.cpp
|
||||||
|
gl/system/gl_swframebuffer.cpp
|
||||||
|
gl/system/gl_swwipe.cpp
|
||||||
gl/system/gl_debug.cpp
|
gl/system/gl_debug.cpp
|
||||||
gl/system/gl_menu.cpp
|
gl/system/gl_menu.cpp
|
||||||
gl/system/gl_wipe.cpp
|
gl/system/gl_wipe.cpp
|
||||||
|
|
3613
src/gl/system/gl_swframebuffer.cpp
Normal file
3613
src/gl/system/gl_swframebuffer.cpp
Normal file
File diff suppressed because it is too large
Load diff
498
src/gl/system/gl_swframebuffer.h
Normal file
498
src/gl/system/gl_swframebuffer.h
Normal 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
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);
|
||||||
|
}
|
|
@ -312,6 +312,7 @@ public:
|
||||||
static void FlipNonSquareBlockRemap (BYTE *blockto, const BYTE *blockfrom, int x, int y, int srcpitch, const BYTE *remap);
|
static void FlipNonSquareBlockRemap (BYTE *blockto, const BYTE *blockfrom, int x, int y, int srcpitch, const BYTE *remap);
|
||||||
|
|
||||||
friend class D3DTex;
|
friend class D3DTex;
|
||||||
|
friend class OpenGLSWFrameBuffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -137,9 +137,13 @@ void I_InitGraphics ()
|
||||||
val.Bool = !!Args->CheckParm ("-devparm");
|
val.Bool = !!Args->CheckParm ("-devparm");
|
||||||
ticker.SetGenericRepDefault (val, CVAR_Bool);
|
ticker.SetGenericRepDefault (val, CVAR_Bool);
|
||||||
|
|
||||||
//currentrenderer = vid_renderer;
|
//#define USE_D3D9_VIDEO
|
||||||
if (currentrenderer==1) Video = gl_CreateVideo();
|
#ifdef USE_D3D9_VIDEO
|
||||||
else Video = new Win32Video (0);
|
if (currentrenderer == 1) Video = gl_CreateVideo();
|
||||||
|
else Video = new Win32Video(0);
|
||||||
|
#else
|
||||||
|
Video = gl_CreateVideo();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (Video == NULL)
|
if (Video == NULL)
|
||||||
I_FatalError ("Failed to initialize display");
|
I_FatalError ("Failed to initialize display");
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "gl/renderer/gl_renderer.h"
|
#include "gl/renderer/gl_renderer.h"
|
||||||
#include "gl/system/gl_framebuffer.h"
|
#include "gl/system/gl_framebuffer.h"
|
||||||
|
#include "gl/system/gl_swframebuffer.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||||
|
@ -387,7 +388,10 @@ DFrameBuffer *Win32GLVideo::CreateFrameBuffer(int width, int height, bool bgra,
|
||||||
//old->GetFlash(flashColor, flashAmount);
|
//old->GetFlash(flashColor, flashAmount);
|
||||||
delete old;
|
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;
|
return fb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
146
wadsrc/static/shaders/glsl/swshader.fp
Normal file
146
wadsrc/static/shaders/glsl/swshader.fp
Normal 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
|
||||||
|
}
|
22
wadsrc/static/shaders/glsl/swshader.vp
Normal file
22
wadsrc/static/shaders/glsl/swshader.vp
Normal 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;
|
||||||
|
}
|
Loading…
Reference in a new issue