diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index cf919b01a..1a4515781 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -38,6 +38,8 @@ #include "gl/renderer/gl_renderbuffers.h" #include "gl/textures/gl_hwtexture.h" +static int op2gl[] = { GL_KEEP, GL_INCR, GL_DECR }; + FGLRenderState gl_RenderState; CVAR(Bool, gl_direct_state_change, true, 0) @@ -226,6 +228,22 @@ void FGLRenderState::Apply() } } + if (mStencil.mChanged) + { + int recursion = GLRenderer->mPortalState.GetRecursion(); + glStencilFunc(GL_EQUAL, recursion + mStencil.mOffsVal, ~0); // draw sky into stencil + glStencilOp(GL_KEEP, GL_KEEP, op2gl[mStencil.mOperation]); // this stage doesn't modify the stencil + + bool cmon = !(mStencil.mFlags & SF_ColorMaskOff); + glColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer + glDepthMask(!(mStencil.mFlags & SF_DepthMaskOff)); + if (mStencil.mFlags & SF_DepthTestOff) + glDisable(GL_DEPTH_TEST); + else + glEnable(GL_DEPTH_TEST); + + } + if (mVertexBuffer != mCurrentVertexBuffer) { if (mVertexBuffer == NULL) glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 8864261b8..0d70ef90a 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -233,6 +233,14 @@ public: return mPassType == GBUFFER_PASS ? 3 : 1; } + void ApplyMaterial() + { + if (mMaterial.mChanged) + { + SetMaterial(mMaterial.mMaterial, mMaterial.mClampMode, mMaterial.mTranslation, mMaterial.mOverrideShader, false); + mMaterial.mChanged = false; + } + } }; extern FGLRenderState gl_RenderState; diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index 96e250a19..6ad9b0109 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -273,5 +273,33 @@ bool FDrawInfo::SetDepthClamp(bool on) return gl_RenderState.SetDepthClamp(on); } +static int dt2gl[] = { GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP }; + +void FDrawInfo::Draw(EDrawType dt, FRenderState &state, int index, int count, bool apply) +{ + assert(&state == &gl_RenderState); + if (apply) + { + gl_RenderState.ApplyMaterial(); + gl_RenderState.Apply(); + } + drawcalls.Clock(); + glDrawArrays(dt2gl[dt], index, count); + drawcalls.Unclock(); +} + +void FDrawInfo::DrawIndexed(EDrawType dt, FRenderState &state, int index, int count, bool apply) +{ + assert(&state == &gl_RenderState); + if (apply) + { + gl_RenderState.ApplyMaterial(); + gl_RenderState.Apply(); + } + drawcalls.Clock(); + glDrawElements(dt2gl[dt], count, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + index); + drawcalls.Unclock(); +} + diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index 227e851ef..204c9a4dc 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -52,6 +52,9 @@ struct FDrawInfo : public HWDrawInfo std::pair AllocVertices(unsigned int count) override; int UploadLights(FDynLightData &data) override; + void Draw(EDrawType dt, FRenderState &state, int index, int count, bool apply = true); + void DrawIndexed(EDrawType dt, FRenderState &state, int index, int count, bool apply = true); + void DrawDecal(GLDecal *gldecal); void DrawDecals(); void DrawDecalsForMirror(GLWall *wall); diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 0822ce4d1..36775c2dd 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -69,9 +69,7 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool istrans) gl_RenderState.ApplyLightIndex(flat->dynlightindex); if (vcount > 0 && !ClipLineShouldBeActive()) { - drawcalls.Clock(); - glDrawElements(GL_TRIANGLES, vcount, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + iboindex); - drawcalls.Unclock(); + DrawIndexed(DT_Triangles, gl_RenderState, iboindex, vcount); flatvertices += vcount; flatprimitives++; } @@ -85,8 +83,7 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool istrans) if (ss_renderflags[sub->Index()] & flat->renderflags || istrans) { - drawcalls.Clock(); - glDrawElements(GL_TRIANGLES, (sub->numlines - 2) * 3, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + index); + DrawIndexed(DT_Triangles, gl_RenderState, index, (sub->numlines - 2) * 3, false); drawcalls.Unclock(); flatvertices += sub->numlines; flatprimitives++; @@ -108,7 +105,7 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool istrans) auto num = node->sub->numlines; flatvertices += num; flatprimitives++; - glDrawArrays(GL_TRIANGLE_FAN, node->vertexindex, num); + Draw(DT_TriangleFan, gl_RenderState, node->vertexindex, num); node = node->next; } // Flood gaps with the back side's ceiling/floor texture @@ -130,7 +127,7 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool istrans) glPolygonOffset(1.0f, 128.0f); SetupFloodStencil(fnode->vertexindex); - glDrawArrays(GL_TRIANGLE_FAN, fnode->vertexindex + 4, 4); + Draw(DT_TriangleFan, gl_RenderState, fnode->vertexindex + 4, 4); ClearFloodStencil(fnode->vertexindex); glPolygonOffset(0.0f, 0.0f); @@ -156,21 +153,12 @@ void FDrawInfo::SetupFloodStencil(int vindex) gl_RenderState.EnableTexture(false); gl_RenderState.Apply(); - glStencilFunc(GL_EQUAL, recursion, ~0); // create stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels - - glColorMask(0, 0, 0, 0); // don't write to the graphics buffer - glEnable(GL_DEPTH_TEST); - glDepthMask(true); + gl_RenderState.SetStencil(0, SOP_Increment, SF_ColorMaskOff); - glDrawArrays(GL_TRIANGLE_FAN, vindex, 4); + Draw(DT_TriangleFan, gl_RenderState, vindex, 4); - glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil + gl_RenderState.SetStencil(1, SOP_Keep, SF_DepthMaskOff | SF_DepthTestOff); - glColorMask(1, 1, 1, 1); // don't write to the graphics buffer - glDisable(GL_DEPTH_TEST); - glDepthMask(false); gl_RenderState.EnableTexture(true); gl_RenderState.SetEffect(EFF_NONE); gl_RenderState.Apply(); @@ -183,18 +171,13 @@ void FDrawInfo::ClearFloodStencil(int vindex) gl_RenderState.SetEffect(EFF_STENCIL); gl_RenderState.EnableTexture(false); gl_RenderState.Apply(); - glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); - // Use revertible color mask, to avoid stomping on anaglyph 3D state - glColorMask(0, 0, 0, 0); // don't write to the graphics buffer - glDrawArrays(GL_TRIANGLE_FAN, vindex, 4); + gl_RenderState.SetStencil(1, SOP_Decrement, SF_ColorMaskOff | SF_DepthMaskOff | SF_DepthTestOff); + + Draw(DT_TriangleFan, gl_RenderState, vindex, 4); // restore old stencil op. - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_EQUAL, recursion, ~0); - glColorMask(1, 1, 1, 1); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); + gl_RenderState.SetStencil(0, SOP_Keep, SF_AllOn); gl_RenderState.EnableTexture(true); gl_RenderState.SetEffect(EFF_NONE); } diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 37999e80c..471bb5bbe 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -7,6 +7,14 @@ #include "hw_viewpointuniforms.h" #include "v_video.h" +enum EDrawType +{ + DT_Points = 0, + DT_Lines = 1, + DT_Triangles = 2, + DT_TriangleFan = 3, + DT_TriangleStrip = 4 +}; struct FSectorPortalGroup; struct FLinePortalSpan; @@ -24,6 +32,7 @@ class IPortal; class FFlatVertexGenerator; class IRenderQueue; class HWScenePortalBase; +class FRenderState; //========================================================================== // @@ -295,5 +304,9 @@ public: virtual GLDecal *AddDecal(bool onmirror) = 0; virtual std::pair AllocVertices(unsigned int count) = 0; + + virtual void Draw(EDrawType dt, FRenderState &state, int index, int count, bool apply = true) = 0; + virtual void DrawIndexed(EDrawType dt, FRenderState &state, int index, int count, bool apply = true) = 0; + }; diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index e095ab2f7..fa65d0fdc 100644 --- a/src/hwrenderer/scene/hw_renderstate.h +++ b/src/hwrenderer/scene/hw_renderstate.h @@ -4,6 +4,7 @@ #include "vectors.h" #include "g_levellocals.h" #include "r_data/matrix.h" +#include "hwrenderer/textures/hw_material.h" struct FColormap; @@ -18,12 +19,27 @@ enum EEffect MAX_EFFECTS }; -enum +enum EAlphaFunc { Alpha_GEqual = 0, Alpha_Greater = 1 }; +enum EStencilOp +{ + SOP_Keep = 0, + SOP_Increment = 1, + SOP_Decrement = 2 +}; + +enum EStencilFlags +{ + SF_AllOn = 0, + SF_ColorMaskOff = 1, + SF_DepthMaskOff = 2, + SF_DepthTestOff = 4 +}; + struct FStateVec4 { float vec[4]; @@ -37,6 +53,40 @@ struct FStateVec4 } }; +struct FMaterialState +{ + FMaterial *mMaterial; + int mClampMode; + int mTranslation; + int mOverrideShader; + bool mChanged; + + void Reset() + { + mMaterial = nullptr; + mTranslation = 0; + mClampMode = CLAMP_NONE; + mOverrideShader = -1; + mChanged = false; + } +}; + +struct FStencilState +{ + int mOffsVal; + int mOperation; + int mFlags; + bool mChanged; + + void Reset() + { + mOffsVal = 0; + mOperation = SOP_Keep; + mFlags = SF_AllOn; + mChanged = false; + } +}; + class FRenderState { protected: @@ -66,6 +116,8 @@ protected: PalEntry mObjectColor2; FStateVec4 mDynColor; + FMaterialState mMaterial; + FStencilState mStencil; // fixed function state float mBias[2]; @@ -95,6 +147,7 @@ public: mSpecialEffect = EFF_NONE; mLightIndex = -1; mBiasOn = false; + mMaterial.Reset(); mColor.Set(1.0f, 1.0f, 1.0f, 1.0f); mGlowTop.Set(0.0f, 0.0f, 0.0f, 0.0f); @@ -283,6 +336,23 @@ public: mBiasOn = false; } + void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader) + { + mMaterial.mMaterial = mat; + mMaterial.mClampMode = clampmode; + mMaterial.mTranslation = translation; + mMaterial.mOverrideShader = overrideshader; + mMaterial.mChanged = true; + } + + void SetStencil(int offs, int op, int flags) + { + mStencil.mOffsVal = offs; + mStencil.mOperation = op; + mStencil.mFlags = flags; + mStencil.mChanged = true; + } + void SetColor(int sectorlightlevel, int rellight, bool fullbright, const FColormap &cm, float alpha, bool weapon = false); void SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *cmap, bool isadditive);