From 1d929dd79b2ff4594a318dad07d427fdae527313 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 6 May 2018 02:54:03 +0200 Subject: [PATCH] - fix translucent walls when r_models is enabled --- src/swrenderer/line/r_line.cpp | 1 + src/swrenderer/scene/r_opaque_pass.cpp | 10 +++ src/swrenderer/scene/r_opaque_pass.h | 4 ++ src/swrenderer/scene/r_translucent_pass.cpp | 2 +- src/swrenderer/segments/r_drawsegment.h | 2 + src/swrenderer/things/r_visiblesprite.cpp | 71 ++++++++++++++----- src/swrenderer/things/r_visiblesprite.h | 3 +- src/swrenderer/things/r_visiblespritelist.cpp | 58 +++++++++++++-- src/swrenderer/things/r_visiblespritelist.h | 5 +- 9 files changed, 130 insertions(+), 26 deletions(-) diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp index 81e0280e2..4b6755cee 100644 --- a/src/swrenderer/line/r_line.cpp +++ b/src/swrenderer/line/r_line.cpp @@ -346,6 +346,7 @@ namespace swrenderer draw_segment->x2 = stop; draw_segment->curline = mLineSegment; draw_segment->foggy = foggy; + draw_segment->SubsectorDepth = Thread->OpaquePass->GetSubsectorDepth(mSubsector->Index()); bool markportal = ShouldMarkPortal(); diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index 4b66e8974..667a17f7e 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -497,6 +497,11 @@ namespace swrenderer { outersubsector = true; InSubsector = sub; + + // Mark the visual sorting depth of this subsector + uint32_t subsectorDepth = (uint32_t)PvsSubsectors.size(); + SubsectorDepths[sub->Index()] = subsectorDepth; + PvsSubsectors.push_back(sub->Index()); } #ifdef RANGECHECK @@ -837,6 +842,11 @@ namespace swrenderer if (Thread->MainThread) WallCycles.Clock(); + for (uint32_t sub : PvsSubsectors) + SubsectorDepths[sub] = 0xffffffff; + SubsectorDepths.resize(level.subsectors.Size(), 0xffffffff); + + PvsSubsectors.clear(); SeenSpriteSectors.clear(); SeenActors.clear(); diff --git a/src/swrenderer/scene/r_opaque_pass.h b/src/swrenderer/scene/r_opaque_pass.h index e17a6109a..a0a1d494a 100644 --- a/src/swrenderer/scene/r_opaque_pass.h +++ b/src/swrenderer/scene/r_opaque_pass.h @@ -71,6 +71,8 @@ namespace swrenderer void ClearSeenSprites() { SeenSpriteSectors.clear(); SeenActors.clear(); } + uint32_t GetSubsectorDepth(int index) const { return SubsectorDepths[index]; } + short floorclip[MAXWIDTH]; short ceilingclip[MAXWIDTH]; @@ -97,5 +99,7 @@ namespace swrenderer SWRenderLine renderline; std::set SeenSpriteSectors; std::set SeenActors; + std::vector PvsSubsectors; + std::vector SubsectorDepths; }; } diff --git a/src/swrenderer/scene/r_translucent_pass.cpp b/src/swrenderer/scene/r_translucent_pass.cpp index 244bb4392..ba077b9d4 100644 --- a/src/swrenderer/scene/r_translucent_pass.cpp +++ b/src/swrenderer/scene/r_translucent_pass.cpp @@ -178,7 +178,7 @@ namespace swrenderer MaskedCycles.Clock(); CollectPortals(); - Thread->SpriteList->Sort(); + Thread->SpriteList->Sort(Thread); Thread->DrawSegments->BuildSegmentGroups(); Clip3DFloors *clip3d = Thread->Clip3D.get(); diff --git a/src/swrenderer/segments/r_drawsegment.h b/src/swrenderer/segments/r_drawsegment.h index 4e2943ab0..a43e4dc28 100644 --- a/src/swrenderer/segments/r_drawsegment.h +++ b/src/swrenderer/segments/r_drawsegment.h @@ -53,6 +53,8 @@ namespace swrenderer int CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping. + int SubsectorDepth; + bool Has3DFloorWalls() const { return b3DFloorBoundary != 0; } bool Has3DFloorFrontSectorWalls() const { return (b3DFloorBoundary & 2) == 2; } bool Has3DFloorBackSectorWalls() const { return (b3DFloorBoundary & 1) == 1; } diff --git a/src/swrenderer/things/r_visiblesprite.cpp b/src/swrenderer/things/r_visiblesprite.cpp index 3bbd25a23..e4e7f80e2 100644 --- a/src/swrenderer/things/r_visiblesprite.cpp +++ b/src/swrenderer/things/r_visiblesprite.cpp @@ -53,6 +53,22 @@ namespace swrenderer { if (IsModel()) { + // Draw segments behind model + DrawSegmentList *segmentlist = thread->DrawSegments.get(); + RenderPortal *renderportal = thread->Portal.get(); + for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) + { + DrawSegment *ds = segmentlist->TranslucentSegment(index); + if (ds->SubsectorDepth >= SubsectorDepth && ds->CurrentPortalUniq == renderportal->CurrentPortalUniq) + { + int r1 = MAX(ds->x1, 0); + int r2 = MIN(ds->x2, viewwidth - 1); + + RenderDrawSegment renderer(thread); + renderer.Render(ds, r1, r2, clip3DFloor); + } + } + Render(thread, nullptr, nullptr, 0, 0, clip3DFloor); return; } @@ -299,33 +315,52 @@ namespace swrenderer RenderPortal *renderportal = thread->Portal.get(); // Render draw segments behind sprite - for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) + if (r_models) { - DrawSegment *ds = segmentlist->TranslucentSegment(index); - - if (ds->x1 >= x2 || ds->x2 <= x1) + int subsectordepth = spr->SubsectorDepth; + for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) { - continue; - } - - float neardepth = MIN(ds->sz1, ds->sz2); - float fardepth = MAX(ds->sz1, ds->sz2); - - // Check if sprite is in front of draw seg: - if ((!spr->IsWallSprite() && neardepth > spr->depth) || ((spr->IsWallSprite() || fardepth > spr->depth) && - (spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) - - (spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0)) - { - if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq) + DrawSegment *ds = segmentlist->TranslucentSegment(index); + if (ds->SubsectorDepth >= subsectordepth && ds->CurrentPortalUniq == renderportal->CurrentPortalUniq) { - int r1 = MAX(ds->x1, x1); - int r2 = MIN(ds->x2, x2); + int r1 = MAX(ds->x1, 0); + int r2 = MIN(ds->x2, viewwidth - 1); RenderDrawSegment renderer(thread); renderer.Render(ds, r1, r2, clip3DFloor); } } } + else + { + for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) + { + DrawSegment *ds = segmentlist->TranslucentSegment(index); + + if (ds->x1 >= x2 || ds->x2 <= x1) + { + continue; + } + + float neardepth = MIN(ds->sz1, ds->sz2); + float fardepth = MAX(ds->sz1, ds->sz2); + + // Check if sprite is in front of draw seg: + if ((!spr->IsWallSprite() && neardepth > spr->depth) || ((spr->IsWallSprite() || fardepth > spr->depth) && + (spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) - + (spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0)) + { + if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq) + { + int r1 = MAX(ds->x1, x1); + int r2 = MIN(ds->x2, x2); + + RenderDrawSegment renderer(thread); + renderer.Render(ds, r1, r2, clip3DFloor); + } + } + } + } for (unsigned int groupIndex = 0; groupIndex < segmentlist->SegmentGroups.Size(); groupIndex++) { diff --git a/src/swrenderer/things/r_visiblesprite.h b/src/swrenderer/things/r_visiblesprite.h index 782196486..b1ddebae7 100644 --- a/src/swrenderer/things/r_visiblesprite.h +++ b/src/swrenderer/things/r_visiblesprite.h @@ -43,10 +43,9 @@ namespace swrenderer bool IsCurrentPortalUniq(int portalUniq) const { return CurrentPortalUniq == portalUniq; } const FVector3 &WorldPos() const { return gpos; } - double SortDist2D() const { return DVector2(deltax, deltay).LengthSquared(); } float SortDist() const { return idepth; } - float DrawSegDepth() const { return depth; } + int SubsectorDepth; protected: virtual bool IsParticle() const { return false; } diff --git a/src/swrenderer/things/r_visiblespritelist.cpp b/src/swrenderer/things/r_visiblespritelist.cpp index ef91e6bed..0fee922b2 100644 --- a/src/swrenderer/things/r_visiblespritelist.cpp +++ b/src/swrenderer/things/r_visiblespritelist.cpp @@ -59,7 +59,7 @@ namespace swrenderer Sprites.Push(sprite); } - void VisibleSpriteList::Sort() + void VisibleSpriteList::Sort(RenderThread *thread) { unsigned int first = StartIndices.Size() == 0 ? 0 : StartIndices.Last(); unsigned int count = Sprites.Size() - first; @@ -83,9 +83,59 @@ namespace swrenderer SortedSprites[i] = Sprites[first + count - i - 1]; } - std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool + if (r_models) // To do: only do this if models are spotted - just in case there's some lame renderhack somewhere that relies on Carmacks algorithm { - return a->SortDist() > b->SortDist(); - }); + for (unsigned int i = 0; i < count; i++) + { + FVector2 worldPos = SortedSprites[i]->WorldPos().XY(); + SortedSprites[i]->SubsectorDepth = FindSubsectorDepth(thread, { worldPos.X, worldPos.Y }); + } + + std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool + { + if (a->SubsectorDepth != b->SubsectorDepth) + return a->SubsectorDepth < b->SubsectorDepth; + else + return a->SortDist() > b->SortDist(); + }); + } + else + { + std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool + { + return a->SortDist() > b->SortDist(); + }); + } + } + + uint32_t VisibleSpriteList::FindSubsectorDepth(RenderThread *thread, const DVector2 &worldPos) + { + if (level.nodes.Size() == 0) + { + subsector_t *sub = &level.subsectors[0]; + return thread->OpaquePass->GetSubsectorDepth(sub->Index()); + } + else + { + return FindSubsectorDepth(thread, worldPos, level.HeadNode()); + } + } + + uint32_t VisibleSpriteList::FindSubsectorDepth(RenderThread *thread, const DVector2 &worldPos, void *node) + { + while (!((size_t)node & 1)) // Keep going until found a subsector + { + node_t *bsp = (node_t *)node; + + DVector2 planePos(FIXED2DBL(bsp->x), FIXED2DBL(bsp->y)); + DVector2 planeNormal = DVector2(FIXED2DBL(-bsp->dy), FIXED2DBL(bsp->dx)); + double planeD = planeNormal | planePos; + + int side = (worldPos | planeNormal) > planeD; + node = bsp->children[side]; + } + + subsector_t *sub = (subsector_t *)((uint8_t *)node - 1); + return thread->OpaquePass->GetSubsectorDepth(sub->Index()); } } diff --git a/src/swrenderer/things/r_visiblespritelist.h b/src/swrenderer/things/r_visiblespritelist.h index 52ee1772c..da347edc3 100644 --- a/src/swrenderer/things/r_visiblespritelist.h +++ b/src/swrenderer/things/r_visiblespritelist.h @@ -12,11 +12,14 @@ namespace swrenderer void PushPortal(); void PopPortal(); void Push(VisibleSprite *sprite); - void Sort(); + void Sort(RenderThread *thread); TArray SortedSprites; private: + uint32_t FindSubsectorDepth(RenderThread *thread, const DVector2 &worldPos); + uint32_t FindSubsectorDepth(RenderThread *thread, const DVector2 &worldPos, void *node); + TArray Sprites; TArray StartIndices; };