From 2321c9973f778717da202ae9907c58fc2ea50aca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 29 Feb 2016 12:39:03 +0100 Subject: [PATCH] - fixed some serious efficiency problems with clipping masked geometry against portals. The function to do the work scanned the full list of drawsegs to find portals, which with a large amount of masked geometry and/or drawsegs could become extremely slow. Changed it so that R_DrawMasked collects all portal related drawsegs up front so that the actual clipping code can a) scan a far shorter list and b) can skip half of the validation. Also using P_PointOnLinePrecise to shave off a small bit of additional time. --- src/r_things.cpp | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/r_things.cpp b/src/r_things.cpp index 1fb4c845be..21fd1605b7 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -324,18 +324,19 @@ nextpost: // [ZZ] // R_ClipSpriteColumnWithPortals // -static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprite_t* spr) -{ - // [ZZ] 10.01.2016: don't clip sprites from the root of a skybox. - if (CurrentPortalInSkybox) - return false; +static TArray portaldrawsegs; + +static inline void R_CollectPortals() +{ + // This function collects all drawsegs that may be of interest to R_ClipSpriteColumnWithPortals + // Having that function over the entire list of drawsegs can break down performance quite drastically. + // This is doing the costly stuff only once so that R_ClipSpriteColumnWithPortals can + // a) exit early if no relevant info is found and + // b) skip most of the collected drawsegs which have no portal attached. + portaldrawsegs.Clear(); for (drawseg_t* seg = ds_p; seg-- > firstdrawseg; ) // copied code from killough below { - // ignore segs from other portals - if (seg->CurrentPortalUniq != CurrentPortalUniq) - continue; - // I don't know what makes this happen (some old top-down portal code or possibly skybox code? something adds null lines...) // crashes at the first frame of the first map of Action2.wad if (!seg->curline) continue; @@ -352,8 +353,28 @@ static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprit if (seg->curline->sidedef != line->sidedef[0]) continue; + portaldrawsegs.Push(seg); + } +} + +static inline bool R_ClipSpriteColumnWithPortals(fixed_t x, fixed_t y, vissprite_t* spr) +{ + // [ZZ] 10.01.2016: don't clip sprites from the root of a skybox. + if (CurrentPortalInSkybox) + return false; + + for(drawseg_t *seg : portaldrawsegs) + { + // ignore segs from other portals + if (seg->CurrentPortalUniq != CurrentPortalUniq) + continue; + + // (all checks that are already done in R_CollectPortals have been removed for performance reasons.) + + line_t* line = seg->curline->linedef; + // don't clip if the sprite is in front of the portal - if (!P_PointOnLineSide(x, y, line)) + if (!P_PointOnLineSidePrecise(x, y, line)) continue; // now if current column is covered by this drawseg, we clip it away @@ -364,6 +385,7 @@ static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprit return false; } + // // R_DrawVisSprite // mfloorclip and mceilingclip should also be set. @@ -2332,6 +2354,7 @@ void R_DrawHeightPlanes(fixed_t height); // kg3D - fake planes void R_DrawMasked (void) { + R_CollectPortals(); R_SortVisSprites (DrewAVoxel ? sv_compare2d : sv_compare, firstvissprite - vissprites); if (height_top == NULL)