Merge remote-tracking branch 'gzdoom/master' into newmaster

This commit is contained in:
Major Cooke 2019-11-17 10:37:18 -06:00
commit 5c11e668eb
13 changed files with 190 additions and 408 deletions

View file

@ -54,15 +54,12 @@
namespace swrenderer
{
void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const DrawSegmentClipInfo& clip, const ProjectedWallLight &wallLight)
void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const short* uclip, const short* dclip, const ProjectedWallLight &wallLight)
{
// This is essentially the same as R_MapVisPlane but with an extra step
// to create new horizontal spans whenever the light changes enough that
// we need to use a new colormap.
const short* uclip = clip.sprtopclip;
const short* dclip = clip.sprbottomclip;
int wallshade = LightVisibility::LightLevelToShade(wallLight.GetLightLevel(), wallLight.GetFoggy(), thread->Viewport.get());
int x = x2 - 1;
int t2 = uclip[x];

View file

@ -31,7 +31,7 @@ namespace swrenderer
class RenderFogBoundary
{
public:
void Render(RenderThread *thread, int x1, int x2, const DrawSegmentClipInfo &clip, const ProjectedWallLight &wallLight);
void Render(RenderThread *thread, int x1, int x2, const short* uclip, const short* dclip, const ProjectedWallLight &wallLight);
private:
void RenderSection(RenderThread *thread, int y, int y2, int x1);

View file

@ -62,7 +62,6 @@
CVAR(Bool, r_fogboundary, true, 0)
CVAR(Bool, r_drawmirrors, true, 0)
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer
{
@ -405,8 +404,6 @@ namespace swrenderer
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);
}
}
@ -446,7 +443,7 @@ namespace swrenderer
// [ZZ] Only if not an active mirror
if (!markportal)
{
RenderDecal::RenderDecals(Thread, mLineSegment->sidedef, draw_segment, mLineSegment, mLight, walltop.ScreenY, wallbottom.ScreenY, false);
RenderDecal::RenderDecals(Thread, draw_segment, mLineSegment, mFrontSector, walltop.ScreenY, wallbottom.ScreenY, false);
}
if (markportal)
@ -661,22 +658,6 @@ namespace swrenderer
}
}
}
FTexture *ftex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
FSoftwareTexture *midtex = ftex && ftex->isValid() ? ftex->GetSoftwareTexture() : nullptr;
bool segtextured = ftex != NULL || mTopTexture != NULL || mBottomTexture != NULL;
if (m3DFloor.type == Fake3DOpaque::Normal)
{
mLight.SetColormap(mFrontSector, mLineSegment);
}
// calculate light table
if (segtextured || (mBackSector && IsFogBoundary(mFrontSector, mBackSector)))
{
mLight.SetLightLeft(Thread, WallC);
}
}
void SWRenderLine::SetTextures()
@ -900,7 +881,7 @@ namespace swrenderer
texcoords.ProjectTop(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mTopTexture);
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mTopTexture, x1, x2, walltop.ScreenY, wallupper.ScreenY, texcoords, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mBackCeilingZ1, mBackCeilingZ2), false, false, OPAQUE, mLight, GetLightList());
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mTopTexture, x1, x2, walltop.ScreenY, wallupper.ScreenY, texcoords, false, false, OPAQUE);
}
void SWRenderLine::RenderMiddleTexture(int x1, int x2)
@ -912,7 +893,7 @@ namespace swrenderer
texcoords.ProjectMid(Thread->Viewport.get(), mFrontSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mMiddleTexture);
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mMiddleTexture, x1, x2, walltop.ScreenY, wallbottom.ScreenY, texcoords, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, mLight, GetLightList());
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mMiddleTexture, x1, x2, walltop.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE);
}
void SWRenderLine::RenderBottomTexture(int x1, int x2)
@ -925,18 +906,7 @@ namespace swrenderer
texcoords.ProjectBottom(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mBottomTexture);
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mBottomTexture, x1, x2, walllower.ScreenY, wallbottom.ScreenY, texcoords, MAX(mBackFloorZ1, mBackFloorZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, mLight, GetLightList());
}
FLightNode *SWRenderLine::GetLightList()
{
CameraLight *cameraLight = CameraLight::Instance();
if ((cameraLight->FixedLightLevel() >= 0) || cameraLight->FixedColormap())
return nullptr; // [SP] Don't draw dynlights if invul/lightamp active
else if (mLineSegment && mLineSegment->sidedef)
return mLineSegment->sidedef->lighthead;
else
return nullptr;
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mBottomTexture, x1, x2, walllower.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE);
}
////////////////////////////////////////////////////////////////////////////

