From 0acfd9661bfcfc646bdc0adab6d1498350ad9899 Mon Sep 17 00:00:00 2001 From: "Dileep V. Reddy" Date: Thu, 13 Feb 2025 21:54:36 -0700 Subject: [PATCH] Making 3D-floors respond to r_dithertransparency properly. --- src/gamedata/r_defs.h | 5 ++++ src/rendering/hwrenderer/scene/hw_bsp.cpp | 5 ++-- .../hwrenderer/scene/hw_drawinfo.cpp | 30 +++++++++++++++++-- src/rendering/hwrenderer/scene/hw_walls.cpp | 22 ++++++++++++-- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index a6f4c2c4f3..663f3aa388 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -1196,6 +1196,9 @@ enum WALLF_ABSLIGHTING_BOTTOM = WALLF_ABSLIGHTING_TIER << 2, // Bottom tier light is absolute instead of relative WALLF_DITHERTRANS = 8192, // Render with dithering transparency shader (gets reset every frame) + WALLF_DITHERTRANS_TOP = WALLF_DITHERTRANS << 0, // Top tier (gets reset every frame) + WALLF_DITHERTRANS_MID = WALLF_DITHERTRANS << 1, // Mid tier (gets reset every frame) + WALLF_DITHERTRANS_BOTTOM = WALLF_DITHERTRANS << 2, // Bottom tier (gets reset every frame) }; struct side_t @@ -1271,6 +1274,8 @@ struct side_t int numsegs; int sidenum; + int dithertranscount; + int GetLightLevel (bool foggy, int baselight, int which, bool is3dlight=false, int *pfakecontrast_usedbygzdoom=NULL) const; void SetLight(int16_t l) diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index ced71a6fa2..5e64c8fdd0 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -297,6 +297,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) if (in_area == area_default) in_area = hw_CheckViewArea(seg->v1, seg->v2, seg->frontsector, seg->backsector); backsector = hw_FakeFlat(seg->backsector, in_area, true); if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR); + backsector = nullptr; } } @@ -335,7 +336,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) if (!seg->backsector) { if(!Viewpoint.IsAllowedOoB()) - if (!(seg->sidedef->Flags & WALLF_DITHERTRANS)) clipper.SafeAddClipRange(startAngle, endAngle); + if (!(seg->sidedef->Flags & WALLF_DITHERTRANS_MID)) clipper.SafeAddClipRange(startAngle, endAngle); } else if (!ispoly) // Two-sided polyobjects never obstruct the view { @@ -362,7 +363,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) if (hw_CheckClip(seg->sidedef, currentsector, backsector)) { - if(!Viewpoint.IsAllowedOoB() && !(seg->sidedef->Flags & WALLF_DITHERTRANS)) + if(!Viewpoint.IsAllowedOoB() && !(seg->sidedef->Flags & WALLF_DITHERTRANS_MID)) clipper.SafeAddClipRange(startAngle, endAngle); } } diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 10ee57b882..0fc7bc8961 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -691,14 +691,28 @@ static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* switch(res.HitType) { case TRACE_HitWall: - if (!(res.Line->sidedef[res.Side]->Flags & WALLF_DITHERTRANS)) { sector_t* linesec = res.Line->sidedef[res.Side]->sector; if (linesec->subsectorcount > 0 && (*CurMapSections)[linesec->subsectors[0]->mapsection]) { bf = res.Line->sidedef[res.Side]->sector->floorplane.ZatPoint(res.HitPos.XY()); bc = res.Line->sidedef[res.Side]->sector->ceilingplane.ZatPoint(res.HitPos.XY()); - if ((res.HitPos.Z <= bc) && (res.HitPos.Z >= bf)) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS; + if (res.Line->sidedef[!res.Side]) + { + // Two sided line! So let's find out if mid, top, or bottom texture needs dithered transparency + bf = max(bf, res.Line->sidedef[!res.Side]->sector->floorplane.ZatPoint(res.HitPos.XY())); + bc = min(bc, res.Line->sidedef[!res.Side]->sector->ceilingplane.ZatPoint(res.HitPos.XY())); + if (res.HitPos.Z <= bf) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS_BOTTOM; + else if (res.HitPos.Z < bc) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS_MID; + else res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS_TOP; + + res.Line->sidedef[res.Side]->dithertranscount = max(1, res.Line->sidedef[!res.Side]->sector->e->XFloor.ffloors.Size()); + } + else if ((res.HitPos.Z <= bc) && (res.HitPos.Z >= bf)) + { + res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS_MID; + res.Line->sidedef[res.Side]->dithertranscount = 1; + } } } break; @@ -793,6 +807,18 @@ void HWDrawInfo::SetDitherTransFlags(AActor* actor) campos.Z -= actor->Height * 0.5; campos.X += horix; campos.Y -= horiy; } + + // Tracers don't work on 3D floors when you are starting in the same sector (standing under them, for example) + if (actor->Sector->e->XFloor.ffloors.Size()) // 3D floor + { + F3DFloor *rover; + for (int kk = 0; kk < (int)actor->Sector->e->XFloor.ffloors.Size(); kk++) + { + rover = actor->Sector->e->XFloor.ffloors[kk]; + rover->top.plane->dithertransflag = true; + rover->bottom.plane->dithertransflag = true; + } + } } } diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index 97b0c91a6a..47e651bd47 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -83,15 +83,31 @@ void SetSplitPlanes(FRenderState& state, const secplane_t& top, const secplane_t void HWWall::RenderWall(FRenderState &state, int textured) { - if (seg->sidedef->Flags & WALLF_DITHERTRANS) state.SetEffect(EFF_DITHERTRANS); + bool ditherT = (type == RENDERWALL_BOTTOM) && (seg->sidedef->Flags & WALLF_DITHERTRANS_BOTTOM); + ditherT |= (type == RENDERWALL_TOP) && (seg->sidedef->Flags & WALLF_DITHERTRANS_TOP); + ditherT |= seg->sidedef->Flags & WALLF_DITHERTRANS_MID; + if (ditherT) + { + state.SetEffect(EFF_DITHERTRANS); + } assert(vertcount > 0); state.SetLightIndex(dynlightindex); state.Draw(DT_TriangleFan, vertindex, vertcount); vertexcount += vertcount; - if (seg->sidedef->Flags & WALLF_DITHERTRANS) + if (ditherT) { state.SetEffect(EFF_NONE); - seg->sidedef->Flags &= ~WALLF_DITHERTRANS; // reset this every frame + switch(type) // reset this every frame + { + case RENDERWALL_TOP: + seg->sidedef->Flags &= ~WALLF_DITHERTRANS_TOP; + break; + case RENDERWALL_BOTTOM: + seg->sidedef->Flags &= ~WALLF_DITHERTRANS_BOTTOM; + break; + default: + if (seg->sidedef->dithertranscount-- <= 0) seg->sidedef->Flags &= ~WALLF_DITHERTRANS_MID; + } } }