From 642cd2b16091e7e7e71af80c87768dfe6293c9b2 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 14 Nov 2019 02:28:53 +0100 Subject: [PATCH] Fix 3d floor rendering bug --- src/rendering/swrenderer/line/r_line.cpp | 121 ++++++++---------- .../swrenderer/line/r_renderdrawsegment.cpp | 13 +- src/rendering/swrenderer/line/r_wallsetup.cpp | 1 - src/rendering/swrenderer/line/r_wallsetup.h | 3 - src/rendering/swrenderer/scene/r_portal.cpp | 1 - .../swrenderer/scene/r_translucent_pass.cpp | 4 +- .../swrenderer/segments/r_drawsegment.h | 21 +-- .../swrenderer/things/r_visiblesprite.cpp | 2 +- 8 files changed, 73 insertions(+), 93 deletions(-) diff --git a/src/rendering/swrenderer/line/r_line.cpp b/src/rendering/swrenderer/line/r_line.cpp index 51814d8463..e6b3c03c1a 100644 --- a/src/rendering/swrenderer/line/r_line.cpp +++ b/src/rendering/swrenderer/line/r_line.cpp @@ -287,9 +287,6 @@ namespace swrenderer // A wall segment will be drawn between start and stop pixels (inclusive). bool SWRenderLine::RenderWallSegment(int start, int stop) { - int i; - bool maskedtexture = false; - if (!rw_prepped) { rw_prepped = true; @@ -320,9 +317,11 @@ namespace swrenderer if (markportal) { + draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip); + draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, Thread->OpaquePass->floorclip); draw_segment->drawsegclip.silhouette = SIL_BOTH; } - else if (mBackSector == NULL) + else if (!mBackSector) { draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight); draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1); @@ -331,14 +330,12 @@ namespace swrenderer else { // two sided line - if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 || - mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0) + if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 || mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0) { draw_segment->drawsegclip.silhouette = SIL_BOTTOM; } - if (mFrontCeilingZ1 < mBackCeilingZ1 || mFrontCeilingZ2 < mBackCeilingZ2 || - mBackSector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0) + if (mFrontCeilingZ1 < mBackCeilingZ1 || mFrontCeilingZ2 < mBackCeilingZ2 || mBackSector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0) { draw_segment->drawsegclip.silhouette |= SIL_TOP; } @@ -351,71 +348,65 @@ namespace swrenderer // // killough 4/7/98: make doorclosed external variable + if (mDoorClosed || (mBackCeilingZ1 <= mFrontFloorZ1 && mBackCeilingZ2 <= mFrontFloorZ2)) { - if (mDoorClosed || (mBackCeilingZ1 <= mFrontFloorZ1 && mBackCeilingZ2 <= mFrontFloorZ2)) - { - draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1); - draw_segment->drawsegclip.silhouette |= SIL_BOTTOM; - } - if (mDoorClosed || (mBackFloorZ1 >= mFrontCeilingZ1 && mBackFloorZ2 >= mFrontCeilingZ2)) - { - draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight); - draw_segment->drawsegclip.silhouette |= SIL_TOP; - } + draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1); + draw_segment->drawsegclip.silhouette |= SIL_BOTTOM; + } + if (mDoorClosed || (mBackFloorZ1 >= mFrontCeilingZ1 && mBackFloorZ2 >= mFrontCeilingZ2)) + { + draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight); + draw_segment->drawsegclip.silhouette |= SIL_TOP; } if (m3DFloor.type == Fake3DOpaque::Normal) { - if (r_3dfloors) - { - if (mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) { - for (i = 0; i < (int)mBackSector->e->XFloor.ffloors.Size(); i++) { - F3DFloor *rover = mBackSector->e->XFloor.ffloors[i]; - if (rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) { - draw_segment->SetHas3DFloorBackSectorWalls(); - break; - } - } - } - if (mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) { - for (i = 0; i < (int)mFrontSector->e->XFloor.ffloors.Size(); i++) { - F3DFloor *rover = mFrontSector->e->XFloor.ffloors[i]; - if (rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) { - draw_segment->SetHas3DFloorFrontSectorWalls(); - break; - } - } - } - } - - // allocate space for masked texture tables, if needed - // [RH] Don't just allocate the space; fill it in too. - if ((sidedef->GetTexture(side_t::mid).isValid() || draw_segment->Has3DFloorWalls() || IsFogBoundary(mFrontSector, mBackSector)) && - (mCeilingClipped != ProjectedWallCull::OutsideBelow || !sidedef->GetTexture(side_t::top).isValid()) && + if ((mCeilingClipped != ProjectedWallCull::OutsideBelow || !sidedef->GetTexture(side_t::top).isValid()) && (mFloorClipped != ProjectedWallCull::OutsideAbove || !sidedef->GetTexture(side_t::bottom).isValid()) && (WallC.sz1 >= TOO_CLOSE_Z && WallC.sz2 >= TOO_CLOSE_Z)) { - maskedtexture = true; - - // kg3D - backup for mid and fake walls - draw_segment->drawsegclip.SetBackupClip(Thread, start, stop, Thread->OpaquePass->ceilingclip); - draw_segment->drawsegclip.bFogBoundary = IsFogBoundary(mFrontSector, mBackSector); - if (sidedef->GetTexture(side_t::mid).isValid()) + if (r_3dfloors) { - FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); - FSoftwareTexture *pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; - if (pic) - { - draw_segment->SetHas3DFloorMidTexture(); - draw_segment->texcoords.ProjectTranslucent(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, pic); + if (mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) { + for (int i = 0; i < (int)mBackSector->e->XFloor.ffloors.Size(); i++) { + F3DFloor* rover = mBackSector->e->XFloor.ffloors[i]; + if (rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) { + draw_segment->SetHas3DFloorBackSectorWalls(); + break; + } + } + } + if (mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) { + for (int i = 0; i < (int)mFrontSector->e->XFloor.ffloors.Size(); i++) { + F3DFloor* rover = mFrontSector->e->XFloor.ffloors[i]; + if (rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) { + draw_segment->SetHas3DFloorFrontSectorWalls(); + break; + } + } } } - draw_segment->light = mLight.GetLightPos(start); - draw_segment->lightstep = mLight.GetLightStep(); + if (IsFogBoundary(mFrontSector, mBackSector)) + draw_segment->SetHasFogBoundary(); - if (draw_segment->drawsegclip.bFogBoundary || draw_segment->texcoords || draw_segment->Has3DFloorWalls()) + if (mLineSegment->linedef->alpha > 0.0f && sidedef->GetTexture(side_t::mid).isValid()) { + FTexture* tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); + FSoftwareTexture* pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; + if (pic) + { + draw_segment->SetHasTranslucentMidTexture(); + draw_segment->texcoords.ProjectTranslucent(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, pic); + draw_segment->drawsegclip.silhouette |= SIL_TOP | SIL_BOTTOM; + } + } + + if (draw_segment->HasFogBoundary() || draw_segment->HasTranslucentMidTexture() || draw_segment->Has3DFloorWalls()) + { + draw_segment->drawsegclip.SetBackupClip(Thread, start, stop, Thread->OpaquePass->ceilingclip); + draw_segment->light = mLight.GetLightPos(start); + draw_segment->lightstep = mLight.GetLightStep(); Thread->DrawSegments->PushTranslucent(draw_segment); } } @@ -435,22 +426,18 @@ namespace swrenderer MarkOpaquePassClip(start, stop); - // save sprite clipping info - if (((draw_segment->drawsegclip.silhouette & SIL_TOP) || maskedtexture) && draw_segment->drawsegclip.sprtopclip == nullptr) + bool needcliplists = draw_segment->HasFogBoundary() || draw_segment->HasTranslucentMidTexture() || draw_segment->Has3DFloorWalls(); + + if (((draw_segment->drawsegclip.silhouette & SIL_TOP) || needcliplists) && !draw_segment->drawsegclip.sprtopclip) { draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip); } - if (((draw_segment->drawsegclip.silhouette & SIL_BOTTOM) || maskedtexture) && draw_segment->drawsegclip.sprbottomclip == nullptr) + if (((draw_segment->drawsegclip.silhouette & SIL_BOTTOM) || needcliplists) && !draw_segment->drawsegclip.sprbottomclip) { draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, Thread->OpaquePass->floorclip); } - if (maskedtexture && mLineSegment->sidedef->GetTexture(side_t::mid).isValid()) - { - draw_segment->drawsegclip.silhouette |= SIL_TOP | SIL_BOTTOM; - } - RenderMiddleTexture(start, stop); RenderTopTexture(start, stop); RenderBottomTexture(start, stop); diff --git a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp index 7be1520360..a28d8f4c4c 100644 --- a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp @@ -90,27 +90,22 @@ namespace swrenderer } } - float alpha = (float)MIN(curline->linedef->alpha, 1.); - bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0; - - bool visible = alpha > 0.0f; - if (!visible && !ds->drawsegclip.bFogBoundary && !ds->Has3DFloorWalls()) + if (!ds->HasTranslucentMidTexture() && !ds->HasFogBoundary() && !ds->Has3DFloorWalls()) { return; } - // [RH] Draw fog partition - if (ds->drawsegclip.bFogBoundary) + if (ds->HasFogBoundary()) { RenderFogBoundary renderfog; renderfog.Render(Thread, x1, x2, ds->drawsegclip, mLight); } bool notrelevant = false; - if (ds->texcoords && visible) + if (ds->HasTranslucentMidTexture()) notrelevant = RenderWall(ds, x1, x2); - if (ds->Has3DFloorFrontSectorWalls() || ds->Has3DFloorBackSectorWalls()) + if (ds->Has3DFloorWalls()) { Render3DFloorWallRange(ds, x1, x2); } diff --git a/src/rendering/swrenderer/line/r_wallsetup.cpp b/src/rendering/swrenderer/line/r_wallsetup.cpp index ee48317bf9..13f0cd58f1 100644 --- a/src/rendering/swrenderer/line/r_wallsetup.cpp +++ b/src/rendering/swrenderer/line/r_wallsetup.cpp @@ -470,7 +470,6 @@ namespace swrenderer this->flipx = flipx; CenterX = viewport->CenterX; WallTMapScale2 = viewport->WallTMapScale2; - valid = true; } float ProjectedWallTexcoords::VStep(int x) const diff --git a/src/rendering/swrenderer/line/r_wallsetup.h b/src/rendering/swrenderer/line/r_wallsetup.h index f8fcfc649a..f7b78c2482 100644 --- a/src/rendering/swrenderer/line/r_wallsetup.h +++ b/src/rendering/swrenderer/line/r_wallsetup.h @@ -75,8 +75,6 @@ namespace swrenderer float VStep(int x) const; fixed_t UPos(int x) const; - explicit operator bool() const { return valid; } - private: void Project(RenderViewport* viewport, double walxrepeat, int x1, int x2, const FWallTmapVals& WallT, bool flipx = false); @@ -85,7 +83,6 @@ namespace swrenderer static double GetXScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart); static double GetYScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart); - bool valid = false; double CenterX; double WallTMapScale2; double walxrepeat; diff --git a/src/rendering/swrenderer/scene/r_portal.cpp b/src/rendering/swrenderer/scene/r_portal.cpp index ce82c4e6b9..a39340c4d3 100644 --- a/src/rendering/swrenderer/scene/r_portal.cpp +++ b/src/rendering/swrenderer/scene/r_portal.cpp @@ -214,7 +214,6 @@ namespace swrenderer draw_segment->drawsegclip.silhouette = SIL_BOTH; draw_segment->drawsegclip.SetTopClip(Thread, pl->left, pl->right, ceilingclip); draw_segment->drawsegclip.SetBottomClip(Thread, pl->left, pl->right, floorclip); - draw_segment->drawsegclip.bFogBoundary = false; draw_segment->curline = nullptr; drawseglist->Push(draw_segment); diff --git a/src/rendering/swrenderer/scene/r_translucent_pass.cpp b/src/rendering/swrenderer/scene/r_translucent_pass.cpp index aad495ffe8..132386a082 100644 --- a/src/rendering/swrenderer/scene/r_translucent_pass.cpp +++ b/src/rendering/swrenderer/scene/r_translucent_pass.cpp @@ -157,13 +157,13 @@ namespace swrenderer if (ds->drawsegclip.CurrentPortalUniq != renderportal->CurrentPortalUniq) continue; - if (ds->texcoords || ds->drawsegclip.bFogBoundary) + if (ds->HasTranslucentMidTexture() || ds->Has3DFloorWalls() || ds->HasFogBoundary()) { RenderDrawSegment renderer(Thread); renderer.Render(ds, ds->x1, ds->x2, clip3DFloor); if (renew) { - ds->drawsegclip.bFogBoundary = false; // don't draw fogboundary again + ds->ClearFogBoundary(); // don't draw fogboundary again ds->drawsegclip.SetRangeUndrawn(ds->x1, ds->x2); } } diff --git a/src/rendering/swrenderer/segments/r_drawsegment.h b/src/rendering/swrenderer/segments/r_drawsegment.h index 8ef1d0ad7a..38cd51c7ff 100644 --- a/src/rendering/swrenderer/segments/r_drawsegment.h +++ b/src/rendering/swrenderer/segments/r_drawsegment.h @@ -36,7 +36,6 @@ namespace swrenderer void SetRangeUndrawn(int x1, int x2); uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both - bool bFogBoundary = false; int CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping. int SubsectorDepth; @@ -61,17 +60,21 @@ namespace swrenderer DrawSegmentClipInfo drawsegclip; - bool Has3DFloorWalls() const { return b3DFloorBoundary != 0; } - bool Has3DFloorFrontSectorWalls() const { return (b3DFloorBoundary & 2) == 2; } - bool Has3DFloorBackSectorWalls() const { return (b3DFloorBoundary & 1) == 1; } - bool Has3DFloorMidTexture() const { return (b3DFloorBoundary & 4) == 4; } + bool HasFogBoundary() const { return (flags & 8) != 0; } + bool Has3DFloorWalls() const { return (flags & 3) != 0; } + bool Has3DFloorFrontSectorWalls() const { return (flags & 2) != 0; } + bool Has3DFloorBackSectorWalls() const { return (flags & 1) != 0; } + bool HasTranslucentMidTexture() const { return (flags & 4) != 0; } - void SetHas3DFloorFrontSectorWalls() { b3DFloorBoundary |= 2; } - void SetHas3DFloorBackSectorWalls() { b3DFloorBoundary |= 1; } - void SetHas3DFloorMidTexture() { b3DFloorBoundary |= 4; } + void SetHasFogBoundary() { flags |= 8; } + void SetHas3DFloorFrontSectorWalls() { flags |= 2; } + void SetHas3DFloorBackSectorWalls() { flags |= 1; } + void SetHasTranslucentMidTexture() { flags |= 4; } + + void ClearFogBoundary() { flags &= ~8; } // Note: this shouldn't be needed as fog boundaries should be able to clip same way as 3dfloor walls private: - uint8_t b3DFloorBoundary = 0; // 1=backsector, 2=frontsector, 4=midtexture + int flags = 0; // 1=backsector, 2=frontsector, 4=midtexture, 8=fogboundary }; struct DrawSegmentGroup diff --git a/src/rendering/swrenderer/things/r_visiblesprite.cpp b/src/rendering/swrenderer/things/r_visiblesprite.cpp index dab3c00664..53596f7c77 100644 --- a/src/rendering/swrenderer/things/r_visiblesprite.cpp +++ b/src/rendering/swrenderer/things/r_visiblesprite.cpp @@ -405,7 +405,7 @@ namespace swrenderer DrawSegment *ds = segmentlist->Segment(index); // determine if the drawseg obscures the sprite - if (ds->x1 >= x2 || ds->x2 <= x1 || (!(ds->drawsegclip.silhouette & SIL_BOTH) && !ds->texcoords && !ds->drawsegclip.bFogBoundary)) + if (ds->x1 >= x2 || ds->x2 <= x1 || (!(ds->drawsegclip.silhouette & SIL_BOTH) && !ds->Has3DFloorWalls() && !ds->HasTranslucentMidTexture() && !ds->HasFogBoundary())) { // does not cover sprite continue;