From d4eb54d6866b806929a2785a635eae08f098d2fb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 20 May 2021 12:36:35 +0200 Subject: [PATCH] - render free standing wall sprites without depth bias. Otherwise they can end up badly ordered with walls. --- source/build/include/buildtypes.h | 3 + source/core/rendering/scene/hw_drawinfo.cpp | 5 +- source/core/rendering/scene/hw_drawstructs.h | 2 + source/core/rendering/scene/hw_walls.cpp | 77 ++++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) diff --git a/source/build/include/buildtypes.h b/source/build/include/buildtypes.h index 98b6bb7f4..3ccba2923 100644 --- a/source/build/include/buildtypes.h +++ b/source/build/include/buildtypes.h @@ -268,6 +268,9 @@ struct spritetype int16_t extra; int16_t detail; int time; + int16_t wall; + int8_t wdist; + #if 0 // make sure we do not accidentally copy this diff --git a/source/core/rendering/scene/hw_drawinfo.cpp b/source/core/rendering/scene/hw_drawinfo.cpp index b459cbfe5..e22857916 100644 --- a/source/core/rendering/scene/hw_drawinfo.cpp +++ b/source/core/rendering/scene/hw_drawinfo.cpp @@ -519,7 +519,6 @@ void HWDrawInfo::RenderScene(FRenderState &state) drawlists[GLDL_MASKEDWALLSV].SortWallsHorz(this); drawlists[GLDL_MASKEDWALLSH].SortWallsVert(this); - state.SetDepthBias(-1, -128); // these lists are only wall and floor sprites - often attached to walls and floors - so they need to be offset from the plane they may be attached to. drawlists[GLDL_MASKEDWALLSS].DrawWalls(this, state, false); @@ -539,6 +538,9 @@ void HWDrawInfo::RenderScene(FRenderState &state) drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false); state.SetColorMask(true); + /* + state.SetDepthBias(-1, -128); + state.SetDepthMask(false); drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false); state.SetDepthMask(true); @@ -546,6 +548,7 @@ void HWDrawInfo::RenderScene(FRenderState &state) drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false); state.SetColorMask(true); state.ClearDepthBias(); + */ drawlists[GLDL_MODELS].Draw(this, state, false); diff --git a/source/core/rendering/scene/hw_drawstructs.h b/source/core/rendering/scene/hw_drawstructs.h index 5a9eeafab..234ab5e13 100644 --- a/source/core/rendering/scene/hw_drawstructs.h +++ b/source/core/rendering/scene/hw_drawstructs.h @@ -133,6 +133,7 @@ public: { RWF_BLANK = 0, RWF_TEXTURED = 1, // actually not being used anymore because with buffers it's even less efficient not writing the texture coordinates - but leave it here + RWF_TRANS = 2, RWF_NORENDER = 8, }; @@ -158,6 +159,7 @@ public: float ViewDistance; float visibility; + int walldist; short shade, palette; PalEntry fade; diff --git a/source/core/rendering/scene/hw_walls.cpp b/source/core/rendering/scene/hw_walls.cpp index f99624b99..22d970555 100644 --- a/source/core/rendering/scene/hw_walls.cpp +++ b/source/core/rendering/scene/hw_walls.cpp @@ -39,6 +39,72 @@ #include "flatvertices.h" #include "glbackend/glbackend.h" + +//========================================================================== +// +// +// +//========================================================================== + +static int GetClosestPointOnWall(vec2_t const* const pos, walltype* wal, vec2_t* const n) +{ + auto w = wal->pos; + auto d = wall[wal->point2].pos - w; + int64_t i = d.x * ((int64_t)pos->x - w.x) + d.y * ((int64_t)pos->y - w.y); + + if (d.x == 0 && d.y == 0) + { + // In Blood's E1M1 this gets triggered for wall 522. + return 1; + } + + if (i < 0) + return 1; + + int64_t j = (int64_t)d.x * d.x + (int64_t)d.y * d.y; + + if (i > j) + return 1; + + i = ((i << 15) / j) << 15; + + n->x = w.x + ((d.x * i) >> 30); + n->y = w.y + ((d.y * i) >> 30); + + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +static int IsOnWall(spritetype* tspr, int height) +{ + int dist = 3, closest = -1; + auto sect = §or[tspr->sectnum]; + vec2_t n; + + int topz = (tspr->z - ((height * tspr->yrepeat) << 2)); + for (int i = sect->wallptr; i < sect->wallptr + sect->wallnum; i++) + { + auto wal = &wall[i]; + if ((wal->nextsector == -1 || ((sector[wal->nextsector].ceilingz > topz) || + sector[wal->nextsector].floorz < tspr->z)) && !GetClosestPointOnWall(&tspr->pos.vec2, wal, &n)) + { + int const dst = abs(tspr->x - n.x) + abs(tspr->y - n.y); + + if (dst <= dist) + { + dist = dst; + closest = i; + } + } + } + return closest == -1? -1 : dist; +} + //========================================================================== // // Create vertices for one wall @@ -169,9 +235,14 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) state.SetNpotEmulation(float(h2) / h, xOffset); } } + else if (walldist >= 0 && !(rflags && RWF_TRANS)) + { + state.SetDepthBias(-1, -128); + } RenderWall(di, state, rflags); + if (!(rflags && RWF_TRANS)) state.ClearDepthBias(); state.SetNpotEmulation(0.f, 0.f); state.SetObjectColor(0xffffffff); /* none of these functions is in use. @@ -1021,6 +1092,11 @@ void HWWall::ProcessWallSprite(HWDrawInfo* di, spritetype* spr, sectortype* sect auto tex = tileGetTexture(spr->picnum); if (!tex || !tex->isValid()) return; + if (spr->owner == 771) + { + int a = 0; + } + seg = nullptr; Sprite = spr; vec2_t pos[2]; @@ -1067,6 +1143,7 @@ void HWWall::ProcessWallSprite(HWDrawInfo* di, spritetype* spr, sectortype* sect height = (int)tex->GetDisplayHeight(); topofs = ((int)tex->GetDisplayTopOffset() + spr->yoffset); } + walldist = IsOnWall(spr, height); if (spr->cstat & CSTAT_SPRITE_YFLIP) topofs = -topofs;