- implemented FMultiBlockLinesIterator for checking a position across portals. This is not fully tested yet.

This commit is contained in:
Christoph Oelckers 2016-02-19 10:39:40 +01:00
parent 884a265d4a
commit 3841a5f626
6 changed files with 236 additions and 91 deletions

View file

@ -1185,21 +1185,10 @@ public:
fixedvec3 ret = { X(), Y(), Z() };
return ret;
}
fixedvec3 PosRelative(AActor *other) const
{
fixedvec3 ret = { X(), Y(), Z() };
return ret;
}
fixedvec3 PosRelative(sector_t *sec) const
{
fixedvec3 ret = { X(), Y(), Z() };
return ret;
}
fixedvec3 PosRelative(line_t *line) const
{
fixedvec3 ret = { X(), Y(), Z() };
return ret;
}
fixedvec3 PosRelative(AActor *other) const;
fixedvec3 PosRelative(sector_t *sec) const;
fixedvec3 PosRelative(line_t *line) const;
fixed_t SoundX() const
{
return X();

View file

@ -2,63 +2,6 @@
#define P_CHECKPOS_H
//============================================================================
//
// This is a dynamic array which holds its first MAX_STATIC entries in normal
// variables to avoid constant allocations which this would otherwise
// require.
//
// When collecting touched portal groups the normal cases are either
// no portals == one group or
// two portals = two groups
//
// Anything with more can happen but far less infrequently, so this
// organization helps avoiding the overhead from heap allocations
// in the vast majority of situations.
//
//============================================================================
struct FPortalGroupArray
{
enum
{
MAX_STATIC = 2
};
FPortalGroupArray()
{
varused = 0;
}
void Clear()
{
data.Clear();
varused = 0;
}
void Add(DWORD num)
{
if (varused < MAX_STATIC) entry[varused++] = num;
else data.Push(num);
}
unsigned Size()
{
return varused + data.Size();
}
DWORD operator[](unsigned index)
{
return index < MAX_STATIC ? entry[index] : data[index - MAX_STATIC];
}
private:
DWORD entry[MAX_STATIC];
unsigned varused;
TArray<DWORD> data;
};
//============================================================================
//
// Used by P_CheckPosition and P_TryMove in place of the original
@ -95,7 +38,6 @@ struct FCheckPosition
bool DoRipping;
TMap<AActor*, bool> LastRipped;
FPortalGroupArray Groups;
int PushTime;
FCheckPosition(bool rip=false)

View file

@ -39,6 +39,7 @@
#include "p_3dmidtex.h"
#include "p_blockmap.h"
#include "r_utility.h"
#include "portal.h"
// State.
#include "r_state.h"
@ -572,7 +573,7 @@ FBlockLinesIterator::FBlockLinesIterator(int _minx, int _miny, int _maxx, int _m
Reset();
}
FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box)
void FBlockLinesIterator::init(const FBoundingBox &box)
{
validcount++;
maxy = GetSafeBlockY(box.Top() - bmaporgy);
@ -582,6 +583,10 @@ FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box)
Reset();
}
FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box)
{
init(box);
}
//===========================================================================
//
@ -681,6 +686,82 @@ line_t *FBlockLinesIterator::Next()
}
}
//===========================================================================
//
// FMultiBlockLinesIterator :: FMultiBlockLinesIterator
//
// An iterator that can check multiple portal groups.
//
//===========================================================================
FMultiBlockLinesIterator::FMultiBlockLinesIterator(AActor *origin, fixed_t checkx, fixed_t checky, fixed_t checkradius)
{
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);
checkpoint.z = checkradius;
basegroup = origin->Sector->PortalGroup;
Reset();
}
bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item)
{
line_t *line = blockIterator.Next();
if (line != NULL)
{
item->line = line;
item->position = offset;
item->portalposition = portalposition;
return true;
}
else if (checklist[index] & FPortalGroupArray::UPPER)
{
if (continueup)
{
sector_t *sector = P_PointInSector(offset.x, offset.y);
if (!sector->PortalBlocksMovement(sector_t::ceiling))
{
startIteratorForGroup(sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
return Next(item);
}
}
}
else if (checklist[index] & FPortalGroupArray::LOWER)
{
if (continuedown)
{
sector_t *sector = P_PointInSector(offset.x, offset.y);
if (!sector->PortalBlocksMovement(sector_t::floor))
{
startIteratorForGroup(sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup);
return Next(item);
}
}
}
index++;
if (index >= checklist.Size()) return false;
startIteratorForGroup(checklist[index]);
return Next(item);
}
void FMultiBlockLinesIterator::startIteratorForGroup(int group)
{
offset = Displacements(basegroup, group);
offset.x += checkpoint.x;
offset.y += checkpoint.y;
FBoundingBox box(offset.x, offset.y, checkpoint.z);
blockIterator.init(box);
}
void FMultiBlockLinesIterator::Reset()
{
continueup = continueup = true;
index = -1;
portalposition = PP_ORIGIN;
startIteratorForGroup(basegroup);
}
//===========================================================================
//
// FBlockThingsIterator :: FBlockThingsIterator

View file

@ -108,8 +108,72 @@ void P_LineOpening (FLineOpening &open, AActor *thing, const line_t *linedef, fi
class FBoundingBox;
struct polyblock_t;
//============================================================================
//
// This is a dynamic array which holds its first MAX_STATIC entries in normal
// variables to avoid constant allocations which this would otherwise
// require.
//
// When collecting touched portal groups the normal cases are either
// no portals == one group or
// two portals = two groups
//
// Anything with more can happen but far less infrequently, so this
// organization helps avoiding the overhead from heap allocations
// in the vast majority of situations.
//
//============================================================================
struct FPortalGroupArray
{
enum
{
LOWER = 0x4000,
UPPER = 0x8000,
FLAT = 0xc000,
};
enum
{
MAX_STATIC = 4
};
FPortalGroupArray()
{
varused = 0;
}
void Clear()
{
data.Clear();
varused = 0;
}
void Add(DWORD num)
{
if (varused < MAX_STATIC) entry[varused++] = (WORD)num;
else data.Push((WORD)num);
}
unsigned Size()
{
return varused + data.Size();
}
DWORD operator[](unsigned index)
{
return index < MAX_STATIC ? entry[index] : data[index - MAX_STATIC];
}
private:
WORD entry[MAX_STATIC];
unsigned varused;
TArray<WORD> data;
};
class FBlockLinesIterator
{
friend class FMultiBlockLinesIterator;
int minx, maxx;
int miny, maxy;
@ -120,6 +184,8 @@ class FBlockLinesIterator
void StartBlock(int x, int y);
FBlockLinesIterator() {}
void init(const FBoundingBox &box);
public:
FBlockLinesIterator(int minx, int miny, int maxx, int maxy, bool keepvalidcount = false);
FBlockLinesIterator(const FBoundingBox &box);
@ -127,6 +193,52 @@ public:
void Reset() { StartBlock(minx, miny); }
};
class FMultiBlockLinesIterator
{
fixedvec3 checkpoint;
fixedvec2 offset;
short basegroup;
short portalposition;
WORD index;
bool continueup;
bool continuedown;
FBlockLinesIterator blockIterator;
FPortalGroupArray checklist;
void startIteratorForGroup(int group);
public:
enum
{
PP_ORIGIN,
PP_ABOVE,
PP_BELOW,
PP_THROUGHLINE
};
struct CheckResult
{
line_t *line;
fixedvec2 position;
int portalposition;
};
FMultiBlockLinesIterator(AActor *origin, fixed_t checkx = FIXED_MAX, fixed_t checky = FIXED_MAX, fixed_t checkradius = -1);
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.
void StopUp()
{
continueup = false;
}
void StopDown()
{
continuedown = false;
}
};
class FBlockThingsIterator
{
int minx, maxx;

View file

@ -1053,7 +1053,7 @@ void P_CreateLinkedPortals()
//
//============================================================================
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out)
bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out)
{
// Keep this temporary work stuff static. This function can never be called recursively
// and this would have to be reallocated for each call otherwise.
@ -1071,9 +1071,9 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
processMask.clear();
foundPortals.Clear();
int thisgroup = actor->Sector->PortalGroup;
int thisgroup = startgroup;
processMask.setBit(thisgroup);
out.Add(thisgroup);
//out.Add(thisgroup);
for (unsigned i = 0; i < linkedPortals.Size(); i++)
{
@ -1082,7 +1082,7 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
FDisplacement &disp = Displacements(thisgroup, othergroup);
if (!disp.isSet) continue; // no connection.
FBoundingBox box(newx + disp.pos.x, newy + disp.pos.y, actor->radius);
FBoundingBox box(position.x + disp.pos.x, position.y + disp.pos.y, checkradius);
if (box.Right() <= ld->bbox[BOXLEFT]
|| box.Left() >= ld->bbox[BOXRIGHT]
@ -1110,27 +1110,27 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
}
}
}
sector_t *sec = P_PointInSector(newx, newy);
sector_t *sec = P_PointInSector(position.x, position.y);
sector_t *wsec = sec;
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && actor->Top() > wsec->SkyBoxes[sector_t::ceiling]->threshold)
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold)
{
sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
fixed_t dx = newx + disp.pos.x;
fixed_t dy = newx + disp.pos.y;
FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + disp.pos.x;
fixed_t dy = position.y + disp.pos.y;
processMask.setBit(othersec->PortalGroup);
out.Add(othersec->PortalGroup);
out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER);
wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat
retval = true;
}
wsec = sec;
while (!wsec->PortalBlocksMovement(sector_t::floor) && actor->Z() < wsec->SkyBoxes[sector_t::floor]->threshold)
while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold)
{
sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
fixed_t dx = newx + disp.pos.x;
fixed_t dy = newx + disp.pos.y;
processMask.setBit(othersec->PortalGroup);
sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector;
FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + disp.pos.x;
fixed_t dy = position.y + disp.pos.y;
processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER);
out.Add(othersec->PortalGroup);
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat
retval = true;

View file

@ -125,7 +125,7 @@ void P_SpawnLinePortal(line_t* line);
void P_FinalizePortals();
bool P_ChangePortal(line_t *ln, int thisid, int destid);
void P_CreateLinkedPortals();
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out);
bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out);
void P_CollectLinkedPortals();
inline int P_NumPortalGroups()
{
@ -245,4 +245,25 @@ inline FDisplacement &sector_t::CeilingDisplacement()
return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
}
inline fixedvec3 AActor::PosRelative(AActor *other) const
{
FDisplacement &disp = Displacements(Sector->PortalGroup, other->Sector->PortalGroup);
fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() };
return ret;
}
inline fixedvec3 AActor::PosRelative(sector_t *sec) const
{
FDisplacement &disp = Displacements(Sector->PortalGroup, sec->PortalGroup);
fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() };
return ret;
}
inline fixedvec3 AActor::PosRelative(line_t *line) const
{
FDisplacement &disp = Displacements(Sector->PortalGroup, line->frontsector->PortalGroup);
fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() };
return ret;
}
#endif