From 7d1de667befd80ef1f64082d358e1c813f453511 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 12 Jul 2017 06:56:34 +0200 Subject: [PATCH] - Added r_line_distance_cull cvar that culls lines beyond the specified distance --- src/CMakeLists.txt | 1 + src/swrenderer/line/r_farclip_line.cpp | 190 +++++++++++++++++++++++++ src/swrenderer/line/r_farclip_line.h | 60 ++++++++ src/swrenderer/r_all.cpp | 1 + src/swrenderer/scene/r_opaque_pass.cpp | 26 +++- 5 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 src/swrenderer/line/r_farclip_line.cpp create mode 100644 src/swrenderer/line/r_farclip_line.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c862d27e5..d44a60b8e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -691,6 +691,7 @@ set ( SWRENDER_SOURCES swrenderer/viewport/r_viewport.cpp swrenderer/viewport/r_walldrawer.cpp swrenderer/line/r_line.cpp + swrenderer/line/r_farclip_line.cpp swrenderer/line/r_walldraw.cpp swrenderer/line/r_wallsetup.cpp swrenderer/line/r_fogboundary.cpp diff --git a/src/swrenderer/line/r_farclip_line.cpp b/src/swrenderer/line/r_farclip_line.cpp new file mode 100644 index 000000000..95e559a24 --- /dev/null +++ b/src/swrenderer/line/r_farclip_line.cpp @@ -0,0 +1,190 @@ +//----------------------------------------------------------------------------- +// +// Copyright 2016 Magnus Norddahl +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//----------------------------------------------------------------------------- +// + +#include +#include +#include "templates.h" +#include "i_system.h" +#include "doomdef.h" +#include "doomstat.h" +#include "doomdata.h" +#include "p_lnspec.h" +#include "p_setup.h" +#include "r_sky.h" +#include "v_video.h" +#include "m_swap.h" +#include "w_wad.h" +#include "stats.h" +#include "a_sharedglobal.h" +#include "d_net.h" +#include "g_level.h" +#include "g_levellocals.h" +#include "r_wallsetup.h" +#include "v_palette.h" +#include "r_utility.h" +#include "r_data/colormaps.h" +#include "swrenderer/r_memory.h" +#include "swrenderer/scene/r_opaque_pass.h" +#include "swrenderer/scene/r_3dfloors.h" +#include "swrenderer/scene/r_portal.h" +#include "swrenderer/scene/r_light.h" +#include "swrenderer/scene/r_scene.h" +#include "swrenderer/viewport/r_viewport.h" +#include "swrenderer/line/r_farclip_line.h" +#include "swrenderer/line/r_walldraw.h" +#include "swrenderer/line/r_wallsetup.h" +#include "swrenderer/drawers/r_draw.h" +#include "swrenderer/segments/r_clipsegment.h" +#include "swrenderer/segments/r_drawsegment.h" +#include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/plane/r_visibleplanelist.h" +#include "swrenderer/viewport/r_skydrawer.h" +#include "swrenderer/r_renderthread.h" + +namespace swrenderer +{ + FarClipLine::FarClipLine(RenderThread *thread) + { + Thread = thread; + } + + void FarClipLine::Render(seg_t *line, subsector_t *subsector, VisiblePlane *linefloorplane, VisiblePlane *lineceilingplane) + { + mSubsector = subsector; + mFrontSector = mSubsector->sector; + mLineSegment = line; + mFloorPlane = linefloorplane; + mCeilingPlane = lineceilingplane; + + DVector2 pt1 = line->v1->fPos() - Thread->Viewport->viewpoint.Pos; + DVector2 pt2 = line->v2->fPos() - Thread->Viewport->viewpoint.Pos; + + // Reject lines not facing viewer + 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))) + return; + + RenderPortal *renderportal = Thread->Portal.get(); + if (WallC.sx1 >= renderportal->WindowRight || WallC.sx2 <= renderportal->WindowLeft) + return; + + if (line->linedef == nullptr) + return; + + // reject lines that aren't seen from the portal (if any) + // [ZZ] 10.01.2016: lines inside a skybox shouldn't be clipped, although this imposes some limitations on portals in skyboxes. + if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos)) + return; + + mFrontCeilingZ1 = mFrontSector->ceilingplane.ZatPoint(line->v1); + mFrontFloorZ1 = mFrontSector->floorplane.ZatPoint(line->v1); + mFrontCeilingZ2 = mFrontSector->ceilingplane.ZatPoint(line->v2); + mFrontFloorZ2 = mFrontSector->floorplane.ZatPoint(line->v2); + + mPrepped = false; + + Thread->ClipSegments->Clip(WallC.sx1, WallC.sx2, true, this); + } + + bool FarClipLine::RenderWallSegment(int x1, int x2) + { + if (!mPrepped) + { + mPrepped = true; + + //walltop.Project(Thread->Viewport.get(), mFrontSector->ceilingplane, &WallC, mLineSegment, Thread->Portal->MirrorFlags & RF_XFLIP); + wallbottom.Project(Thread->Viewport.get(), mFrontSector->floorplane, &WallC, mLineSegment, Thread->Portal->MirrorFlags & RF_XFLIP); + memcpy(walltop.ScreenY, wallbottom.ScreenY, sizeof(short) * MAXWIDTH); + } + + ClipSegmentTopBottom(x1, x2); + MarkCeilingPlane(x1, x2); + MarkFloorPlane(x1, x2); + + return true; + } + + void FarClipLine::ClipSegmentTopBottom(int x1, int x2) + { + // clip wall to the floor and ceiling + auto ceilingclip = Thread->OpaquePass->ceilingclip; + auto floorclip = Thread->OpaquePass->floorclip; + for (int x = x1; x < x2; ++x) + { + if (walltop.ScreenY[x] < ceilingclip[x]) + { + walltop.ScreenY[x] = ceilingclip[x]; + } + if (wallbottom.ScreenY[x] > floorclip[x]) + { + wallbottom.ScreenY[x] = floorclip[x]; + } + } + } + + void FarClipLine::MarkCeilingPlane(int x1, int x2) + { + if (mCeilingPlane) + { + mCeilingPlane = Thread->PlaneList->GetRange(mCeilingPlane, x1, x2); + + auto ceilingclip = Thread->OpaquePass->ceilingclip; + auto floorclip = Thread->OpaquePass->floorclip; + Clip3DFloors *clip3d = Thread->Clip3D.get(); + + for (int x = x1; x < x2; ++x) + { + short top = (clip3d->fakeFloor && clip3d->fake3D & FAKE3D_FAKECEILING) ? clip3d->fakeFloor->ceilingclip[x] : ceilingclip[x]; + short bottom = MIN(walltop.ScreenY[x], floorclip[x]); + if (top < bottom) + { + mCeilingPlane->top[x] = top; + mCeilingPlane->bottom[x] = bottom; + } + } + } + } + + void FarClipLine::MarkFloorPlane(int x1, int x2) + { + if (mFloorPlane) + { + mFloorPlane = Thread->PlaneList->GetRange(mFloorPlane, x1, x2); + + auto ceilingclip = Thread->OpaquePass->ceilingclip; + auto floorclip = Thread->OpaquePass->floorclip; + Clip3DFloors *clip3d = Thread->Clip3D.get(); + + for (int x = x1; x < x2; ++x) + { + short top = MAX(wallbottom.ScreenY[x], ceilingclip[x]); + short bottom = (clip3d->fakeFloor && clip3d->fake3D & FAKE3D_FAKEFLOOR) ? clip3d->fakeFloor->floorclip[x] : floorclip[x]; + if (top < bottom) + { + assert(bottom <= viewheight); + mFloorPlane->top[x] = top; + mFloorPlane->bottom[x] = bottom; + } + } + } + } +} diff --git a/src/swrenderer/line/r_farclip_line.h b/src/swrenderer/line/r_farclip_line.h new file mode 100644 index 000000000..c450a6383 --- /dev/null +++ b/src/swrenderer/line/r_farclip_line.h @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------------- +// +// Copyright 2016 Magnus Norddahl +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//----------------------------------------------------------------------------- +// + +#pragma once + +#include "r_line.h" + +namespace swrenderer +{ + class FarClipLine : VisibleSegmentRenderer + { + public: + FarClipLine(RenderThread *thread); + void Render(seg_t *line, subsector_t *subsector, VisiblePlane *linefloorplane, VisiblePlane *lineceilingplane); + + RenderThread *Thread = nullptr; + + private: + bool RenderWallSegment(int x1, int x2) override; + + void ClipSegmentTopBottom(int x1, int x2); + void MarkCeilingPlane(int x1, int x2); + void MarkFloorPlane(int x1, int x2); + + subsector_t *mSubsector; + sector_t *mFrontSector; + seg_t *mLineSegment; + VisiblePlane *mFloorPlane; + VisiblePlane *mCeilingPlane; + + double mFrontCeilingZ1; + double mFrontCeilingZ2; + double mFrontFloorZ1; + double mFrontFloorZ2; + + FWallCoords WallC; + + bool mPrepped; + + ProjectedWallLine walltop; + ProjectedWallLine wallbottom; + }; +} diff --git a/src/swrenderer/r_all.cpp b/src/swrenderer/r_all.cpp index 20a9f4ee8..296fc04cf 100644 --- a/src/swrenderer/r_all.cpp +++ b/src/swrenderer/r_all.cpp @@ -9,6 +9,7 @@ #include "drawers/r_thread.cpp" #include "line/r_fogboundary.cpp" #include "line/r_line.cpp" +#include "line/r_farclip_line.cpp" #include "line/r_renderdrawsegment.cpp" #include "line/r_walldraw.cpp" #include "line/r_wallsetup.cpp" diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index da820d7d2..1c190d7df 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -47,6 +47,7 @@ #include "swrenderer/things/r_particle.h" #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/line/r_wallsetup.h" +#include "swrenderer/line/r_farclip_line.h" #include "swrenderer/scene/r_scene.h" #include "swrenderer/scene/r_light.h" #include "swrenderer/viewport/r_viewport.h" @@ -72,6 +73,20 @@ EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); EXTERN_CVAR(Bool, r_drawvoxels); +namespace { double line_distance_cull = 1e16; } + +CUSTOM_CVAR(Float, r_line_distance_cull, 8000.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (r_line_distance_cull > 0.0) + { + line_distance_cull = r_line_distance_cull * r_line_distance_cull; + } + else + { + line_distance_cull = 1e16; + } +} + namespace swrenderer { RenderOpaquePass::RenderOpaquePass(RenderThread *thread) : renderline(thread) @@ -730,10 +745,19 @@ namespace swrenderer count = sub->numlines; line = sub->firstline; + DVector2 viewpointPos = Thread->Viewport->viewpoint.Pos.XY(); + basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]); while (count--) { - if (!outersubsector || line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ)) + double dist1 = (line->v1->fPos() - viewpointPos).LengthSquared(); + double dist2 = (line->v2->fPos() - viewpointPos).LengthSquared(); + if (dist1 > line_distance_cull && dist2 > line_distance_cull) + { + FarClipLine farclip(Thread); + farclip.Render(line, InSubsector, floorplane, ceilingplane); + } + else if (!outersubsector || line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ)) { // kg3D - fake planes bounding calculation if (r_3dfloors && line->backsector && frontsector->e && line->backsector->e->XFloor.ffloors.Size())