// //--------------------------------------------------------------------------- // // Copyright(C) 2009-2016 Christoph Oelckers // All rights reserved. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see http://www.gnu.org/licenses/ // //-------------------------------------------------------------------------- // #ifndef __GL_RENDERSTATE_H #define __GL_RENDERSTATE_H #include #include "gl_load/gl_interface.h" #include "r_data/matrix.h" #include "hwrenderer/scene//hw_drawstructs.h" #include "hwrenderer/textures/hw_material.h" #include "c_cvars.h" #include "r_defs.h" #include "r_data/r_translate.h" #include "g_levellocals.h" class FVertexBuffer; class FShader; struct GLSectorPlane; extern TArray gl_MatrixStack; EXTERN_CVAR(Bool, gl_direct_state_change) struct FStateVec4 { float vec[4]; void Set(float r, float g, float b, float a) { vec[0] = r; vec[1] = g; vec[2] = b; vec[3] = a; } }; enum EEffect { EFF_NONE=-1, EFF_FOGBOUNDARY, EFF_SPHEREMAP, EFF_BURN, EFF_STENCIL, MAX_EFFECTS }; enum EPassType { NORMAL_PASS, GBUFFER_PASS, MAX_PASS_TYPES }; class FRenderState { friend void gl_SetTextureMode(int type); bool mTextureEnabled; uint8_t mFogEnabled; bool mGlowEnabled; bool mSplitEnabled; bool mBrightmapEnabled; bool mColorMask[4]; bool currentColorMask[4]; int mSpecialEffect; int mTextureMode; int mDesaturation; int mSoftLight; float mLightParms[4]; int mSrcBlend, mDstBlend; float mAlphaThreshold; int mBlendEquation; bool mModelMatrixEnabled; bool mTextureMatrixEnabled; bool mLastDepthClamp; float mInterpolationFactor; float mGlossiness, mSpecularLevel; float mShaderTimer; FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer; FStateVec4 mNormal; FStateVec4 mColor; FStateVec4 mGlowTop, mGlowBottom; FStateVec4 mGlowTopPlane, mGlowBottomPlane; FStateVec4 mSplitTopPlane, mSplitBottomPlane; PalEntry mFogColor; PalEntry mObjectColor; PalEntry mObjectColor2; FStateVec4 mDynColor; float mClipSplit[2]; int mEffectState; int mTempTM = TM_MODULATE; float stAlphaThreshold; int stSrcBlend, stDstBlend; bool stAlphaTest; int stBlendEquation; FShader *activeShader; EPassType mPassType = NORMAL_PASS; int mNumDrawBuffers = 1; bool ApplyShader(); // Texture binding state FMaterial *lastMaterial = nullptr; int lastClamp = 0; int lastTranslation = 0; int maxBoundMaterial = -1; public: VSMatrix mModelMatrix; VSMatrix mTextureMatrix; FRenderState() { Reset(); } void Reset(); void ClearLastMaterial() { lastMaterial = nullptr; } void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader, bool alphatexture); void Apply(); void ApplyColorMask(); void ApplyLightIndex(int index); void SetVertexBuffer(FVertexBuffer *vb) { mVertexBuffer = vb; } void ResetVertexBuffer() { // forces rebinding with the next 'apply' call. mCurrentVertexBuffer = NULL; } void SetNormal(FVector3 norm) { mNormal.Set(norm.X, norm.Y, norm.Z, 0.f); } void SetNormal(float x, float y, float z) { mNormal.Set(x, y, z, 0.f); } void SetColor(float r, float g, float b, float a = 1.f, int desat = 0) { mColor.Set(r, g, b, a); mDesaturation = desat; } void SetColor(PalEntry pe, int desat = 0) { mColor.Set(pe.r/255.f, pe.g/255.f, pe.b/255.f, pe.a/255.f); mDesaturation = desat; } void SetColorAlpha(PalEntry pe, float alpha = 1.f, int desat = 0) { mColor.Set(pe.r/255.f, pe.g/255.f, pe.b/255.f, alpha); mDesaturation = desat; } void ResetColor() { mColor.Set(1,1,1,1); mDesaturation = 0; } void GetColorMask(bool& r, bool &g, bool& b, bool& a) const { r = mColorMask[0]; g = mColorMask[1]; b = mColorMask[2]; a = mColorMask[3]; } void SetColorMask(bool r, bool g, bool b, bool a) { mColorMask[0] = r; mColorMask[1] = g; mColorMask[2] = b; mColorMask[3] = a; } void ResetColorMask() { for (int i = 0; i < 4; ++i) mColorMask[i] = true; } void SetTextureMode(int mode) { mTextureMode = mode; } int GetTextureMode() { return mTextureMode; } void EnableTexture(bool on) { mTextureEnabled = on; } void EnableFog(uint8_t on) { mFogEnabled = on; } void SetEffect(int eff) { mSpecialEffect = eff; } void EnableGlow(bool on) { mGlowEnabled = on; } void EnableSplit(bool on) { if (!(gl.flags & RFL_NO_CLIP_PLANES)) { mSplitEnabled = on; if (on) { glEnable(GL_CLIP_DISTANCE3); glEnable(GL_CLIP_DISTANCE4); } else { glDisable(GL_CLIP_DISTANCE3); glDisable(GL_CLIP_DISTANCE4); } } } void EnableBrightmap(bool on) { mBrightmapEnabled = on; } void EnableModelMatrix(bool on) { mModelMatrixEnabled = on; } void EnableTextureMatrix(bool on) { mTextureMatrixEnabled = on; } void SetGlowParams(float *t, float *b) { mGlowTop.Set(t[0], t[1], t[2], t[3]); mGlowBottom.Set(b[0], b[1], b[2], b[3]); } void SetSoftLightLevel(int llevel, int blendfactor = 0) { if (level.lightmode == 8 && blendfactor == 0) mLightParms[3] = llevel / 255.f; else mLightParms[3] = -1.f; } void SetGlowPlanes(const secplane_t &top, const secplane_t &bottom) { DVector3 tn = top.Normal(); DVector3 bn = bottom.Normal(); mGlowTopPlane.Set(tn.X, tn.Y, 1. / tn.Z, top.fD()); mGlowBottomPlane.Set(bn.X, bn.Y, 1. / bn.Z, bottom.fD()); } void SetSplitPlanes(const secplane_t &top, const secplane_t &bottom) { DVector3 tn = top.Normal(); DVector3 bn = bottom.Normal(); mSplitTopPlane.Set(tn.X, tn.Y, 1. / tn.Z, top.fD()); mSplitBottomPlane.Set(bn.X, bn.Y, 1. / bn.Z, bottom.fD()); } void SetDynLight(float r, float g, float b) { mDynColor.Set(r, g, b, 0); } void SetObjectColor(PalEntry pe) { mObjectColor = pe; } void SetObjectColor2(PalEntry pe) { mObjectColor2 = pe; } void SetSpecular(float glossiness, float specularLevel) { mGlossiness = glossiness; mSpecularLevel = specularLevel; } void SetFog(PalEntry c, float d) { const float LOG2E = 1.442692f; // = 1/log(2) mFogColor = c; if (d >= 0.0f) mLightParms[2] = d * (-LOG2E / 64000.f); } void SetLightParms(float f, float d) { mLightParms[1] = f; mLightParms[0] = d; } PalEntry GetFogColor() const { return mFogColor; } void SetClipSplit(float bottom, float top) { mClipSplit[0] = bottom; mClipSplit[1] = top; } void SetClipSplit(float *vals) { memcpy(mClipSplit, vals, 2 * sizeof(float)); } void GetClipSplit(float *out) { memcpy(out, mClipSplit, 2 * sizeof(float)); } void ClearClipSplit() { mClipSplit[0] = -1000000.f; mClipSplit[1] = 1000000.f; } void BlendFunc(int src, int dst) { if (!gl_direct_state_change) { mSrcBlend = src; mDstBlend = dst; } else { glBlendFunc(src, dst); } } void AlphaFunc(int func, float thresh) { if (func == GL_GREATER) mAlphaThreshold = thresh; else mAlphaThreshold = thresh - 0.001f; } void BlendEquation(int eq) { if (!gl_direct_state_change) { mBlendEquation = eq; } else { glBlendEquation(eq); } } // This wraps the depth clamp setting because we frequently need to read it which OpenGL is not particularly performant at... bool SetDepthClamp(bool on) { bool res = mLastDepthClamp; if (!on) glDisable(GL_DEPTH_CLAMP); else glEnable(GL_DEPTH_CLAMP); mLastDepthClamp = on; return res; } void SetInterpolationFactor(float fac) { mInterpolationFactor = fac; } float GetInterpolationFactor() { return mInterpolationFactor; } void SetPassType(EPassType passType) { mPassType = passType; } EPassType GetPassType() { return mPassType; } void EnableDrawBuffers(int count) { count = MIN(count, 3); if (mNumDrawBuffers != count) { static GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; glDrawBuffers(count, buffers); mNumDrawBuffers = count; } } int GetPassDrawBufferCount() { return mPassType == GBUFFER_PASS ? 3 : 1; } // Backwards compatibility crap follows void ApplyFixedFunction(); void DrawColormapOverlay(); void SetPlaneTextureRotation(GLSectorPlane *plane, FMaterial *texture) { if (hw_SetPlaneTextureRotation(plane, texture, mTextureMatrix)) { EnableTextureMatrix(true); } } }; extern FRenderState gl_RenderState; #endif