View file

@ -74,8 +74,6 @@ namespace swrenderer
void RenderMiddleTexture(int x1, int x2);
void RenderBottomTexture(int x1, int x2);
FLightNode *GetLightList();
bool IsFogBoundary(sector_t *front, sector_t *back) const;
bool SkyboxCompare(sector_t *frontsector, sector_t *backsector) const;
@ -115,8 +113,6 @@ namespace swrenderer
bool rw_prepped;
ProjectedWallLight mLight;
bool markfloor; // False if the back side is the same plane.
bool markceiling;

View file

@ -71,60 +71,25 @@ namespace swrenderer
frontsector = curline->frontsector;
backsector = curline->backsector;
// killough 4/13/98: get correct lightlevel for 2s normal textures
sector_t tempsec;
const sector_t *sec = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0);
mLight.SetColormap(sec, curline);
mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1);
Clip3DFloors *clip3d = Thread->Clip3D.get();
double clipTop = m3DFloor.clipTop ? m3DFloor.sclipTop : sec->ceilingplane.ZatPoint(Thread->Viewport->viewpoint.Pos);
for (int i = frontsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
{
if (clipTop <= frontsector->e->XFloor.lightlist[i].plane.Zat0())
{
mLight.SetColormap(frontsector, curline, &frontsector->e->XFloor.lightlist[i]);
break;
}
}
if (!ds->HasTranslucentMidTexture() && !ds->HasFogBoundary() && !ds->Has3DFloorWalls())
{
return;
}
if (ds->HasFogBoundary())
{
RenderFogBoundary renderfog;
renderfog.Render(Thread, x1, x2, ds->drawsegclip, mLight);
}
RenderFog(ds, x1, x2);
bool notrelevant = false;
if (ds->HasTranslucentMidTexture())
notrelevant = RenderWall(ds, x1, x2);
RenderWall(ds, x1, x2);
if (ds->Has3DFloorWalls())
{
Render3DFloorWallRange(ds, x1, x2);
}
if (!notrelevant)
{
if (ds->HasFogBoundary() || ds->HasTranslucentMidTexture() || ds->Has3DFloorWalls())
ds->drawsegclip.SetRangeDrawn(x1, x2);
}
}
bool RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2)
void RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2)
{
auto renderstyle = DefaultRenderStyle();
auto viewport = Thread->Viewport.get();
Clip3DFloors *clip3d = Thread->Clip3D.get();
if (!curline->sidedef->GetTexture(side_t::mid).isValid())
return false;
FTexture *ttex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::mid), true);
if (curline->GetLevel()->i_compatflags & COMPATF_MASKEDMIDTEX)
{
@ -139,41 +104,17 @@ namespace swrenderer
if (!wrap)
{ // Texture does not wrap vertically.
// find positioning
double texheight = tex->GetScaledHeightDouble() / fabs(curline->sidedef->GetTextureYScale(side_t::mid));
double texturemid;
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
texturemid = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight;
else
texturemid = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid);
if (tex->useWorldPanning(curline->GetLevel()))
rowoffset /= fabs(tex->GetScale().Y * curline->sidedef->GetTextureYScale(side_t::mid));
double textop = texturemid + rowoffset - Thread->Viewport->viewpoint.Pos.Z;
double ceilZ, floorZ;
GetNoWrapMidTextureZ(ds, tex, ceilZ, floorZ);
// [RH] Don't bother drawing segs that are completely offscreen
if (viewport->globaldclip * ds->WallC.sz1 < -textop && viewport->globaldclip * ds->WallC.sz2 < -textop)
{ // Texture top is below the bottom of the screen
return false;
}
// Texture top is below the bottom of the screen
if (viewport->globaldclip * ds->WallC.sz1 < -ceilZ && viewport->globaldclip * ds->WallC.sz2 < -ceilZ) return;
if (viewport->globaluclip * ds->WallC.sz1 > texheight - textop && viewport->globaluclip * ds->WallC.sz2 > texheight - textop)
{ // Texture bottom is above the top of the screen
return false;
}
// Texture bottom is above the top of the screen
if (viewport->globaluclip * ds->WallC.sz1 > -floorZ && viewport->globaluclip * ds->WallC.sz2 > -floorZ) return;
if (m3DFloor.clipBottom && textop < m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z)
{
return true;
}
if (m3DFloor.clipTop && textop - texheight > m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z)
{
return true;
}
// Unclipped vanilla Doom range for the wall. Relies on ceiling/floor clip to clamp the wall in range.
double ceilZ = textop;
double floorZ = textop - texheight;
if (m3DFloor.clipBottom && ceilZ < m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z) return;
if (m3DFloor.clipTop && floorZ > m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z) return;
// The 3D Floors implementation destroys the ceiling clip when doing its height passes..
if (m3DFloor.clipTop || m3DFloor.clipBottom)
@ -241,35 +182,25 @@ namespace swrenderer
if (m3DFloor.clipTop)
{
wallupper.Project(Thread->Viewport.get(), m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
for (int i = x1; i < x2; i++)
{
if (wallupper.ScreenY[i] < mceilingclip[i])
wallupper.ScreenY[i] = mceilingclip[i];
}
wallupper.ClipTop(x1, x2, ds->drawsegclip);
mceilingclip = wallupper.ScreenY;
}
if (m3DFloor.clipBottom)
{
walllower.Project(Thread->Viewport.get(), m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
for (int i = x1; i < x2; i++)
{
if (walllower.ScreenY[i] > mfloorclip[i])
walllower.ScreenY[i] = mfloorclip[i];
}
walllower.ClipBottom(x1, x2, ds->drawsegclip);
mfloorclip = walllower.ScreenY;
}
}
double top, bot;
GetMaskedWallTopBottom(ds, top, bot);
sector_t tempsec;
const sector_t* lightsector = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0);
float alpha = FLOAT2FIXED((float)MIN(curline->linedef->alpha, 1.));
fixed_t alpha = FLOAT2FIXED((float)MIN(curline->linedef->alpha, 1.));
bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0;
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(frontsector, curline, ds->WallC, tex, x1, x2, mceilingclip, mfloorclip, ds->texcoords, top, bot, true, additive, alpha, mLight, nullptr);
return false;
renderWallpart.Render(lightsector, curline, ds->WallC, tex, x1, x2, mceilingclip, mfloorclip, ds->texcoords, true, additive, alpha);
}
void RenderDrawSegment::Render3DFloorWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic)
@ -278,9 +209,8 @@ namespace swrenderer
if (Alpha <= 0)
return;
mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1);
sector_t* lightsector = (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls()) ? backsector : frontsector;
Clip3DFloors *clip3d = Thread->Clip3D.get();
wallupper.Project(Thread->Viewport.get(), clipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
walllower.Project(Thread->Viewport.get(), clipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
@ -290,13 +220,10 @@ namespace swrenderer
ProjectedWallTexcoords walltexcoords;
walltexcoords.Project3DFloor(Thread->Viewport.get(), rover, curline, ds->WallC.sx1, ds->WallC.sx2, ds->tmapvals, rw_pic);
double top, bot;
GetMaskedWallTopBottom(ds, top, bot);
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(frontsector, curline, ds->WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, walltexcoords, top, bot, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha, mLight, nullptr);
renderWallpart.Render(lightsector, curline, ds->WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, walltexcoords, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha);
RenderDecal::RenderDecals(Thread, curline->sidedef, ds, curline, mLight, wallupper.ScreenY, walllower.ScreenY, true);
RenderDecal::RenderDecals(Thread, ds, curline, lightsector, wallupper.ScreenY, walllower.ScreenY, true);
}
void RenderDrawSegment::Render3DFloorWallRange(DrawSegment *ds, int x1, int x2)
@ -312,16 +239,11 @@ namespace swrenderer
frontsector = curline->frontsector;
backsector = curline->backsector;
if (backsector == nullptr)
{
if (!backsector)
return;
}
if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls())
{
sector_t *sec = backsector;
backsector = frontsector;
frontsector = sec;
}
std::swap(frontsector, backsector);
floorHeight = backsector->CenterFloor();
ceilingHeight = backsector->CenterCeiling();
@ -490,38 +412,6 @@ namespace swrenderer
if (rw_pic && !swimmable_found)
{
// correct colors now
lightlist_t *lit = nullptr;
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedLightLevel() < 0)
{
if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls())
{
for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
{
lit = &backsector->e->XFloor.lightlist[j];
break;
}
}
}
else
{
for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
{
lit = &frontsector->e->XFloor.lightlist[j];
break;
}
}
}
}
//mLight.lightlevel = ds->lightlevel;
mLight.SetColormap(frontsector, curline, lit);
Render3DFloorWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic);
}
break;
@ -673,37 +563,6 @@ namespace swrenderer
if (rw_pic && !swimmable_found)
{
// correct colors now
lightlist_t *lit = nullptr;
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedLightLevel() < 0)
{
if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls())
{
for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
{
lit = &backsector->e->XFloor.lightlist[j];
break;
}
}
}
else
{
for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
{
lit = &frontsector->e->XFloor.lightlist[j];
break;
}
}
}
}
//mLight.lightlevel = ds->lightlevel;
mLight.SetColormap(frontsector, curline, lit);
Render3DFloorWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic);
}
break;
@ -711,6 +570,36 @@ namespace swrenderer
}
}
void RenderDrawSegment::RenderFog(DrawSegment* ds, int x1, int x2)
{
const short* mfloorclip = ds->drawsegclip.sprbottomclip;
const short* mceilingclip = ds->drawsegclip.sprtopclip;
if (m3DFloor.clipTop)
{
wallupper.Project(Thread->Viewport.get(), m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
wallupper.ClipTop(x1, x2, ds->drawsegclip);
mceilingclip = wallupper.ScreenY;
}
if (m3DFloor.clipBottom)
{
walllower.Project(Thread->Viewport.get(), m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
walllower.ClipBottom(x1, x2, ds->drawsegclip);
mfloorclip = walllower.ScreenY;
}
sector_t tempsec;
const sector_t* lightsector = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0);
ProjectedWallLight walllight;
walllight.SetColormap(lightsector, curline);
walllight.SetLightLeft(Thread, ds->WallC);
RenderFogBoundary renderfog;
renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, walllight);
}
// Clip a midtexture to the floor and ceiling of the sector in front of it.
void RenderDrawSegment::ClipMidtex(DrawSegment* ds, int x1, int x2)
{
@ -750,4 +639,22 @@ namespace swrenderer
bot = MAX(bot, m3DFloor.sclipBottom);
}
}
void RenderDrawSegment::GetNoWrapMidTextureZ(DrawSegment* ds, FSoftwareTexture* tex, double& ceilZ, double& floorZ)
{
double texheight = tex->GetScaledHeightDouble() / fabs(curline->sidedef->GetTextureYScale(side_t::mid));
double texturemid;
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
texturemid = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight;
else
texturemid = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid);
if (tex->useWorldPanning(curline->GetLevel()))
rowoffset /= fabs(tex->GetScale().Y * curline->sidedef->GetTextureYScale(side_t::mid));
double textop = texturemid + rowoffset - Thread->Viewport->viewpoint.Pos.Z;
// Unclipped vanilla Doom range for the wall. Relies on ceiling/floor clip to clamp the wall in range.
ceilZ = textop;
floorZ = textop - texheight;
}
}

View file

@ -37,10 +37,12 @@ namespace swrenderer
RenderThread *Thread = nullptr;
private:
bool RenderWall(DrawSegment *ds, int x1, int x2);
void ClipMidtex(DrawSegment* ds, int x1, int x2);
void RenderWall(DrawSegment *ds, int x1, int x2);
void Render3DFloorWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic);
void Render3DFloorWallRange(DrawSegment *ds, int x1, int x2);
void RenderFog(DrawSegment* ds, int x1, int x2);
void ClipMidtex(DrawSegment* ds, int x1, int x2);
void GetNoWrapMidTextureZ(DrawSegment* ds, FSoftwareTexture* tex, double& ceilZ, double& floorZ);
void GetMaskedWallTopBottom(DrawSegment *ds, double &top, double &bot);
sector_t *frontsector = nullptr;
@ -49,8 +51,6 @@ namespace swrenderer
seg_t *curline = nullptr;
Fake3DTranslucent m3DFloor;
ProjectedWallLight mLight;
ProjectedWallLine wallupper;
ProjectedWallLine walllower;
};

View file

@ -54,12 +54,75 @@
namespace swrenderer
{
void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords)
RenderWallPart::RenderWallPart(RenderThread* thread)
{
if (rw_pic == nullptr)
Thread = thread;
}
void RenderWallPart::Render(const sector_t* lightsector, seg_t* curline, const FWallCoords& WallC, FSoftwareTexture* pic, int x1, int x2, const short* walltop, const short* wallbottom, const ProjectedWallTexcoords& texcoords, bool mask, bool additive, fixed_t alpha)
{
if (pic == nullptr)
return;
int fracbits = 32 - rw_pic->GetHeightBits();
this->x1 = x1;
this->x2 = x2;
this->lightsector = lightsector;
this->curline = curline;
this->WallC = WallC;
this->pic = pic;
this->mask = mask;
this->additive = additive;
this->alpha = alpha;
light_list = GetLightList();
mLight.SetColormap(lightsector, curline);
mLight.SetLightLeft(Thread, WallC);
Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here.
CameraLight* cameraLight = CameraLight::Instance();
if (cameraLight->FixedColormap() || cameraLight->FixedLightLevel() >= 0 || !(lightsector->e && lightsector->e->XFloor.lightlist.Size()))
{
ProcessNormalWall(walltop, wallbottom, texcoords);
}
else
{
ProcessStripedWall(walltop, wallbottom, texcoords);
}
}
void RenderWallPart::ProcessStripedWall(const short* uwal, const short* dwal, const ProjectedWallTexcoords& texcoords)
{
RenderPortal* renderportal = Thread->Portal.get();
ProjectedWallLine most1, most2, most3;
const short* up = uwal;
short* down = most1.ScreenY;
for (unsigned int i = 0; i < lightsector->e->XFloor.lightlist.Size(); i++)
{
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), lightsector->e->XFloor.lightlist[i].plane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
if (j != ProjectedWallCull::OutsideAbove)
{
for (int j = x1; j < x2; ++j)
{
down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]);
}
ProcessNormalWall(up, down, texcoords);
up = down;
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
mLight.SetColormap(lightsector, curline, &lightsector->e->XFloor.lightlist[i]);
}
ProcessNormalWall(up, dwal, texcoords);
}
void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords)
{
int fracbits = 32 - pic->GetHeightBits();
if (fracbits == 32)
{ // Hack for one pixel tall textures
fracbits = 0;
@ -69,7 +132,7 @@ namespace swrenderer
drawerargs.SetTextureFracBits(Thread->Viewport->RenderTarget->IsBgra() ? FRACBITS : fracbits);
// Textures that aren't masked can use the faster opaque drawer
if (!rw_pic->GetTexture()->isMasked() && mask && alpha >= OPAQUE && !additive)
if (!pic->GetTexture()->isMasked() && mask && alpha >= OPAQUE && !additive)
{
drawerargs.SetStyle(true, false, OPAQUE, mLight.GetBaseColormap());
}
@ -114,13 +177,13 @@ namespace swrenderer
if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(texcoords.UPos(x + 1)) - FIXED2DBL(texcoords.UPos(x)));
fixed_t xxoffset = (texcoords.UPos(x) + FLOAT2FIXED(xmagnitude * 0.5)) * rw_pic->GetPhysicalScale();
fixed_t xxoffset = (texcoords.UPos(x) + FLOAT2FIXED(xmagnitude * 0.5)) * pic->GetPhysicalScale();
// Normalize to 0-1 range:
double uv_stepd = texcoords.VStep(x) * texcoords.yscale;
double v = (texcoords.texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / rw_pic->GetHeight();
double v = (texcoords.texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / pic->GetHeight();
v = v - floor(v);
double v_step = uv_stepd / rw_pic->GetHeight();
double v_step = uv_stepd / pic->GetHeight();
if (std::isnan(v) || std::isnan(v_step)) // this should never happen, but it apparently does..
{
@ -141,9 +204,9 @@ namespace swrenderer
bool magnifying = lod < 0.0f;
int mipmap_offset = 0;
int mip_width = rw_pic->GetPhysicalWidth();
int mip_height = rw_pic->GetPhysicalHeight();
if (r_mipmap && rw_pic->Mipmapped() && mip_width > 1 && mip_height > 1)
int mip_width = pic->GetPhysicalWidth();
int mip_height = pic->GetPhysicalHeight();
if (r_mipmap && pic->Mipmapped() && mip_width > 1 && mip_height > 1)
{
uint32_t xpos = (uint32_t)((((uint64_t)xxoffset) << FRACBITS) / mip_width);
@ -158,7 +221,7 @@ namespace swrenderer
xxoffset = (xpos >> FRACBITS) * mip_width;
}
const uint32_t *pixels = rw_pic->GetPixelsBgra() + mipmap_offset;
const uint32_t *pixels = pic->GetPixelsBgra() + mipmap_offset;
const uint8_t *source;
const uint8_t *source2;
@ -208,10 +271,10 @@ namespace swrenderer
}
else
{
uint32_t height = rw_pic->GetPhysicalHeight();
uint32_t height = pic->GetPhysicalHeight();
uint32_t uv_max;
int uv_fracbits = 32 - rw_pic->GetHeightBits();
int uv_fracbits = 32 - pic->GetHeightBits();
if (uv_fracbits != 32)
uv_max = height << uv_fracbits;
@ -230,20 +293,20 @@ namespace swrenderer
uint32_t uv_pos;
uint32_t uv_step;
fixed_t xxoffset = (texcoords.UPos(x) + FLOAT2FIXED(xmagnitude * 0.5)) * rw_pic->GetPhysicalScale();
fixed_t xxoffset = (texcoords.UPos(x) + FLOAT2FIXED(xmagnitude * 0.5)) * pic->GetPhysicalScale();
if (uv_fracbits != 32)
{
// Find start uv in [0-base_height[ range.
// Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range.
double uv_stepd = texcoords.VStep(x) * texcoords.yscale;
double v = (texcoords.texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / rw_pic->GetHeight();
double v = (texcoords.texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / pic->GetHeight();
v = v - floor(v);
v *= height;
v *= (1 << uv_fracbits);
uv_pos = (uint32_t)(int64_t)v;
uv_step = xs_ToFixed(uv_fracbits, uv_stepd * rw_pic->GetPhysicalScale());
uv_step = xs_ToFixed(uv_fracbits, uv_stepd * pic->GetPhysicalScale());
if (uv_step == 0) // To prevent divide by zero elsewhere
uv_step = 1;
}
@ -259,12 +322,12 @@ namespace swrenderer
// If the texture's width isn't a power of 2, then we need to make it a
// positive offset for proper clamping.
int width;
if (col < 0 && (width = rw_pic->GetPhysicalWidth()) != (1 << rw_pic->GetWidthBits()))
if (col < 0 && (width = pic->GetPhysicalWidth()) != (1 << pic->GetWidthBits()))
{
col = width + (col % width);
}
drawerargs.SetTexture(rw_pic->GetColumn(DefaultRenderStyle(), col, nullptr), nullptr, height);
drawerargs.SetTexture(pic->GetColumn(DefaultRenderStyle(), col, nullptr), nullptr, height);
if (haslights)
SetLights(drawerargs, x, y1);
@ -408,154 +471,14 @@ namespace swrenderer
}
}
void RenderWallPart::ProcessStripedWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords)
FLightNode* RenderWallPart::GetLightList()
{
ProjectedWallLine most1, most2, most3;
const short *up;
short *down;
up = uwal;
down = most1.ScreenY;
assert(WallC.sx1 <= x1);
assert(WallC.sx2 >= x2);
RenderPortal *renderportal = Thread->Portal.get();
// kg3D - fake floors instead of zdoom light list
for (unsigned int i = 0; i < frontsector->e->XFloor.lightlist.Size(); i++)
{
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), frontsector->e->XFloor.lightlist[i].plane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
if (j != ProjectedWallCull::OutsideAbove)
{
for (int j = x1; j < x2; ++j)
{
down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]);
}
ProcessNormalWall(up, down, texcoords);
up = down;
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
mLight.SetColormap(frontsector, curline, &frontsector->e->XFloor.lightlist[i]);
}
ProcessNormalWall(up, dwal, texcoords);
}
void RenderWallPart::ProcessWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords)
{
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedColormap() != NULL || cameraLight->FixedLightLevel() >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size()))
{
ProcessNormalWall(uwal, dwal, texcoords);
}
CameraLight* cameraLight = CameraLight::Instance();
if ((cameraLight->FixedLightLevel() >= 0) || cameraLight->FixedColormap())
return nullptr; // [SP] Don't draw dynlights if invul/lightamp active
else if (curline && curline->sidedef)
return curline->sidedef->lighthead;
else
{
ProcessStripedWall(uwal, dwal, texcoords);
}
}
//=============================================================================
//
// ProcessWallNP2
//
// This is a wrapper around ProcessWall that helps it tile textures whose heights
// are not powers of 2. It divides the wall into texture-sized strips and calls
// ProcessNormalWall for each of those. Since only one repetition of the texture fits
// in each strip, ProcessWall will not tile.
//
//=============================================================================
void RenderWallPart::ProcessWallNP2(const short *uwal, const short *dwal, ProjectedWallTexcoords texcoords, double top, double bot)
{
ProjectedWallLine most1, most2, most3;
double texheight = rw_pic->GetHeight();
double partition;
double scaledtexheight = texheight / texcoords.yscale;
if (texcoords.yscale >= 0)
{ // normal orientation: draw strips from top to bottom
partition = top - fmod(top - texcoords.texturemid / texcoords.yscale - Thread->Viewport->viewpoint.Pos.Z, scaledtexheight);
if (partition == top)
{
partition -= scaledtexheight;
}
const short *up = uwal;
short *down = most1.ScreenY;
texcoords.texturemid = (partition - Thread->Viewport->viewpoint.Pos.Z) * texcoords.yscale + texheight;
while (partition > bot)
{
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), partition - Thread->Viewport->viewpoint.Pos.Z, &WallC);
if (j != ProjectedWallCull::OutsideAbove)
{
for (int j = x1; j < x2; ++j)
{
down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]);
}
ProcessWall(up, down, texcoords);
up = down;
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
partition -= scaledtexheight;
texcoords.texturemid -= texheight;
}
ProcessWall(up, dwal, texcoords);
}
else
{ // upside down: draw strips from bottom to top
partition = bot - fmod(bot - texcoords.texturemid / texcoords.yscale - Thread->Viewport->viewpoint.Pos.Z, scaledtexheight);
short *up = most1.ScreenY;
const short *down = dwal;
texcoords.texturemid = (partition - Thread->Viewport->viewpoint.Pos.Z) * texcoords.yscale + texheight;
while (partition < top)
{
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), partition - Thread->Viewport->viewpoint.Pos.Z, &WallC);
if (j != ProjectedWallCull::OutsideBelow)
{
for (int j = x1; j < x2; ++j)
{
up[j] = clamp(most3.ScreenY[j], uwal[j], down[j]);
}
ProcessWall(up, down, texcoords);
down = up;
up = (up == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
partition -= scaledtexheight;
texcoords.texturemid -= texheight;
}
ProcessWall(uwal, down, texcoords);
}
}
void RenderWallPart::Render(sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FSoftwareTexture *pic, int x1, int x2, const short *walltop, const short *wallbottom, const ProjectedWallTexcoords& texcoords, double top, double bottom, bool mask, bool additive, fixed_t alpha, const ProjectedWallLight &light, FLightNode *light_list)
{
this->x1 = x1;
this->x2 = x2;
this->frontsector = frontsector;
this->curline = curline;
this->WallC = WallC;
this->mLight = light;
this->light_list = light_list;
this->rw_pic = pic;
this->mask = mask;
this->additive = additive;
this->alpha = alpha;
Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here.
if (rw_pic->GetHeight() != (1 << rw_pic->GetHeightBits()))
{
ProcessWallNP2(walltop, wallbottom, texcoords, top, bottom);
}
else
{
ProcessWall(walltop, wallbottom, texcoords);
}
}
RenderWallPart::RenderWallPart(RenderThread *thread)
{
Thread = thread;
return nullptr;
}
}

