diff --git a/src/rendering/swrenderer/line/r_farclip_line.cpp b/src/rendering/swrenderer/line/r_farclip_line.cpp index 91f2774a2..9e094768a 100644 --- a/src/rendering/swrenderer/line/r_farclip_line.cpp +++ b/src/rendering/swrenderer/line/r_farclip_line.cpp @@ -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(); diff --git a/src/rendering/swrenderer/line/r_line.cpp b/src/rendering/swrenderer/line/r_line.cpp index 6780bb10c..56557c8eb 100644 --- a/src/rendering/swrenderer/line/r_line.cpp +++ b/src/rendering/swrenderer/line/r_line.cpp @@ -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; - } } diff --git a/src/rendering/swrenderer/line/r_line.h b/src/rendering/swrenderer/line/r_line.h index a4edca524..24d57f099 100644 --- a/src/rendering/swrenderer/line/r_line.h +++ b/src/rendering/swrenderer/line/r_line.h @@ -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: diff --git a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp index b6d990133..2fac2a8ef 100644 --- a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp @@ -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); diff --git a/src/rendering/swrenderer/line/r_walldraw.cpp b/src/rendering/swrenderer/line/r_walldraw.cpp index ee0ce6238..bfbdddd3c 100644 --- a/src/rendering/swrenderer/line/r_walldraw.cpp +++ b/src/rendering/swrenderer/line/r_walldraw.cpp @@ -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(texelStepX) * (1.0 / 0x1'0000'0000LL)); + double ymagnitude = fabs(static_cast(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(texelY)* texheight) >> (32 - fracbits); + texelStepY = (static_cast(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) diff --git a/src/rendering/swrenderer/line/r_wallsetup.cpp b/src/rendering/swrenderer/line/r_wallsetup.cpp index 13f0cd58f..8511956f8 100644 --- a/src/rendering/swrenderer/line/r_wallsetup.cpp +++ b/src/rendering/swrenderer/line/r_wallsetup.cpp @@ -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(); diff --git a/src/rendering/swrenderer/line/r_wallsetup.h b/src/rendering/swrenderer/line/r_wallsetup.h index 923d33fec..82dfcfc7c 100644 --- a/src/rendering/swrenderer/line/r_wallsetup.h +++ b/src/rendering/swrenderer/line/r_wallsetup.h @@ -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; diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.h b/src/rendering/swrenderer/scene/r_opaque_pass.h index 4bd18bdd7..d834327d5 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.h +++ b/src/rendering/swrenderer/scene/r_opaque_pass.h @@ -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 { diff --git a/src/rendering/swrenderer/segments/r_drawsegment.h b/src/rendering/swrenderer/segments/r_drawsegment.h index 43c33b0b4..af3aa9391 100644 --- a/src/rendering/swrenderer/segments/r_drawsegment.h +++ b/src/rendering/swrenderer/segments/r_drawsegment.h @@ -54,7 +54,6 @@ namespace swrenderer short x1, x2; FWallCoords WallC; - FWallTmapVals tmapvals; ProjectedWallTexcoords texcoords; DrawSegmentClipInfo drawsegclip; diff --git a/src/rendering/swrenderer/things/r_decal.cpp b/src/rendering/swrenderer/things/r_decal.cpp index 49edf5e19..cfcc01ccd 100644 --- a/src/rendering/swrenderer/things/r_decal.cpp +++ b/src/rendering/swrenderer/things/r_decal.cpp @@ -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 diff --git a/src/rendering/swrenderer/things/r_playersprite.cpp b/src/rendering/swrenderer/things/r_playersprite.cpp index 0aefb48a2..d12495bbd 100644 --- a/src/rendering/swrenderer/things/r_playersprite.cpp +++ b/src/rendering/swrenderer/things/r_playersprite.cpp @@ -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); } } diff --git a/src/rendering/swrenderer/things/r_sprite.cpp b/src/rendering/swrenderer/things/r_sprite.cpp index 1ae8119c2..c06f138e7 100644 --- a/src/rendering/swrenderer/things/r_sprite.cpp +++ b/src/rendering/swrenderer/things/r_sprite.cpp @@ -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(); + 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); } } } diff --git a/src/rendering/swrenderer/things/r_sprite.h b/src/rendering/swrenderer/things/r_sprite.h index fefe5df68..0e7d97bcb 100644 --- a/src/rendering/swrenderer/things/r_sprite.h +++ b/src/rendering/swrenderer/things/r_sprite.h @@ -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; diff --git a/src/rendering/swrenderer/things/r_wallsprite.cpp b/src/rendering/swrenderer/things/r_wallsprite.cpp index a5952a414..d80cb0edc 100644 --- a/src/rendering/swrenderer/things/r_wallsprite.cpp +++ b/src/rendering/swrenderer/things/r_wallsprite.cpp @@ -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); } } diff --git a/src/rendering/swrenderer/viewport/r_spritedrawer.cpp b/src/rendering/swrenderer/viewport/r_spritedrawer.cpp index 619f75054..99a7eb997 100644 --- a/src/rendering/swrenderer/viewport/r_spritedrawer.cpp +++ b/src/rendering/swrenderer/viewport/r_spritedrawer.cpp @@ -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(texelStepX)* (1.0 / 0x1'0000'0000LL)); + double ymagnitude = fabs(static_cast(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) diff --git a/src/rendering/swrenderer/viewport/r_spritedrawer.h b/src/rendering/swrenderer/viewport/r_spritedrawer.h index d213be3c0..f07b81fba 100644 --- a/src/rendering/swrenderer/viewport/r_spritedrawer.h +++ b/src/rendering/swrenderer/viewport/r_spritedrawer.h @@ -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;