mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 12:11:25 +00:00
- implemented FMultiBlockLinesIterator for checking a position across portals. This is not fully tested yet.
This commit is contained in:
parent
884a265d4a
commit
3841a5f626
6 changed files with 236 additions and 91 deletions
19
src/actor.h
19
src/actor.h
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
112
src/p_maputl.h
112
src/p_maputl.h
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
23
src/portal.h
23
src/portal.h
|
@ -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 §or_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
|
Loading…
Reference in a new issue