View file

@ -46,36 +46,31 @@ namespace swrenderer
RenderWallPart(RenderThread *thread);
void Render(
sector_t *frontsector,
const sector_t *lightsector,
seg_t *curline,
const FWallCoords &WallC,
FSoftwareTexture *rw_pic,
FSoftwareTexture *pic,
int x1,
int x2,
const short *walltop,
const short *wallbottom,
const ProjectedWallTexcoords &texcoords,
double top,
double bottom,
bool mask,
bool additive,
fixed_t alpha,
const ProjectedWallLight &light,
FLightNode *light_list);
RenderThread *Thread = nullptr;
fixed_t alpha);
private:
void ProcessWallNP2(const short *uwal, const short *dwal, ProjectedWallTexcoords texcoords, double top, double bot);
void ProcessWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords);
void ProcessStripedWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords);
void ProcessNormalWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords);
void SetLights(WallDrawerArgs &drawerargs, int x, int y1);
FLightNode* GetLightList();
RenderThread* Thread = nullptr;
int x1 = 0;
int x2 = 0;
FSoftwareTexture *rw_pic = nullptr;
sector_t *frontsector = nullptr;
FSoftwareTexture *pic = nullptr;
const sector_t *lightsector = nullptr;
seg_t *curline = nullptr;
FWallCoords WallC;

View file

@ -110,8 +110,6 @@ namespace swrenderer
float GetLightStep() const { return lightstep; }
void SetColormap(const sector_t *frontsector, seg_t *lineseg, lightlist_t *lit = nullptr);
void SetLightLeft(float left, float step, int startx) { lightleft = left; lightstep = step; x1 = startx; }
void SetLightLeft(RenderThread *thread, const FWallCoords &wallc);
private:

View file

@ -161,11 +161,9 @@ namespace swrenderer
{
RenderDrawSegment renderer(Thread);
renderer.Render(ds, ds->x1, ds->x2, clip3DFloor);
if (renew)
{
ds->ClearFogBoundary(); // don't draw fogboundary again
ds->drawsegclip.SetRangeUndrawn(ds->x1, ds->x2);
}
}
}
}

View file

@ -51,8 +51,7 @@ namespace swrenderer
struct DrawSegment
{
seg_t *curline;
float light, lightstep;
short x1, x2; // Same as sx1 and sx2, but clipped to the drawseg
short x1, x2;
FWallCoords WallC;
FWallTmapVals tmapvals;
@ -71,8 +70,6 @@ namespace swrenderer
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:
int flags = 0; // 1=backsector, 2=frontsector, 4=midtexture, 8=fogboundary
};

View file

