- 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:
parent
1085287af1
commit
236b476933
16 changed files with 676 additions and 845 deletions
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue