- implemented the FMultiBlockThingsIterator and converted P_TeleportMove to use it.

This commit is contained in:
Christoph Oelckers 2016-02-20 20:36:45 +01:00
parent cfbb3bcbb2
commit 58fcd8d742
3 changed files with 196 additions and 14 deletions

View file

@ -334,7 +334,7 @@ void P_FindFloorCeiling(AActor *actor, int flags)
validcount++;
FPortalGroupArray grouplist;
FMultiBlockLinesIterator mit(grouplist, actor, tmf.x, tmf.y, actor->radius);
FMultiBlockLinesIterator mit(grouplist, actor);
FMultiBlockLinesIterator::CheckResult cres;
// if we already have a valid floor/ceiling sector within the current sector,
@ -420,7 +420,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
thing->SetZ(z);
FPortalGroupArray grouplist;
FMultiBlockLinesIterator mit(grouplist, thing, tmf.x, tmf.y, thing->radius);
FMultiBlockLinesIterator mit(grouplist, x, y, z, thing->height, thing->radius);
FMultiBlockLinesIterator::CheckResult cres;
while (mit.Next(&cres))
@ -431,11 +431,13 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz;
FBlockThingsIterator it2(FBoundingBox(x, y, thing->radius));
AActor *th;
FMultiBlockThingsIterator mit2(grouplist, x, y, z, thing->height, thing->radius);
FMultiBlockThingsIterator::CheckResult cres2;
while ((th = it2.Next()))
while (mit2.Next(&cres2))
{
AActor *th = cres2.thing;
if (!(th->flags & MF_SHOOTABLE))
continue;
@ -444,7 +446,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
continue;
fixed_t blockdist = th->radius + tmf.thing->radius;
if (abs(th->X() - tmf.x) >= blockdist || abs(th->Y() - tmf.y) >= blockdist)
if (abs(th->X() - cres.position.x) >= blockdist || abs(th->Y() - cres.position.y) >= blockdist)
continue;
if ((th->flags2 | tmf.thing->flags2) & MF2_THRUACTORS)

View file

@ -711,18 +711,34 @@ line_t *FBlockLinesIterator::Next()
//
//===========================================================================
FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkx, fixed_t checky, fixed_t checkradius)
FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius)
: checklist(check)
{
checkpoint = origin->Pos();
if (checkx != FIXED_MAX) checkpoint.x = checkx;
if (checky != FIXED_MAX) checkpoint.y = checky;
P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist);
if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist);
checkpoint.z = checkradius;
basegroup = origin->Sector->PortalGroup;
Reset();
}
FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius)
: checklist(check)
{
checkpoint.x = checkx;
checkpoint.y = checky;
checkpoint.z = checkz;
basegroup = P_PointInSector(checkx, checky)->PortalGroup;
if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist);
checkpoint.z = checkradius;
Reset();
}
//===========================================================================
//
// Go up a ceiling portal
//
//===========================================================================
bool FMultiBlockLinesIterator::GoUp(fixed_t x, fixed_t y)
{
if (continueup)
@ -739,6 +755,12 @@ bool FMultiBlockLinesIterator::GoUp(fixed_t x, fixed_t y)
return false;
}
//===========================================================================
//
// Go down a floor portal
//
//===========================================================================
bool FMultiBlockLinesIterator::GoDown(fixed_t x, fixed_t y)
{
if (continuedown)
@ -755,6 +777,12 @@ bool FMultiBlockLinesIterator::GoDown(fixed_t x, fixed_t y)
return false;
}
//===========================================================================
//
// Gets the next line - also manages switching between portal groups
//
//===========================================================================
bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item)
{
line_t *line = blockIterator.Next();
@ -808,6 +836,12 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item)
return Next(item);
}
//===========================================================================
//
// start iterating a new group
//
//===========================================================================
void FMultiBlockLinesIterator::startIteratorForGroup(int group)
{
offset = Displacements(basegroup, group);
@ -817,6 +851,12 @@ void FMultiBlockLinesIterator::startIteratorForGroup(int group)
blockIterator.init(bbox);
}
//===========================================================================
//
// Resets the iterator
//
//===========================================================================
void FMultiBlockLinesIterator::Reset()
{
continueup = continueup = true;
@ -851,8 +891,7 @@ FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int
Reset();
}
FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box)
: DynHash(0)
void FBlockThingsIterator::init(const FBoundingBox &box)
{
maxy = GetSafeBlockY(box.Top() - bmaporgy);
miny = GetSafeBlockY(box.Bottom() - bmaporgy);
@ -994,6 +1033,108 @@ AActor *FBlockThingsIterator::Next(bool centeronly)
}
//===========================================================================
//
// FMultiBlockThingsIterator :: FMultiBlockThingsIterator
//
// An iterator that can check multiple portal groups.
//
//===========================================================================
FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius)
: checklist(check)
{
checkpoint = origin->Pos();
if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist);
checkpoint.z = checkradius;
basegroup = origin->Sector->PortalGroup;
Reset();
}
FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius)
: checklist(check)
{
checkpoint.x = checkx;
checkpoint.y = checky;
checkpoint.z = checkz;
basegroup = P_PointInSector(checkx, checky)->PortalGroup;
if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist);
checkpoint.z = checkradius;
Reset();
}
//===========================================================================
//
// Gets the next line - also manages switching between portal groups
//
//===========================================================================
bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *item)
{
AActor *thing = blockIterator.Next();
if (thing != NULL)
{
item->thing = thing;
item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup);
item->portalflags = portalflags;
return true;
}
bool onlast = unsigned(index + 1) >= checklist.Size();
int nextflags = onlast ? 0 : checklist[index + 1] & FPortalGroupArray::FLAT;
if (onlast)
{
return false;
}
index++;
startIteratorForGroup(checklist[index] & ~FPortalGroupArray::FLAT);
switch (nextflags)
{
case FPortalGroupArray::UPPER:
portalflags = FFCF_NOFLOOR;
break;
case FPortalGroupArray::LOWER:
portalflags = FFCF_NOCEILING;
break;
default:
portalflags = 0;
}
return Next(item);
}
//===========================================================================
//
// start iterating a new group
//
//===========================================================================
void FMultiBlockThingsIterator::startIteratorForGroup(int group)
{
fixedvec2 offset = Displacements(basegroup, group);
offset.x += checkpoint.x;
offset.y += checkpoint.y;
bbox.setBox(offset.x, offset.y, checkpoint.z);
blockIterator.init(bbox);
}
//===========================================================================
//
// Resets the iterator
//
//===========================================================================
void FMultiBlockThingsIterator::Reset()
{
index = -1;
portalflags = 0;
startIteratorForGroup(basegroup);
}
//===========================================================================
//
// FPathTraverse :: Intercepts

View file

@ -224,7 +224,8 @@ public:
int portalflags;
};
FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkx = FIXED_MAX, fixed_t checky = FIXED_MAX, fixed_t checkradius = -1);
FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1);
FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius);
bool Next(CheckResult *item);
void Reset();
// for stopping group traversal through portals. Only the calling code can decide whether this is needed so this needs to be set from the outside.
@ -274,14 +275,52 @@ class FBlockThingsIterator
FBlockThingsIterator();
friend class FPathTraverse;
friend class FMultiBlockThingsIterator;
public:
FBlockThingsIterator(int minx, int miny, int maxx, int maxy);
FBlockThingsIterator(const FBoundingBox &box);
FBlockThingsIterator(const FBoundingBox &box)
{
init(box);
}
void init(const FBoundingBox &box);
AActor *Next(bool centeronly = false);
void Reset() { StartBlock(minx, miny); }
};
class FMultiBlockThingsIterator
{
FPortalGroupArray &checklist;
fixedvec3 checkpoint;
short basegroup;
short portalflags;
short index;
FBlockThingsIterator blockIterator;
FBoundingBox bbox;
void startIteratorForGroup(int group);
public:
struct CheckResult
{
AActor *thing;
fixedvec3 position;
int portalflags;
};
FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1);
FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius);
bool Next(CheckResult *item);
void Reset();
const FBoundingBox &Box() const
{
return bbox;
}
};
class FPathTraverse
{
static TArray<intercept_t> intercepts;