From 3c25b2c066e55f58e09c02c27bacf464c145ed10 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Mar 2016 21:58:34 +0100 Subject: [PATCH] - some redesign of P_CheckSight to handle portals. Portal stuff not tested yet. --- src/actionspecials.h | 2 +- src/actor.h | 2 +- src/doomdata.h | 4 +- src/p_local.h | 2 +- src/p_map.cpp | 1 - src/p_maputl.cpp | 2 +- src/p_mobj.cpp | 3 +- src/p_sight.cpp | 281 ++++++++++++++++++++++++++++++++++--------- src/portal.cpp | 22 +++- src/portal.h | 6 + src/r_defs.h | 8 +- 11 files changed, 268 insertions(+), 65 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 07a177bfa..6d9d2feb8 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -140,7 +140,7 @@ DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2) DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3) // portal specials -DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3) +DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 4) // GZDoom/Vavoom specials // Although ZDoom doesn't support them it's better to have them defined so that // WADs using them somewhere can at least be started without aborting due diff --git a/src/actor.h b/src/actor.h index 344f5c267..760b11c27 100644 --- a/src/actor.h +++ b/src/actor.h @@ -743,7 +743,7 @@ public: inline bool IsNoClip2() const; void CheckPortalTransition(bool islinked); - fixedvec3 GetPortalTransition(fixed_t byoffset); + fixedvec3 GetPortalTransition(fixed_t byoffset, sector_t **pSec = NULL); // What species am I? virtual FName GetSpecies(); diff --git a/src/doomdata.h b/src/doomdata.h index 469847eaa..4d8254757 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -121,7 +121,7 @@ struct maplinedef2_t // LineDef attributes. // -enum ELineFlags +enum ELineFlags : unsigned { ML_BLOCKING =0x00000001, // solid, is an obstacle ML_BLOCKMONSTERS =0x00000002, // blocks monsters only @@ -163,6 +163,8 @@ enum ELineFlags ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING + + ML_PORTALCONNECT = 0x80000000, // for internal use only: This line connects to a sector with a linked portal (used to speed up sight checks.) }; diff --git a/src/p_local.h b/src/p_local.h index 47911f5f1..abd759d2a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -275,7 +275,7 @@ void P_PlayerStartStomp (AActor *actor, bool mononly=false); // [RH] Stomp on t void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); bool P_BounceWall (AActor *mo); bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); -bool P_CheckSight (const AActor *t1, const AActor *t2, int flags=0); +bool P_CheckSight (AActor *t1, AActor *t2, int flags=0); enum ESightFlags { diff --git a/src/p_map.cpp b/src/p_map.cpp index e3ed9329f..e4830c68f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5575,7 +5575,6 @@ void P_FindBelowIntersectors(AActor *actor) if (!(actor->flags & MF_SOLID)) return; - AActor *thing; FPortalGroupArray check; FMultiBlockThingsIterator it(check, actor); FMultiBlockThingsIterator::CheckResult cres; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index ffaa2b4e4..20fe996a5 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -162,7 +162,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, front = linedef->frontsector; back = linedef->backsector; - if (!(flags & FFCF_NOPORTALS)) + if (!(flags & FFCF_NOPORTALS) && (linedef->flags & ML_PORTALCONNECT)) { if (!linedef->frontsector->PortalBlocksMovement(sector_t::ceiling)) fc = FIXED_MAX; if (!linedef->backsector->PortalBlocksMovement(sector_t::ceiling)) bc = FIXED_MAX; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index cfbce5a73..a9e23c2a8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3285,7 +3285,7 @@ void AActor::SetRoll(angle_t r, bool interpolate) } -fixedvec3 AActor::GetPortalTransition(fixed_t byoffset) +fixedvec3 AActor::GetPortalTransition(fixed_t byoffset, sector_t **pSec) { bool moved = false; sector_t *sec = Sector; @@ -3316,6 +3316,7 @@ fixedvec3 AActor::GetPortalTransition(fixed_t byoffset) else break; } } + if (pSec) *pSec = sec; return pos; } diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 0b1afe430..39807e484 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -48,13 +48,48 @@ static int sightcounts[6]; static cycle_t SightCycles; static cycle_t MaxSightCycles; +enum +{ + SO_TOPFRONT = 1, + SO_TOPBACK = 2, + SO_BOTTOMFRONT = 4, + SO_BOTTOMBACK = 8, + +}; + +struct SightOpening +{ + fixed_t top; + fixed_t bottom; + int range; + int portalflags; + + void SwapSides() + { + portalflags = ((portalflags & (SO_TOPFRONT | SO_BOTTOMFRONT)) << 1) | ((portalflags & (SO_TOPBACK | SO_BOTTOMBACK)) >> 1); + } +}; + +struct SightTask +{ + fixed_t frac; + fixed_t topslope; + fixed_t bottomslope; + int direction; + int portalgroup; +}; + + static TArray intercepts (128); +static TArray portals(32); class SightCheck { - fixed_t sightzstart; // eye z of looker - const AActor * sightthing; - const AActor * seeingthing; + fixedvec3 sightstart; + fixedvec2 sightend; + fixed_t startfrac; + + AActor * seeingthing; fixed_t lastztop; // z at last line fixed_t lastzbottom; // z at last line sector_t * lastsector; // last sector being entered by trace @@ -63,28 +98,95 @@ class SightCheck divline_t trace; unsigned int myseethrough; + void P_SightOpening(SightOpening &open, const line_t *linedef, fixed_t x, fixed_t y); bool PTR_SightTraverse (intercept_t *in); bool P_SightCheckLine (line_t *ld); - bool P_SightBlockLinesIterator (int x, int y); + int P_SightBlockLinesIterator (int x, int y); bool P_SightTraverseIntercepts (); public: - bool P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); + bool P_SightPathTraverse (); - SightCheck(const AActor * t1, const AActor * t2, int flags) + void init(AActor * t1, AActor * t2, sector_t *startsector, SightTask *task, int flags) { - lastztop = lastzbottom = sightzstart = t1->Z() + t1->height - (t1->height>>2); - lastsector = t1->Sector; - sightthing=t1; + sightstart = t1->PosRelative(startsector); + sightend = t2->PosRelative(startsector); + sightstart.z += t1->height - (t1->height >> 2); + + startfrac = task->frac; + trace = { sightstart.x, sightstart.y, sightend.x - sightstart.x, sightend.y - sightstart.y }; + lastztop = lastzbottom = sightstart.z; + lastsector = startsector; seeingthing=t2; - bottomslope = t2->Z() - sightzstart; - topslope = bottomslope + t2->height; + topslope = task->topslope; + bottomslope = task->bottomslope; Flags = flags; + portaldir = task->direction; myseethrough = FF_SEETHROUGH; + + if (portaldir != sector_t::floor && !t1->Sector->PortalBlocksSight(sector_t::ceiling)) + { + portals.Push({ 0, topslope, bottomslope, sector_t::ceiling, t1->Sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup }); + } + if (portaldir != sector_t::ceiling && !t1->Sector->PortalBlocksSight(sector_t::floor)) + { + portals.Push({ 0, topslope, bottomslope, sector_t::floor, t1->Sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup }); + } } }; +//========================================================================== +// +// P_SightOpening +// +// Simplified version that removes everything not needed for a sight check +// +//========================================================================== + +void SightCheck::P_SightOpening(SightOpening &open, const line_t *linedef, fixed_t x, fixed_t y) +{ + open.portalflags = 0; + sector_t *front = linedef->frontsector; + sector_t *back = linedef->backsector; + + if (back == NULL) + { + // single sided line + if (linedef->flags & ML_PORTALCONNECT) + { + if (!front->PortalBlocksSight(sector_t::ceiling)) open.portalflags |= SO_TOPFRONT; + if (!front->PortalBlocksSight(sector_t::floor)) open.portalflags |= SO_BOTTOMFRONT; + } + + open.range = 0; + return; + } + + + fixed_t fc = 0, ff = 0, bc = 0, bf = 0; + + if (linedef->flags & ML_PORTALCONNECT) + { + if (!front->PortalBlocksSight(sector_t::ceiling)) fc = FIXED_MAX, open.portalflags |= SO_TOPFRONT; + if (!back->PortalBlocksSight(sector_t::ceiling)) bc = FIXED_MAX, open.portalflags |= SO_TOPBACK; + if (!front->PortalBlocksSight(sector_t::floor)) ff = FIXED_MIN, open.portalflags |= SO_BOTTOMFRONT; + if (!back->PortalBlocksSight(sector_t::floor)) bf = FIXED_MIN, open.portalflags |= SO_BOTTOMBACK; + } + + if (fc == 0) fc = front->ceilingplane.ZatPoint(x, y); + if (bc == 0) bc = back->ceilingplane.ZatPoint(x, y); + if (ff == 0) ff = front->floorplane.ZatPoint(x, y); + if (bf == 0) bf = back->floorplane.ZatPoint(x, y); + + open.bottom = MAX(ff, bf); + open.top = MIN(fc, bc); + + // we only want to know if there is an opening, not how large it is. + open.range = open.bottom >= open.top ? 0 : 1; +} + + /* ============== = @@ -93,14 +195,12 @@ public: ============== */ -/* -static bool PTR_SightTraverse (intercept_t *in) -*/ bool SightCheck::PTR_SightTraverse (intercept_t *in) { line_t *li; fixed_t slope; - FLineOpening open; + SightOpening open; + int frontflag = -1; li = in->d.line; @@ -114,30 +214,68 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) fixed_t trX=trace.x + FixedMul (trace.dx, in->frac); fixed_t trY=trace.y + FixedMul (trace.dy, in->frac); - P_LineOpening (open, NULL, li, trX, trY); + P_SightOpening (open, li, trX, trY); - if (open.range <= 0) // quick test for totally closed doors + FLinePortal *lport = li->getPortal(); + + if (open.range == 0 && open.portalflags == 0 && (lport == NULL || lport->mType != PORTT_LINKED)) // quick test for totally closed doors (must be delayed if portal checks are needed, though) return false; // stop // check bottom - slope = FixedDiv (open.bottom - sightzstart, in->frac); - if (slope > bottomslope) - bottomslope = slope; + if (open.bottom > FIXED_MIN) + { + slope = FixedDiv(open.bottom - sightstart.z, in->frac); + if (slope > bottomslope) + bottomslope = slope; + } // check top - slope = FixedDiv (open.top - sightzstart, in->frac); - if (slope < topslope) - topslope = slope; + if (open.top < FIXED_MAX) + { + slope = FixedDiv(open.top - sightstart.z, in->frac); + if (slope < topslope) + topslope = slope; + } - if (topslope <= bottomslope) + if (open.portalflags) + { + sector_t *frontsec, *backsec; + frontflag = P_PointOnLineSidePrecise(sightstart.x, sightstart.y, li); + if (!frontflag) + { + frontsec = li->frontsector; + backsec = li->backsector; + } + else + { + frontsec = li->backsector; + if (!frontsec) return false; // We are looking through the backside of a one-sided line. Just abort if that happens. + backsec = li->backsector; + open.SwapSides(); // swap flags to make the next checks simpler. + } + + if (portaldir != sector_t::floor && (open.portalflags & SO_TOPBACK) && !(open.portalflags & SO_TOPFRONT)) + { + portals.Push({ in->frac, topslope, bottomslope, sector_t::ceiling, backsec->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup }); + } + if (portaldir != sector_t::ceiling && (open.portalflags & SO_BOTTOMBACK) && !(open.portalflags & SO_BOTTOMFRONT)) + { + portals.Push({ in->frac, topslope, bottomslope, sector_t::floor, backsec->SkyBoxes[sector_t::floor]->Sector->PortalGroup }); + } + } + if (lport) + { + portals.Push({ in->frac, topslope, bottomslope, portaldir, lport->mDestination->frontsector->PortalGroup }); + return false; + } + + if (topslope <= bottomslope || open.range == 0) return false; // stop // now handle 3D-floors if(li->frontsector->e->XFloor.ffloors.Size() || li->backsector->e->XFloor.ffloors.Size()) { - int frontflag; - - frontflag = P_PointOnLineSidePrecise(sightthing->X(), sightthing->Y(), li); + if (frontflag == -1) frontflag = P_PointOnLineSidePrecise(sightstart.x, sightstart.y, li); //Check 3D FLOORS! for(int i=1;i<=2;i++) @@ -145,8 +283,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) sector_t * s=i==1? li->frontsector:li->backsector; fixed_t highslope, lowslope; - fixed_t topz= FixedMul (topslope, in->frac) + sightzstart; - fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightzstart; + fixed_t topz= FixedMul (topslope, in->frac) + sightstart.z; + fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightstart.z; for(unsigned int j=0;je->XFloor.ffloors.Size();j++) { @@ -158,8 +296,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) fixed_t ff_bottom=rover->bottom.plane->ZatPoint(trX, trY); fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY); - highslope = FixedDiv (ff_top - sightzstart, in->frac); - lowslope = FixedDiv (ff_bottom - sightzstart, in->frac); + highslope = FixedDiv (ff_top - sightstart.z, in->frac); + lowslope = FixedDiv (ff_bottom - sightstart.z, in->frac); if (highslope>=topslope) { @@ -221,8 +359,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) } else lastsector=NULL; // don't need it if there are no 3D-floors - lastztop= FixedMul (topslope, in->frac) + sightzstart; - lastzbottom= FixedMul (bottomslope, in->frac) + sightzstart; + lastztop= FixedMul (topslope, in->frac) + sightstart.z; + lastzbottom= FixedMul (bottomslope, in->frac) + sightstart.z; return true; // keep going } @@ -308,18 +446,22 @@ bool SightCheck::P_SightCheckLine (line_t *ld) =================== */ -bool SightCheck::P_SightBlockLinesIterator (int x, int y) +int SightCheck::P_SightBlockLinesIterator (int x, int y) { int offset; int *list; + int res = 1; + bool portals; polyblock_t *polyLink; unsigned int i; extern polyblock_t **PolyBlockMap; offset = y*bmapwidth+x; + portals = PortalBlockmap(x, y).containsLinkedPortals; polyLink = PolyBlockMap[offset]; + portals |= (polyLink && PortalBlockmap.hasLinkedPolyPortals); while (polyLink) { if (polyLink->polyobj) @@ -329,8 +471,11 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y) polyLink->polyobj->validcount = validcount; for (i = 0; i < polyLink->polyobj->Linedefs.Size(); i++) { - if (!P_SightCheckLine (polyLink->polyobj->Linedefs[i])) - return false; + if (!P_SightCheckLine(polyLink->polyobj->Linedefs[i])) + { + if (!portals) return 0; + else res = -1; + } } } } @@ -342,10 +487,13 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y) for (list = blockmaplump + offset + 1; *list != -1; list++) { if (!P_SightCheckLine (&lines[*list])) - return false; + { + if (!portals) return 0; + else res = -1; + } } - return true; // everything was checked + return res; // everything was checked } /* @@ -378,8 +526,7 @@ bool SightCheck::P_SightTraverseIntercepts () // // go through in order -// [RH] Is it really necessary to go through in order? All we care about is if -// the trace is obstructed, not what specifically obstructed it. +// proper order is needed to handle 3D floors and portals. // in = NULL; @@ -408,8 +555,8 @@ bool SightCheck::P_SightTraverseIntercepts () { // we must do one last check whether the trace has crossed a 3D floor in the last sector - fixed_t topz= topslope + sightzstart; - fixed_t bottomz= bottomslope + sightzstart; + fixed_t topz= topslope + sightstart.z; + fixed_t bottomz= bottomslope + sightstart.z; for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) { @@ -441,8 +588,9 @@ bool SightCheck::P_SightTraverseIntercepts () ================== */ -bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) +bool SightCheck::P_SightPathTraverse () { + fixed_t x1, x2, y1, y2; fixed_t xt1,yt1,xt2,yt2; long long _x1,_y1,_x2,_y2; fixed_t xstep,ystep; @@ -453,6 +601,11 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ validcount++; intercepts.Clear (); + x1 = sightstart.x + FixedMul(startfrac, trace.dx); + y1 = sightstart.y + FixedMul(startfrac, trace.dy); + x2 = sightend.x; + y2 = sightend.y; + if (lastsector == NULL) lastsector = P_PointInSector(x1, y1); // for FF_SEETHROUGH the following rule applies: // If the viewer is in an area without FF_SEETHROUGH he can only see into areas without this flag @@ -463,10 +616,10 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ if(!(rover->flags & FF_EXISTS)) continue; - fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightthing); - fixed_t ff_top=rover->top.plane->ZatPoint(sightthing); + fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightstart); + fixed_t ff_top=rover->top.plane->ZatPoint(sightstart); - if (sightzstart < ff_top && sightzstart >= ff_bottom) + if (sightstart.z < ff_top && sightstart.z >= ff_bottom) { myseethrough = rover->flags & FF_SEETHROUGH; break; @@ -477,10 +630,6 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ x1 += FRACUNIT; // don't side exactly on a line if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0) y1 += FRACUNIT; // don't side exactly on a line - trace.x = x1; - trace.y = y1; - trace.dx = x2 - x1; - trace.dy = y2 - y1; _x1 = (long long)x1 - bmaporgx; _y1 = (long long)y1 - bmaporgy; @@ -572,13 +721,15 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ for (count = 0 ; count < 100 ; count++) { - if (!P_SightBlockLinesIterator (mapx, mapy)) + int res = P_SightBlockLinesIterator(mapx, mapy); + if (res == 0) { sightcounts[1]++; return false; // early out } - if ((mapxstep | mapystep) == 0) + // either reached the end or had an early-out condition with portals left to check, + if (res == -1 || (mapxstep | mapystep) == 0) break; switch ((((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx)) @@ -649,7 +800,7 @@ sightcounts[2]++; ===================== */ -bool P_CheckSight (const AActor *t1, const AActor *t2, int flags) +bool P_CheckSight (AActor *t1, AActor *t2, int flags) { SightCycles.Clock(); @@ -717,8 +868,28 @@ sightcounts[0]++; validcount++; { - SightCheck s(t1, t2, flags); - res = s.P_SightPathTraverse (t1->X(), t1->Y(), t2->X(), t2->Y()); + sector_t *sec; + fixed_t lookheight = t1->height - (t1->height >> 2); + t1->GetPortalTransition(lookheight, &sec); + + fixed_t bottomslope = t2->Z() - (t1->Z() + lookheight); + fixed_t topslope = bottomslope + t2->height; + SightTask task = { 0, topslope, bottomslope, -1, sec->PortalGroup }; + + + SightCheck s; + s.init(t1, t2, sec, &task, flags); + res = s.P_SightPathTraverse (); + if (!res) + { + fixed_t dist = t1->AproxDistance(t2); + for (unsigned i = 0; i < portals.Size(); i++) + { + portals[i].frac += FixedDiv(FRACUNIT, dist); + s.init(t1, t2, NULL, &portals[i], flags); + if (s.P_SightPathTraverse()) break; + } + } } done: diff --git a/src/portal.cpp b/src/portal.cpp index e37697944..d615da3c9 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -122,15 +122,27 @@ static void BuildBlockmap() PortalBlockmap.containsLines = true; block.portallines.Push(ld); block.neighborContainsLines = true; + if (ld->getPortal()->mType == PORTT_LINKED) block.containsLinkedPortals = true; if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true; if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true; if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true; if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).neighborContainsLines = true; } + else + { + + bool yes = ld->frontsector->PortalIsLinked(sector_t::ceiling) || ld->frontsector->PortalIsLinked(sector_t::floor); + if (ld->backsector) + { + yes |= ld->backsector->PortalIsLinked(sector_t::ceiling) || ld->backsector->PortalIsLinked(sector_t::floor); + } + block.containsLinkedPortals |= yes; + PortalBlockmap.hasLinkedSectorPortals |= yes; + + } } } } - if (!PortalBlockmap.containsLines) PortalBlockmap.Clear(); } //=========================================================================== @@ -1066,6 +1078,14 @@ void P_CreateLinkedPortals() { sectors[i].CheckPortalPlane(sector_t::floor); sectors[i].CheckPortalPlane(sector_t::ceiling); + // set a flag on each line connecting to a plane portal sector. This is used to reduce the amount of checks in P_CheckSight. + if (sectors[i].PortalIsLinked(sector_t::floor) || sectors[i].PortalIsLinked(sector_t::ceiling)) + { + for (int j = 0; j < sectors[j].linecount; j++) + { + sectors[i].lines[j]->flags |= ML_PORTALCONNECT; + } + } } //BuildBlockmap(); } diff --git a/src/portal.h b/src/portal.h index b8a5d3ba3..d5a781f2d 100644 --- a/src/portal.h +++ b/src/portal.h @@ -78,11 +78,13 @@ extern FDisplacementTable Displacements; struct FPortalBlock { bool neighborContainsLines; // this is for skipping the traverser and exiting early if we can quickly decide that there's no portals nearby. + bool containsLinkedPortals; // this is for sight check optimization. We can't early-out on an impenetrable line if there may be portals being found in the same block later on. TArray portallines; FPortalBlock() { neighborContainsLines = false; + containsLinkedPortals = false; } }; @@ -91,6 +93,8 @@ struct FPortalBlockmap TArray data; int dx, dy; bool containsLines; + bool hasLinkedSectorPortals; // global flag to shortcut portal checks if the map has none. + bool hasLinkedPolyPortals; // this means that any early-outs in P_CheckSight need to be disabled if a block contains polyobjects. void Create(int blockx, int blocky) { @@ -105,6 +109,8 @@ struct FPortalBlockmap data.ShrinkToFit(); dx = dy = 0; containsLines = false; + hasLinkedPolyPortals = false; + hasLinkedSectorPortals = false; } FPortalBlock &operator()(int x, int y) diff --git a/src/r_defs.h b/src/r_defs.h index 468144ffc..248329da4 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -185,7 +185,6 @@ public: // class DSectorEffect; struct sector_t; -struct line_t; struct FRemapTable; enum @@ -769,7 +768,7 @@ struct sector_t bool PortalBlocksSight(int plane) { if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; - return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } bool PortalBlocksMovement(int plane) @@ -784,6 +783,11 @@ struct sector_t return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } + bool PortalIsLinked(int plane) + { + return (SkyBoxes[plane] != NULL && SkyBoxes[plane]->special1 == SKYBOX_LINKEDPORTAL); + } + // These may only be called if the portal has been validated fixedvec2 FloorDisplacement() {