mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
- refactored P_CollectConnectedGroups to avoid frequent heap allocations for the common cases
* the temporary checking arrays are now static * the array that gets the returned values only starts allocating memory when the third touched sector group is found. The most common cases (no touched portal and one touched portal) can be handled without accessing the heap. - did some streamlining of AActor::LinkToSector: * there's only now version of this function that can handle everything * moved the FIXMAPTHINGPOS stuff into a separate function. * removed LinkToWorldForMapThing and put all special handling this function did into P_PointInSectorBuggy.
This commit is contained in:
parent
b9037ef3ee
commit
22e8678903
7 changed files with 294 additions and 230 deletions
|
@ -44,6 +44,7 @@
|
||||||
struct subsector_t;
|
struct subsector_t;
|
||||||
class PClassAmmo;
|
class PClassAmmo;
|
||||||
struct FBlockNode;
|
struct FBlockNode;
|
||||||
|
struct FPortalGroupArray;
|
||||||
|
|
||||||
//
|
//
|
||||||
// NOTES: AActor
|
// NOTES: AActor
|
||||||
|
@ -1131,11 +1132,10 @@ private:
|
||||||
friend class FActorIterator;
|
friend class FActorIterator;
|
||||||
friend bool P_IsTIDUsed(int tid);
|
friend bool P_IsTIDUsed(int tid);
|
||||||
|
|
||||||
sector_t *LinkToWorldForMapThing ();
|
bool FixMapthingPos();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void LinkToWorld (bool buggy=false);
|
void LinkToWorld (bool spawningmapthing=false, FPortalGroupArray *groups = NULL, sector_t *sector = NULL);
|
||||||
void LinkToWorld (sector_t *sector);
|
|
||||||
void UnlinkFromWorld ();
|
void UnlinkFromWorld ();
|
||||||
void AdjustFloorClip ();
|
void AdjustFloorClip ();
|
||||||
void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false);
|
void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false);
|
||||||
|
|
|
@ -10,12 +10,13 @@ struct FBlockNode
|
||||||
{
|
{
|
||||||
AActor *Me; // actor this node references
|
AActor *Me; // actor this node references
|
||||||
int BlockIndex; // index into blocklinks for the block this node is in
|
int BlockIndex; // index into blocklinks for the block this node is in
|
||||||
|
int Group; // portal group this link belongs to (can be different than the actor's own group
|
||||||
FBlockNode **PrevActor; // previous actor in this block
|
FBlockNode **PrevActor; // previous actor in this block
|
||||||
FBlockNode *NextActor; // next actor in this block
|
FBlockNode *NextActor; // next actor in this block
|
||||||
FBlockNode **PrevBlock; // previous block this actor is in
|
FBlockNode **PrevBlock; // previous block this actor is in
|
||||||
FBlockNode *NextBlock; // next block this actor is in
|
FBlockNode *NextBlock; // next block this actor is in
|
||||||
|
|
||||||
static FBlockNode *Create (AActor *who, int x, int y);
|
static FBlockNode *Create (AActor *who, int x, int y, int group = -1);
|
||||||
void Release ();
|
void Release ();
|
||||||
|
|
||||||
static FBlockNode *FreeBlocks;
|
static FBlockNode *FreeBlocks;
|
||||||
|
|
|
@ -4,41 +4,58 @@
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// Data structure which collects all portals being touched by an actor
|
// This is a dynamic array which holds its first MAX_STATIC entries in normal
|
||||||
// when checking its position.
|
// 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 FPortalGroupTable
|
struct FPortalGroupArray
|
||||||
{
|
{
|
||||||
TArray<DWORD> data;
|
enum
|
||||||
TArray<int> touchingGroups;
|
|
||||||
|
|
||||||
void setSize(int num)
|
|
||||||
{
|
{
|
||||||
data.Resize((num + 31) / 32);
|
MAX_STATIC = 2
|
||||||
memset(&data[0], 0, data.Size()*sizeof(DWORD));
|
};
|
||||||
|
|
||||||
|
FPortalGroupArray()
|
||||||
|
{
|
||||||
|
varused = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
data.Clear();
|
data.Clear();
|
||||||
touchingGroups.Clear();
|
varused = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBit(int group)
|
void Add(DWORD num)
|
||||||
{
|
{
|
||||||
if (!getBit(group))
|
if (varused < MAX_STATIC) entry[varused++] = num;
|
||||||
{
|
else data.Push(num);
|
||||||
data[group >> 5] |= (1 << (group & 31));
|
|
||||||
touchingGroups.Push(group);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getBit(int group)
|
unsigned Size()
|
||||||
{
|
{
|
||||||
return data[group >> 5] & (1 << (group & 31));
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +95,7 @@ struct FCheckPosition
|
||||||
bool DoRipping;
|
bool DoRipping;
|
||||||
TMap<AActor*, bool> LastRipped;
|
TMap<AActor*, bool> LastRipped;
|
||||||
|
|
||||||
FPortalGroupTable Groups;
|
FPortalGroupArray Groups;
|
||||||
int PushTime;
|
int PushTime;
|
||||||
|
|
||||||
FCheckPosition(bool rip=false)
|
FCheckPosition(bool rip=false)
|
||||||
|
|
371
src/p_maputl.cpp
371
src/p_maputl.cpp
|
@ -46,6 +46,8 @@
|
||||||
#include "po_man.h"
|
#include "po_man.h"
|
||||||
|
|
||||||
static AActor *RoughBlockCheck (AActor *mo, int index, void *);
|
static AActor *RoughBlockCheck (AActor *mo, int index, void *);
|
||||||
|
static int R_PointOnSideSlow(fixed_t x, fixed_t y, node_t *node);
|
||||||
|
sector_t *P_PointInSectorBuggy(fixed_t x, fixed_t y);
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -315,39 +317,118 @@ void AActor::UnlinkFromWorld ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// If the thing is exactly on a line, move it into the sector
|
||||||
|
// slightly in order to resolve clipping issues in the renderer.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool AActor::FixMapthingPos()
|
||||||
|
{
|
||||||
|
sector_t *secstart = P_PointInSectorBuggy(X(), Y());
|
||||||
|
|
||||||
|
int blockx = GetSafeBlockX(X() - bmaporgx);
|
||||||
|
int blocky = GetSafeBlockY(Y() - bmaporgy);
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
if ((unsigned int)blockx < (unsigned int)bmapwidth &&
|
||||||
|
(unsigned int)blocky < (unsigned int)bmapheight)
|
||||||
|
{
|
||||||
|
int *list;
|
||||||
|
|
||||||
|
for (list = blockmaplump + blockmap[blocky*bmapwidth + blockx] + 1; *list != -1; ++list)
|
||||||
|
{
|
||||||
|
line_t *ldef = &lines[*list];
|
||||||
|
|
||||||
|
if (ldef->frontsector == ldef->backsector)
|
||||||
|
{ // Skip two-sided lines inside a single sector
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ldef->backsector != NULL)
|
||||||
|
{
|
||||||
|
if (ldef->frontsector->floorplane == ldef->backsector->floorplane &&
|
||||||
|
ldef->frontsector->ceilingplane == ldef->backsector->ceilingplane)
|
||||||
|
{ // Skip two-sided lines without any height difference on either side
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not inside the line's bounding box
|
||||||
|
if (X() + radius <= ldef->bbox[BOXLEFT]
|
||||||
|
|| X() - radius >= ldef->bbox[BOXRIGHT]
|
||||||
|
|| Y() + radius <= ldef->bbox[BOXBOTTOM]
|
||||||
|
|| Y() - radius >= ldef->bbox[BOXTOP])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get the exact distance to the line
|
||||||
|
divline_t dll, dlv;
|
||||||
|
fixed_t linelen = (fixed_t)sqrt((double)ldef->dx*ldef->dx + (double)ldef->dy*ldef->dy);
|
||||||
|
|
||||||
|
P_MakeDivline(ldef, &dll);
|
||||||
|
|
||||||
|
dlv.x = X();
|
||||||
|
dlv.y = Y();
|
||||||
|
dlv.dx = FixedDiv(dll.dy, linelen);
|
||||||
|
dlv.dy = -FixedDiv(dll.dx, linelen);
|
||||||
|
|
||||||
|
fixed_t distance = abs(P_InterceptVector(&dlv, &dll));
|
||||||
|
|
||||||
|
if (distance < radius)
|
||||||
|
{
|
||||||
|
DPrintf("%s at (%d,%d) lies on %s line %td, distance = %f\n",
|
||||||
|
this->GetClass()->TypeName.GetChars(), X() >> FRACBITS, Y() >> FRACBITS,
|
||||||
|
ldef->dx == 0 ? "vertical" : ldef->dy == 0 ? "horizontal" : "diagonal",
|
||||||
|
ldef - lines, FIXED2DBL(distance));
|
||||||
|
angle_t finean = R_PointToAngle2(0, 0, ldef->dx, ldef->dy);
|
||||||
|
if (ldef->backsector != NULL && ldef->backsector == secstart)
|
||||||
|
{
|
||||||
|
finean += ANGLE_90;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
finean -= ANGLE_90;
|
||||||
|
}
|
||||||
|
finean >>= ANGLETOFINESHIFT;
|
||||||
|
|
||||||
|
// Get the distance we have to move the object away from the wall
|
||||||
|
distance = radius - distance;
|
||||||
|
SetXY(X() + FixedMul(distance, finecosine[finean]), Y() + FixedMul(distance, finesine[finean]));
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// P_SetThingPosition
|
// P_SetThingPosition
|
||||||
// Links a thing into both a block and a subsector based on it's x y.
|
// Links a thing into both a block and a subsector based on its x y.
|
||||||
// Sets thing->sector properly
|
// Sets thing->sector properly
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void AActor::LinkToWorld (bool buggy)
|
void AActor::LinkToWorld (bool spawningmapthing, FPortalGroupArray *groups, sector_t *sector)
|
||||||
{
|
{
|
||||||
// link into subsector
|
if (spawningmapthing && (flags4 & MF4_FIXMAPTHINGPOS) && sector == NULL)
|
||||||
sector_t *sec;
|
|
||||||
|
|
||||||
if (!buggy || numgamenodes == 0)
|
|
||||||
{
|
{
|
||||||
sec = P_PointInSector (X(), Y());
|
if (FixMapthingPos()) spawningmapthing = false;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sec = LinkToWorldForMapThing ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkToWorld (sec);
|
if (sector == NULL)
|
||||||
}
|
|
||||||
|
|
||||||
void AActor::LinkToWorld (sector_t *sec)
|
|
||||||
{
|
|
||||||
if (sec == NULL)
|
|
||||||
{
|
{
|
||||||
LinkToWorld ();
|
if (!spawningmapthing || numgamenodes == 0)
|
||||||
return;
|
{
|
||||||
|
sector = P_PointInSector(X(), Y());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sector = P_PointInSectorBuggy(X(), Y());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Sector = sec;
|
|
||||||
|
Sector = sector;
|
||||||
subsector = R_PointInSubsector(X(), Y()); // this is from the rendering nodes, not the gameplay nodes!
|
subsector = R_PointInSubsector(X(), Y()); // this is from the rendering nodes, not the gameplay nodes!
|
||||||
|
|
||||||
if ( !(flags & MF_NOSECTOR) )
|
if ( !(flags & MF_NOSECTOR) )
|
||||||
|
@ -356,7 +437,7 @@ void AActor::LinkToWorld (sector_t *sec)
|
||||||
// killough 8/11/98: simpler scheme using pointer-to-pointer prev
|
// killough 8/11/98: simpler scheme using pointer-to-pointer prev
|
||||||
// pointers, allows head nodes to be treated like everything else
|
// pointers, allows head nodes to be treated like everything else
|
||||||
|
|
||||||
AActor **link = &sec->thinglist;
|
AActor **link = §or->thinglist;
|
||||||
AActor *next = *link;
|
AActor *next = *link;
|
||||||
if ((snext = next))
|
if ((snext = next))
|
||||||
next->sprev = &snext;
|
next->sprev = &snext;
|
||||||
|
@ -405,7 +486,7 @@ void AActor::LinkToWorld (sector_t *sec)
|
||||||
for (int x = x1; x <= x2; ++x)
|
for (int x = x1; x <= x2; ++x)
|
||||||
{
|
{
|
||||||
FBlockNode **link = &blocklinks[y*bmapwidth + x];
|
FBlockNode **link = &blocklinks[y*bmapwidth + x];
|
||||||
FBlockNode *node = FBlockNode::Create (this, x, y);
|
FBlockNode *node = FBlockNode::Create (this, x, y, this->Sector->PortalGroup);
|
||||||
|
|
||||||
// Link in to block
|
// Link in to block
|
||||||
if ((node->NextActor = *link) != NULL)
|
if ((node->NextActor = *link) != NULL)
|
||||||
|
@ -426,168 +507,6 @@ void AActor::LinkToWorld (sector_t *sec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// [RH] LinkToWorldForMapThing
|
|
||||||
//
|
|
||||||
// Emulate buggy PointOnLineSide and fix actors that lie on
|
|
||||||
// lines to compensate for some IWAD maps.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node)
|
|
||||||
{
|
|
||||||
// [RH] This might have been faster than two multiplies and an
|
|
||||||
// add on a 386/486, but it certainly isn't on anything newer than that.
|
|
||||||
fixed_t dx;
|
|
||||||
fixed_t dy;
|
|
||||||
double left;
|
|
||||||
double right;
|
|
||||||
|
|
||||||
if (!node->dx)
|
|
||||||
{
|
|
||||||
if (x <= node->x)
|
|
||||||
return node->dy > 0;
|
|
||||||
|
|
||||||
return node->dy < 0;
|
|
||||||
}
|
|
||||||
if (!node->dy)
|
|
||||||
{
|
|
||||||
if (y <= node->y)
|
|
||||||
return node->dx < 0;
|
|
||||||
|
|
||||||
return node->dx > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dx = (x - node->x);
|
|
||||||
dy = (y - node->y);
|
|
||||||
|
|
||||||
// Try to quickly decide by looking at sign bits.
|
|
||||||
if ( (node->dy ^ node->dx ^ dx ^ dy)&0x80000000 )
|
|
||||||
{
|
|
||||||
if ( (node->dy ^ dx) & 0x80000000 )
|
|
||||||
{
|
|
||||||
// (left is negative)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we must use doubles here because the fixed point code will produce errors due to loss of precision for extremely short linedefs.
|
|
||||||
left = (double)node->dy * (double)dx;
|
|
||||||
right = (double)dy * (double)node->dx;
|
|
||||||
|
|
||||||
if (right < left)
|
|
||||||
{
|
|
||||||
// front side
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// back side
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sector_t *AActor::LinkToWorldForMapThing ()
|
|
||||||
{
|
|
||||||
node_t *node = gamenodes + numgamenodes - 1;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// Use original buggy point-on-side test when spawning
|
|
||||||
// things at level load so that the map spots in the
|
|
||||||
// emerald key room of Hexen MAP01 are spawned on the
|
|
||||||
// window ledge instead of the blocking floor in front
|
|
||||||
// of it. Why do I consider it buggy? Because a point
|
|
||||||
// that lies directly on a line should always be
|
|
||||||
// considered as "in front" of the line. The orientation
|
|
||||||
// of the line should be irrelevant.
|
|
||||||
node = (node_t *)node->children[R_PointOnSideSlow (X(), Y(), node)];
|
|
||||||
}
|
|
||||||
while (!((size_t)node & 1));
|
|
||||||
|
|
||||||
subsector_t *ssec = (subsector_t *)((BYTE *)node - 1);
|
|
||||||
|
|
||||||
if (flags4 & MF4_FIXMAPTHINGPOS)
|
|
||||||
{
|
|
||||||
// If the thing is exactly on a line, move it into the subsector
|
|
||||||
// slightly in order to resolve clipping issues in the renderer.
|
|
||||||
// This check needs to use the blockmap, because an actor on a
|
|
||||||
// one-sided line might go into a subsector behind the line, so
|
|
||||||
// the line would not be included as one of its subsector's segs.
|
|
||||||
|
|
||||||
int blockx = GetSafeBlockX(X() - bmaporgx);
|
|
||||||
int blocky = GetSafeBlockY(Y() - bmaporgy);
|
|
||||||
|
|
||||||
if ((unsigned int)blockx < (unsigned int)bmapwidth &&
|
|
||||||
(unsigned int)blocky < (unsigned int)bmapheight)
|
|
||||||
{
|
|
||||||
int *list;
|
|
||||||
|
|
||||||
for (list = blockmaplump + blockmap[blocky*bmapwidth + blockx] + 1; *list != -1; ++list)
|
|
||||||
{
|
|
||||||
line_t *ldef = &lines[*list];
|
|
||||||
|
|
||||||
if (ldef->frontsector == ldef->backsector)
|
|
||||||
{ // Skip two-sided lines inside a single sector
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ldef->backsector != NULL)
|
|
||||||
{
|
|
||||||
if (ldef->frontsector->floorplane == ldef->backsector->floorplane &&
|
|
||||||
ldef->frontsector->ceilingplane == ldef->backsector->ceilingplane)
|
|
||||||
{ // Skip two-sided lines without any height difference on either side
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not inside the line's bounding box
|
|
||||||
if (X() + radius <= ldef->bbox[BOXLEFT]
|
|
||||||
|| X() - radius >= ldef->bbox[BOXRIGHT]
|
|
||||||
|| Y() + radius <= ldef->bbox[BOXBOTTOM]
|
|
||||||
|| Y() - radius >= ldef->bbox[BOXTOP] )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Get the exact distance to the line
|
|
||||||
divline_t dll, dlv;
|
|
||||||
fixed_t linelen = (fixed_t)sqrt((double)ldef->dx*ldef->dx + (double)ldef->dy*ldef->dy);
|
|
||||||
|
|
||||||
P_MakeDivline (ldef, &dll);
|
|
||||||
|
|
||||||
dlv.x = X();
|
|
||||||
dlv.y = Y();
|
|
||||||
dlv.dx = FixedDiv(dll.dy, linelen);
|
|
||||||
dlv.dy = -FixedDiv(dll.dx, linelen);
|
|
||||||
|
|
||||||
fixed_t distance = abs(P_InterceptVector(&dlv, &dll));
|
|
||||||
|
|
||||||
if (distance < radius)
|
|
||||||
{
|
|
||||||
DPrintf ("%s at (%d,%d) lies on %s line %td, distance = %f\n",
|
|
||||||
this->GetClass()->TypeName.GetChars(), X()>>FRACBITS, Y()>>FRACBITS,
|
|
||||||
ldef->dx == 0? "vertical" : ldef->dy == 0? "horizontal" : "diagonal",
|
|
||||||
ldef-lines, FIXED2DBL(distance));
|
|
||||||
angle_t finean = R_PointToAngle2 (0, 0, ldef->dx, ldef->dy);
|
|
||||||
if (ldef->backsector != NULL && ldef->backsector == ssec->sector)
|
|
||||||
{
|
|
||||||
finean += ANGLE_90;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
finean -= ANGLE_90;
|
|
||||||
}
|
|
||||||
finean >>= ANGLETOFINESHIFT;
|
|
||||||
|
|
||||||
// Get the distance we have to move the object away from the wall
|
|
||||||
distance = radius - distance;
|
|
||||||
SetXY(X() + FixedMul(distance, finecosine[finean]), Y() + FixedMul(distance, finesine[finean]));
|
|
||||||
return P_PointInSector (X(), Y());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ssec->sector;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving)
|
void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving)
|
||||||
{
|
{
|
||||||
UnlinkFromWorld ();
|
UnlinkFromWorld ();
|
||||||
|
@ -601,7 +520,7 @@ void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving)
|
||||||
|
|
||||||
FBlockNode *FBlockNode::FreeBlocks = NULL;
|
FBlockNode *FBlockNode::FreeBlocks = NULL;
|
||||||
|
|
||||||
FBlockNode *FBlockNode::Create (AActor *who, int x, int y)
|
FBlockNode *FBlockNode::Create (AActor *who, int x, int y, int group)
|
||||||
{
|
{
|
||||||
FBlockNode *block;
|
FBlockNode *block;
|
||||||
|
|
||||||
|
@ -1528,6 +1447,67 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// [RH] LinkToWorldForMapThing
|
||||||
|
//
|
||||||
|
// Emulate buggy PointOnLineSide and fix actors that lie on
|
||||||
|
// lines to compensate for some IWAD maps.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static int R_PointOnSideSlow(fixed_t x, fixed_t y, node_t *node)
|
||||||
|
{
|
||||||
|
// [RH] This might have been faster than two multiplies and an
|
||||||
|
// add on a 386/486, but it certainly isn't on anything newer than that.
|
||||||
|
fixed_t dx;
|
||||||
|
fixed_t dy;
|
||||||
|
double left;
|
||||||
|
double right;
|
||||||
|
|
||||||
|
if (!node->dx)
|
||||||
|
{
|
||||||
|
if (x <= node->x)
|
||||||
|
return node->dy > 0;
|
||||||
|
|
||||||
|
return node->dy < 0;
|
||||||
|
}
|
||||||
|
if (!node->dy)
|
||||||
|
{
|
||||||
|
if (y <= node->y)
|
||||||
|
return node->dx < 0;
|
||||||
|
|
||||||
|
return node->dx > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = (x - node->x);
|
||||||
|
dy = (y - node->y);
|
||||||
|
|
||||||
|
// Try to quickly decide by looking at sign bits.
|
||||||
|
if ((node->dy ^ node->dx ^ dx ^ dy) & 0x80000000)
|
||||||
|
{
|
||||||
|
if ((node->dy ^ dx) & 0x80000000)
|
||||||
|
{
|
||||||
|
// (left is negative)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we must use doubles here because the fixed point code will produce errors due to loss of precision for extremely short linedefs.
|
||||||
|
left = (double)node->dy * (double)dx;
|
||||||
|
right = (double)dy * (double)node->dx;
|
||||||
|
|
||||||
|
if (right < left)
|
||||||
|
{
|
||||||
|
// front side
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// back side
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// P_VanillaPointOnLineSide
|
// P_VanillaPointOnLineSide
|
||||||
|
@ -1616,3 +1596,24 @@ int P_VanillaPointOnDivlineSide(fixed_t x, fixed_t y, const divline_t* line)
|
||||||
return 1; // back side
|
return 1; // back side
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sector_t *P_PointInSectorBuggy(fixed_t x, fixed_t y)
|
||||||
|
{
|
||||||
|
node_t *node = gamenodes + numgamenodes - 1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Use original buggy point-on-side test when spawning
|
||||||
|
// things at level load so that the map spots in the
|
||||||
|
// emerald key room of Hexen MAP01 are spawned on the
|
||||||
|
// window ledge instead of the blocking floor in front
|
||||||
|
// of it. Why do I consider it buggy? Because a point
|
||||||
|
// that lies directly on a line should always be
|
||||||
|
// considered as "in front" of the line. The orientation
|
||||||
|
// of the line should be irrelevant.
|
||||||
|
node = (node_t *)node->children[R_PointOnSideSlow(x, y, node)];
|
||||||
|
} while (!((size_t)node & 1));
|
||||||
|
|
||||||
|
subsector_t *ssec = (subsector_t *)((BYTE *)node - 1);
|
||||||
|
return ssec->sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -456,7 +456,7 @@ void AActor::Serialize (FArchive &arc)
|
||||||
if (arc.IsLoading ())
|
if (arc.IsLoading ())
|
||||||
{
|
{
|
||||||
touching_sectorlist = NULL;
|
touching_sectorlist = NULL;
|
||||||
LinkToWorld (Sector);
|
LinkToWorld (false, NULL, Sector);
|
||||||
AddToHash ();
|
AddToHash ();
|
||||||
SetShade (fillcolor);
|
SetShade (fillcolor);
|
||||||
if (player)
|
if (player)
|
||||||
|
|
|
@ -62,6 +62,39 @@ FDisplacementTable Displacements;
|
||||||
TArray<FLinePortal> linePortals;
|
TArray<FLinePortal> linePortals;
|
||||||
TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups.
|
TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups.
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// This is used to mark processed portals for some collection functions.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
struct FPortalBits
|
||||||
|
{
|
||||||
|
TArray<DWORD> data;
|
||||||
|
|
||||||
|
void setSize(int num)
|
||||||
|
{
|
||||||
|
data.Resize((num + 31) / 32);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
memset(&data[0], 0, data.Size()*sizeof(DWORD));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBit(int group)
|
||||||
|
{
|
||||||
|
data[group >> 5] |= (1 << (group & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
int getBit(int group)
|
||||||
|
{
|
||||||
|
return data[group >> 5] & (1 << (group & 31));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
|
@ -1021,22 +1054,31 @@ void P_CreateLinkedPortals()
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupTable &out)
|
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out)
|
||||||
{
|
{
|
||||||
TArray<FLinePortal*> foundPortals;
|
// Keep this temporary work stuff static. This function can never be called recursively
|
||||||
|
// and this would have to be reallocated for each call otherwise.
|
||||||
|
static FPortalBits processMask;
|
||||||
|
static TArray<FLinePortal*> foundPortals;
|
||||||
|
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
if (linePortals.Size() == 0)
|
if (linkedPortals.Size() == 0)
|
||||||
{
|
{
|
||||||
|
// If there are no portals, all sectors are in group 0.
|
||||||
|
out.Add(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out.setSize(Displacements.size);
|
processMask.setSize(linkedPortals.Size());
|
||||||
out.setBit(actor->Sector->PortalGroup);
|
processMask.clear();
|
||||||
//FBoundingBox box(newx, newy, actor->radius);
|
foundPortals.Clear();
|
||||||
|
|
||||||
int thisgroup = actor->Sector->PortalGroup;
|
int thisgroup = actor->Sector->PortalGroup;
|
||||||
for (unsigned i = 0; i < linePortals.Size(); i++)
|
processMask.setBit(thisgroup);
|
||||||
|
out.Add(thisgroup);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < linkedPortals.Size(); i++)
|
||||||
{
|
{
|
||||||
if (linePortals[i].mType != PORTT_LINKED) continue; // not a linked portal
|
line_t *ld = linkedPortals[i]->mOrigin;
|
||||||
line_t *ld = linePortals[i].mOrigin;
|
|
||||||
int othergroup = ld->frontsector->PortalGroup;
|
int othergroup = ld->frontsector->PortalGroup;
|
||||||
FDisplacement &disp = Displacements(thisgroup, othergroup);
|
FDisplacement &disp = Displacements(thisgroup, othergroup);
|
||||||
if (!disp.isSet) continue; // no connection.
|
if (!disp.isSet) continue; // no connection.
|
||||||
|
@ -1049,8 +1091,8 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
|
||||||
|| box.Bottom() >= ld->bbox[BOXTOP])
|
|| box.Bottom() >= ld->bbox[BOXTOP])
|
||||||
continue; // not touched
|
continue; // not touched
|
||||||
|
|
||||||
if (box.BoxOnLineSide(linePortals[i].mOrigin) != -1) continue; // not touched
|
if (box.BoxOnLineSide(linkedPortals[i]->mOrigin) != -1) continue; // not touched
|
||||||
foundPortals.Push(&linePortals[i]);
|
foundPortals.Push(linkedPortals[i]);
|
||||||
}
|
}
|
||||||
bool foundone = true;
|
bool foundone = true;
|
||||||
while (foundone)
|
while (foundone)
|
||||||
|
@ -1058,10 +1100,11 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
|
||||||
foundone = false;
|
foundone = false;
|
||||||
for (int i = foundPortals.Size() - 1; i >= 0; i--)
|
for (int i = foundPortals.Size() - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
if (out.getBit(foundPortals[i]->mOrigin->frontsector->PortalGroup) &&
|
if (processMask.getBit(foundPortals[i]->mOrigin->frontsector->PortalGroup) &&
|
||||||
!out.getBit(foundPortals[i]->mDestination->frontsector->PortalGroup))
|
!processMask.getBit(foundPortals[i]->mDestination->frontsector->PortalGroup))
|
||||||
{
|
{
|
||||||
out.setBit(foundPortals[i]->mDestination->frontsector->PortalGroup);
|
processMask.setBit(foundPortals[i]->mDestination->frontsector->PortalGroup);
|
||||||
|
out.Add(foundPortals[i]->mDestination->frontsector->PortalGroup);
|
||||||
foundone = true;
|
foundone = true;
|
||||||
retval = true;
|
retval = true;
|
||||||
foundPortals.Delete(i);
|
foundPortals.Delete(i);
|
||||||
|
@ -1076,8 +1119,9 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
|
||||||
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
|
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
|
||||||
fixed_t dx = newx + disp.x;
|
fixed_t dx = newx + disp.x;
|
||||||
fixed_t dy = newx + disp.y;
|
fixed_t dy = newx + disp.y;
|
||||||
out.setBit(othersec->PortalGroup);
|
processMask.setBit(othersec->PortalGroup);
|
||||||
wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat,
|
out.Add(othersec->PortalGroup);
|
||||||
|
wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat
|
||||||
retval = true;
|
retval = true;
|
||||||
}
|
}
|
||||||
wsec = sec;
|
wsec = sec;
|
||||||
|
@ -1087,8 +1131,9 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
|
||||||
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
|
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
|
||||||
fixed_t dx = newx + disp.x;
|
fixed_t dx = newx + disp.x;
|
||||||
fixed_t dy = newx + disp.y;
|
fixed_t dy = newx + disp.y;
|
||||||
out.setBit(othersec->PortalGroup);
|
processMask.setBit(othersec->PortalGroup);
|
||||||
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat,
|
out.Add(othersec->PortalGroup);
|
||||||
|
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat
|
||||||
retval = true;
|
retval = true;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "m_bbox.h"
|
#include "m_bbox.h"
|
||||||
#include "a_sharedglobal.h"
|
#include "a_sharedglobal.h"
|
||||||
|
|
||||||
struct FPortalGroupTable;
|
struct FPortalGroupArray;
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// This table holds the offsets for the different parts of a map
|
// This table holds the offsets for the different parts of a map
|
||||||
|
@ -120,7 +120,7 @@ void P_SpawnLinePortal(line_t* line);
|
||||||
void P_FinalizePortals();
|
void P_FinalizePortals();
|
||||||
bool P_ChangePortal(line_t *ln, int thisid, int destid);
|
bool P_ChangePortal(line_t *ln, int thisid, int destid);
|
||||||
void P_CreateLinkedPortals();
|
void P_CreateLinkedPortals();
|
||||||
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupTable &out);
|
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out);
|
||||||
void P_CollectLinkedPortals();
|
void P_CollectLinkedPortals();
|
||||||
inline int P_NumPortalGroups()
|
inline int P_NumPortalGroups()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue