mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-11 15:22:15 +00:00
- 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 679 additions and 848 deletions
|
@ -81,7 +81,7 @@ namespace swrenderer
|
|||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
return;
|
||||
|
||||
if (WallC.Init(Thread, pt1, pt2, 32.0 / (1 << 12)))
|
||||
if (WallC.Init(Thread, pt1, pt2, line))
|
||||
return;
|
||||
|
||||
RenderPortal *renderportal = Thread->Portal.get();
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace swrenderer
|
|||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
return;
|
||||
|
||||
if (WallC.Init(Thread, pt1, pt2, 32.0 / (1 << 12)))
|
||||
if (WallC.Init(Thread, pt1, pt2, line))
|
||||
return;
|
||||
|
||||
RenderPortal *renderportal = Thread->Portal.get();
|
||||
|
@ -108,8 +108,6 @@ namespace swrenderer
|
|||
if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos))
|
||||
return;
|
||||
|
||||
WallT.InitFromLine(Thread, line);
|
||||
|
||||
mFrontCeilingZ1 = mFrontSector->ceilingplane.ZatPoint(line->v1);
|
||||
mFrontFloorZ1 = mFrontSector->floorplane.ZatPoint(line->v1);
|
||||
mFrontCeilingZ2 = mFrontSector->ceilingplane.ZatPoint(line->v2);
|
||||
|
@ -306,7 +304,6 @@ namespace swrenderer
|
|||
|
||||
draw_segment->drawsegclip.CurrentPortalUniq = renderportal->CurrentPortalUniq;
|
||||
draw_segment->WallC = WallC;
|
||||
draw_segment->tmapvals = WallT;
|
||||
draw_segment->x1 = start;
|
||||
draw_segment->x2 = stop;
|
||||
draw_segment->curline = mLineSegment;
|
||||
|
@ -396,7 +393,7 @@ namespace swrenderer
|
|||
if (pic)
|
||||
{
|
||||
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, pic);
|
||||
draw_segment->drawsegclip.silhouette |= SIL_TOP | SIL_BOTTOM;
|
||||
}
|
||||
}
|
||||
|
@ -878,7 +875,7 @@ namespace swrenderer
|
|||
if (!viewactive) return;
|
||||
|
||||
ProjectedWallTexcoords texcoords;
|
||||
texcoords.ProjectTop(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mTopTexture);
|
||||
texcoords.ProjectTop(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC, mTopTexture);
|
||||
|
||||
RenderWallPart renderWallpart(Thread);
|
||||
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mTopTexture, x1, x2, walltop.ScreenY, wallupper.ScreenY, texcoords, false, false, OPAQUE);
|
||||
|
@ -890,7 +887,7 @@ namespace swrenderer
|
|||
if (!viewactive) return;
|
||||
|
||||
ProjectedWallTexcoords texcoords;
|
||||
texcoords.ProjectMid(Thread->Viewport.get(), mFrontSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mMiddleTexture);
|
||||
texcoords.ProjectMid(Thread->Viewport.get(), mFrontSector, mLineSegment, WallC, mMiddleTexture);
|
||||
|
||||
RenderWallPart renderWallpart(Thread);
|
||||
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mMiddleTexture, x1, x2, walltop.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE);
|
||||
|
@ -903,85 +900,9 @@ namespace swrenderer
|
|||
if (!viewactive) return;
|
||||
|
||||
ProjectedWallTexcoords texcoords;
|
||||
texcoords.ProjectBottom(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mBottomTexture);
|
||||
texcoords.ProjectBottom(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC, mBottomTexture);
|
||||
|
||||
RenderWallPart renderWallpart(Thread);
|
||||
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mBottomTexture, x1, x2, walllower.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Transform and clip coordinates. Returns true if it was clipped away
|
||||
bool FWallCoords::Init(RenderThread *thread, const DVector2 &pt1, const DVector2 &pt2, double too_close)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
fsz1 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X + tleft.Y) / den;
|
||||
}
|
||||
|
||||
if (fsz1 < too_close)
|
||||
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;
|
||||
}
|
||||
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;
|
||||
fsz2 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X - tleft.Y) / den;
|
||||
}
|
||||
|
||||
if (fsz2 < too_close)
|
||||
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);
|
||||
|
||||
return sx2 <= sx1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,17 +39,6 @@ namespace swrenderer
|
|||
class RenderThread;
|
||||
struct VisiblePlane;
|
||||
|
||||
struct FWallCoords
|
||||
{
|
||||
FVector2 tleft; // coords at left of wall in view space rx1,ry1
|
||||
FVector2 tright; // coords at right of wall in view space rx2,ry2
|
||||
|
||||
float sz1, sz2; // depth at left, right of wall in screen space yb1,yb2
|
||||
short sx1, sx2; // x coords at left, right of wall in screen space xb1,xb2
|
||||
|
||||
bool Init(RenderThread *thread, const DVector2 &pt1, const DVector2 &pt2, double too_close);
|
||||
};
|
||||
|
||||
class SWRenderLine : VisibleSegmentRenderer
|
||||
{
|
||||
public:
|
||||
|
@ -107,7 +96,6 @@ namespace swrenderer
|
|||
bool mDoorClosed;
|
||||
|
||||
FWallCoords WallC;
|
||||
FWallTmapVals WallT;
|
||||
|
||||
// Wall segment variables:
|
||||
|
||||
|
|
|
@ -218,7 +218,7 @@ namespace swrenderer
|
|||
walllower.ClipBottom(x1, x2, ds->drawsegclip);
|
||||
|
||||
ProjectedWallTexcoords walltexcoords;
|
||||
walltexcoords.Project3DFloor(Thread->Viewport.get(), rover, curline, ds->WallC.sx1, ds->WallC.sx2, ds->tmapvals, rw_pic);
|
||||
walltexcoords.Project3DFloor(Thread->Viewport.get(), rover, curline, ds->WallC, rw_pic);
|
||||
|
||||
RenderWallPart renderWallpart(Thread);
|
||||
renderWallpart.Render(lightsector, curline, ds->WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, walltexcoords, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha);
|
||||
|
|
|
@ -120,16 +120,117 @@ namespace swrenderer
|
|||
ProcessNormalWall(up, dwal, texcoords);
|
||||
}
|
||||
|
||||
void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords)
|
||||
static void DrawWallColumn32(RenderThread* thread, WallDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepX, uint32_t texelStepY, FSoftwareTexture* pic, int texwidth, int texheight)
|
||||
{
|
||||
int fracbits = 32 - pic->GetHeightBits();
|
||||
if (fracbits == 32)
|
||||
{ // Hack for one pixel tall textures
|
||||
fracbits = 0;
|
||||
double xmagnitude = fabs(static_cast<int32_t>(texelStepX) * (1.0 / 0x1'0000'0000LL));
|
||||
double ymagnitude = fabs(static_cast<int32_t>(texelStepY) * (1.0 / 0x1'0000'0000LL));
|
||||
double magnitude = MAX(ymagnitude, xmagnitude);
|
||||
double min_lod = -1000.0;
|
||||
double lod = MAX(log2(magnitude) + r_lod_bias, min_lod);
|
||||
bool magnifying = lod < 0.0f;
|
||||
|
||||
int mipmap_offset = 0;
|
||||
int mip_width = texwidth;
|
||||
int mip_height = texheight;
|
||||
if (r_mipmap && pic->Mipmapped() && mip_width > 1 && mip_height > 1)
|
||||
{
|
||||
int level = (int)lod;
|
||||
while (level > 0 && mip_width > 1 && mip_height > 1)
|
||||
{
|
||||
mipmap_offset += mip_width * mip_height;
|
||||
level--;
|
||||
mip_width = MAX(mip_width >> 1, 1);
|
||||
mip_height = MAX(mip_height >> 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t* pixels = pic->GetPixelsBgra() + mipmap_offset;
|
||||
fixed_t xxoffset = (texelX >> 16) * mip_width;
|
||||
|
||||
const uint8_t* source;
|
||||
const uint8_t* source2;
|
||||
uint32_t texturefracx;
|
||||
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
|
||||
if (filter_nearest)
|
||||
{
|
||||
int tx = (xxoffset >> FRACBITS) % mip_width;
|
||||
source = (uint8_t*)(pixels + tx * mip_height);
|
||||
source2 = nullptr;
|
||||
texturefracx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xxoffset -= FRACUNIT / 2;
|
||||
int tx0 = (xxoffset >> FRACBITS) % mip_width;
|
||||
if (tx0 < 0)
|
||||
tx0 += mip_width;
|
||||
int tx1 = (tx0 + 1) % mip_width;
|
||||
source = (uint8_t*)(pixels + tx0 * mip_height);
|
||||
source2 = (uint8_t*)(pixels + tx1 * mip_height);
|
||||
texturefracx = (xxoffset >> (FRACBITS - 4)) & 15;
|
||||
}
|
||||
|
||||
int count = y2 - y1;
|
||||
drawerargs.SetDest(thread->Viewport.get(), x, y1);
|
||||
drawerargs.SetCount(count);
|
||||
drawerargs.SetTexture(source, source2, mip_height);
|
||||
drawerargs.SetTextureUPos(texturefracx);
|
||||
drawerargs.SetTextureVPos(texelY);
|
||||
drawerargs.SetTextureVStep(texelStepY);
|
||||
drawerargs.DrawColumn(thread);
|
||||
}
|
||||
|
||||
static void DrawWallColumn8(RenderThread* thread, WallDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepY, FSoftwareTexture* pic, int texwidth, int texheight, int fracbits, uint32_t uv_max)
|
||||
{
|
||||
texelY = (static_cast<uint64_t>(texelY)* texheight) >> (32 - fracbits);
|
||||
texelStepY = (static_cast<uint64_t>(texelStepY)* texheight) >> (32 - fracbits);
|
||||
|
||||
const uint8_t* pixels = pic->GetColumn(DefaultRenderStyle(), ((texelX >> 16)* texwidth) >> 16, nullptr);
|
||||
|
||||
drawerargs.SetTexture(pixels, nullptr, texheight);
|
||||
drawerargs.SetTextureVStep(texelStepY);
|
||||
|
||||
if (uv_max == 0 || texelStepY == 0) // power of two
|
||||
{
|
||||
int count = y2 - y1;
|
||||
|
||||
drawerargs.SetDest(thread->Viewport.get(), x, y1);
|
||||
drawerargs.SetCount(count);
|
||||
drawerargs.SetTextureVPos(texelY);
|
||||
drawerargs.DrawColumn(thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t left = y2 - y1;
|
||||
int y = y1;
|
||||
while (left > 0)
|
||||
{
|
||||
uint32_t available = uv_max - texelY;
|
||||
uint32_t next_uv_wrap = available / texelStepY;
|
||||
if (available % texelStepY != 0)
|
||||
next_uv_wrap++;
|
||||
uint32_t count = MIN(left, next_uv_wrap);
|
||||
|
||||
drawerargs.SetDest(thread->Viewport.get(), x, y);
|
||||
drawerargs.SetCount(count);
|
||||
drawerargs.SetTextureVPos(texelY);
|
||||
drawerargs.DrawColumn(thread);
|
||||
|
||||
y += count;
|
||||
left -= count;
|
||||
texelY += texelStepY * count;
|
||||
if (texelY >= uv_max)
|
||||
texelY -= uv_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWallPart::ProcessNormalWall(const short* uwal, const short* dwal, const ProjectedWallTexcoords& texcoords)
|
||||
{
|
||||
CameraLight* cameraLight = CameraLight::Instance();
|
||||
RenderViewport* viewport = Thread->Viewport.get();
|
||||
|
||||
WallDrawerArgs drawerargs;
|
||||
drawerargs.SetTextureFracBits(Thread->Viewport->RenderTarget->IsBgra() ? FRACBITS : fracbits);
|
||||
|
||||
// Textures that aren't masked can use the faster opaque drawer
|
||||
if (!pic->GetTexture()->isMasked() && mask && alpha >= OPAQUE && !additive)
|
||||
|
@ -141,13 +242,9 @@ namespace swrenderer
|
|||
drawerargs.SetStyle(mask, additive, alpha, mLight.GetBaseColormap());
|
||||
}
|
||||
|
||||
RenderViewport *viewport = Thread->Viewport.get();
|
||||
|
||||
CameraLight *cameraLight = CameraLight::Instance();
|
||||
bool fixed = (cameraLight->FixedColormap() || cameraLight->FixedLightLevel() >= 0);
|
||||
|
||||
bool haslights = r_dynlights && light_list;
|
||||
|
||||
if (haslights)
|
||||
{
|
||||
float dx = WallC.tright.X - WallC.tleft.X;
|
||||
|
@ -158,218 +255,73 @@ namespace swrenderer
|
|||
drawerargs.dc_normal.Z = 0.0f;
|
||||
}
|
||||
|
||||
double xmagnitude = 1.0;
|
||||
int texwidth = pic->GetPhysicalWidth();
|
||||
int texheight = pic->GetPhysicalHeight();
|
||||
|
||||
int fracbits = 32 - pic->GetHeightBits();
|
||||
if (fracbits == 32) fracbits = 0; // One pixel tall textures
|
||||
if (viewport->RenderTarget->IsBgra()) fracbits = 32;
|
||||
drawerargs.SetTextureFracBits(fracbits);
|
||||
|
||||
uint32_t uv_max;
|
||||
int uv_fracbits = 32 - pic->GetHeightBits();
|
||||
if (uv_fracbits != 32)
|
||||
uv_max = texheight << uv_fracbits;
|
||||
|
||||
float curlight = mLight.GetLightPos(x1);
|
||||
float lightstep = mLight.GetLightStep();
|
||||
|
||||
if (viewport->RenderTarget->IsBgra())
|
||||
float upos = texcoords.upos, ustepX = texcoords.ustepX, ustepY = texcoords.ustepY;
|
||||
float vpos = texcoords.vpos, vstepX = texcoords.vstepX, vstepY = texcoords.vstepY;
|
||||
float wpos = texcoords.wpos, wstepX = texcoords.wstepX, wstepY = texcoords.wstepY;
|
||||
float startX = texcoords.startX;
|
||||
|
||||
upos += ustepX * (x1 + 0.5f - startX);
|
||||
vpos += vstepX * (x1 + 0.5f - startX);
|
||||
wpos += wstepX * (x1 + 0.5f - startX);
|
||||
|
||||
float centerY = Thread->Viewport->CenterY;
|
||||
centerY -= 0.5f;
|
||||
|
||||
for (int x = x1; x < x2; x++)
|
||||
{
|
||||
for (int x = x1; x < x2; x++, curlight += lightstep)
|
||||
int y1 = uwal[x];
|
||||
int y2 = dwal[x];
|
||||
if (y2 > y1)
|
||||
{
|
||||
int y1 = uwal[x];
|
||||
int y2 = dwal[x];
|
||||
if (y2 <= y1)
|
||||
continue;
|
||||
|
||||
if (!fixed)
|
||||
drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport);
|
||||
|
||||
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)) * 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)) / pic->GetHeight();
|
||||
v = v - floor(v);
|
||||
double v_step = uv_stepd / pic->GetHeight();
|
||||
|
||||
if (std::isnan(v) || std::isnan(v_step)) // this should never happen, but it apparently does..
|
||||
{
|
||||
uv_stepd = 0.0;
|
||||
v = 0.0;
|
||||
v_step = 0.0;
|
||||
}
|
||||
|
||||
// Convert to uint32_t:
|
||||
uint32_t uv_pos = (uint32_t)(int64_t)(v * 0x100000000LL);
|
||||
uint32_t uv_step = (uint32_t)(int64_t)(v_step * 0x100000000LL);
|
||||
|
||||
// Texture mipmap and filter selection:
|
||||
double ymagnitude = fabs(uv_stepd);
|
||||
double magnitude = MAX(ymagnitude, xmagnitude);
|
||||
double min_lod = -1000.0;
|
||||
double lod = MAX(log2(magnitude) + r_lod_bias, min_lod);
|
||||
bool magnifying = lod < 0.0f;
|
||||
|
||||
int mipmap_offset = 0;
|
||||
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);
|
||||
|
||||
int level = (int)lod;
|
||||
while (level > 0 && mip_width > 1 && mip_height > 1)
|
||||
{
|
||||
mipmap_offset += mip_width * mip_height;
|
||||
level--;
|
||||
mip_width = MAX(mip_width >> 1, 1);
|
||||
mip_height = MAX(mip_height >> 1, 1);
|
||||
}
|
||||
xxoffset = (xpos >> FRACBITS) * mip_width;
|
||||
}
|
||||
|
||||
const uint32_t *pixels = pic->GetPixelsBgra() + mipmap_offset;
|
||||
|
||||
const uint8_t *source;
|
||||
const uint8_t *source2;
|
||||
uint32_t texturefracx;
|
||||
uint32_t height;
|
||||
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
|
||||
if (filter_nearest)
|
||||
{
|
||||
int tx = (xxoffset >> FRACBITS) % mip_width;
|
||||
if (tx < 0)
|
||||
tx += mip_width;
|
||||
source = (uint8_t*)(pixels + tx * mip_height);
|
||||
source2 = nullptr;
|
||||
height = mip_height;
|
||||
texturefracx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xxoffset -= FRACUNIT / 2;
|
||||
int tx0 = (xxoffset >> FRACBITS) % mip_width;
|
||||
if (tx0 < 0)
|
||||
tx0 += mip_width;
|
||||
int tx1 = (tx0 + 1) % mip_width;
|
||||
source = (uint8_t*)(pixels + tx0 * mip_height);
|
||||
source2 = (uint8_t*)(pixels + tx1 * mip_height);
|
||||
height = mip_height;
|
||||
texturefracx = (xxoffset >> (FRACBITS - 4)) & 15;
|
||||
}
|
||||
|
||||
drawerargs.SetTexture(source, source2, height);
|
||||
|
||||
if (!fixed) drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport);
|
||||
if (haslights)
|
||||
SetLights(drawerargs, x, y1);
|
||||
else
|
||||
drawerargs.dc_num_lights = 0;
|
||||
|
||||
drawerargs.SetTextureUPos(texturefracx);
|
||||
drawerargs.SetTextureVStep(uv_step);
|
||||
float dy = (y1 - centerY);
|
||||
float u = upos + ustepY * dy;
|
||||
float v = vpos + vstepY * dy;
|
||||
float w = wpos + wstepY * dy;
|
||||
float scaleU = ustepX;
|
||||
float scaleV = vstepY;
|
||||
w = 1.0f / w;
|
||||
u *= w;
|
||||
v *= w;
|
||||
scaleU *= w;
|
||||
scaleV *= w;
|
||||
|
||||
int count = y2 - y1;
|
||||
uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL);
|
||||
uint32_t texelY = (uint32_t)(int64_t)((v - std::floor(v)) * 0x1'0000'0000LL);
|
||||
uint32_t texelStepX = (uint32_t)(int64_t)(scaleU * 0x1'0000'0000LL);
|
||||
uint32_t texelStepY = (uint32_t)(int64_t)(scaleV * 0x1'0000'0000LL);
|
||||
|
||||
drawerargs.SetDest(viewport, x, y1);
|
||||
drawerargs.SetCount(count);
|
||||
drawerargs.SetTextureVPos(uv_pos);
|
||||
drawerargs.DrawColumn(Thread);
|
||||
if (fracbits != 32)
|
||||
DrawWallColumn8(Thread, drawerargs, x, y1, y2, texelX, texelY, texelStepY, pic, texwidth, texheight, fracbits, uv_max);
|
||||
else
|
||||
DrawWallColumn32(Thread, drawerargs, x, y1, y2, texelX, texelY, texelStepX, texelStepY, pic, texwidth, texheight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t height = pic->GetPhysicalHeight();
|
||||
|
||||
uint32_t uv_max;
|
||||
int uv_fracbits = 32 - pic->GetHeightBits();
|
||||
if (uv_fracbits != 32)
|
||||
uv_max = height << uv_fracbits;
|
||||
|
||||
for (int x = x1; x < x2; x++, curlight += lightstep)
|
||||
{
|
||||
int y1 = uwal[x];
|
||||
int y2 = dwal[x];
|
||||
if (y2 <= y1)
|
||||
continue;
|
||||
|
||||
if (!fixed)
|
||||
drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport);
|
||||
|
||||
if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(texcoords.UPos(x + 1)) - FIXED2DBL(texcoords.UPos(x)));
|
||||
|
||||
uint32_t uv_pos;
|
||||
uint32_t uv_step;
|
||||
|
||||
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)) / 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 * pic->GetPhysicalScale());
|
||||
if (uv_step == 0) // To prevent divide by zero elsewhere
|
||||
uv_step = 1;
|
||||
}
|
||||
else
|
||||
{ // Hack for one pixel tall textures
|
||||
uv_pos = 0;
|
||||
uv_step = 0;
|
||||
uv_max = 1;
|
||||
}
|
||||
|
||||
int col = xxoffset >> FRACBITS;
|
||||
|
||||
// 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 = pic->GetPhysicalWidth()) != (1 << pic->GetWidthBits()))
|
||||
{
|
||||
col = width + (col % width);
|
||||
}
|
||||
|
||||
drawerargs.SetTexture(pic->GetColumn(DefaultRenderStyle(), col, nullptr), nullptr, height);
|
||||
|
||||
if (haslights)
|
||||
SetLights(drawerargs, x, y1);
|
||||
else
|
||||
drawerargs.dc_num_lights = 0;
|
||||
|
||||
drawerargs.SetTextureVStep(uv_step);
|
||||
|
||||
if (uv_max == 0 || uv_step == 0) // power of two
|
||||
{
|
||||
int count = y2 - y1;
|
||||
|
||||
drawerargs.SetDest(viewport, x, y1);
|
||||
drawerargs.SetCount(count);
|
||||
drawerargs.SetTextureVPos(uv_pos);
|
||||
drawerargs.DrawColumn(Thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t left = y2 - y1;
|
||||
int y = y1;
|
||||
while (left > 0)
|
||||
{
|
||||
uint32_t available = uv_max - uv_pos;
|
||||
uint32_t next_uv_wrap = available / uv_step;
|
||||
if (available % uv_step != 0)
|
||||
next_uv_wrap++;
|
||||
uint32_t count = MIN(left, next_uv_wrap);
|
||||
|
||||
drawerargs.SetDest(viewport, x, y);
|
||||
drawerargs.SetCount(count);
|
||||
drawerargs.SetTextureVPos(uv_pos);
|
||||
drawerargs.DrawColumn(Thread);
|
||||
|
||||
y += count;
|
||||
left -= count;
|
||||
uv_pos += uv_step * count;
|
||||
if (uv_pos >= uv_max)
|
||||
uv_pos -= uv_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
upos += ustepX;
|
||||
vpos += vstepX;
|
||||
wpos += wstepX;
|
||||
curlight += lightstep;
|
||||
}
|
||||
|
||||
if (r_modelscene)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -27,9 +27,21 @@
|
|||
|
||||
namespace swrenderer
|
||||
{
|
||||
struct FWallCoords;
|
||||
struct DrawSegmentClipInfo;
|
||||
|
||||
struct FWallCoords
|
||||
{
|
||||
FVector2 tleft; // coords at left of wall in view space rx1,ry1
|
||||
FVector2 tright; // coords at right of wall in view space rx2,ry2
|
||||
|
||||
float sz1, sz2; // depth at left, right of wall in screen space yb1,yb2
|
||||
short sx1, sx2; // x coords at left, right of wall in screen space xb1,xb2
|
||||
|
||||
float tx1, tx2; // texture coordinate fractions
|
||||
|
||||
bool Init(RenderThread* thread, const DVector2& pt1, const DVector2& pt2, seg_t* lineseg = nullptr);
|
||||
};
|
||||
|
||||
enum class ProjectedWallCull
|
||||
{
|
||||
Visible,
|
||||
|
@ -50,53 +62,54 @@ namespace swrenderer
|
|||
void ClipBottom(int x1, int x2, const DrawSegmentClipInfo& clip);
|
||||
};
|
||||
|
||||
struct FWallTmapVals
|
||||
{
|
||||
void InitFromWallCoords(RenderThread* thread, const FWallCoords* wallc);
|
||||
void InitFromLine(RenderThread* thread, seg_t* line);
|
||||
|
||||
private:
|
||||
float UoverZorg, UoverZstep;
|
||||
float InvZorg, InvZstep;
|
||||
|
||||
friend class ProjectedWallTexcoords;
|
||||
};
|
||||
|
||||
class ProjectedWallTexcoords
|
||||
{
|
||||
public:
|
||||
void ProjectTop(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
|
||||
void ProjectMid(RenderViewport* viewport, sector_t* frontsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
|
||||
void ProjectBottom(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
|
||||
void ProjectTranslucent(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
|
||||
void Project3DFloor(RenderViewport* viewport, F3DFloor* rover, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
|
||||
void ProjectSprite(RenderViewport* viewport, double topZ, double scale, bool flipX, bool flipY, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
|
||||
void ProjectTop(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
|
||||
void ProjectMid(RenderViewport* viewport, sector_t* frontsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
|
||||
void ProjectBottom(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
|
||||
void ProjectTranslucent(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
|
||||
void Project3DFloor(RenderViewport* viewport, F3DFloor* rover, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
|
||||
|
||||
float VStep(int x) const;
|
||||
fixed_t UPos(int x) const;
|
||||
// Gradients
|
||||
float upos, ustepX, ustepY;
|
||||
float vpos, vstepX, vstepY;
|
||||
float wpos, wstepX, wstepY;
|
||||
float startX;
|
||||
|
||||
private:
|
||||
void Project(RenderViewport* viewport, double walxrepeat, int x1, int x2, const FWallTmapVals& WallT, bool flipx = false);
|
||||
void Project(RenderViewport* viewport, double walxrepeat, const FWallCoords& WallC, FSoftwareTexture* pic, bool flipx);
|
||||
|
||||
static fixed_t GetXOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart);
|
||||
static double GetRowOffset(seg_t* lineseg, 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);
|
||||
|
||||
double CenterX;
|
||||
double WallTMapScale2;
|
||||
double walxrepeat;
|
||||
int x1;
|
||||
int x2;
|
||||
FWallTmapVals WallT;
|
||||
bool flipx;
|
||||
|
||||
float yscale = 1.0f;
|
||||
fixed_t xoffset = 0;
|
||||
double texturemid = 0.0f;
|
||||
|
||||
friend class RenderWallPart;
|
||||
friend class SpriteDrawerArgs;
|
||||
struct Vertex
|
||||
{
|
||||
float x, y, w;
|
||||
float u, v;
|
||||
};
|
||||
|
||||
float FindGradientX(float bottomX, float c0, float c1, float c2, const Vertex& v1, const Vertex& v2, const Vertex& v3)
|
||||
{
|
||||
c0 *= v1.w;
|
||||
c1 *= v2.w;
|
||||
c2 *= v3.w;
|
||||
return ((c1 - c2) * (v1.y - v3.y) - (c0 - c2) * (v2.y - v3.y)) / bottomX;
|
||||
}
|
||||
|
||||
float FindGradientY(float bottomY, float c0, float c1, float c2, const Vertex& v1, const Vertex& v2, const Vertex& v3)
|
||||
{
|
||||
c0 *= v1.w;
|
||||
c1 *= v2.w;
|
||||
c2 *= v3.w;
|
||||
return ((c1 - c2) * (v1.x - v3.x) - (c0 - c2) * (v2.x - v3.x)) / bottomY;
|
||||
}
|
||||
};
|
||||
|
||||
class ProjectedWallLight
|
||||
|
@ -108,14 +121,17 @@ namespace swrenderer
|
|||
|
||||
float GetLightPos(int x) const { return lightleft + lightstep * (x - x1); }
|
||||
float GetLightStep() const { return lightstep; }
|
||||
bool IsSpriteLight() const { return spritelight; }
|
||||
|
||||
void SetColormap(const sector_t *frontsector, seg_t *lineseg, lightlist_t *lit = nullptr);
|
||||
void SetLightLeft(RenderThread *thread, const FWallCoords &wallc);
|
||||
void SetSpriteLight() { lightleft = 0.0f; lightstep = 0.0f; spritelight = true; }
|
||||
|
||||
private:
|
||||
int lightlevel;
|
||||
bool foggy;
|
||||
FDynamicColormap *basecolormap;
|
||||
bool spritelight;
|
||||
|
||||
int x1;
|
||||
float lightleft;
|
||||
|
|
|
@ -35,10 +35,10 @@ namespace swrenderer
|
|||
class RenderThread;
|
||||
struct VisiblePlane;
|
||||
|
||||
// The 3072 below is just an arbitrary value picked to avoid
|
||||
// The 32 below is just an arbitrary value picked to avoid
|
||||
// drawing lines the player is too close to that would overflow
|
||||
// the texture calculations.
|
||||
#define TOO_CLOSE_Z (3072.0 / (1<<12))
|
||||
#define TOO_CLOSE_Z (32.0 / (1 << 12))
|
||||
|
||||
enum class WaterFakeSide
|
||||
{
|
||||
|
|
|
@ -54,7 +54,6 @@ namespace swrenderer
|
|||
short x1, x2;
|
||||
|
||||
FWallCoords WallC;
|
||||
FWallTmapVals tmapvals;
|
||||
ProjectedWallTexcoords texcoords;
|
||||
|
||||
DrawSegmentClipInfo drawsegclip;
|
||||
|
|
|
@ -148,10 +148,8 @@ namespace swrenderer
|
|||
decal_left = decal_pos - edge_left * angvec - thread->Viewport->viewpoint.Pos;
|
||||
decal_right = decal_pos + edge_right * angvec - thread->Viewport->viewpoint.Pos;
|
||||
|
||||
CameraLight *cameraLight;
|
||||
|
||||
FWallCoords WallC;
|
||||
if (WallC.Init(thread, decal_left, decal_right, TOO_CLOSE_Z))
|
||||
if (WallC.Init(thread, decal_left, decal_right))
|
||||
return;
|
||||
|
||||
x1 = WallC.sx1;
|
||||
|
@ -240,43 +238,19 @@ namespace swrenderer
|
|||
usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate);
|
||||
}
|
||||
|
||||
float lightpos = light.GetLightPos(x1);
|
||||
|
||||
cameraLight = CameraLight::Instance();
|
||||
|
||||
// Draw it
|
||||
|
||||
FWallTmapVals WallT;
|
||||
WallT.InitFromWallCoords(thread, &WallC);
|
||||
|
||||
ProjectedWallTexcoords walltexcoords;
|
||||
walltexcoords.ProjectSprite(thread->Viewport.get(), zpos, decal->ScaleY, decal->RenderFlags & RF_XFLIP, decal->RenderFlags & RF_YFLIP, x1, x2, WallT, WallSpriteTile);
|
||||
|
||||
do
|
||||
{
|
||||
int x = x1;
|
||||
|
||||
ColormapLight cmlight;
|
||||
cmlight.SetColormap(thread, MINZ, light.GetLightLevel(), light.GetFoggy(), usecolormap, decal->RenderFlags & RF_FULLBRIGHT, false, false, false, false);
|
||||
|
||||
SpriteDrawerArgs drawerargs;
|
||||
bool visible = drawerargs.SetStyle(thread->Viewport.get(), decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor, cmlight);
|
||||
bool calclighting = cameraLight->FixedLightLevel() < 0 && !cameraLight->FixedColormap();
|
||||
|
||||
if (visible)
|
||||
{
|
||||
thread->PrepareTexture(WallSpriteTile, decal->RenderStyle);
|
||||
bool sprflipvert = (decal->RenderFlags & RF_YFLIP);
|
||||
while (x < x2)
|
||||
{
|
||||
if (calclighting)
|
||||
{ // calculate lighting
|
||||
drawerargs.SetLight(lightpos, light.GetLightLevel(), light.GetFoggy(), thread->Viewport.get());
|
||||
}
|
||||
drawerargs.DrawMaskedColumn(thread, x, WallSpriteTile, walltexcoords, sprflipvert, mfloorclip, mceilingclip, decal->RenderStyle);
|
||||
lightpos += light.GetLightStep();
|
||||
x++;
|
||||
}
|
||||
drawerargs.DrawMasked(thread, zpos + WallSpriteTile->GetTopOffset(0) * decal->ScaleY, decal->ScaleY, decal->RenderFlags & RF_XFLIP, decal->RenderFlags & RF_YFLIP, WallC, light, WallSpriteTile, mfloorclip, mceilingclip, decal->RenderStyle);
|
||||
}
|
||||
|
||||
// If this sprite is RF_CLIPFULL on a two-sided line, needrepeat will
|
||||
|
|
|
@ -70,6 +70,8 @@ EXTERN_CVAR(Bool, r_drawplayersprites)
|
|||
EXTERN_CVAR(Bool, r_deathcamera)
|
||||
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
|
||||
|
||||
CVAR(Bool, r_noaccel, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
RenderPlayerSprites::RenderPlayerSprites(RenderThread *thread)
|
||||
|
@ -325,7 +327,7 @@ namespace swrenderer
|
|||
if (vis.x1 > x1)
|
||||
vis.startfrac += vis.xiscale*(vis.x1 - x1);
|
||||
|
||||
noaccel = false;
|
||||
noaccel = r_noaccel;
|
||||
FDynamicColormap *colormap_to_use = nullptr;
|
||||
if (pspr->GetID() < PSP_TARGETCENTER)
|
||||
{
|
||||
|
@ -489,46 +491,23 @@ namespace swrenderer
|
|||
|
||||
void NoAccelPlayerSprite::Render(RenderThread *thread)
|
||||
{
|
||||
if (xscale == 0 || fabs(yscale) < (1.0f / 32000.0f))
|
||||
{ // scaled to 0; can't see
|
||||
return;
|
||||
}
|
||||
|
||||
SpriteDrawerArgs drawerargs;
|
||||
bool visible = drawerargs.SetStyle(thread->Viewport.get(), RenderStyle, Alpha, Translation, FillColor, Light);
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
double spryscale = yscale;
|
||||
bool sprflipvert = false;
|
||||
fixed_t iscale = FLOAT2FIXED(1 / yscale);
|
||||
|
||||
auto viewport = thread->Viewport.get();
|
||||
|
||||
double sprtopscreen;
|
||||
double centerY = viewheight / 2;
|
||||
double y1, y2;
|
||||
if (renderflags & RF_YFLIP)
|
||||
{
|
||||
sprflipvert = true;
|
||||
spryscale = -spryscale;
|
||||
iscale = -iscale;
|
||||
sprtopscreen = viewport->CenterY + (texturemid - pic->GetHeight()) * spryscale;
|
||||
y1 = centerY + (texturemid - pic->GetHeight()) * (-yscale);
|
||||
y2 = y1 + pic->GetHeight() * (-yscale);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprflipvert = false;
|
||||
sprtopscreen = viewport->CenterY - texturemid * spryscale;
|
||||
}
|
||||
|
||||
// clip to screen bounds
|
||||
short *mfloorclip = screenheightarray;
|
||||
short *mceilingclip = zeroarray;
|
||||
|
||||
fixed_t frac = startfrac;
|
||||
thread->PrepareTexture(pic, RenderStyle);
|
||||
for (int x = x1; x < x2; x++)
|
||||
{
|
||||
drawerargs.DrawMaskedColumn(thread, x, iscale, pic, frac + xiscale / 2, spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, RenderStyle, false);
|
||||
frac += xiscale;
|
||||
y1 = centerY - texturemid * yscale;
|
||||
y2 = y1 + pic->GetHeight() * yscale;
|
||||
}
|
||||
drawerargs.DrawMasked2D(thread, x1, x2, y1, y2, pic, RenderStyle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
#include "a_dynlight.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
|
||||
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
|
||||
EXTERN_CVAR(Bool, gl_light_sprites)
|
||||
|
||||
namespace swrenderer
|
||||
|
@ -75,32 +74,20 @@ namespace swrenderer
|
|||
void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ttex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap)
|
||||
{
|
||||
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
|
||||
// transform the origin point
|
||||
double tr_x = pos.X - thread->Viewport->viewpoint.Pos.X;
|
||||
double tr_y = pos.Y - thread->Viewport->viewpoint.Pos.Y;
|
||||
|
||||
double tz = tr_x * thread->Viewport->viewpoint.TanCos + tr_y * thread->Viewport->viewpoint.TanSin;
|
||||
auto viewport = thread->Viewport.get();
|
||||
|
||||
// thing is behind view plane?
|
||||
if (tz < MINZ)
|
||||
const double thingxscalemul = spriteScale.X / tex->GetScale().X;
|
||||
|
||||
// Calculate billboard line for the sprite
|
||||
DVector2 dir = { viewport->viewpoint.Sin, -viewport->viewpoint.Cos };
|
||||
DVector2 pt1 = pos.XY() - viewport->viewpoint.Pos.XY() - dir * (((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->GetLeftOffsetSW() - 1) : tex->GetLeftOffsetSW()) * thingxscalemul);
|
||||
DVector2 pt2 = pt1 + dir * (tex->GetWidth() * thingxscalemul);
|
||||
|
||||
FWallCoords wallc;
|
||||
if (wallc.Init(thread, pt1, pt2))
|
||||
return;
|
||||
|
||||
double tx = tr_x * thread->Viewport->viewpoint.Sin - tr_y * thread->Viewport->viewpoint.Cos;
|
||||
|
||||
// [RH] Flip for mirrors
|
||||
RenderPortal *renderportal = thread->Portal.get();
|
||||
if (renderportal->MirrorFlags & RF_XFLIP)
|
||||
{
|
||||
tx = -tx;
|
||||
}
|
||||
//tx2 = tx >> 4;
|
||||
|
||||
// too far off the side?
|
||||
if (fabs(tx / 64) > fabs(tz))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// [RH] Added scaling
|
||||
int scaled_to = tex->GetScaledTopOffsetSW();
|
||||
int scaled_bo = scaled_to - tex->GetScaledHeight();
|
||||
|
@ -134,86 +121,41 @@ namespace swrenderer
|
|||
}
|
||||
}
|
||||
|
||||
auto viewport = thread->Viewport.get();
|
||||
|
||||
double xscale = viewport->CenterX / tz;
|
||||
|
||||
// [RH] Reject sprites that are off the top or bottom of the screen
|
||||
if (viewport->globaluclip * tz > viewport->viewpoint.Pos.Z - gzb || viewport->globaldclip * tz < viewport->viewpoint.Pos.Z - gzt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// [RH] Flip for mirrors
|
||||
auto renderportal = thread->Portal.get();
|
||||
renderflags ^= renderportal->MirrorFlags & RF_XFLIP;
|
||||
|
||||
// [SP] SpriteFlip
|
||||
if (thing->renderflags & RF_SPRITEFLIP)
|
||||
renderflags ^= RF_XFLIP;
|
||||
|
||||
// calculate edges of the shape
|
||||
const double thingxscalemul = spriteScale.X / tex->GetScale().X;
|
||||
|
||||
tx -= ((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->GetLeftOffsetSW() - 1) : tex->GetLeftOffsetSW()) * thingxscalemul;
|
||||
double dtx1 = tx * xscale;
|
||||
int x1 = viewport->viewwindow.centerx + xs_RoundToInt(dtx1);
|
||||
|
||||
// off the right side?
|
||||
if (x1 >= renderportal->WindowRight)
|
||||
return;
|
||||
|
||||
tx += tex->GetWidth() * thingxscalemul;
|
||||
int x2 = viewport->viewwindow.centerx + xs_RoundToInt(tx * xscale);
|
||||
|
||||
// off the left side or too small?
|
||||
if ((x2 < renderportal->WindowLeft || x2 <= x1))
|
||||
return;
|
||||
|
||||
xscale = spriteScale.X * xscale / tex->GetScale().X;
|
||||
fixed_t iscale = (fixed_t)(FRACUNIT / xscale); // Round towards zero to avoid wrapping in edge cases
|
||||
|
||||
double yscale = spriteScale.Y / tex->GetScale().Y;
|
||||
|
||||
// store information in a vissprite
|
||||
RenderSprite *vis = thread->FrameMemory->NewObject<RenderSprite>();
|
||||
|
||||
vis->wallc = wallc;
|
||||
vis->SpriteScale = yscale;
|
||||
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
|
||||
vis->xscale = FLOAT2FIXED(xscale);
|
||||
vis->yscale = float(viewport->InvZtoScale * yscale / tz);
|
||||
vis->idepth = float(1 / tz);
|
||||
vis->yscale = float(viewport->InvZtoScale * yscale / wallc.sz1);
|
||||
vis->idepth = float(1 / wallc.sz1);
|
||||
vis->floorclip = thing->Floorclip / yscale;
|
||||
vis->texturemid = tex->GetTopOffsetSW() - (viewport->viewpoint.Pos.Z - pos.Z + thing->Floorclip) / yscale;
|
||||
vis->x1 = x1 < renderportal->WindowLeft ? renderportal->WindowLeft : x1;
|
||||
vis->x2 = x2 > renderportal->WindowRight ? renderportal->WindowRight : x2;
|
||||
//vis->Angle = thing->Angles.Yaw;
|
||||
|
||||
if (renderflags & RF_XFLIP)
|
||||
{
|
||||
vis->startfrac = (tex->GetWidth() << FRACBITS) - 1;
|
||||
vis->xiscale = -iscale;
|
||||
}
|
||||
else
|
||||
{
|
||||
vis->startfrac = 0;
|
||||
vis->xiscale = iscale;
|
||||
}
|
||||
|
||||
vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - viewport->viewwindow.centerx + 0.5 - dtx1));
|
||||
|
||||
// killough 3/27/98: save sector for special clipping later
|
||||
vis->x1 = wallc.sx1 < renderportal->WindowLeft ? renderportal->WindowLeft : wallc.sx1;
|
||||
vis->x2 = wallc.sx2 > renderportal->WindowRight ? renderportal->WindowRight : wallc.sx2;
|
||||
vis->heightsec = heightsec;
|
||||
vis->sector = thing->Sector;
|
||||
vis->section = thing->section;
|
||||
|
||||
vis->depth = (float)tz;
|
||||
vis->depth = (float)wallc.sz1;
|
||||
vis->gpos = { (float)pos.X, (float)pos.Y, (float)pos.Z };
|
||||
vis->gzb = (float)gzb; // [RH] use gzb, not thing->z
|
||||
vis->gzt = (float)gzt; // killough 3/27/98
|
||||
vis->gzb = (float)gzb;
|
||||
vis->gzt = (float)gzt;
|
||||
vis->deltax = float(pos.X - viewport->viewpoint.Pos.X);
|
||||
vis->deltay = float(pos.Y - viewport->viewpoint.Pos.Y);
|
||||
vis->renderflags = renderflags;
|
||||
if (thing->flags5 & MF5_BRIGHT)
|
||||
vis->renderflags |= RF_FULLBRIGHT; // kg3D
|
||||
vis->renderflags |= RF_FULLBRIGHT;
|
||||
vis->RenderStyle = thing->RenderStyle;
|
||||
if (r_UseVanillaTransparency)
|
||||
{
|
||||
|
@ -226,11 +168,7 @@ namespace swrenderer
|
|||
vis->Alpha = float(thing->Alpha);
|
||||
vis->fakefloor = fakefloor;
|
||||
vis->fakeceiling = fakeceiling;
|
||||
//vis->bInMirror = renderportal->MirrorFlags & RF_XFLIP;
|
||||
//vis->bSplitSprite = false;
|
||||
|
||||
vis->pic = tex;
|
||||
|
||||
vis->foggy = foggy;
|
||||
|
||||
// The software renderer cannot invert the source without inverting the overlay
|
||||
|
@ -300,74 +238,36 @@ namespace swrenderer
|
|||
vis->dynlightcolor = 0;
|
||||
}
|
||||
|
||||
vis->Light.SetColormap(thread, tz, lightlevel, foggy, basecolormap, fullbright, invertcolormap, fadeToBlack, false, false);
|
||||
vis->Light.SetColormap(thread, wallc.sz1, lightlevel, foggy, basecolormap, fullbright, invertcolormap, fadeToBlack, false, false);
|
||||
|
||||
thread->SpriteList->Push(vis);
|
||||
}
|
||||
|
||||
void RenderSprite::Render(RenderThread *thread, short *mfloorclip, short *mceilingclip, int, int, Fake3DTranslucent)
|
||||
{
|
||||
auto vis = this;
|
||||
|
||||
fixed_t frac;
|
||||
FSoftwareTexture *tex;
|
||||
int x2;
|
||||
fixed_t xiscale;
|
||||
|
||||
double spryscale, sprtopscreen;
|
||||
bool sprflipvert;
|
||||
|
||||
if (vis->xscale == 0 || fabs(vis->yscale) < (1.0f / 32000.0f))
|
||||
{ // scaled to 0; can't see
|
||||
return;
|
||||
}
|
||||
|
||||
SpriteDrawerArgs drawerargs;
|
||||
drawerargs.SetDynamicLight(dynlightcolor);
|
||||
bool visible = drawerargs.SetStyle(thread->Viewport.get(), vis->RenderStyle, vis->Alpha, vis->Translation, vis->FillColor, vis->Light);
|
||||
|
||||
bool visible = drawerargs.SetStyle(thread->Viewport.get(), RenderStyle, Alpha, Translation, FillColor, Light);
|
||||
if (visible)
|
||||
{
|
||||
tex = vis->pic;
|
||||
spryscale = vis->yscale;
|
||||
sprflipvert = false;
|
||||
fixed_t iscale = FLOAT2FIXED(1 / vis->yscale);
|
||||
frac = vis->startfrac;
|
||||
xiscale = vis->xiscale;
|
||||
double texturemid = vis->texturemid;
|
||||
|
||||
auto viewport = thread->Viewport.get();
|
||||
|
||||
if (vis->renderflags & RF_YFLIP)
|
||||
RenderTranslucentPass *translucentPass = thread->TranslucentPass.get();
|
||||
short portalfloorclip[MAXWIDTH];
|
||||
int x2 = wallc.sx2;
|
||||
for (int x = wallc.sx1; x < x2; x++)
|
||||
{
|
||||
sprflipvert = true;
|
||||
spryscale = -spryscale;
|
||||
iscale = -iscale;
|
||||
texturemid -= vis->pic->GetHeight();
|
||||
sprtopscreen = viewport->CenterY + texturemid * spryscale;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprflipvert = false;
|
||||
sprtopscreen = viewport->CenterY - texturemid * spryscale;
|
||||
if (translucentPass->ClipSpriteColumnWithPortals(x, this))
|
||||
portalfloorclip[x] = mceilingclip[x];
|
||||
else
|
||||
portalfloorclip[x] = mfloorclip[x];
|
||||
}
|
||||
|
||||
int x = vis->x1;
|
||||
x2 = vis->x2;
|
||||
thread->PrepareTexture(pic, RenderStyle);
|
||||
|
||||
if (x < x2)
|
||||
{
|
||||
RenderTranslucentPass *translucentPass = thread->TranslucentPass.get();
|
||||
ProjectedWallLight mlight;
|
||||
mlight.SetSpriteLight();
|
||||
|
||||
thread->PrepareTexture(tex, vis->RenderStyle);
|
||||
while (x < x2)
|
||||
{
|
||||
if (!translucentPass->ClipSpriteColumnWithPortals(x, vis))
|
||||
drawerargs.DrawMaskedColumn(thread, x, iscale, tex, frac, spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, vis->RenderStyle, false);
|
||||
x++;
|
||||
frac += xiscale;
|
||||
}
|
||||
}
|
||||
drawerargs.SetBaseColormap(Light.BaseColormap);
|
||||
drawerargs.DrawMasked(thread, gzt - floorclip, SpriteScale, renderflags & RF_XFLIP, renderflags & RF_YFLIP, wallc, mlight, pic, portalfloorclip, mceilingclip, RenderStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,8 @@ namespace swrenderer
|
|||
void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override;
|
||||
|
||||
private:
|
||||
fixed_t xscale = 0;
|
||||
fixed_t startfrac = 0; // horizontal position of x1
|
||||
fixed_t xiscale = 0; // negative if flipped
|
||||
FWallCoords wallc;
|
||||
double SpriteScale;
|
||||
|
||||
uint32_t Translation = 0;
|
||||
uint32_t FillColor = 0;
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace swrenderer
|
|||
right.Y = left.Y + x2 * angsin;
|
||||
|
||||
// Is it off-screen?
|
||||
if (wallc.Init(thread, left, right, TOO_CLOSE_Z))
|
||||
if (wallc.Init(thread, left, right))
|
||||
return;
|
||||
|
||||
RenderPortal *renderportal = thread->Portal.get();
|
||||
|
@ -180,35 +180,25 @@ namespace swrenderer
|
|||
if (!visible)
|
||||
return;
|
||||
|
||||
float lightleft = float(thread->Light->WallVis(spr->wallc.sz1, foggy));
|
||||
float lightstep = float((thread->Light->WallVis(spr->wallc.sz2, foggy) - lightleft) / (spr->wallc.sx2 - spr->wallc.sx1));
|
||||
float light = lightleft + (x1 - spr->wallc.sx1) * lightstep;
|
||||
CameraLight *cameraLight = CameraLight::Instance();
|
||||
bool calclighting = cameraLight->FixedLightLevel() < 0 && !cameraLight->FixedColormap();
|
||||
ProjectedWallLight mlight;
|
||||
mlight.SetLightLeft(thread, wallc);
|
||||
|
||||
// Draw it
|
||||
auto WallSpriteTile = spr->pic;
|
||||
|
||||
FWallTmapVals WallT;
|
||||
WallT.InitFromWallCoords(thread, &spr->wallc);
|
||||
|
||||
ProjectedWallTexcoords walltexcoords;
|
||||
walltexcoords.ProjectSprite(thread->Viewport.get(), spr->gzt, spr->yscale, spr->renderflags & RF_XFLIP, spr->renderflags & RF_YFLIP, x1, x2, WallT, WallSpriteTile);
|
||||
|
||||
RenderTranslucentPass *translucentPass = thread->TranslucentPass.get();
|
||||
|
||||
thread->PrepareTexture(WallSpriteTile, spr->RenderStyle);
|
||||
bool sprflipvert = (spr->renderflags & RF_YFLIP);
|
||||
|
||||
RenderTranslucentPass* translucentPass = thread->TranslucentPass.get();
|
||||
short floorclip[MAXWIDTH];
|
||||
for (int x = x1; x < x2; x++)
|
||||
{
|
||||
if (calclighting)
|
||||
{
|
||||
drawerargs.SetBaseColormap(spr->Light.BaseColormap);
|
||||
drawerargs.SetLight(light, spr->sector->lightlevel, spr->foggy, thread->Viewport.get());
|
||||
}
|
||||
if (!translucentPass->ClipSpriteColumnWithPortals(x, spr))
|
||||
drawerargs.DrawMaskedColumn(thread, x, WallSpriteTile, walltexcoords, sprflipvert, mfloorclip, mceilingclip, spr->RenderStyle);
|
||||
light += lightstep;
|
||||
if (translucentPass->ClipSpriteColumnWithPortals(x, spr))
|
||||
floorclip[x] = mceilingclip[x];
|
||||
else
|
||||
floorclip[x] = mfloorclip[x];
|
||||
}
|
||||
|
||||
drawerargs.SetBaseColormap(spr->Light.BaseColormap);
|
||||
drawerargs.DrawMasked(thread, spr->gzt, spr->yscale, spr->renderflags & RF_XFLIP, spr->renderflags & RF_YFLIP, spr->wallc, mlight, WallSpriteTile, floorclip, mceilingclip, spr->RenderStyle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,221 +43,246 @@ namespace swrenderer
|
|||
colfunc = &SWPixelFormatDrawers::DrawColumn;
|
||||
}
|
||||
|
||||
void SpriteDrawerArgs::DrawMaskedColumn(RenderThread* thread, int x, FSoftwareTexture* WallSpriteTile, const ProjectedWallTexcoords& walltexcoords, bool sprflipvert, const short* mfloorclip, const short* mceilingclip, FRenderStyle style)
|
||||
void SpriteDrawerArgs::DrawMasked(RenderThread* thread, double topZ, double scale, bool flipX, bool flipY, const FWallCoords& WallC, const ProjectedWallLight& light, FSoftwareTexture* tex, const short* mfloorclip, const short* mceilingclip, FRenderStyle style)
|
||||
{
|
||||
auto viewport = thread->Viewport.get();
|
||||
auto cameraLight = CameraLight::Instance();
|
||||
|
||||
float iscale = walltexcoords.VStep(x) * walltexcoords.yscale;
|
||||
double spryscale = 1 / iscale;
|
||||
double sprtopscreen;
|
||||
if (sprflipvert)
|
||||
sprtopscreen = viewport->CenterY + walltexcoords.texturemid * spryscale;
|
||||
else
|
||||
sprtopscreen = viewport->CenterY - walltexcoords.texturemid * spryscale;
|
||||
bool calclighting = cameraLight->FixedLightLevel() < 0 && !cameraLight->FixedColormap() && !light.IsSpriteLight();
|
||||
|
||||
DrawMaskedColumn(thread, x, FLOAT2FIXED(iscale), WallSpriteTile, walltexcoords.UPos(x), spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, style);
|
||||
}
|
||||
float wpos = 1.0f / WallC.sz1;
|
||||
float wstepX = (1.0f / WallC.sz2 - wpos) / (WallC.sx2 - WallC.sx1);
|
||||
|
||||
void SpriteDrawerArgs::DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked)
|
||||
{
|
||||
if (x < thread->X1 || x >= thread->X2)
|
||||
return;
|
||||
|
||||
col *= tex->GetPhysicalScale();
|
||||
iscale *= tex->GetPhysicalScale();
|
||||
spryscale /= tex->GetPhysicalScale();
|
||||
|
||||
auto viewport = thread->Viewport.get();
|
||||
|
||||
// Handle the linear filtered version in a different function to reduce chances of merge conflicts from zdoom.
|
||||
if (viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input) // To do: add support to R_DrawColumnHoriz_rgba
|
||||
float upos, ustepX;
|
||||
if (flipX)
|
||||
{
|
||||
DrawMaskedColumnBgra(thread, x, iscale, tex, col, spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, unmasked);
|
||||
return;
|
||||
upos = (1.0f - WallC.tx1) / WallC.sz1;
|
||||
ustepX = ((1.0f - WallC.tx2) / WallC.sz2 - upos) / (WallC.sx2 - WallC.sx1);
|
||||
}
|
||||
else
|
||||
{
|
||||
upos = WallC.tx1 / WallC.sz1;
|
||||
ustepX = (WallC.tx2 / WallC.sz2 - upos) / (WallC.sx2 - WallC.sx1);
|
||||
}
|
||||
|
||||
float iscale = 1.0f / scale;
|
||||
if (flipY)
|
||||
iscale = -iscale;
|
||||
float vstepY = iscale / WallC.sz1 / (viewport->InvZtoScale / WallC.sz1);
|
||||
|
||||
wpos += wstepX * 0.5f;
|
||||
upos += ustepX * 0.5f;
|
||||
|
||||
int x1 = WallC.sx1;
|
||||
int x2 = WallC.sx2;
|
||||
|
||||
float centerY = thread->Viewport->CenterY;
|
||||
topZ -= thread->Viewport->viewpoint.Pos.Z;
|
||||
|
||||
if (flipY)
|
||||
topZ -= tex->GetHeight() * scale;
|
||||
|
||||
int texwidth = tex->GetPhysicalWidth();
|
||||
int texheight = tex->GetPhysicalHeight();
|
||||
|
||||
float lightpos = light.GetLightPos(x1);
|
||||
float lightstep = light.GetLightStep();
|
||||
|
||||
dc_viewport = viewport;
|
||||
dc_x = x;
|
||||
dc_iscale = iscale;
|
||||
dc_textureheight = tex->GetPhysicalHeight();
|
||||
dc_textureheight = texheight;
|
||||
|
||||
const FSoftwareTextureSpan *span;
|
||||
const uint8_t *column;
|
||||
if (viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input)
|
||||
column = (const uint8_t *)tex->GetColumnBgra(col >> FRACBITS, &span);
|
||||
else
|
||||
column = tex->GetColumn(style, col >> FRACBITS, &span);
|
||||
bool bgra = viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input;
|
||||
|
||||
FSoftwareTextureSpan unmaskedSpan[2];
|
||||
if (unmasked)
|
||||
for (int x = x1; x < x2; x++)
|
||||
{
|
||||
span = unmaskedSpan;
|
||||
unmaskedSpan[0].TopOffset = 0;
|
||||
unmaskedSpan[0].Length = tex->GetPhysicalHeight();
|
||||
unmaskedSpan[1].TopOffset = 0;
|
||||
unmaskedSpan[1].Length = 0;
|
||||
}
|
||||
|
||||
int pixelsize = viewport->RenderTarget->IsBgra() ? 4 : 1;
|
||||
|
||||
while (span->Length != 0)
|
||||
{
|
||||
const int length = span->Length;
|
||||
const int top = span->TopOffset;
|
||||
|
||||
// calculate unclipped screen coordinates for post
|
||||
dc_yl = (int)(sprtopscreen + spryscale * top + 0.5);
|
||||
dc_yh = (int)(sprtopscreen + spryscale * (top + length) + 0.5) - 1;
|
||||
|
||||
if (sprflipvert)
|
||||
if (calclighting)
|
||||
{
|
||||
swapvalues(dc_yl, dc_yh);
|
||||
SetLight(lightpos, light.GetLightLevel(), light.GetFoggy(), thread->Viewport.get());
|
||||
}
|
||||
|
||||
if (dc_yh >= mfloorclip[dc_x])
|
||||
{
|
||||
dc_yh = mfloorclip[dc_x] - 1;
|
||||
}
|
||||
if (dc_yl < mceilingclip[dc_x])
|
||||
{
|
||||
dc_yl = mceilingclip[dc_x];
|
||||
}
|
||||
float w = 1.0f / wpos;
|
||||
float y1 = centerY - topZ * wpos * viewport->InvZtoScale;
|
||||
float u = upos * w;
|
||||
float scaleU = ustepX * w;
|
||||
float scaleV = vstepY * w;
|
||||
|
||||
if (dc_yl <= dc_yh)
|
||||
{
|
||||
dc_texturefrac = FLOAT2FIXED((dc_yl + 0.5 - sprtopscreen) / spryscale);
|
||||
dc_source = column;
|
||||
dc_source2 = nullptr;
|
||||
SetDest(viewport, dc_x, dc_yl);
|
||||
dc_count = dc_yh - dc_yl + 1;
|
||||
uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL);
|
||||
uint32_t texelStepX = (uint32_t)(int64_t)(scaleU * 0x1'0000'0000LL);
|
||||
uint32_t texelStepY = (uint32_t)(int64_t)(scaleV * 0x1'0000'0000LL);
|
||||
|
||||
fixed_t maxfrac = ((top + length) << FRACBITS) - 1;
|
||||
dc_texturefrac = MAX(dc_texturefrac, 0);
|
||||
dc_texturefrac = MIN(dc_texturefrac, maxfrac);
|
||||
if (dc_iscale > 0)
|
||||
dc_count = MIN(dc_count, (maxfrac - dc_texturefrac + dc_iscale - 1) / dc_iscale);
|
||||
else if (dc_iscale < 0)
|
||||
dc_count = MIN(dc_count, (dc_texturefrac - dc_iscale) / (-dc_iscale));
|
||||
DrawMaskedColumn(thread, x, y1, mceilingclip[x], mfloorclip[x], texelX, texelStepX, texelStepY, scaleV, flipY, tex, texwidth, texheight, bgra, style);
|
||||
|
||||
(thread->Drawers(dc_viewport)->*colfunc)(*this);
|
||||
}
|
||||
span++;
|
||||
upos += ustepX;
|
||||
wpos += wstepX;
|
||||
lightpos += lightstep;
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteDrawerArgs::DrawMaskedColumnBgra(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, bool unmasked)
|
||||
void SpriteDrawerArgs::DrawMasked2D(RenderThread* thread, double x0, double x1, double y0, double y1, FSoftwareTexture* tex, FRenderStyle style)
|
||||
{
|
||||
dc_viewport = thread->Viewport.get();
|
||||
dc_x = x;
|
||||
dc_iscale = iscale;
|
||||
int sx0 = MAX((int)x0, 0);
|
||||
int sx1 = MIN((int)x1, viewwidth);
|
||||
int sy0 = MAX((int)y0, 0);
|
||||
int sy1 = MIN((int)y1, viewheight);
|
||||
|
||||
// Normalize to 0-1 range:
|
||||
double uv_stepd = FIXED2DBL(dc_iscale);
|
||||
double v_step = uv_stepd / tex->GetPhysicalHeight();
|
||||
if (sx0 >= sx1 || sy0 >= sy1)
|
||||
return;
|
||||
|
||||
// Convert to uint32_t:
|
||||
dc_iscale = (uint32_t)(v_step * (1 << 30));
|
||||
float ustepX = 1.0f / (x1 - x0);
|
||||
float vstepY = 1.0f / (y1 - y0);
|
||||
float upos = ustepX * (sx0 + 0.5f - x0);
|
||||
|
||||
// Texture mipmap and filter selection:
|
||||
fixed_t xoffset = col;
|
||||
uint32_t texelStepX = (uint32_t)(int64_t)(ustepX * 0x1'0000'0000LL);
|
||||
uint32_t texelStepY = (uint32_t)(int64_t)(vstepY * 0x1'0000'0000LL);
|
||||
|
||||
double xmagnitude = 1.0; // To do: pass this into R_DrawMaskedColumn
|
||||
double ymagnitude = fabs(uv_stepd);
|
||||
double magnitude = MAX(ymagnitude, xmagnitude);
|
||||
double min_lod = -1000.0;
|
||||
double lod = MAX(log2(magnitude) + r_lod_bias, min_lod);
|
||||
bool magnifying = lod < 0.0f;
|
||||
bool bgra = thread->Viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input;
|
||||
int texwidth = tex->GetPhysicalWidth();
|
||||
int texheight = tex->GetPhysicalHeight();
|
||||
|
||||
int mipmap_offset = 0;
|
||||
int mip_width = tex->GetPhysicalWidth();
|
||||
int mip_height = tex->GetPhysicalHeight();
|
||||
uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width);
|
||||
if (r_mipmap && tex->Mipmapped() && mip_width > 1 && mip_height > 1)
|
||||
vstepY *= texheight;
|
||||
|
||||
for (int x = sx0; x < sx1; x++)
|
||||
{
|
||||
int level = (int)lod;
|
||||
while (level > 0 && mip_width > 1 && mip_height > 1)
|
||||
{
|
||||
mipmap_offset += mip_width * mip_height;
|
||||
level--;
|
||||
mip_width = MAX(mip_width >> 1, 1);
|
||||
mip_height = MAX(mip_height >> 1, 1);
|
||||
}
|
||||
float u = upos;
|
||||
uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL);
|
||||
|
||||
DrawMaskedColumn(thread, x, sy0, sy0, sy1, texelX, texelStepX, texelStepY, vstepY, false, tex, texwidth, texheight, bgra, style);
|
||||
|
||||
upos += ustepX;
|
||||
}
|
||||
xoffset = (xpos >> FRACBITS) * mip_width;
|
||||
}
|
||||
|
||||
const uint32_t *pixels = tex->GetPixelsBgra() + mipmap_offset;
|
||||
|
||||
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
|
||||
if (filter_nearest)
|
||||
void SpriteDrawerArgs::DrawMaskedColumn(RenderThread* thread, int x, int y1, int cliptop, int clipbottom, uint32_t texelX, uint32_t texelStepX, uint32_t texelStepY, float scaleV, bool flipY, FSoftwareTexture* tex, int texwidth, int texheight, bool bgra, FRenderStyle style)
|
||||
{
|
||||
const FSoftwareTextureSpan* span;
|
||||
if (bgra)
|
||||
{
|
||||
xoffset = MAX(MIN(xoffset, (mip_width << FRACBITS) - 1), 0);
|
||||
double xmagnitude = fabs(static_cast<int32_t>(texelStepX)* (1.0 / 0x1'0000'0000LL));
|
||||
double ymagnitude = fabs(static_cast<int32_t>(texelStepY)* (1.0 / 0x1'0000'0000LL));
|
||||
double magnitude = MAX(ymagnitude, xmagnitude);
|
||||
double min_lod = -1000.0;
|
||||
double lod = MAX(log2(magnitude) + r_lod_bias, min_lod);
|
||||
bool magnifying = lod < 0.0f;
|
||||
|
||||
int tx = xoffset >> FRACBITS;
|
||||
dc_source = (uint8_t*)(pixels + tx * mip_height);
|
||||
dc_source2 = nullptr;
|
||||
dc_textureheight = mip_height;
|
||||
dc_texturefracx = 0;
|
||||
int mipmap_offset = 0;
|
||||
int mip_width = texwidth;
|
||||
int mip_height = texheight;
|
||||
if (r_mipmap && tex->Mipmapped() && mip_width > 1 && mip_height > 1)
|
||||
{
|
||||
int level = (int)lod;
|
||||
while (level > 0 && mip_width > 1 && mip_height > 1)
|
||||
{
|
||||
mipmap_offset += mip_width * mip_height;
|
||||
level--;
|
||||
mip_width = MAX(mip_width >> 1, 1);
|
||||
mip_height = MAX(mip_height >> 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t* pixels = tex->GetPixelsBgra() + mipmap_offset;
|
||||
fixed_t xoffset = (texelX >> 16)* mip_width;
|
||||
|
||||
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
|
||||
if (filter_nearest)
|
||||
{
|
||||
xoffset = MAX(MIN(xoffset, (mip_width << FRACBITS) - 1), 0);
|
||||
|
||||
int tx = xoffset >> FRACBITS;
|
||||
dc_source = (uint8_t*)(pixels + tx * mip_height);
|
||||
dc_source2 = nullptr;
|
||||
dc_textureheight = mip_height;
|
||||
dc_texturefracx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xoffset = MAX(MIN(xoffset - (FRACUNIT / 2), (mip_width << FRACBITS) - 1), 0);
|
||||
|
||||
int tx0 = xoffset >> FRACBITS;
|
||||
int tx1 = MIN(tx0 + 1, mip_width - 1);
|
||||
dc_source = (uint8_t*)(pixels + tx0 * mip_height);
|
||||
dc_source2 = (uint8_t*)(pixels + tx1 * mip_height);
|
||||
dc_textureheight = mip_height;
|
||||
dc_texturefracx = (xoffset >> (FRACBITS - 4)) & 15;
|
||||
}
|
||||
|
||||
int col = ((texelX >> 16)* texwidth) >> 16;
|
||||
tex->GetColumnBgra(col, &span);
|
||||
|
||||
dc_iscale = (uint32_t)(int64_t)(scaleV / texheight * (1 << 30));
|
||||
dc_x = x;
|
||||
|
||||
while (span->Length != 0)
|
||||
{
|
||||
const int length = span->Length;
|
||||
const int top = span->TopOffset;
|
||||
|
||||
// calculate unclipped screen coordinates for post
|
||||
dc_yl = (int)(y1 + top / scaleV + 0.5f);
|
||||
dc_yh = (int)(y1 + (top + length) / scaleV + 0.5f);
|
||||
|
||||
if (flipY)
|
||||
std::swap(dc_yl, dc_yh);
|
||||
|
||||
dc_yl = std::max(dc_yl, cliptop);
|
||||
dc_yh = std::min(dc_yh, clipbottom);
|
||||
|
||||
if (dc_yl <= dc_yh)
|
||||
{
|
||||
double v = ((dc_yl + 0.5f - y1) * scaleV) / texheight;
|
||||
dc_texturefrac = (uint32_t)(v * (1 << 30));
|
||||
|
||||
SetDest(dc_viewport, dc_x, dc_yl);
|
||||
dc_count = dc_yh - dc_yl;
|
||||
dc_yl--;
|
||||
|
||||
(thread->Drawers(dc_viewport)->*colfunc)(*this);
|
||||
}
|
||||
span++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xoffset = MAX(MIN(xoffset - (FRACUNIT / 2), (mip_width << FRACBITS) - 1), 0);
|
||||
int col = ((texelX >> 16)* texwidth) >> 16;
|
||||
dc_source = tex->GetColumn(style, col, &span);
|
||||
dc_source2 = nullptr;
|
||||
|
||||
int tx0 = xoffset >> FRACBITS;
|
||||
int tx1 = MIN(tx0 + 1, mip_width - 1);
|
||||
dc_source = (uint8_t*)(pixels + tx0 * mip_height);
|
||||
dc_source2 = (uint8_t*)(pixels + tx1 * mip_height);
|
||||
dc_textureheight = mip_height;
|
||||
dc_texturefracx = (xoffset >> (FRACBITS - 4)) & 15;
|
||||
}
|
||||
dc_iscale = FLOAT2FIXED(scaleV);
|
||||
dc_x = x;
|
||||
|
||||
// Grab the posts we need to draw
|
||||
const FSoftwareTextureSpan *span;
|
||||
tex->GetColumnBgra(col >> FRACBITS, &span);
|
||||
FSoftwareTextureSpan unmaskedSpan[2];
|
||||
if (unmasked)
|
||||
{
|
||||
span = unmaskedSpan;
|
||||
unmaskedSpan[0].TopOffset = 0;
|
||||
unmaskedSpan[0].Length = tex->GetPhysicalHeight();
|
||||
unmaskedSpan[1].TopOffset = 0;
|
||||
unmaskedSpan[1].Length = 0;
|
||||
}
|
||||
|
||||
// Draw each span post
|
||||
while (span->Length != 0)
|
||||
{
|
||||
const int length = span->Length;
|
||||
const int top = span->TopOffset;
|
||||
|
||||
// calculate unclipped screen coordinates for post
|
||||
dc_yl = (int)(sprtopscreen + spryscale * top + 0.5);
|
||||
dc_yh = (int)(sprtopscreen + spryscale * (top + length) + 0.5) - 1;
|
||||
|
||||
if (sprflipvert)
|
||||
while (span->Length != 0)
|
||||
{
|
||||
swapvalues(dc_yl, dc_yh);
|
||||
}
|
||||
const int length = span->Length;
|
||||
const int top = span->TopOffset;
|
||||
|
||||
if (dc_yh >= mfloorclip[dc_x])
|
||||
{
|
||||
dc_yh = mfloorclip[dc_x] - 1;
|
||||
}
|
||||
if (dc_yl < mceilingclip[dc_x])
|
||||
{
|
||||
dc_yl = mceilingclip[dc_x];
|
||||
}
|
||||
// calculate unclipped screen coordinates for post
|
||||
dc_yl = (int)(y1 + top / scaleV + 0.5f);
|
||||
dc_yh = (int)(y1 + (top + length) / scaleV + 0.5f);
|
||||
|
||||
if (dc_yl <= dc_yh)
|
||||
{
|
||||
SetDest(dc_viewport, dc_x, dc_yl);
|
||||
dc_count = dc_yh - dc_yl + 1;
|
||||
if (flipY)
|
||||
std::swap(dc_yl, dc_yh);
|
||||
|
||||
double v = ((dc_yl + 0.5 - sprtopscreen) / spryscale) / tex->GetPhysicalHeight();
|
||||
dc_texturefrac = (uint32_t)(v * (1 << 30));
|
||||
dc_yl = std::max(dc_yl, cliptop);
|
||||
dc_yh = std::min(dc_yh, clipbottom);
|
||||
|
||||
(thread->Drawers(dc_viewport)->*colfunc)(*this);
|
||||
if (dc_yl < dc_yh)
|
||||
{
|
||||
dc_texturefrac = FLOAT2FIXED((dc_yl + 0.5f - y1) * scaleV);
|
||||
SetDest(thread->Viewport.get(), dc_x, dc_yl);
|
||||
dc_count = dc_yh - dc_yl;
|
||||
dc_yl--;
|
||||
|
||||
fixed_t maxfrac = ((top + length) << FRACBITS) - 1;
|
||||
dc_texturefrac = MAX(dc_texturefrac, 0);
|
||||
dc_texturefrac = MIN(dc_texturefrac, maxfrac);
|
||||
if (dc_iscale > 0)
|
||||
dc_count = MIN(dc_count, (maxfrac - dc_texturefrac + dc_iscale - 1) / dc_iscale);
|
||||
else if (dc_iscale < 0)
|
||||
dc_count = MIN(dc_count, (dc_texturefrac - dc_iscale) / (-dc_iscale));
|
||||
|
||||
(thread->Drawers(dc_viewport)->*colfunc)(*this);
|
||||
}
|
||||
span++;
|
||||
}
|
||||
span++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -517,35 +542,10 @@ namespace swrenderer
|
|||
return SetStyle(viewport, style, FLOAT2FIXED(alpha), translation, color, light);
|
||||
}
|
||||
|
||||
void SpriteDrawerArgs::FillColumn(RenderThread *thread)
|
||||
{
|
||||
thread->Drawers(dc_viewport)->FillColumn(*this);
|
||||
}
|
||||
|
||||
void SpriteDrawerArgs::DrawVoxelBlocks(RenderThread *thread, const VoxelBlock *blocks, int blockcount)
|
||||
{
|
||||
SetDest(thread->Viewport.get(), 0, 0);
|
||||
thread->Drawers(dc_viewport)->DrawVoxelBlocks(*this, blocks, blockcount);
|
||||
#if 0
|
||||
if (dc_viewport->RenderTarget->IsBgra())
|
||||
{
|
||||
double v = vPos / (double)voxelsCount / FRACUNIT;
|
||||
double vstep = vStep / (double)voxelsCount / FRACUNIT;
|
||||
dc_texturefrac = (int)(v * (1 << 30));
|
||||
dc_iscale = (int)(vstep * (1 << 30));
|
||||
}
|
||||
else
|
||||
{
|
||||
dc_texturefrac = vPos;
|
||||
dc_iscale = vStep;
|
||||
}
|
||||
|
||||
dc_texturefracx = 0;
|
||||
dc_source = voxels;
|
||||
dc_source2 = 0;
|
||||
dc_textureheight = voxelsCount;
|
||||
(thread->Drawers(dc_viewport)->*colfunc)(*this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpriteDrawerArgs::SetDest(RenderViewport *viewport, int x, int y)
|
||||
|
|
|
@ -9,7 +9,8 @@ struct FLightNode;
|
|||
namespace swrenderer
|
||||
{
|
||||
class RenderThread;
|
||||
class ProjectedWallTexcoords;
|
||||
struct FWallCoords;
|
||||
class ProjectedWallLight;
|
||||
|
||||
class VoxelBlock
|
||||
{
|
||||
|
@ -29,14 +30,11 @@ namespace swrenderer
|
|||
|
||||
bool SetStyle(RenderViewport *viewport, FRenderStyle style, fixed_t alpha, int translation, uint32_t color, const ColormapLight &light);
|
||||
bool SetStyle(RenderViewport *viewport, FRenderStyle style, float alpha, int translation, uint32_t color, const ColormapLight &light);
|
||||
void SetDest(RenderViewport *viewport, int x, int y);
|
||||
void SetCount(int count) { dc_count = count; }
|
||||
void SetSolidColor(int color) { dc_color = color; dc_color_bgra = GPalette.BaseColors[color]; }
|
||||
void SetDynamicLight(uint32_t color) { dynlightcolor = color; }
|
||||
|
||||
void DrawMaskedColumn(RenderThread* thread, int x, FSoftwareTexture* WallSpriteTile, const ProjectedWallTexcoords& walltexcoords, bool sprflipvert, const short* mfloorclip, const short* mceilingclip, FRenderStyle style);
|
||||
void DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *texture, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked = false);
|
||||
void FillColumn(RenderThread *thread);
|
||||
void DrawMasked(RenderThread* thread, double topZ, double scale, bool flipX, bool flipY, const FWallCoords& WallC, const ProjectedWallLight& light, FSoftwareTexture* texture, const short* mfloorclip, const short* mceilingclip, FRenderStyle style);
|
||||
void DrawMasked2D(RenderThread *thread, double x0, double x1, double y0, double y1, FSoftwareTexture* texture, FRenderStyle style);
|
||||
void DrawVoxelBlocks(RenderThread *thread, const VoxelBlock *blocks, int blockcount);
|
||||
|
||||
uint8_t *Dest() const { return dc_dest; }
|
||||
|
@ -71,9 +69,13 @@ namespace swrenderer
|
|||
RenderViewport *Viewport() const { return dc_viewport; }
|
||||
|
||||
private:
|
||||
void DrawMaskedColumn(RenderThread* thread, int x, int y1, int cliptop, int clipbottom, uint32_t texelX, uint32_t texelStepX, uint32_t texelStepY, float scaleV, bool flipY, FSoftwareTexture* tex, int texwidth, int texheight, bool bgra, FRenderStyle style);
|
||||
|
||||
void SetDest(RenderViewport* viewport, int x, int y);
|
||||
void SetCount(int count) { dc_count = count; }
|
||||
|
||||
bool SetBlendFunc(int op, fixed_t fglevel, fixed_t bglevel, int flags);
|
||||
static fixed_t GetAlpha(int type, fixed_t alpha);
|
||||
void DrawMaskedColumnBgra(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, bool unmasked);
|
||||
|
||||
uint8_t *dc_dest = nullptr;
|
||||
int dc_dest_y = 0;
|
||||
|
|
Loading…
Reference in a new issue