@ -53,19 +53,17 @@
#include "swrenderer/r_memory.h"
#include "swrenderer/r_renderthread.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer
{
void RenderDecal::RenderDecals(RenderThread *thread, side_t *sidedef, DrawSegment *draw_segment, seg_t *curline, const ProjectedWallLight &light, const short *walltop, const short *wallbottom, bool drawsegPass)
void RenderDecal::RenderDecals(RenderThread *thread, DrawSegment *draw_segment, seg_t *curline, const sector_t* lightsector, const short *walltop, const short *wallbottom, bool drawsegPass)
{
for (DBaseDecal *decal = sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext)
for (DBaseDecal *decal = curline->sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext)
{
Render(thread, sidedef, decal, draw_segment, curline, light, walltop, wallbottom, drawsegPass);
Render(thread, decal, draw_segment, curline, lightsector, walltop, wallbottom, drawsegPass);
}
}
void RenderDecal::Render(RenderThread *thread, side_t *wall, DBaseDecal *decal, DrawSegment *clipper, seg_t *curline, const ProjectedWallLight &light, const short *walltop, const short *wallbottom, bool drawsegPass)
void RenderDecal::Render(RenderThread *thread, DBaseDecal *decal, DrawSegment *clipper, seg_t *curline, const sector_t* lightsector, const short *walltop, const short *wallbottom, bool drawsegPass)
{
DVector2 decal_left, decal_right, decal_pos;
int x1, x2;
@ -142,7 +140,7 @@ namespace swrenderer
edge_left *= decal->ScaleX;
double dcx, dcy;
decal->GetXY(wall, dcx, dcy);
decal->GetXY(curline->sidedef, dcx, dcy);
decal_pos = { dcx, dcy };
DVector2 angvec = (curline->v2->fPos() - curline->v1->fPos()).Unit();
@ -231,6 +229,9 @@ namespace swrenderer
}
// Prepare lighting
ProjectedWallLight light;
light.SetColormap(lightsector, curline);
light.SetLightLeft(thread, WallC);
usecolormap = light.GetBaseColormap();
// Decals that are added to the scene must fade to black.

View file

@ -12,9 +12,9 @@ namespace swrenderer
class RenderDecal
{
public:
static void RenderDecals(RenderThread *thread, side_t *wall, DrawSegment *draw_segment, seg_t *curline, const ProjectedWallLight &light, const short *walltop, const short *wallbottom, bool drawsegPass);
static void RenderDecals(RenderThread *thread, DrawSegment *draw_segment, seg_t *curline, const sector_t* lightsector, const short *walltop, const short *wallbottom, bool drawsegPass);
private:
static void Render(RenderThread *thread, side_t *wall, DBaseDecal *first, DrawSegment *clipper, seg_t *curline, const ProjectedWallLight &light, const short *walltop, const short *wallbottom, bool drawsegPass);
static void Render(RenderThread *thread, DBaseDecal *first, DrawSegment *clipper, seg_t *curline, const sector_t* lightsector, const short *walltop, const short *wallbottom, bool drawsegPass);
};
}