mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 07:12:02 +00:00
Fix 3d floor rendering bug
This commit is contained in:
parent
a74be69371
commit
642cd2b160
8 changed files with 73 additions and 93 deletions
|
@ -287,9 +287,6 @@ namespace swrenderer
|
||||||
// A wall segment will be drawn between start and stop pixels (inclusive).
|
// A wall segment will be drawn between start and stop pixels (inclusive).
|
||||||
bool SWRenderLine::RenderWallSegment(int start, int stop)
|
bool SWRenderLine::RenderWallSegment(int start, int stop)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
bool maskedtexture = false;
|
|
||||||
|
|
||||||
if (!rw_prepped)
|
if (!rw_prepped)
|
||||||
{
|
{
|
||||||
rw_prepped = true;
|
rw_prepped = true;
|
||||||
|
@ -320,9 +317,11 @@ namespace swrenderer
|
||||||
|
|
||||||
if (markportal)
|
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;
|
draw_segment->drawsegclip.silhouette = SIL_BOTH;
|
||||||
}
|
}
|
||||||
else if (mBackSector == NULL)
|
else if (!mBackSector)
|
||||||
{
|
{
|
||||||
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight);
|
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight);
|
||||||
draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1);
|
draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1);
|
||||||
|
@ -331,14 +330,12 @@ namespace swrenderer
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// two sided line
|
// two sided line
|
||||||
if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 ||
|
if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 || mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
|
||||||
mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
|
|
||||||
{
|
{
|
||||||
draw_segment->drawsegclip.silhouette = SIL_BOTTOM;
|
draw_segment->drawsegclip.silhouette = SIL_BOTTOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFrontCeilingZ1 < mBackCeilingZ1 || mFrontCeilingZ2 < mBackCeilingZ2 ||
|
if (mFrontCeilingZ1 < mBackCeilingZ1 || mFrontCeilingZ2 < mBackCeilingZ2 || mBackSector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
|
||||||
mBackSector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
|
|
||||||
{
|
{
|
||||||
draw_segment->drawsegclip.silhouette |= SIL_TOP;
|
draw_segment->drawsegclip.silhouette |= SIL_TOP;
|
||||||
}
|
}
|
||||||
|
@ -351,7 +348,6 @@ namespace swrenderer
|
||||||
//
|
//
|
||||||
// killough 4/7/98: make doorclosed external variable
|
// 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.SetBottomClip(Thread, start, stop, -1);
|
||||||
|
@ -362,15 +358,18 @@ namespace swrenderer
|
||||||
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight);
|
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight);
|
||||||
draw_segment->drawsegclip.silhouette |= SIL_TOP;
|
draw_segment->drawsegclip.silhouette |= SIL_TOP;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (m3DFloor.type == Fake3DOpaque::Normal)
|
if (m3DFloor.type == Fake3DOpaque::Normal)
|
||||||
|
{
|
||||||
|
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))
|
||||||
{
|
{
|
||||||
if (r_3dfloors)
|
if (r_3dfloors)
|
||||||
{
|
{
|
||||||
if (mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) {
|
if (mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) {
|
||||||
for (i = 0; i < (int)mBackSector->e->XFloor.ffloors.Size(); i++) {
|
for (int i = 0; i < (int)mBackSector->e->XFloor.ffloors.Size(); i++) {
|
||||||
F3DFloor *rover = mBackSector->e->XFloor.ffloors[i];
|
F3DFloor* rover = mBackSector->e->XFloor.ffloors[i];
|
||||||
if (rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) {
|
if (rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) {
|
||||||
draw_segment->SetHas3DFloorBackSectorWalls();
|
draw_segment->SetHas3DFloorBackSectorWalls();
|
||||||
break;
|
break;
|
||||||
|
@ -378,8 +377,8 @@ namespace swrenderer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) {
|
if (mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) {
|
||||||
for (i = 0; i < (int)mFrontSector->e->XFloor.ffloors.Size(); i++) {
|
for (int i = 0; i < (int)mFrontSector->e->XFloor.ffloors.Size(); i++) {
|
||||||
F3DFloor *rover = mFrontSector->e->XFloor.ffloors[i];
|
F3DFloor* rover = mFrontSector->e->XFloor.ffloors[i];
|
||||||
if (rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) {
|
if (rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) {
|
||||||
draw_segment->SetHas3DFloorFrontSectorWalls();
|
draw_segment->SetHas3DFloorFrontSectorWalls();
|
||||||
break;
|
break;
|
||||||
|
@ -388,34 +387,26 @@ namespace swrenderer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate space for masked texture tables, if needed
|
if (IsFogBoundary(mFrontSector, mBackSector))
|
||||||
// [RH] Don't just allocate the space; fill it in too.
|
draw_segment->SetHasFogBoundary();
|
||||||
if ((sidedef->GetTexture(side_t::mid).isValid() || draw_segment->Has3DFloorWalls() || IsFogBoundary(mFrontSector, mBackSector)) &&
|
|
||||||
(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
|
if (mLineSegment->linedef->alpha > 0.0f && sidedef->GetTexture(side_t::mid).isValid())
|
||||||
draw_segment->drawsegclip.SetBackupClip(Thread, start, stop, Thread->OpaquePass->ceilingclip);
|
|
||||||
draw_segment->drawsegclip.bFogBoundary = IsFogBoundary(mFrontSector, mBackSector);
|
|
||||||
if (sidedef->GetTexture(side_t::mid).isValid())
|
|
||||||
{
|
{
|
||||||
FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
|
FTexture* tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
|
||||||
FSoftwareTexture *pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
|
FSoftwareTexture* pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
|
||||||
if (pic)
|
if (pic)
|
||||||
{
|
{
|
||||||
draw_segment->SetHas3DFloorMidTexture();
|
draw_segment->SetHasTranslucentMidTexture();
|
||||||
draw_segment->texcoords.ProjectTranslucent(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, pic);
|
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->light = mLight.GetLightPos(start);
|
||||||
draw_segment->lightstep = mLight.GetLightStep();
|
draw_segment->lightstep = mLight.GetLightStep();
|
||||||
|
|
||||||
if (draw_segment->drawsegclip.bFogBoundary || draw_segment->texcoords || draw_segment->Has3DFloorWalls())
|
|
||||||
{
|
|
||||||
Thread->DrawSegments->PushTranslucent(draw_segment);
|
Thread->DrawSegments->PushTranslucent(draw_segment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,22 +426,18 @@ namespace swrenderer
|
||||||
|
|
||||||
MarkOpaquePassClip(start, stop);
|
MarkOpaquePassClip(start, stop);
|
||||||
|
|
||||||
// save sprite clipping info
|
bool needcliplists = draw_segment->HasFogBoundary() || draw_segment->HasTranslucentMidTexture() || draw_segment->Has3DFloorWalls();
|
||||||
if (((draw_segment->drawsegclip.silhouette & SIL_TOP) || maskedtexture) && draw_segment->drawsegclip.sprtopclip == nullptr)
|
|
||||||
|
if (((draw_segment->drawsegclip.silhouette & SIL_TOP) || needcliplists) && !draw_segment->drawsegclip.sprtopclip)
|
||||||
{
|
{
|
||||||
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip);
|
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);
|
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);
|
RenderMiddleTexture(start, stop);
|
||||||
RenderTopTexture(start, stop);
|
RenderTopTexture(start, stop);
|
||||||
RenderBottomTexture(start, stop);
|
RenderBottomTexture(start, stop);
|
||||||
|
|
|
@ -90,27 +90,22 @@ namespace swrenderer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float alpha = (float)MIN(curline->linedef->alpha, 1.);
|
if (!ds->HasTranslucentMidTexture() && !ds->HasFogBoundary() && !ds->Has3DFloorWalls())
|
||||||
bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0;
|
|
||||||
|
|
||||||
bool visible = alpha > 0.0f;
|
|
||||||
if (!visible && !ds->drawsegclip.bFogBoundary && !ds->Has3DFloorWalls())
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [RH] Draw fog partition
|
if (ds->HasFogBoundary())
|
||||||
if (ds->drawsegclip.bFogBoundary)
|
|
||||||
{
|
{
|
||||||
RenderFogBoundary renderfog;
|
RenderFogBoundary renderfog;
|
||||||
renderfog.Render(Thread, x1, x2, ds->drawsegclip, mLight);
|
renderfog.Render(Thread, x1, x2, ds->drawsegclip, mLight);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool notrelevant = false;
|
bool notrelevant = false;
|
||||||
if (ds->texcoords && visible)
|
if (ds->HasTranslucentMidTexture())
|
||||||
notrelevant = RenderWall(ds, x1, x2);
|
notrelevant = RenderWall(ds, x1, x2);
|
||||||
|
|
||||||
if (ds->Has3DFloorFrontSectorWalls() || ds->Has3DFloorBackSectorWalls())
|
if (ds->Has3DFloorWalls())
|
||||||
{
|
{
|
||||||
Render3DFloorWallRange(ds, x1, x2);
|
Render3DFloorWallRange(ds, x1, x2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,7 +470,6 @@ namespace swrenderer
|
||||||
this->flipx = flipx;
|
this->flipx = flipx;
|
||||||
CenterX = viewport->CenterX;
|
CenterX = viewport->CenterX;
|
||||||
WallTMapScale2 = viewport->WallTMapScale2;
|
WallTMapScale2 = viewport->WallTMapScale2;
|
||||||
valid = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float ProjectedWallTexcoords::VStep(int x) const
|
float ProjectedWallTexcoords::VStep(int x) const
|
||||||
|
|
|
@ -75,8 +75,6 @@ namespace swrenderer
|
||||||
float VStep(int x) const;
|
float VStep(int x) const;
|
||||||
fixed_t UPos(int x) const;
|
fixed_t UPos(int x) const;
|
||||||
|
|
||||||
explicit operator bool() const { return valid; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Project(RenderViewport* viewport, double walxrepeat, int x1, int x2, const FWallTmapVals& WallT, bool flipx = false);
|
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 GetXScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart);
|
||||||
static double GetYScale(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 CenterX;
|
||||||
double WallTMapScale2;
|
double WallTMapScale2;
|
||||||
double walxrepeat;
|
double walxrepeat;
|
||||||
|
|
|
@ -214,7 +214,6 @@ namespace swrenderer
|
||||||
draw_segment->drawsegclip.silhouette = SIL_BOTH;
|
draw_segment->drawsegclip.silhouette = SIL_BOTH;
|
||||||
draw_segment->drawsegclip.SetTopClip(Thread, pl->left, pl->right, ceilingclip);
|
draw_segment->drawsegclip.SetTopClip(Thread, pl->left, pl->right, ceilingclip);
|
||||||
draw_segment->drawsegclip.SetBottomClip(Thread, pl->left, pl->right, floorclip);
|
draw_segment->drawsegclip.SetBottomClip(Thread, pl->left, pl->right, floorclip);
|
||||||
draw_segment->drawsegclip.bFogBoundary = false;
|
|
||||||
draw_segment->curline = nullptr;
|
draw_segment->curline = nullptr;
|
||||||
drawseglist->Push(draw_segment);
|
drawseglist->Push(draw_segment);
|
||||||
|
|
||||||
|
|
|
@ -157,13 +157,13 @@ namespace swrenderer
|
||||||
if (ds->drawsegclip.CurrentPortalUniq != renderportal->CurrentPortalUniq)
|
if (ds->drawsegclip.CurrentPortalUniq != renderportal->CurrentPortalUniq)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ds->texcoords || ds->drawsegclip.bFogBoundary)
|
if (ds->HasTranslucentMidTexture() || ds->Has3DFloorWalls() || ds->HasFogBoundary())
|
||||||
{
|
{
|
||||||
RenderDrawSegment renderer(Thread);
|
RenderDrawSegment renderer(Thread);
|
||||||
renderer.Render(ds, ds->x1, ds->x2, clip3DFloor);
|
renderer.Render(ds, ds->x1, ds->x2, clip3DFloor);
|
||||||
if (renew)
|
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);
|
ds->drawsegclip.SetRangeUndrawn(ds->x1, ds->x2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ namespace swrenderer
|
||||||
void SetRangeUndrawn(int x1, int x2);
|
void SetRangeUndrawn(int x1, int x2);
|
||||||
|
|
||||||
uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both
|
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 CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping.
|
||||||
int SubsectorDepth;
|
int SubsectorDepth;
|
||||||
|
|
||||||
|
@ -61,17 +60,21 @@ namespace swrenderer
|
||||||
|
|
||||||
DrawSegmentClipInfo drawsegclip;
|
DrawSegmentClipInfo drawsegclip;
|
||||||
|
|
||||||
bool Has3DFloorWalls() const { return b3DFloorBoundary != 0; }
|
bool HasFogBoundary() const { return (flags & 8) != 0; }
|
||||||
bool Has3DFloorFrontSectorWalls() const { return (b3DFloorBoundary & 2) == 2; }
|
bool Has3DFloorWalls() const { return (flags & 3) != 0; }
|
||||||
bool Has3DFloorBackSectorWalls() const { return (b3DFloorBoundary & 1) == 1; }
|
bool Has3DFloorFrontSectorWalls() const { return (flags & 2) != 0; }
|
||||||
bool Has3DFloorMidTexture() const { return (b3DFloorBoundary & 4) == 4; }
|
bool Has3DFloorBackSectorWalls() const { return (flags & 1) != 0; }
|
||||||
|
bool HasTranslucentMidTexture() const { return (flags & 4) != 0; }
|
||||||
|
|
||||||
void SetHas3DFloorFrontSectorWalls() { b3DFloorBoundary |= 2; }
|
void SetHasFogBoundary() { flags |= 8; }
|
||||||
void SetHas3DFloorBackSectorWalls() { b3DFloorBoundary |= 1; }
|
void SetHas3DFloorFrontSectorWalls() { flags |= 2; }
|
||||||
void SetHas3DFloorMidTexture() { b3DFloorBoundary |= 4; }
|
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:
|
private:
|
||||||
uint8_t b3DFloorBoundary = 0; // 1=backsector, 2=frontsector, 4=midtexture
|
int flags = 0; // 1=backsector, 2=frontsector, 4=midtexture, 8=fogboundary
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DrawSegmentGroup
|
struct DrawSegmentGroup
|
||||||
|
|
|
@ -405,7 +405,7 @@ namespace swrenderer
|
||||||
DrawSegment *ds = segmentlist->Segment(index);
|
DrawSegment *ds = segmentlist->Segment(index);
|
||||||
|
|
||||||
// determine if the drawseg obscures the sprite
|
// 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
|
// does not cover sprite
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in a new issue