raze-gles/source/glbackend/glbackend.h

552 lines
12 KiB
C++

#pragma once
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <map>
#include "gl_samplers.h"
#include "gl_hwtexture.h"
#include "gl_renderstate.h"
#include "matrix.h"
#include "palentry.h"
#include "renderstyle.h"
class FSamplerManager;
class FShader;
class PolymostShader;
class SurfaceShader;
class FTexture;
class GLInstance;
class F2DDrawer;
struct palette_t;
extern int xdim, ydim;
struct PaletteData
{
int32_t crc32;
PalEntry colors[256];
bool shadesdone;
int whiteindex, blackindex;
FHardwareTexture* paltexture;
};
struct PalswapData
{
int32_t crc32;
bool isbright;
const uint8_t *lookup; // points to the original data. This is static so no need to copy
FHardwareTexture* swaptexture;
PalEntry fadeColor;
uint8_t brightcolors[255];
};
enum
{
PALSWAP_TEXTURE_SIZE = 2048
};
class PaletteManager
{
// The current engine limit is 256 palettes and 256 palswaps.
uint32_t palettemap[256] = {};
uint32_t palswapmap[256] = {};
uint32_t lastindex = ~0u;
uint32_t lastsindex = ~0u;
int numshades = 1;
// All data is being stored in contiguous blocks that can be used as uniform buffers as-is.
TArray<PaletteData> palettes;
TArray<PalswapData> palswaps;
TMap<int, int> swappedpalmap;
FHardwareTexture* palswapTexture = nullptr;
GLInstance* const inst;
//OpenGLRenderer::GLDataBuffer* palswapBuffer = nullptr;
unsigned FindPalswap(const uint8_t* paldata, palette_t& fadecolor);
public:
PaletteManager(GLInstance *inst_) : inst(inst_)
{}
~PaletteManager();
void DeleteAll();
void DeleteAllTextures();
void SetPalette(int index, const uint8_t *data);
void SetPalswapData(int index, const uint8_t* data, int numshades, palette_t &fadecolor);
void BindPalette(int index);
void BindPalswap(int index);
int ActivePalswap() const { return lastsindex; }
int LookupPalette(int palette, int palswap, bool brightmap, bool nontransparent255 = false);
const PalEntry *GetPaletteData(int palid) const { return palettes[palid].colors; }
unsigned FindPalette(const uint8_t* paldata);
};
struct glinfo_t {
float maxanisotropy;
};
enum EDrawType
{
DT_TRIANGLES,
DT_TRIANGLE_STRIP,
DT_TRIANGLE_FAN,
DT_LINES
};
enum ECull
{
Cull_None,
Cull_Front,
Cull_Back
};
enum EDepthFunc
{
Depth_Always,
Depth_Less,
Depth_Equal,
Depth_LessEqual
};
enum EWinding
{
Winding_CCW,
Winding_CW
};
enum ETexType
{
TT_INDEXED,
TT_TRUECOLOR,
TT_HICREPLACE,
TT_BRIGHTMAP
};
struct ImDrawData;
struct palette_t;
extern float shadediv[256];
enum
{
MAX_TEXTURES = 6, /*15*/ // slot 15 is used internally and not available. - The renderer uses only 5, though.
};
struct GLState
{
int Flags = STF_COLORMASK | STF_DEPTHMASK;
FRenderStyle Style{};
int DepthFunc = -1;
int TexId[MAX_TEXTURES] = {}, SamplerId[MAX_TEXTURES] = {};
};
class GLInstance
{
TArray<PolymostRenderState> rendercommands;
int maxTextureSize;
PaletteManager palmanager;
int lastPalswapIndex = -1;
FHardwareTexture* texv;
FTexture* currentTexture = nullptr;
int TextureType;
int MatrixChange = 0;
// Cached GL state.
GLState lastState;
float mProjectionM5 = 1.0f; // needed by ssao
PolymostRenderState renderState;
FShader* activeShader;
PolymostShader* polymostShader;
SurfaceShader* surfaceShader;
public:
glinfo_t glinfo;
FSamplerManager *mSamplers;
void Init(int y);
void InitGLState(int fogmode, int multisample);
void LoadPolymostShader();
void Draw2D(F2DDrawer* drawer);
void DrawImGui(ImDrawData*);
void ResetFrame();
void Deinit();
static int GetTexDimension(int value)
{
//if (value > gl.max_texturesize) return gl.max_texturesize;
return value;
}
GLInstance();
void Draw(EDrawType type, size_t start, size_t count);
void DoDraw();
void DrawElement(EDrawType type, size_t start, size_t count, PolymostRenderState& renderState);
FHardwareTexture* NewTexture();
void SetVertexBuffer(IVertexBuffer* vb, int offset1, int offset2);
void SetIndexBuffer(IIndexBuffer* vb);
void ClearBufferState();
float GetProjectionM5() { return mProjectionM5; }
int SetMatrix(int num, const VSMatrix *mat );
int SetMatrix(int num, const float *mat)
{
return SetMatrix(num, reinterpret_cast<const VSMatrix*>(mat));
}
int SetIdentityMatrix(int num)
{
auto r = renderState.matrixIndex[num];
renderState.matrixIndex[num] = 0;
return r;
}
void RestoreMatrix(int num, int index)
{
renderState.matrixIndex[num] = index;
}
void SetPolymostShader();
void SetSurfaceShader();
void SetPalette(int palette);
void ReadPixels(int w, int h, uint8_t* buffer);
void SetDepthBias(float a, float b)
{
renderState.mBias.mFactor = a;
renderState.mBias.mUnits = b;
renderState.mBias.mChanged = true;
}
void ClearDepthBias()
{
renderState.mBias.mFactor = 0;
renderState.mBias.mUnits = 0;
renderState.mBias.mChanged = true;
}
void SetPaletteData(int index, const uint8_t* data)
{
palmanager.SetPalette(index, data);
}
void SetPalswapData(int index, const uint8_t* data, int numshades, palette_t& fadecolor)
{
palmanager.SetPalswapData(index, data, numshades, fadecolor);
}
void SetPalswap(int index);
int GetClamp()
{
return 0;// int(renderState.Clamp[0] + 2 * renderState.Clamp[1]);
}
void SetClamp(int clamp)
{
// This option is totally pointless and should be removed.
//renderState.Clamp[0] = clamp & 1;
//renderState.Clamp[1] = !!(clamp & 2);
}
void SetShade(int32_t shade, int numshades)
{
renderState.Shade = shade;
renderState.NumShades = numshades;
}
void SetVisibility(float visibility, float fviewingrange)
{
renderState.VisFactor = visibility* fviewingrange* (1.f / (64.f * 65536.f));
}
void EnableBlend(bool on)
{
if (on) renderState.StateFlags |= STF_BLEND;
else renderState.StateFlags &= ~STF_BLEND;
}
void EnableDepthTest(bool on)
{
if (on) renderState.StateFlags |= STF_DEPTHTEST;
else renderState.StateFlags &= ~STF_DEPTHTEST;
}
void EnableMultisampling(bool on)
{
if (on) renderState.StateFlags |= STF_MULTISAMPLE;
else renderState.StateFlags &= ~STF_MULTISAMPLE;
}
void EnableStencilWrite(int value)
{
renderState.StateFlags |= STF_STENCILWRITE;
renderState.StateFlags &= ~STF_STENCILTEST;
}
void EnableStencilTest(int value)
{
renderState.StateFlags &= ~STF_STENCILWRITE;
renderState.StateFlags |= STF_STENCILTEST;
}
void DisableStencil()
{
renderState.StateFlags &= ~(STF_STENCILWRITE | STF_STENCILTEST);
}
void SetCull(int type, int winding = Winding_CW)
{
renderState.StateFlags &= ~(STF_CULLCCW | STF_CULLCW);
if (type != Cull_None)
{
if (winding == Winding_CW) renderState.StateFlags |= STF_CULLCW;
else renderState.StateFlags |= STF_CULLCCW;
}
}
void SetColorMask(bool on)
{
if (on) renderState.StateFlags |= STF_COLORMASK;
else renderState.StateFlags &= ~STF_COLORMASK;
}
void SetDepthMask(bool on)
{
if (on) renderState.StateFlags |= STF_DEPTHMASK;
else renderState.StateFlags &= ~STF_DEPTHMASK;
}
void SetWireframe(bool on)
{
if (on) renderState.StateFlags |= STF_WIREFRAME;
else renderState.StateFlags &= ~STF_WIREFRAME;
}
void ClearScreen(PalEntry pe, bool depth)
{
renderState.ClearColor = pe;
renderState.StateFlags |= STF_CLEARCOLOR;
if (depth) renderState.StateFlags |= STF_CLEARDEPTH;
}
void SetViewport(int x, int y, int w, int h)
{
renderState.vp_x = (short)x;
renderState.vp_y = (short)y;
renderState.vp_w = (short)w;
renderState.vp_h = (short)h;
renderState.StateFlags |= STF_VIEWPORTSET;
}
void SetScissor(int x1, int y1, int x2, int y2)
{
renderState.sc_x = (short)x1;
renderState.sc_y = (short)y1;
renderState.sc_w = (short)x2;
renderState.sc_h = (short)y2;
renderState.StateFlags |= STF_SCISSORSET;
}
void DisableScissor()
{
renderState.sc_x = SHRT_MIN;
renderState.StateFlags |= STF_SCISSORSET;
}
void SetDepthFunc(int func)
{
renderState.DepthFunc = func;
}
void ClearScreen(PalEntry pe)
{
//twod->Clear();
SetViewport(0, 0, xdim, ydim);
ClearScreen(pe, false);
}
void ClearDepth()
{
renderState.StateFlags |= STF_CLEARDEPTH;
}
void SetRenderStyle(FRenderStyle style)
{
renderState.Style = style;
}
void SetColor(float r, float g, float b, float a = 1.f)
{
renderState.Color[0] = r;
renderState.Color[1] = g;
renderState.Color[2] = b;
renderState.Color[3] = a;
}
void SetColorub(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255)
{
SetColor(r * (1 / 255.f), g * (1 / 255.f), b * (1 / 255.f), a * (1 / 255.f));
}
void BindTexture(int texunit, FHardwareTexture* tex, int sampler = NoSampler)
{
if (!tex) return;
if (texunit == 0)
{
if (tex->isIndexed()) renderState.Flags |= RF_UsePalette;
else renderState.Flags &= ~RF_UsePalette;
}
renderState.texIds[texunit] = tex->GetTextureHandle();
renderState.samplerIds[texunit] = sampler == NoSampler ? tex->GetSampler() : sampler;
}
void UnbindTexture(int texunit)
{
renderState.texIds[texunit] = 0;
renderState.samplerIds[texunit] = 0;
}
void UnbindAllTextures()
{
for (int texunit = 0; texunit < MAX_TEXTURES; texunit++)
{
UnbindTexture(texunit);
}
}
void UseColorOnly(bool yes)
{
if (yes) renderState.Flags |= RF_ColorOnly;
else renderState.Flags &= ~RF_ColorOnly;
}
void UseDetailMapping(bool yes)
{
if (yes) renderState.Flags |= RF_DetailMapping;
else renderState.Flags &= ~RF_DetailMapping;
}
void UseGlowMapping(bool yes)
{
if (yes) renderState.Flags |= RF_GlowMapping;
else renderState.Flags &= ~RF_GlowMapping;
}
void UseBrightmaps(bool yes)
{
if (yes) renderState.Flags |= RF_Brightmapping;
else renderState.Flags &= ~RF_Brightmapping;
}
void SetNpotEmulation(bool yes, float factor, float xOffset)
{
if (yes)
{
renderState.Flags |= RF_NPOTEmulation;
renderState.NPOTEmulationFactor = factor;
renderState.NPOTEmulationXOffset = xOffset;
}
else renderState.Flags &= ~RF_NPOTEmulation;
}
void SetShadeInterpolate(int32_t yes)
{
if (yes) renderState.Flags |= RF_ShadeInterpolate;
else renderState.Flags &= ~RF_ShadeInterpolate;
}
void SetFadeColor(PalEntry color)
{
renderState.FogColor = color;
};
void SetFadeDisable(bool yes)
{
if (yes) renderState.Flags |= RF_FogDisabled;
else renderState.Flags &= ~RF_FogDisabled;
}
// Hack...
bool useMapFog = false;
void SetMapFog(bool yes)
{
useMapFog = yes;
}
void applyMapFog()
{
if (useMapFog) renderState.Flags |= RF_MapFog;
else renderState.Flags &= ~RF_MapFog;
}
void clearMapFog()
{
renderState.Flags &= ~RF_MapFog;
}
void SetBrightness(int brightness)
{
renderState.Brightness = 8.f / (brightness + 8.f);
}
void SetTinting(int flags, PalEntry color, PalEntry overlayColor)
{
renderState.hictint = color;
renderState.hictint_overlay = overlayColor;
renderState.hictint_flags = flags;
}
void SetBasepalTint(PalEntry color)
{
renderState.fullscreenTint = color;
}
int GetPaletteIndex(PalEntry* palette)
{
return palmanager.FindPalette((uint8_t*)palette);
}
void EnableAlphaTest(bool on)
{
renderState.AlphaTest = on;
}
void SetAlphaThreshold(float al)
{
renderState.AlphaThreshold = al;
}
int LookupPalette(int palette, int palswap, bool brightmap, bool nontransparent255 = false)
{
return palmanager.LookupPalette(palette, palswap, brightmap, nontransparent255);
}
const PalEntry* GetPaletteData(int palid) const { return palmanager.GetPaletteData(palid); }
FHardwareTexture* CreateIndexedTexture(FTexture* tex);
FHardwareTexture* CreateTrueColorTexture(FTexture* tex, int palid, bool checkfulltransparency = false, bool rgb8bit = false);
FHardwareTexture *LoadTexture(FTexture* tex, int texturetype, int palid);
bool SetTextureInternal(int globalpicnum, FTexture* tex, int palette, int method, int sampleroverride, FTexture *det, float detscale, FTexture *glow);
bool SetNamedTexture(FTexture* tex, int palette, int sampleroverride);
bool SetTexture(int globalpicnum, FTexture* tex, int palette, int method, int sampleroverride)
{
return SetTextureInternal(globalpicnum, tex, palette, method, sampleroverride, nullptr, 1, nullptr);
}
bool SetModelTexture(FTexture *tex, int palette, FTexture *det, float detscale, FTexture *glow)
{
return SetTextureInternal(-1, tex, palette, 8/*DAMETH_MODEL*/, -1, det, detscale, glow);
}
};
extern GLInstance GLInterface;