// //--------------------------------------------------------------------------- // // 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/system/gl_interface.h" #include "gl/data/gl_data.h" #include "gl/data/gl_matrix.h" #include "gl/textures/gl_material.h" #include "c_cvars.h" #include "r_defs.h" #include "r_data/r_translate.h" class FVertexBuffer; class FShader; 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 { bool mTextureEnabled; bool mFogEnabled; bool mGlowEnabled; bool mSplitEnabled; bool mClipLineEnabled; bool mBrightmapEnabled; bool mColorMask[4]; bool currentColorMask[4]; int mLightIndex; 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 mClipHeight, mClipHeightDirection; float mShaderTimer; FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer; FStateVec4 mColor; FStateVec4 mCameraPos; FStateVec4 mGlowTop, mGlowBottom; FStateVec4 mGlowTopPlane, mGlowBottomPlane; FStateVec4 mSplitTopPlane, mSplitBottomPlane; FStateVec4 mClipLine; PalEntry mFogColor; PalEntry mObjectColor; FStateVec4 mDynColor; float mClipSplit[2]; int mEffectState; int mColormapState; float stAlphaThreshold; int stSrcBlend, stDstBlend; bool stAlphaTest; int stBlendEquation; FShader *activeShader; EPassType mPassType = NORMAL_PASS; bool ApplyShader(); public: VSMatrix mProjectionMatrix; VSMatrix mViewMatrix; VSMatrix mModelMatrix; VSMatrix mTextureMatrix; FRenderState() { Reset(); } void Reset(); void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader, bool alphatexture) { // textures without their own palette are a special case for use as an alpha texture: // They use the color index directly as an alpha value instead of using the palette's red. // To handle this case, we need to set a special translation for such textures. // Without shaders this translation must be applied to any texture. if (alphatexture) { if (mat->tex->UseBasePalette() || gl.legacyMode) translation = TRANSLATION(TRANSLATION_Standard, 8); } mEffectState = overrideshader >= 0? overrideshader : mat->mShaderIndex; mShaderTimer = mat->tex->gl_info.shaderspeed; mat->Bind(clampmode, translation); } void Apply(); void ApplyColorMask(); void ApplyMatrices(); void ApplyLightIndex(int index); void SetVertexBuffer(FVertexBuffer *vb) { mVertexBuffer = vb; } void ResetVertexBuffer() { // forces rebinding with the next 'apply' call. mCurrentVertexBuffer = NULL; } float GetClipHeight() { return mClipHeight; } float GetClipHeightDirection() { return mClipHeightDirection; } FStateVec4 &GetClipLine() { return mClipLine; } bool GetClipLineState() { return mClipLineEnabled; } void SetClipHeight(float height, float direction); 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(bool 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 SetClipLine(line_t *line) { mClipLine.Set(line->v1->fX(), line->v1->fY(), line->Delta().X, line->Delta().Y); } void EnableClipLine(bool on) { if (!(gl.flags & RFL_NO_CLIP_PLANES)) { mClipLineEnabled = on; if (on) { glEnable(GL_CLIP_DISTANCE0); } else { glDisable(GL_CLIP_DISTANCE0); } } } void SetLightIndex(int n) { mLightIndex = n; } void EnableBrightmap(bool on) { mBrightmapEnabled = on; } void EnableModelMatrix(bool on) { mModelMatrixEnabled = on; } void EnableTextureMatrix(bool on) { mTextureMatrixEnabled = on; } void SetCameraPos(float x, float y, float z) { mCameraPos.Set(x, z, y, 0); } 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 level) { if (glset.lightmode == 8) mLightParms[3] = level / 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 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; } void SetFixedColormap(int cm) { mColormapState = cm; } int GetFixedColormap() { return mColormapState; } 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; } // Backwards compatibility crap follows void ApplyFixedFunction(); void DrawColormapOverlay(); }; extern FRenderState gl_RenderState; #endif