mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-01-31 13:00:59 +00:00
- some redesign of P_CheckSight to handle portals.
Portal stuff not tested yet.
This commit is contained in:
parent
f82c217047
commit
3c25b2c066
11 changed files with 268 additions and 65 deletions
|
@ -140,7 +140,7 @@ DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2)
|
||||||
|
|
||||||
DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3)
|
DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3)
|
||||||
// portal specials
|
// portal specials
|
||||||
DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3)
|
DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 4)
|
||||||
// GZDoom/Vavoom specials
|
// GZDoom/Vavoom specials
|
||||||
// Although ZDoom doesn't support them it's better to have them defined so that
|
// 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
|
// WADs using them somewhere can at least be started without aborting due
|
||||||
|
|
|
@ -743,7 +743,7 @@ public:
|
||||||
|
|
||||||
inline bool IsNoClip2() const;
|
inline bool IsNoClip2() const;
|
||||||
void CheckPortalTransition(bool islinked);
|
void CheckPortalTransition(bool islinked);
|
||||||
fixedvec3 GetPortalTransition(fixed_t byoffset);
|
fixedvec3 GetPortalTransition(fixed_t byoffset, sector_t **pSec = NULL);
|
||||||
|
|
||||||
// What species am I?
|
// What species am I?
|
||||||
virtual FName GetSpecies();
|
virtual FName GetSpecies();
|
||||||
|
|
|
@ -121,7 +121,7 @@ struct maplinedef2_t
|
||||||
// LineDef attributes.
|
// LineDef attributes.
|
||||||
//
|
//
|
||||||
|
|
||||||
enum ELineFlags
|
enum ELineFlags : unsigned
|
||||||
{
|
{
|
||||||
ML_BLOCKING =0x00000001, // solid, is an obstacle
|
ML_BLOCKING =0x00000001, // solid, is an obstacle
|
||||||
ML_BLOCKMONSTERS =0x00000002, // blocks monsters only
|
ML_BLOCKMONSTERS =0x00000002, // blocks monsters only
|
||||||
|
@ -163,6 +163,8 @@ enum ELineFlags
|
||||||
ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight
|
ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight
|
||||||
ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks
|
ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks
|
||||||
ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING
|
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.)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps);
|
||||||
bool P_BounceWall (AActor *mo);
|
bool P_BounceWall (AActor *mo);
|
||||||
bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop);
|
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
|
enum ESightFlags
|
||||||
{
|
{
|
||||||
|
|
|
@ -5575,7 +5575,6 @@ void P_FindBelowIntersectors(AActor *actor)
|
||||||
if (!(actor->flags & MF_SOLID))
|
if (!(actor->flags & MF_SOLID))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AActor *thing;
|
|
||||||
FPortalGroupArray check;
|
FPortalGroupArray check;
|
||||||
FMultiBlockThingsIterator it(check, actor);
|
FMultiBlockThingsIterator it(check, actor);
|
||||||
FMultiBlockThingsIterator::CheckResult cres;
|
FMultiBlockThingsIterator::CheckResult cres;
|
||||||
|
|
|
@ -162,7 +162,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
|
||||||
front = linedef->frontsector;
|
front = linedef->frontsector;
|
||||||
back = linedef->backsector;
|
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->frontsector->PortalBlocksMovement(sector_t::ceiling)) fc = FIXED_MAX;
|
||||||
if (!linedef->backsector->PortalBlocksMovement(sector_t::ceiling)) bc = FIXED_MAX;
|
if (!linedef->backsector->PortalBlocksMovement(sector_t::ceiling)) bc = FIXED_MAX;
|
||||||
|
|
|
@ -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;
|
bool moved = false;
|
||||||
sector_t *sec = Sector;
|
sector_t *sec = Sector;
|
||||||
|
@ -3316,6 +3316,7 @@ fixedvec3 AActor::GetPortalTransition(fixed_t byoffset)
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (pSec) *pSec = sec;
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
273
src/p_sight.cpp
273
src/p_sight.cpp
|
@ -48,13 +48,48 @@ static int sightcounts[6];
|
||||||
static cycle_t SightCycles;
|
static cycle_t SightCycles;
|
||||||
static cycle_t MaxSightCycles;
|
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<intercept_t> intercepts (128);
|
static TArray<intercept_t> intercepts (128);
|
||||||
|
static TArray<SightTask> portals(32);
|
||||||
|
|
||||||
class SightCheck
|
class SightCheck
|
||||||
{
|
{
|
||||||
fixed_t sightzstart; // eye z of looker
|
fixedvec3 sightstart;
|
||||||
const AActor * sightthing;
|
fixedvec2 sightend;
|
||||||
const AActor * seeingthing;
|
fixed_t startfrac;
|
||||||
|
|
||||||
|
AActor * seeingthing;
|
||||||
fixed_t lastztop; // z at last line
|
fixed_t lastztop; // z at last line
|
||||||
fixed_t lastzbottom; // z at last line
|
fixed_t lastzbottom; // z at last line
|
||||||
sector_t * lastsector; // last sector being entered by trace
|
sector_t * lastsector; // last sector being entered by trace
|
||||||
|
@ -63,28 +98,95 @@ class SightCheck
|
||||||
divline_t trace;
|
divline_t trace;
|
||||||
unsigned int myseethrough;
|
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 PTR_SightTraverse (intercept_t *in);
|
||||||
bool P_SightCheckLine (line_t *ld);
|
bool P_SightCheckLine (line_t *ld);
|
||||||
bool P_SightBlockLinesIterator (int x, int y);
|
int P_SightBlockLinesIterator (int x, int y);
|
||||||
bool P_SightTraverseIntercepts ();
|
bool P_SightTraverseIntercepts ();
|
||||||
|
|
||||||
public:
|
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);
|
sightstart = t1->PosRelative(startsector);
|
||||||
lastsector = t1->Sector;
|
sightend = t2->PosRelative(startsector);
|
||||||
sightthing=t1;
|
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;
|
seeingthing=t2;
|
||||||
bottomslope = t2->Z() - sightzstart;
|
topslope = task->topslope;
|
||||||
topslope = bottomslope + t2->height;
|
bottomslope = task->bottomslope;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
|
portaldir = task->direction;
|
||||||
|
|
||||||
myseethrough = FF_SEETHROUGH;
|
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)
|
bool SightCheck::PTR_SightTraverse (intercept_t *in)
|
||||||
{
|
{
|
||||||
line_t *li;
|
line_t *li;
|
||||||
fixed_t slope;
|
fixed_t slope;
|
||||||
FLineOpening open;
|
SightOpening open;
|
||||||
|
int frontflag = -1;
|
||||||
|
|
||||||
li = in->d.line;
|
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 trX=trace.x + FixedMul (trace.dx, in->frac);
|
||||||
fixed_t trY=trace.y + FixedMul (trace.dy, 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
|
return false; // stop
|
||||||
|
|
||||||
// check bottom
|
// check bottom
|
||||||
slope = FixedDiv (open.bottom - sightzstart, in->frac);
|
if (open.bottom > FIXED_MIN)
|
||||||
|
{
|
||||||
|
slope = FixedDiv(open.bottom - sightstart.z, in->frac);
|
||||||
if (slope > bottomslope)
|
if (slope > bottomslope)
|
||||||
bottomslope = slope;
|
bottomslope = slope;
|
||||||
|
}
|
||||||
|
|
||||||
// check top
|
// check top
|
||||||
slope = FixedDiv (open.top - sightzstart, in->frac);
|
if (open.top < FIXED_MAX)
|
||||||
|
{
|
||||||
|
slope = FixedDiv(open.top - sightstart.z, in->frac);
|
||||||
if (slope < topslope)
|
if (slope < topslope)
|
||||||
topslope = slope;
|
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
|
return false; // stop
|
||||||
|
|
||||||
// now handle 3D-floors
|
// now handle 3D-floors
|
||||||
if(li->frontsector->e->XFloor.ffloors.Size() || li->backsector->e->XFloor.ffloors.Size())
|
if(li->frontsector->e->XFloor.ffloors.Size() || li->backsector->e->XFloor.ffloors.Size())
|
||||||
{
|
{
|
||||||
int frontflag;
|
if (frontflag == -1) frontflag = P_PointOnLineSidePrecise(sightstart.x, sightstart.y, li);
|
||||||
|
|
||||||
frontflag = P_PointOnLineSidePrecise(sightthing->X(), sightthing->Y(), li);
|
|
||||||
|
|
||||||
//Check 3D FLOORS!
|
//Check 3D FLOORS!
|
||||||
for(int i=1;i<=2;i++)
|
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;
|
sector_t * s=i==1? li->frontsector:li->backsector;
|
||||||
fixed_t highslope, lowslope;
|
fixed_t highslope, lowslope;
|
||||||
|
|
||||||
fixed_t topz= FixedMul (topslope, in->frac) + sightzstart;
|
fixed_t topz= FixedMul (topslope, in->frac) + sightstart.z;
|
||||||
fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightzstart;
|
fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightstart.z;
|
||||||
|
|
||||||
for(unsigned int j=0;j<s->e->XFloor.ffloors.Size();j++)
|
for(unsigned int j=0;j<s->e->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_bottom=rover->bottom.plane->ZatPoint(trX, trY);
|
||||||
fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY);
|
fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY);
|
||||||
|
|
||||||
highslope = FixedDiv (ff_top - sightzstart, in->frac);
|
highslope = FixedDiv (ff_top - sightstart.z, in->frac);
|
||||||
lowslope = FixedDiv (ff_bottom - sightzstart, in->frac);
|
lowslope = FixedDiv (ff_bottom - sightstart.z, in->frac);
|
||||||
|
|
||||||
if (highslope>=topslope)
|
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
|
else lastsector=NULL; // don't need it if there are no 3D-floors
|
||||||
|
|
||||||
lastztop= FixedMul (topslope, in->frac) + sightzstart;
|
lastztop= FixedMul (topslope, in->frac) + sightstart.z;
|
||||||
lastzbottom= FixedMul (bottomslope, in->frac) + sightzstart;
|
lastzbottom= FixedMul (bottomslope, in->frac) + sightstart.z;
|
||||||
|
|
||||||
return true; // keep going
|
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 offset;
|
||||||
int *list;
|
int *list;
|
||||||
|
int res = 1;
|
||||||
|
bool portals;
|
||||||
|
|
||||||
polyblock_t *polyLink;
|
polyblock_t *polyLink;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
extern polyblock_t **PolyBlockMap;
|
extern polyblock_t **PolyBlockMap;
|
||||||
|
|
||||||
offset = y*bmapwidth+x;
|
offset = y*bmapwidth+x;
|
||||||
|
portals = PortalBlockmap(x, y).containsLinkedPortals;
|
||||||
|
|
||||||
polyLink = PolyBlockMap[offset];
|
polyLink = PolyBlockMap[offset];
|
||||||
|
portals |= (polyLink && PortalBlockmap.hasLinkedPolyPortals);
|
||||||
while (polyLink)
|
while (polyLink)
|
||||||
{
|
{
|
||||||
if (polyLink->polyobj)
|
if (polyLink->polyobj)
|
||||||
|
@ -329,8 +471,11 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y)
|
||||||
polyLink->polyobj->validcount = validcount;
|
polyLink->polyobj->validcount = validcount;
|
||||||
for (i = 0; i < polyLink->polyobj->Linedefs.Size(); i++)
|
for (i = 0; i < polyLink->polyobj->Linedefs.Size(); i++)
|
||||||
{
|
{
|
||||||
if (!P_SightCheckLine (polyLink->polyobj->Linedefs[i]))
|
if (!P_SightCheckLine(polyLink->polyobj->Linedefs[i]))
|
||||||
return false;
|
{
|
||||||
|
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++)
|
for (list = blockmaplump + offset + 1; *list != -1; list++)
|
||||||
{
|
{
|
||||||
if (!P_SightCheckLine (&lines[*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
|
// go through in order
|
||||||
// [RH] Is it really necessary to go through in order? All we care about is if
|
// proper order is needed to handle 3D floors and portals.
|
||||||
// the trace is obstructed, not what specifically obstructed it.
|
|
||||||
//
|
//
|
||||||
in = NULL;
|
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
|
// 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 topz= topslope + sightstart.z;
|
||||||
fixed_t bottomz= bottomslope + sightzstart;
|
fixed_t bottomz= bottomslope + sightstart.z;
|
||||||
|
|
||||||
for(unsigned int i=0;i<lastsector->e->XFloor.ffloors.Size();i++)
|
for(unsigned int i=0;i<lastsector->e->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;
|
fixed_t xt1,yt1,xt2,yt2;
|
||||||
long long _x1,_y1,_x2,_y2;
|
long long _x1,_y1,_x2,_y2;
|
||||||
fixed_t xstep,ystep;
|
fixed_t xstep,ystep;
|
||||||
|
@ -453,6 +601,11 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_
|
||||||
|
|
||||||
validcount++;
|
validcount++;
|
||||||
intercepts.Clear ();
|
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:
|
// 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
|
// 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;
|
if(!(rover->flags & FF_EXISTS)) continue;
|
||||||
|
|
||||||
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightthing);
|
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightstart);
|
||||||
fixed_t ff_top=rover->top.plane->ZatPoint(sightthing);
|
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;
|
myseethrough = rover->flags & FF_SEETHROUGH;
|
||||||
break;
|
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
|
x1 += FRACUNIT; // don't side exactly on a line
|
||||||
if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
|
if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
|
||||||
y1 += FRACUNIT; // don't side exactly on a line
|
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;
|
_x1 = (long long)x1 - bmaporgx;
|
||||||
_y1 = (long long)y1 - bmaporgy;
|
_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++)
|
for (count = 0 ; count < 100 ; count++)
|
||||||
{
|
{
|
||||||
if (!P_SightBlockLinesIterator (mapx, mapy))
|
int res = P_SightBlockLinesIterator(mapx, mapy);
|
||||||
|
if (res == 0)
|
||||||
{
|
{
|
||||||
sightcounts[1]++;
|
sightcounts[1]++;
|
||||||
return false; // early out
|
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;
|
break;
|
||||||
|
|
||||||
switch ((((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx))
|
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();
|
SightCycles.Clock();
|
||||||
|
|
||||||
|
@ -717,8 +868,28 @@ sightcounts[0]++;
|
||||||
|
|
||||||
validcount++;
|
validcount++;
|
||||||
{
|
{
|
||||||
SightCheck s(t1, t2, flags);
|
sector_t *sec;
|
||||||
res = s.P_SightPathTraverse (t1->X(), t1->Y(), t2->X(), t2->Y());
|
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:
|
done:
|
||||||
|
|
|
@ -122,15 +122,27 @@ static void BuildBlockmap()
|
||||||
PortalBlockmap.containsLines = true;
|
PortalBlockmap.containsLines = true;
|
||||||
block.portallines.Push(ld);
|
block.portallines.Push(ld);
|
||||||
block.neighborContainsLines = true;
|
block.neighborContainsLines = true;
|
||||||
|
if (ld->getPortal()->mType == PORTT_LINKED) block.containsLinkedPortals = true;
|
||||||
if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true;
|
if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true;
|
||||||
if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true;
|
if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true;
|
||||||
if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true;
|
if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true;
|
||||||
if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).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::floor);
|
||||||
sectors[i].CheckPortalPlane(sector_t::ceiling);
|
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();
|
//BuildBlockmap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,11 +78,13 @@ extern FDisplacementTable Displacements;
|
||||||
struct FPortalBlock
|
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 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<line_t*> portallines;
|
TArray<line_t*> portallines;
|
||||||
|
|
||||||
FPortalBlock()
|
FPortalBlock()
|
||||||
{
|
{
|
||||||
neighborContainsLines = false;
|
neighborContainsLines = false;
|
||||||
|
containsLinkedPortals = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,6 +93,8 @@ struct FPortalBlockmap
|
||||||
TArray<FPortalBlock> data;
|
TArray<FPortalBlock> data;
|
||||||
int dx, dy;
|
int dx, dy;
|
||||||
bool containsLines;
|
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)
|
void Create(int blockx, int blocky)
|
||||||
{
|
{
|
||||||
|
@ -105,6 +109,8 @@ struct FPortalBlockmap
|
||||||
data.ShrinkToFit();
|
data.ShrinkToFit();
|
||||||
dx = dy = 0;
|
dx = dy = 0;
|
||||||
containsLines = false;
|
containsLines = false;
|
||||||
|
hasLinkedPolyPortals = false;
|
||||||
|
hasLinkedSectorPortals = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FPortalBlock &operator()(int x, int y)
|
FPortalBlock &operator()(int x, int y)
|
||||||
|
|
|
@ -185,7 +185,6 @@ public:
|
||||||
//
|
//
|
||||||
class DSectorEffect;
|
class DSectorEffect;
|
||||||
struct sector_t;
|
struct sector_t;
|
||||||
struct line_t;
|
|
||||||
struct FRemapTable;
|
struct FRemapTable;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -769,7 +768,7 @@ struct sector_t
|
||||||
bool PortalBlocksSight(int plane)
|
bool PortalBlocksSight(int plane)
|
||||||
{
|
{
|
||||||
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
|
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)
|
bool PortalBlocksMovement(int plane)
|
||||||
|
@ -784,6 +783,11 @@ struct sector_t
|
||||||
return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
|
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
|
// These may only be called if the portal has been validated
|
||||||
fixedvec2 FloorDisplacement()
|
fixedvec2 FloorDisplacement()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue