Fix 3d floor rendering bug

This commit is contained in:
Magnus Norddahl 2019-11-14 02:28:53 +01:00
parent a74be69371
commit 642cd2b160
8 changed files with 73 additions and 93 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -470,7 +470,6 @@ namespace swrenderer
this->flipx = flipx;
CenterX = viewport->CenterX;
WallTMapScale2 = viewport->WallTMapScale2;
valid = true;
}
float ProjectedWallTexcoords::VStep(int x) const

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;