diff --git a/src/rendering/swrenderer/line/r_fogboundary.cpp b/src/rendering/swrenderer/line/r_fogboundary.cpp index 8831e15c4..c17f90019 100644 --- a/src/rendering/swrenderer/line/r_fogboundary.cpp +++ b/src/rendering/swrenderer/line/r_fogboundary.cpp @@ -54,12 +54,15 @@ namespace swrenderer { - void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, const ProjectedWallLight &wallLight) + void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const DrawSegmentClipInfo& clip, const ProjectedWallLight &wallLight) { // This is essentially the same as R_MapVisPlane but with an extra step // to create new horizontal spans whenever the light changes enough that // we need to use a new colormap. + const short* uclip = clip.sprtopclip; + const short* dclip = clip.sprbottomclip; + int wallshade = LightVisibility::LightLevelToShade(wallLight.GetLightLevel(), wallLight.GetFoggy(), thread->Viewport.get()); int x = x2 - 1; int t2 = uclip[x]; diff --git a/src/rendering/swrenderer/line/r_fogboundary.h b/src/rendering/swrenderer/line/r_fogboundary.h index a98f96996..4f7696cd6 100644 --- a/src/rendering/swrenderer/line/r_fogboundary.h +++ b/src/rendering/swrenderer/line/r_fogboundary.h @@ -31,7 +31,7 @@ namespace swrenderer class RenderFogBoundary { public: - void Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, const ProjectedWallLight &wallLight); + void Render(RenderThread *thread, int x1, int x2, const DrawSegmentClipInfo &clip, const ProjectedWallLight &wallLight); private: void RenderSection(RenderThread *thread, int y, int y2, int x1); diff --git a/src/rendering/swrenderer/line/r_line.cpp b/src/rendering/swrenderer/line/r_line.cpp index f0714c751..51814d846 100644 --- a/src/rendering/swrenderer/line/r_line.cpp +++ b/src/rendering/swrenderer/line/r_line.cpp @@ -290,11 +290,6 @@ namespace swrenderer int i; bool maskedtexture = false; -#ifdef RANGECHECK - if (start >= viewwidth || start >= stop) - I_Error("Bad R_StoreWallRange: %i to %i", start, stop); -#endif - if (!rw_prepped) { rw_prepped = true; @@ -329,10 +324,8 @@ namespace swrenderer } else if (mBackSector == NULL) { - draw_segment->drawsegclip.sprtopclip = Thread->FrameMemory->AllocMemory(stop - start); - draw_segment->drawsegclip.sprbottomclip = Thread->FrameMemory->AllocMemory(stop - start); - fillshort(draw_segment->drawsegclip.sprtopclip, stop - start, viewheight); - memset(draw_segment->drawsegclip.sprbottomclip, -1, (stop - start) * sizeof(short)); + draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight); + draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1); draw_segment->drawsegclip.silhouette = SIL_BOTH; } else @@ -361,14 +354,12 @@ namespace swrenderer { if (mDoorClosed || (mBackCeilingZ1 <= mFrontFloorZ1 && mBackCeilingZ2 <= mFrontFloorZ2)) { - draw_segment->drawsegclip.sprbottomclip = Thread->FrameMemory->AllocMemory(stop - start); - memset(draw_segment->drawsegclip.sprbottomclip, -1, (stop - start) * sizeof(short)); + draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1); draw_segment->drawsegclip.silhouette |= SIL_BOTTOM; } if (mDoorClosed || (mBackFloorZ1 >= mFrontCeilingZ1 && mBackFloorZ2 >= mFrontCeilingZ2)) - { // killough 1/17/98, 2/8/98 - draw_segment->drawsegclip.sprtopclip = Thread->FrameMemory->AllocMemory(stop - start); - fillshort(draw_segment->drawsegclip.sprtopclip, stop - start, viewheight); + { + draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight); draw_segment->drawsegclip.silhouette |= SIL_TOP; } } @@ -407,9 +398,7 @@ namespace swrenderer maskedtexture = true; // kg3D - backup for mid and fake walls - draw_segment->drawsegclip.bkup = Thread->FrameMemory->AllocMemory(stop - start); - memcpy(draw_segment->drawsegclip.bkup, &Thread->OpaquePass->ceilingclip[start], sizeof(short)*(stop - start)); - + draw_segment->drawsegclip.SetBackupClip(Thread, start, stop, Thread->OpaquePass->ceilingclip); draw_segment->drawsegclip.bFogBoundary = IsFogBoundary(mFrontSector, mBackSector); if (sidedef->GetTexture(side_t::mid).isValid()) { @@ -449,14 +438,12 @@ namespace swrenderer // save sprite clipping info if (((draw_segment->drawsegclip.silhouette & SIL_TOP) || maskedtexture) && draw_segment->drawsegclip.sprtopclip == nullptr) { - draw_segment->drawsegclip.sprtopclip = Thread->FrameMemory->AllocMemory(stop - start); - memcpy(draw_segment->drawsegclip.sprtopclip, &Thread->OpaquePass->ceilingclip[start], sizeof(short)*(stop - start)); + draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip); } if (((draw_segment->drawsegclip.silhouette & SIL_BOTTOM) || maskedtexture) && draw_segment->drawsegclip.sprbottomclip == nullptr) { - draw_segment->drawsegclip.sprbottomclip = Thread->FrameMemory->AllocMemory(stop - start); - memcpy(draw_segment->drawsegclip.sprbottomclip, &Thread->OpaquePass->floorclip[start], sizeof(short)*(stop - start)); + draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, Thread->OpaquePass->floorclip); } if (maskedtexture && mLineSegment->sidedef->GetTexture(side_t::mid).isValid()) diff --git a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp index 7258167af..7be152036 100644 --- a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp @@ -102,11 +102,8 @@ namespace swrenderer // [RH] Draw fog partition if (ds->drawsegclip.bFogBoundary) { - const short *mfloorclip = ds->drawsegclip.sprbottomclip - ds->x1; - const short *mceilingclip = ds->drawsegclip.sprtopclip - ds->x1; - RenderFogBoundary renderfog; - renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, mLight); + renderfog.Render(Thread, x1, x2, ds->drawsegclip, mLight); } bool notrelevant = false; @@ -120,8 +117,7 @@ namespace swrenderer if (!notrelevant) { - ds->drawsegclip.sprclipped = true; - fillshort(ds->drawsegclip.sprtopclip - ds->x1 + x1, x2 - x1, viewheight); + ds->drawsegclip.SetRangeDrawn(x1, x2); } } @@ -141,8 +137,8 @@ namespace swrenderer } FSoftwareTexture *tex = ttex->GetSoftwareTexture(); - const short *mfloorclip = ds->drawsegclip.sprbottomclip - ds->x1; - const short *mceilingclip = ds->drawsegclip.sprtopclip - ds->x1; + const short *mfloorclip = ds->drawsegclip.sprbottomclip; + const short *mceilingclip = ds->drawsegclip.sprtopclip; bool wrap = (curline->linedef->flags & ML_WRAP_MIDTEX) || (curline->sidedef->Flags & WALLF_WRAP_MIDTEX); if (!wrap) @@ -214,16 +210,8 @@ namespace swrenderer wallupper.Project(Thread->Viewport.get(), ceilZ, &ds->WallC); walllower.Project(Thread->Viewport.get(), floorZ, &ds->WallC); - for (int i = x1; i < x2; i++) - { - if (wallupper.ScreenY[i] < mceilingclip[i]) - wallupper.ScreenY[i] = mceilingclip[i]; - } - for (int i = x1; i < x2; i++) - { - if (walllower.ScreenY[i] > mfloorclip[i]) - walllower.ScreenY[i] = mfloorclip[i]; - } + wallupper.ClipTop(x1, x2, ds->drawsegclip); + walllower.ClipBottom(x1, x2, ds->drawsegclip); if (clip3d->CurrentSkybox) { // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor @@ -297,23 +285,12 @@ namespace swrenderer mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1); - const short *mfloorclip = ds->drawsegclip.sprbottomclip - ds->x1; - const short *mceilingclip = ds->drawsegclip.sprtopclip - ds->x1; - Clip3DFloors *clip3d = Thread->Clip3D.get(); wallupper.Project(Thread->Viewport.get(), clipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC); walllower.Project(Thread->Viewport.get(), clipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC); - for (int i = x1; i < x2; i++) - { - if (wallupper.ScreenY[i] < mceilingclip[i]) - wallupper.ScreenY[i] = mceilingclip[i]; - } - for (int i = x1; i < x2; i++) - { - if (walllower.ScreenY[i] > mfloorclip[i]) - walllower.ScreenY[i] = mfloorclip[i]; - } + wallupper.ClipTop(x1, x2, ds->drawsegclip); + 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); diff --git a/src/rendering/swrenderer/line/r_wallsetup.cpp b/src/rendering/swrenderer/line/r_wallsetup.cpp index 9e61d7902..ee48317bf 100644 --- a/src/rendering/swrenderer/line/r_wallsetup.cpp +++ b/src/rendering/swrenderer/line/r_wallsetup.cpp @@ -168,6 +168,22 @@ namespace swrenderer } } + void ProjectedWallLine::ClipTop(int x1, int x2, const DrawSegmentClipInfo& clip) + { + for (int i = x1; i < x2; i++) + { + ScreenY[i] = std::max(ScreenY[i], clip.sprtopclip[i]); + } + } + + void ProjectedWallLine::ClipBottom(int x1, int x2, const DrawSegmentClipInfo& clip) + { + for (int i = x1; i < x2; i++) + { + ScreenY[i] = std::min(ScreenY[i], clip.sprbottomclip[i]); + } + } + ///////////////////////////////////////////////////////////////////////// void FWallTmapVals::InitFromWallCoords(RenderThread* thread, const FWallCoords* wallc) diff --git a/src/rendering/swrenderer/line/r_wallsetup.h b/src/rendering/swrenderer/line/r_wallsetup.h index c19148ffd..f8fcfc649 100644 --- a/src/rendering/swrenderer/line/r_wallsetup.h +++ b/src/rendering/swrenderer/line/r_wallsetup.h @@ -28,6 +28,7 @@ namespace swrenderer { struct FWallCoords; + struct DrawSegmentClipInfo; enum class ProjectedWallCull { @@ -44,6 +45,9 @@ namespace swrenderer ProjectedWallCull Project(RenderViewport *viewport, double z1, double z2, const FWallCoords *wallc); ProjectedWallCull Project(RenderViewport *viewport, const secplane_t &plane, const FWallCoords *wallc, seg_t *line, bool xflip); ProjectedWallCull Project(RenderViewport *viewport, double z, const FWallCoords *wallc); + + void ClipTop(int x1, int x2, const DrawSegmentClipInfo& clip); + void ClipBottom(int x1, int x2, const DrawSegmentClipInfo& clip); }; struct FWallTmapVals diff --git a/src/rendering/swrenderer/scene/r_portal.cpp b/src/rendering/swrenderer/scene/r_portal.cpp index 40528777b..ce82c4e6b 100644 --- a/src/rendering/swrenderer/scene/r_portal.cpp +++ b/src/rendering/swrenderer/scene/r_portal.cpp @@ -212,12 +212,10 @@ namespace swrenderer draw_segment->x1 = pl->left; draw_segment->x2 = pl->right; draw_segment->drawsegclip.silhouette = SIL_BOTH; - draw_segment->drawsegclip.sprbottomclip = Thread->FrameMemory->AllocMemory(pl->right - pl->left); - draw_segment->drawsegclip.sprtopclip = Thread->FrameMemory->AllocMemory(pl->right - pl->left); + draw_segment->drawsegclip.SetTopClip(Thread, pl->left, pl->right, ceilingclip); + draw_segment->drawsegclip.SetBottomClip(Thread, pl->left, pl->right, floorclip); draw_segment->drawsegclip.bFogBoundary = false; draw_segment->curline = nullptr; - memcpy(draw_segment->drawsegclip.sprbottomclip, floorclip + pl->left, (pl->right - pl->left) * sizeof(short)); - memcpy(draw_segment->drawsegclip.sprtopclip, ceilingclip + pl->left, (pl->right - pl->left) * sizeof(short)); drawseglist->Push(draw_segment); Thread->OpaquePass->RenderScene(Thread->Viewport->Level()); diff --git a/src/rendering/swrenderer/scene/r_translucent_pass.cpp b/src/rendering/swrenderer/scene/r_translucent_pass.cpp index 02e1afe63..aad495ffe 100644 --- a/src/rendering/swrenderer/scene/r_translucent_pass.cpp +++ b/src/rendering/swrenderer/scene/r_translucent_pass.cpp @@ -156,17 +156,15 @@ namespace swrenderer // [ZZ] the same as above if (ds->drawsegclip.CurrentPortalUniq != renderportal->CurrentPortalUniq) continue; + if (ds->texcoords || ds->drawsegclip.bFogBoundary) { RenderDrawSegment renderer(Thread); renderer.Render(ds, ds->x1, ds->x2, clip3DFloor); - if (renew && ds->drawsegclip.bFogBoundary) // don't draw fogboundary again - ds->drawsegclip.bFogBoundary = false; - - if (renew && ds->drawsegclip.sprclipped) + if (renew) { - memcpy(ds->drawsegclip.sprtopclip, ds->drawsegclip.bkup, (ds->x2 - ds->x1) * sizeof(short)); - ds->drawsegclip.sprclipped = false; + ds->drawsegclip.bFogBoundary = false; // don't draw fogboundary again + ds->drawsegclip.SetRangeUndrawn(ds->x1, ds->x2); } } } diff --git a/src/rendering/swrenderer/segments/r_drawsegment.cpp b/src/rendering/swrenderer/segments/r_drawsegment.cpp index f5d2cc6a6..f90f8db55 100644 --- a/src/rendering/swrenderer/segments/r_drawsegment.cpp +++ b/src/rendering/swrenderer/segments/r_drawsegment.cpp @@ -134,7 +134,7 @@ namespace swrenderer if (ds->drawsegclip.silhouette & SIL_BOTTOM) { short *clip1 = clipbottom + ds->x1; - const short *clip2 = ds->drawsegclip.sprbottomclip; + const short *clip2 = ds->drawsegclip.sprbottomclip + ds->x1; int i = ds->x2 - ds->x1; do { @@ -148,7 +148,7 @@ namespace swrenderer if (ds->drawsegclip.silhouette & SIL_TOP) { short *clip1 = cliptop + ds->x1; - const short *clip2 = ds->drawsegclip.sprtopclip; + const short *clip2 = ds->drawsegclip.sprtopclip + ds->x1; int i = ds->x2 - ds->x1; do { @@ -168,4 +168,58 @@ namespace swrenderer SegmentGroups.Push(group); } } + + ///////////////////////////////////////////////////////////////////////// + + void DrawSegmentClipInfo::SetTopClip(RenderThread* thread, int x1, int x2, const short* ceilingclip) + { + short* clip = thread->FrameMemory->AllocMemory(x2 - x1); + memcpy(clip, ceilingclip + x1, (x2 - x1) * sizeof(short)); + sprtopclip = clip - x1; + } + + void DrawSegmentClipInfo::SetTopClip(RenderThread* thread, int x1, int x2, short value) + { + short* clip = thread->FrameMemory->AllocMemory(x2 - x1); + for (int i = 0; i < x2 - x1; i++) + clip[i] = value; + sprtopclip = clip - x1; + } + + void DrawSegmentClipInfo::SetBottomClip(RenderThread* thread, int x1, int x2, const short* floorclip) + { + short* clip = thread->FrameMemory->AllocMemory(x2 - x1); + memcpy(clip, floorclip + x1, (x2 - x1) * sizeof(short)); + sprbottomclip = clip - x1; + } + + void DrawSegmentClipInfo::SetBottomClip(RenderThread* thread, int x1, int x2, short value) + { + short* clip = thread->FrameMemory->AllocMemory(x2 - x1); + for (int i = 0; i < x2 - x1; i++) + clip[i] = value; + sprbottomclip = clip - x1; + } + + void DrawSegmentClipInfo::SetBackupClip(RenderThread* thread, int x1, int x2, const short* ceilingclip) + { + short* clip = thread->FrameMemory->AllocMemory(x2 - x1); + memcpy(clip, ceilingclip + x1, (x2 - x1) * sizeof(short)); + bkup = clip - x1; + } + + void DrawSegmentClipInfo::SetRangeDrawn(int x1, int x2) + { + sprclipped = true; + fillshort(const_cast(sprtopclip) + x1, x2 - x1, viewheight); + } + + void DrawSegmentClipInfo::SetRangeUndrawn(int x1, int x2) + { + if (sprclipped) + { + sprclipped = false; + memcpy(const_cast(sprtopclip) + x1, bkup + x1, (x2 - x1) * sizeof(short)); + } + } } diff --git a/src/rendering/swrenderer/segments/r_drawsegment.h b/src/rendering/swrenderer/segments/r_drawsegment.h index b814c57f6..8ef1d0ad7 100644 --- a/src/rendering/swrenderer/segments/r_drawsegment.h +++ b/src/rendering/swrenderer/segments/r_drawsegment.h @@ -27,16 +27,26 @@ namespace swrenderer { struct DrawSegmentClipInfo { - // Pointers to lists for sprite clipping, all three adjusted so [x1] is first value. - short* sprtopclip = nullptr; - short* sprbottomclip = nullptr; - short* bkup = nullptr; // sprtopclip backup, for translucent and 3d floor walls + void SetTopClip(RenderThread* thread, int x1, int x2, const short* ceilingclip); + void SetTopClip(RenderThread* thread, int x1, int x2, short value); + void SetBottomClip(RenderThread* thread, int x1, int x2, const short* floorclip); + void SetBottomClip(RenderThread* thread, int x1, int x2, short value); + void SetBackupClip(RenderThread* thread, int x1, int x2, const short* ceilingclip); + void SetRangeDrawn(int x1, int x2); + void SetRangeUndrawn(int x1, int x2); - bool sprclipped = false; // True if draw segment was used for clipping sprites uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both bool bFogBoundary = false; int CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping. int SubsectorDepth; + + // Pointers to lists for sprite clipping, all three adjusted so [x1] is first value. + const short* sprtopclip = nullptr; + const short* sprbottomclip = nullptr; + + private: + bool sprclipped = false; // True if draw segment was used for clipping sprites + const short* bkup = nullptr; }; struct DrawSegment diff --git a/src/rendering/swrenderer/segments/r_portalsegment.cpp b/src/rendering/swrenderer/segments/r_portalsegment.cpp index 34ed3677d..983921533 100644 --- a/src/rendering/swrenderer/segments/r_portalsegment.cpp +++ b/src/rendering/swrenderer/segments/r_portalsegment.cpp @@ -52,8 +52,8 @@ namespace swrenderer ceilingclip = thread->FrameMemory->AllocMemory(len); floorclip = thread->FrameMemory->AllocMemory(len); - memcpy(ceilingclip, topclip, len * sizeof(short)); - memcpy(floorclip, bottomclip, len * sizeof(short)); + memcpy(ceilingclip, topclip + x1, len * sizeof(short)); + memcpy(floorclip, bottomclip + x1, len * sizeof(short)); for (int i = 0; i < x2 - x1; i++) { diff --git a/src/rendering/swrenderer/things/r_visiblesprite.cpp b/src/rendering/swrenderer/things/r_visiblesprite.cpp index f2f9a843c..dab3c0066 100644 --- a/src/rendering/swrenderer/things/r_visiblesprite.cpp +++ b/src/rendering/swrenderer/things/r_visiblesprite.cpp @@ -434,7 +434,7 @@ namespace swrenderer if (ds->drawsegclip.silhouette & SIL_BOTTOM) //bottom sil { short *clip1 = clipbot + r1; - const short *clip2 = ds->drawsegclip.sprbottomclip + r1 - ds->x1; + const short *clip2 = ds->drawsegclip.sprbottomclip + r1; int i = r2 - r1; do { @@ -448,7 +448,7 @@ namespace swrenderer if (ds->drawsegclip.silhouette & SIL_TOP) // top sil { short *clip1 = cliptop + r1; - const short *clip2 = ds->drawsegclip.sprtopclip + r1 - ds->x1; + const short *clip2 = ds->drawsegclip.sprtopclip + r1; int i = r2 - r1; do {