- change ProjectedWallTexcoords to use gradients for its texture coordinate calculations

- change SpriteDrawerArgs to draw a full sprite instead of one column at a time
- add r_noaccel cvar to allow forced software rendering of the psprites (useful for debugging and also one person on the forum actually requested this feature)
- remove FWallTmapVals and calculate texture coordinates directly from FWallCoords
- move portal clipping out of the inner sprite drawing loop
This commit is contained in:
Magnus Norddahl 2019-11-20 04:50:24 +01:00
commit 236b476933
16 changed files with 676 additions and 845 deletions

View file

@ -48,6 +48,107 @@
namespace swrenderer
{
// Transform and clip coordinates. Returns true if it was clipped away
bool FWallCoords::Init(RenderThread* thread, const DVector2& pt1, const DVector2& pt2, seg_t* lineseg)
{
auto viewport = thread->Viewport.get();
RenderPortal* renderportal = thread->Portal.get();
tleft.X = float(pt1.X * viewport->viewpoint.Sin - pt1.Y * viewport->viewpoint.Cos);
tright.X = float(pt2.X * viewport->viewpoint.Sin - pt2.Y * viewport->viewpoint.Cos);
tleft.Y = float(pt1.X * viewport->viewpoint.TanCos + pt1.Y * viewport->viewpoint.TanSin);
tright.Y = float(pt2.X * viewport->viewpoint.TanCos + pt2.Y * viewport->viewpoint.TanSin);
if (renderportal->MirrorFlags & RF_XFLIP)
{
float t = -tleft.X;
tleft.X = -tright.X;
tright.X = t;
swapvalues(tleft.Y, tright.Y);
}
float fsx1, fsz1, fsx2, fsz2;
if (tleft.X >= -tleft.Y)
{
if (tleft.X > tleft.Y) return true; // left edge is off the right side
if (tleft.Y == 0) return true;
fsx1 = viewport->CenterX + tleft.X * viewport->CenterX / tleft.Y;
fsz1 = tleft.Y;
tx1 = 0.0f;
}
else
{
if (tright.X < -tright.Y) return true; // wall is off the left side
float den = tleft.X - tright.X - tright.Y + tleft.Y;
if (den == 0) return true;
fsx1 = 0;
tx1 = (tleft.X + tleft.Y) / den;
fsz1 = tleft.Y + (tright.Y - tleft.Y) * tx1;
}
if (fsz1 < TOO_CLOSE_Z)
return true;
if (tright.X <= tright.Y)
{
if (tright.X < -tright.Y) return true; // right edge is off the left side
if (tright.Y == 0) return true;
fsx2 = viewport->CenterX + tright.X * viewport->CenterX / tright.Y;
fsz2 = tright.Y;
tx2 = 1.0f;
}
else
{
if (tleft.X > tleft.Y) return true; // wall is off the right side
float den = tright.Y - tleft.Y - tright.X + tleft.X;
if (den == 0) return true;
fsx2 = viewwidth;
tx2 = (tleft.X - tleft.Y) / den;
fsz2 = tleft.Y + (tright.Y - tleft.Y) * tx2;
}
if (fsz2 < TOO_CLOSE_Z)
return true;
sx1 = xs_RoundToInt(fsx1);
sx2 = xs_RoundToInt(fsx2);
float delta = fsx2 - fsx1;
float t1 = (sx1 + 0.5f - fsx1) / delta;
float t2 = (sx2 + 0.5f - fsx1) / delta;
float invZ1 = 1.0f / fsz1;
float invZ2 = 1.0f / fsz2;
sz1 = 1.0f / (invZ1 * (1.0f - t1) + invZ2 * t1);
sz2 = 1.0f / (invZ1 * (1.0f - t2) + invZ2 * t2);
if (sx2 <= sx1)
return true;
if (lineseg && lineseg->linedef)
{
line_t* line = lineseg->linedef;
if (fabs(line->delta.X) > fabs(line->delta.Y))
{
t1 = (lineseg->v1->fX() - line->v1->fX()) / line->delta.X;
t2 = (lineseg->v2->fX() - line->v1->fX()) / line->delta.X;
}
else
{
t1 = (lineseg->v1->fY() - line->v1->fY()) / line->delta.Y;
t2 = (lineseg->v2->fY() - line->v1->fY()) / line->delta.Y;
}
tx1 = t1 + tx1 * (t2 - t1);
tx2 = t1 + tx2 * (t2 - t1);
}
return false;
}
////////////////////////////////////////////////////////////////////////////
ProjectedWallCull ProjectedWallLine::Project(RenderViewport *viewport, double z, const FWallCoords *wallc)
{
return Project(viewport, z, z, wallc);
@ -186,58 +287,7 @@ namespace swrenderer
/////////////////////////////////////////////////////////////////////////
void FWallTmapVals::InitFromWallCoords(RenderThread* thread, const FWallCoords* wallc)
{
const FVector2* left = &wallc->tleft;
const FVector2* right = &wallc->tright;
if (thread->Portal->MirrorFlags & RF_XFLIP)
{
swapvalues(left, right);
}
UoverZorg = left->X * thread->Viewport->CenterX;
UoverZstep = -left->Y;
InvZorg = (left->X - right->X) * thread->Viewport->CenterX;
InvZstep = right->Y - left->Y;
}
void FWallTmapVals::InitFromLine(RenderThread* thread, seg_t* line)
{
auto viewport = thread->Viewport.get();
auto renderportal = thread->Portal.get();
vertex_t* v1 = line->linedef->v1;
vertex_t* v2 = line->linedef->v2;
if (line->linedef->sidedef[0] != line->sidedef)
{
swapvalues(v1, v2);
}
DVector2 left = v1->fPos() - viewport->viewpoint.Pos;
DVector2 right = v2->fPos() - viewport->viewpoint.Pos;
double viewspaceX1 = left.X * viewport->viewpoint.Sin - left.Y * viewport->viewpoint.Cos;
double viewspaceX2 = right.X * viewport->viewpoint.Sin - right.Y * viewport->viewpoint.Cos;
double viewspaceY1 = left.X * viewport->viewpoint.TanCos + left.Y * viewport->viewpoint.TanSin;
double viewspaceY2 = right.X * viewport->viewpoint.TanCos + right.Y * viewport->viewpoint.TanSin;
if (renderportal->MirrorFlags & RF_XFLIP)
{
viewspaceX1 = -viewspaceX1;
viewspaceX2 = -viewspaceX2;
}
UoverZorg = float(viewspaceX1 * viewport->CenterX);
UoverZstep = float(-viewspaceY1);
InvZorg = float((viewspaceX1 - viewspaceX2) * viewport->CenterX);
InvZstep = float(viewspaceY2 - viewspaceY1);
}
/////////////////////////////////////////////////////////////////////////
void ProjectedWallTexcoords::ProjectTop(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
void ProjectedWallTexcoords::ProjectTop(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
@ -269,12 +319,12 @@ namespace swrenderer
}
texturemid += GetRowOffset(lineseg, pic, side_t::top);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::top), x1, x2, WallT);
xoffset = GetXOffset(lineseg, pic, side_t::top);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::top), WallC, pic, false);
}
void ProjectedWallTexcoords::ProjectMid(RenderViewport* viewport, sector_t* frontsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
void ProjectedWallTexcoords::ProjectMid(RenderViewport* viewport, sector_t* frontsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
@ -306,12 +356,12 @@ namespace swrenderer
}
texturemid += GetRowOffset(lineseg, pic, side_t::mid);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::mid), x1, x2, WallT);
xoffset = GetXOffset(lineseg, pic, side_t::mid);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::mid), WallC, pic, false);
}
void ProjectedWallTexcoords::ProjectBottom(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
void ProjectedWallTexcoords::ProjectBottom(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
@ -351,12 +401,12 @@ namespace swrenderer
}
texturemid += GetRowOffset(lineseg, pic, side_t::bottom);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::bottom), x1, x2, WallT);
xoffset = GetXOffset(lineseg, pic, side_t::bottom);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::bottom), WallC, pic, false);
}
void ProjectedWallTexcoords::ProjectTranslucent(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
void ProjectedWallTexcoords::ProjectTranslucent(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
line_t* linedef = lineseg->linedef;
side_t* sidedef = lineseg->sidedef;
@ -391,12 +441,12 @@ namespace swrenderer
}
texturemid += GetRowOffset(lineseg, pic, side_t::mid);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::mid), x1, x2, WallT);
xoffset = GetXOffset(lineseg, pic, side_t::mid);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::mid), WallC, pic, false);
}
void ProjectedWallTexcoords::Project3DFloor(RenderViewport* viewport, F3DFloor* rover, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
void ProjectedWallTexcoords::Project3DFloor(RenderViewport* viewport, F3DFloor* rover, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
// find positioning
side_t* scaledside;
@ -445,35 +495,89 @@ namespace swrenderer
texturemid += rowoffset;
}
Project(viewport, lineseg->sidedef->TexelLength * xscale, x1, x2, WallT);
Project(viewport, lineseg->sidedef->TexelLength * xscale, WallC, pic, false);
}
void ProjectedWallTexcoords::ProjectSprite(RenderViewport* viewport, double topZ, double scale, bool flipX, bool flipY, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
void ProjectedWallTexcoords::Project(RenderViewport *viewport, double walxrepeat, const FWallCoords& WallC, FSoftwareTexture* pic, bool flipx)
{
yscale = 1.0 / scale;
texturemid = pic->GetTopOffset(0) + (topZ - viewport->viewpoint.Pos.Z) * yscale;
if (flipY)
float texwidth = pic->GetWidth();
float texheight = pic->GetHeight();
float texU1 = FIXED2FLOAT(xoffset) / texwidth;
float texU2 = texU1 + walxrepeat / texwidth;
if (walxrepeat < 0.0)
{
yscale = -yscale;
texturemid -= pic->GetHeight();
texU1 += 1.0f;
texU2 += 1.0f;
}
if (flipx)
{
texU1 = 1.0f - texU1;
texU2 = 1.0f - texU2;
}
Project(viewport, pic->GetWidth(), x1, x2, WallT, flipX);
}
void ProjectedWallTexcoords::Project(RenderViewport *viewport, double walxrepeat, int x1, int x2, const FWallTmapVals &WallT, bool flipx)
{
this->walxrepeat = walxrepeat;
this->x1 = x1;
this->x2 = x2;
this->WallT = WallT;
this->flipx = flipx;
CenterX = viewport->CenterX;
WallTMapScale2 = viewport->WallTMapScale2;
float texV = texturemid / texheight;
// Set up some fake vertices as that makes it easier to calculate the gradients using code already known to work.
Vertex v1;
v1.x = WallC.sx1 + 0.5f;// WallC.tleft.X;
v1.y = 0.0f;
v1.w = WallC.sz1;//WallC.tleft.Y;
Vertex v2;
v2.x = WallC.sx2 + 0.5f;// WallC.tright.X;
v2.y = 0.0f;
v2.w = WallC.sz2;// WallC.tright.Y;
v1.u = texU1 * (1.0f - WallC.tx1) + texU2 * WallC.tx1;
v2.u = texU1 * (1.0f - WallC.tx2) + texU2 * WallC.tx2;
v1.v = texV;
v2.v = texV;
Vertex v3;
v3.x = v1.x;
v3.y = v1.y - 100.0f;
v3.w = v1.w;
v3.u = v1.u;
v3.v = v1.v + 1.0f / yscale * 100.0f / texheight;
// Project to screen space
v1.w = 1.0f / v1.w;
v2.w = 1.0f / v2.w;
v3.w = 1.0f / v3.w;
//v1.x = viewport->CenterX + v1.x * v1.w * viewport->CenterX;
//v2.x = viewport->CenterX + v2.x * v2.w * viewport->CenterX;
//v3.x = viewport->CenterX + v3.x * v3.w * viewport->CenterX;
v1.y = viewport->CenterY - v1.y * v1.w * viewport->InvZtoScale;
v2.y = viewport->CenterY - v2.y * v2.w * viewport->InvZtoScale;
v3.y = viewport->CenterY - v3.y * v3.w * viewport->InvZtoScale;
// Calculate gradients
float bottomX = (v2.x - v3.x) * (v1.y - v3.y) - (v1.x - v3.x) * (v2.y - v3.y);
float bottomY = (v1.x - v3.x) * (v2.y - v3.y) - (v2.x - v3.x) * (v1.y - v3.y);
wstepX = FindGradientX(bottomX, 1.0f, 1.0f, 1.0f, v1, v2, v3);
ustepX = FindGradientX(bottomX, v1.u, v2.u, v3.u, v1, v2, v3);
vstepX = FindGradientX(bottomX, v1.v, v2.v, v3.v, v1, v2, v3);
wstepY = FindGradientY(bottomY, 1.0f, 1.0f, 1.0f, v1, v2, v3);
ustepY = FindGradientY(bottomY, v1.u, v2.u, v3.u, v1, v2, v3);
vstepY = FindGradientY(bottomY, v1.v, v2.v, v3.v, v1, v2, v3);
startX = v1.x;
upos = v1.u * v1.w;
vpos = v1.v * v1.w;
wpos = v1.w;
}
#if 0
float ProjectedWallTexcoords::VStep(int x) const
{
return 0.0001f;
/*
float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX);
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX);
float uGradient = WallT.UoverZstep;
@ -483,10 +587,13 @@ namespace swrenderer
float u = (uOverZ + uGradient * (x - x1)) / (invZ + zGradient * (x - x1));
return depthOrg + u * depthScale;
*/
}
fixed_t ProjectedWallTexcoords::UPos(int x) const
{
return 0;
/*
float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX);
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX);
float uGradient = WallT.UoverZstep;
@ -510,7 +617,9 @@ namespace swrenderer
}
return value + xoffset;
*/
}
#endif
double ProjectedWallTexcoords::GetRowOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart)
{
@ -584,6 +693,8 @@ namespace swrenderer
void ProjectedWallLight::SetLightLeft(RenderThread *thread, const FWallCoords &wallc)
{
spritelight = false;
x1 = wallc.sx1;
CameraLight *cameraLight = CameraLight::Instance();