diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index feafbc5861..5143b76c5b 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -52,23 +52,24 @@ static void matrixToGL(const VSMatrix &mat, int loc) //========================================================================== // -// +// This only gets called once upon setup. +// With OpenGL the state is persistent and cannot be cleared, once set up. // //========================================================================== void FGLRenderState::Reset() { FRenderState::Reset(); - mSplitEnabled = false; mSrcBlend = GL_SRC_ALPHA; mDstBlend = GL_ONE_MINUS_SRC_ALPHA; mBlendEquation = GL_FUNC_ADD; - mVertexBuffer = mCurrentVertexBuffer = NULL; + mVertexBuffer = mCurrentVertexBuffer = nullptr; mGlossiness = 0.0f; mSpecularLevel = 0.0f; mShaderTimer = 0.0f; ClearClipSplit(); + stRenderStyle = DefaultRenderStyle(); stSrcBlend = stDstBlend = -1; stBlendEquation = -1; stAlphaTest = 0; @@ -216,6 +217,21 @@ void FGLRenderState::Apply() stRenderStyle = mRenderStyle; } + if (mSplitEnabled != stSplitEnabled) + { + if (mSplitEnabled) + { + glEnable(GL_CLIP_DISTANCE3); + glEnable(GL_CLIP_DISTANCE4); + } + else + { + glDisable(GL_CLIP_DISTANCE3); + glDisable(GL_CLIP_DISTANCE4); + } + stSplitEnabled = mSplitEnabled; + } + if (mMaterial.mChanged) { ApplyMaterial(mMaterial.mMaterial, mMaterial.mClampMode, mMaterial.mTranslation, mMaterial.mOverrideShader); diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 51bf8224c8..00353e6607 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -49,7 +49,6 @@ enum EPassType class FGLRenderState : public FRenderState { - uint8_t mSplitEnabled : 1; uint8_t mLastDepthClamp : 1; int mSrcBlend, mDstBlend; @@ -68,6 +67,7 @@ class FGLRenderState : public FRenderState FRenderStyle stRenderStyle; int stSrcBlend, stDstBlend; bool stAlphaTest; + bool stSplitEnabled; int stBlendEquation; FShader *activeShader; @@ -115,25 +115,6 @@ public: mCurrentVertexBuffer = NULL; } - - 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 SetSpecular(float glossiness, float specularLevel) { mGlossiness = glossiness; diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index ba2fb67c5d..fc6b179fcc 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -57,16 +57,7 @@ struct FDrawInfo : public HWDrawInfo 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, FRenderState &state); - void DrawDecals(FRenderState &state); - void DrawDecalsForMirror(GLWall *wall, FRenderState &state); - void StartScene(); - void SetupFloodStencil(int vindex); - void ClearFloodStencil(int vindex); - void DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling); - void FloodUpperGap(seg_t * seg); - void FloodLowerGap(seg_t * seg); // Wall drawer void RenderWall(GLWall *wall, int textured); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 83f3ebb2fc..1fe72e37ed 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -203,14 +203,9 @@ void FDrawInfo::RenderScene(int recursion) // Part 4: Draw decals (not a real pass) glDepthFunc(GL_LEQUAL); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -128.0f); glDepthMask(false); - DrawDecals(gl_RenderState); + DrawDecals(gl_RenderState, decals[0]); - gl_RenderState.SetTextureMode(TM_NORMAL); - glPolygonOffset(0.0f, 0.0f); - glDisable(GL_POLYGON_OFFSET_FILL); glDepthMask(true); RenderAll.Unclock(); } diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index 209bef6104..d590935c9f 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -122,14 +122,9 @@ void FDrawInfo::RenderMirrorSurface(GLWall *wall) // because the depth buffer won't get set by translucent items. if (wall->seg->sidedef->AttachedDecals) { - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -128.0f); glDepthMask(false); - DrawDecalsForMirror(wall, gl_RenderState); + wall->DrawDecalsForMirror(this, gl_RenderState, decals[1]); glDepthMask(true); - glPolygonOffset(0.0f, 0.0f); - glDisable(GL_POLYGON_OFFSET_FILL); - gl_RenderState.SetTextureMode(TM_NORMAL); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } } @@ -440,138 +435,3 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype) wall->vertcount = 0; } -//========================================================================== -// -// -// -//========================================================================== -void FDrawInfo::DrawDecal(GLDecal *gldecal, FRenderState &state) -{ - auto decal = gldecal->decal; - auto tex = gldecal->gltexture; - - // calculate dynamic light effect. - if (level.HasDynamicLights && !isFullbrightScene() && gl_light_sprites) - { - // Note: This should be replaced with proper shader based lighting. - double x, y; - float out[3]; - decal->GetXY(decal->Side, x, y); - GetDynSpriteLight(nullptr, x, y, gldecal->zcenter, decal->Side->lighthead, decal->Side->sector->PortalGroup, out); - gl_RenderState.SetDynLight(out[0], out[1], out[2]); - } - - // alpha color only has an effect when using an alpha texture. - if (decal->RenderStyle.Flags & (STYLEF_RedIsAlpha | STYLEF_ColorIsFixed)) - { - gl_RenderState.SetObjectColor(decal->AlphaColor | 0xff000000); - } - - gl_RenderState.SetTextureMode(decal->RenderStyle); - gl_RenderState.SetRenderStyle(decal->RenderStyle); - gl_RenderState.SetMaterial(tex, CLAMP_XY, decal->Translation, -1); - - - // If srcalpha is one it looks better with a higher alpha threshold - if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) gl_RenderState.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); - else gl_RenderState.AlphaFunc(Alpha_Greater, 0.f); - - - SetColor(gldecal->lightlevel, gldecal->rellight, gldecal->Colormap, gldecal->alpha); - // for additively drawn decals we must temporarily set the fog color to black. - PalEntry fc = gl_RenderState.GetFogColor(); - if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One) - { - gl_RenderState.SetFog(0, -1); - } - - gl_RenderState.SetNormal(gldecal->Normal); - - if (gldecal->lightlist == nullptr) - { - Draw(DT_TriangleFan, gl_RenderState, gldecal->vertindex, 4); - } - else - { - auto &lightlist = *gldecal->lightlist; - - for (unsigned k = 0; k < lightlist.Size(); k++) - { - secplane_t &lowplane = k == lightlist.Size() - 1 ? gldecal->bottomplane : lightlist[k + 1].plane; - - DecalVertex *dv = gldecal->dv; - float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y); - float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y); - - if (low1 < dv[1].z || low2 < dv[2].z) - { - int thisll = lightlist[k].caster != nullptr ? hw_ClampLight(*lightlist[k].p_lightlevel) : gldecal->lightlevel; - FColormap thiscm; - thiscm.FadeColor = gldecal->Colormap.FadeColor; - thiscm.CopyFrom3DLight(&lightlist[k]); - SetColor(thisll, gldecal->rellight, thiscm, gldecal->alpha); - if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) thiscm.Decolorize(); - SetFog(thisll, gldecal->rellight, &thiscm, false); - gl_RenderState.SetSplitPlanes(lightlist[k].plane, lowplane); - - Draw(DT_TriangleFan, gl_RenderState, gldecal->vertindex, 4); - } - if (low1 <= dv[0].z && low2 <= dv[3].z) break; - } - } - - rendered_decals++; - gl_RenderState.SetTextureMode(TM_NORMAL); - gl_RenderState.SetObjectColor(0xffffffff); - gl_RenderState.SetFog(fc, -1); - gl_RenderState.SetDynLight(0, 0, 0); -} - -//========================================================================== -// -// -// -//========================================================================== -void FDrawInfo::DrawDecals(FRenderState &state) -{ - side_t *wall = nullptr; - bool splitting = false; - for (auto gldecal : decals[0]) - { - if (gldecal->decal->Side != wall) - { - wall = gldecal->decal->Side; - if (gldecal->lightlist != nullptr) - { - gl_RenderState.EnableSplit(true); - splitting = true; - } - else - { - gl_RenderState.EnableSplit(false); - splitting = false; - SetFog(gldecal->lightlevel, gldecal->rellight, &gldecal->Colormap, false); - } - } - DrawDecal(gldecal, state); - } - if (splitting) gl_RenderState.EnableSplit(false); -} - -//========================================================================== -// -// This list will never get long, so this code should be ok. -// -//========================================================================== -void FDrawInfo::DrawDecalsForMirror(GLWall *wall, FRenderState &state) -{ - SetFog(wall->lightlevel, wall->rellight + getExtraLight(), &wall->Colormap, false); - for (auto gldecal : decals[1]) - { - if (gldecal->decal->Side == wall->seg->sidedef) - { - DrawDecal(gldecal, state); - } - } -} - diff --git a/src/hwrenderer/scene/hw_decal.cpp b/src/hwrenderer/scene/hw_decal.cpp index f9c59a79fa..fcfc707736 100644 --- a/src/hwrenderer/scene/hw_decal.cpp +++ b/src/hwrenderer/scene/hw_decal.cpp @@ -34,7 +34,153 @@ #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/utility/hw_lighting.h" +#include "hwrenderer/utility/hw_clock.h" #include "hwrenderer/data/flatvertices.h" +#include "hw_renderstate.h" + +//========================================================================== +// +// +// +//========================================================================== + +void GLDecal::DrawDecal(HWDrawInfo *di, FRenderState &state) +{ + auto tex = gltexture; + + // calculate dynamic light effect. + if (level.HasDynamicLights && !di->isFullbrightScene() && gl_light_sprites) + { + // Note: This should be replaced with proper shader based lighting. + double x, y; + float out[3]; + decal->GetXY(decal->Side, x, y); + di->GetDynSpriteLight(nullptr, x, y, zcenter, decal->Side->lighthead, decal->Side->sector->PortalGroup, out); + state.SetDynLight(out[0], out[1], out[2]); + } + + // alpha color only has an effect when using an alpha texture. + if (decal->RenderStyle.Flags & (STYLEF_RedIsAlpha | STYLEF_ColorIsFixed)) + { + state.SetObjectColor(decal->AlphaColor | 0xff000000); + } + + state.SetTextureMode(decal->RenderStyle); + state.SetRenderStyle(decal->RenderStyle); + state.SetMaterial(tex, CLAMP_XY, decal->Translation, -1); + + + // If srcalpha is one it looks better with a higher alpha threshold + if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); + else state.AlphaFunc(Alpha_Greater, 0.f); + + + state.SetColor(lightlevel, rellight, di->isFullbrightScene(), Colormap, alpha); + // for additively drawn decals we must temporarily set the fog color to black. + PalEntry fc = state.GetFogColor(); + if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One) + { + state.SetFog(0, -1); + } + + state.SetNormal(Normal); + + if (lightlist == nullptr) + { + di->Draw(DT_TriangleFan, state, vertindex, 4); + } + else + { + auto &lightlist = *this->lightlist; + + for (unsigned k = 0; k < lightlist.Size(); k++) + { + secplane_t &lowplane = k == lightlist.Size() - 1 ? bottomplane : lightlist[k + 1].plane; + + float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y); + float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y); + + if (low1 < dv[1].z || low2 < dv[2].z) + { + int thisll = lightlist[k].caster != nullptr ? hw_ClampLight(*lightlist[k].p_lightlevel) : lightlevel; + FColormap thiscm; + thiscm.FadeColor = Colormap.FadeColor; + thiscm.CopyFrom3DLight(&lightlist[k]); + state.SetColor(thisll, rellight, di->isFullbrightScene(), thiscm, alpha); + if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) thiscm.Decolorize(); + state.SetFog(thisll, rellight, di->isFullbrightScene(), &thiscm, false); + state.SetSplitPlanes(lightlist[k].plane, lowplane); + + di->Draw(DT_TriangleFan, state, vertindex, 4); + } + if (low1 <= dv[0].z && low2 <= dv[3].z) break; + } + } + + rendered_decals++; + state.SetTextureMode(TM_NORMAL); + state.SetObjectColor(0xffffffff); + state.SetFog(fc, -1); + state.SetDynLight(0, 0, 0); +} + +//========================================================================== +// +// +// +//========================================================================== +void HWDrawInfo::DrawDecals(FRenderState &state, TArray &decals) +{ + side_t *wall = nullptr; + state.SetDepthBias(-1, -128); + for (auto gldecal : decals) + { + if (gldecal->decal->Side != wall) + { + wall = gldecal->decal->Side; + if (gldecal->lightlist != nullptr) + { + state.EnableSplit(true); + } + else + { + state.EnableSplit(false); + state.SetFog(gldecal->lightlevel, gldecal->rellight, isFullbrightScene(), &gldecal->Colormap, false); + } + } + gldecal->DrawDecal(this, state); + } + state.EnableSplit(false); + state.ClearDepthBias(); + state.SetTextureMode(TM_NORMAL); +} + +//========================================================================== +// +// This list will never get long, so this code should be ok. +// +//========================================================================== + +void GLWall::DrawDecalsForMirror(HWDrawInfo *di, FRenderState &state, TArray &decals) +{ + state.SetDepthBias(-1, -128); + state.SetFog(lightlevel, rellight + getExtraLight(), di->isFullbrightScene(), &Colormap, false); + for (auto gldecal : decals) + { + if (gldecal->decal->Side == seg->sidedef) + { + gldecal->DrawDecal(di, state); + } + } + state.ClearDepthBias(); + state.SetTextureMode(TM_NORMAL); +} + +//========================================================================== +// +// +// +//========================================================================== void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &normal) { @@ -271,6 +417,7 @@ void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor // // //========================================================================== + void GLWall::ProcessDecals(HWDrawInfo *di) { if (seg->sidedef != nullptr) diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index ec2c618af5..53a6d79462 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -284,6 +284,8 @@ public: void SetupView(float vx, float vy, float vz, bool mirror, bool planemirror); angle_t FrustumAngle(); + void DrawDecals(FRenderState &state, TArray &decals); + virtual void DrawWall(GLWall *wall, int pass) = 0; virtual void DrawSprite(GLSprite *sprite, int pass) = 0; diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index 94310ac692..4e99c75158 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -26,6 +26,7 @@ class VSMatrix; struct FSpriteModelFrame; struct particle_t; class FRenderState; +struct GLDecal; enum area_t : int; enum HWRenderStyle @@ -284,6 +285,8 @@ public: return -((y-glseg.y1)*(glseg.x2-glseg.x1)-(x-glseg.x1)*(glseg.y2-glseg.y1)); } + void DrawDecalsForMirror(HWDrawInfo *di, FRenderState &state, TArray &decals); + }; //========================================================================== @@ -436,6 +439,8 @@ struct GLDecal secplane_t bottomplane; FVector3 Normal; + void DrawDecal(HWDrawInfo *di, FRenderState &state); + }; diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index 3cc8f22a08..473f60ae06 100644 --- a/src/hwrenderer/scene/hw_renderstate.h +++ b/src/hwrenderer/scene/hw_renderstate.h @@ -111,6 +111,7 @@ protected: uint8_t mBrightmapEnabled : 1; uint8_t mModelMatrixEnabled : 1; uint8_t mTextureMatrixEnabled : 1; + uint8_t mSplitEnabled : 1; int mLightIndex; int mSpecialEffect; @@ -154,6 +155,7 @@ public: mAlphaThreshold = 0.5f; mModelMatrixEnabled = false; mTextureMatrixEnabled = false; + mSplitEnabled = false; mObjectColor = 0xffffffff; mObjectColor2 = 0; mSoftLight = 0; @@ -264,6 +266,11 @@ public: mBrightmapEnabled = on; } + void EnableSplit(bool on) + { + mSplitEnabled = on; + } + void EnableModelMatrix(bool on) { mModelMatrixEnabled = on;