- added a function which collects all portal group an actor would touch if standing in a given position.

This commit is contained in:
Christoph Oelckers 2016-02-15 00:53:59 +01:00
parent 0dce22ce85
commit 405db83393
4 changed files with 167 additions and 18 deletions

View file

@ -524,6 +524,7 @@ void P_SerializeWorld (FArchive &arc)
{
linePortals.Clear();
}
P_CollectLinkedPortals();
}
void extsector_t::Serialize(FArchive &arc)

View file

@ -18,6 +18,7 @@ CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
FDisplacementTable Displacements;
TArray<FLinePortal> linePortals;
TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups.
FArchive &operator<< (FArchive &arc, FLinePortal &port)
@ -168,6 +169,19 @@ void P_UpdatePortal(FLinePortal *port)
}
}
void P_CollectLinkedPortals()
{
linkedPortals.Clear();
for (unsigned i = 0; i < linePortals.Size(); i++)
{
FLinePortal * port = &linePortals[i];
if (port->mType == PORTT_LINKED)
{
linkedPortals.Push(port);
}
}
}
void P_FinalizePortals()
{
for (unsigned i = 0; i < linePortals.Size(); i++)
@ -175,6 +189,7 @@ void P_FinalizePortals()
FLinePortal * port = &linePortals[i];
P_UpdatePortal(port);
}
P_CollectLinkedPortals();
}
static bool ChangePortalLine(line_t *line, int destid)
@ -839,6 +854,88 @@ void P_CreateLinkedPortals()
//BuildBlockmap();
}
//============================================================================
//
// Collect all portal groups this actor would occupy at the given position
// This is used to determine which parts of the map need to be checked.
//
//============================================================================
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupTable &out)
{
TArray<FLinePortal*> foundPortals;
bool retval = false;
if (linePortals.Size() == 0)
{
return false;
}
out.setSize(Displacements.size);
out.setBit(actor->Sector->PortalGroup);
//FBoundingBox box(newx, newy, actor->radius);
int thisgroup = actor->Sector->PortalGroup;
for (unsigned i = 0; i < linePortals.Size(); i++)
{
if (linePortals[i].mType != PORTT_LINKED) continue; // not a linked portal
line_t *ld = linePortals[i].mOrigin;
int othergroup = ld->frontsector->PortalGroup;
FDisplacement &disp = Displacements(thisgroup, othergroup);
if (!disp.isSet) continue; // no connection.
FBoundingBox box(newx + disp.x, newy + disp.y, actor->radius);
if (box.Right() <= ld->bbox[BOXLEFT]
|| box.Left() >= ld->bbox[BOXRIGHT]
|| box.Top() <= ld->bbox[BOXBOTTOM]
|| box.Bottom() >= ld->bbox[BOXTOP])
continue; // not touched
if (box.BoxOnLineSide(linePortals[i].mOrigin) != -1) continue; // not touched
foundPortals.Push(&linePortals[i]);
}
bool foundone = true;
while (foundone)
{
foundone = false;
for (int i = foundPortals.Size() - 1; i >= 0; i--)
{
if (out.getBit(foundPortals[i]->mOrigin->frontsector->PortalGroup) &&
!out.getBit(foundPortals[i]->mDestination->frontsector->PortalGroup))
{
out.setBit(foundPortals[i]->mDestination->frontsector->PortalGroup);
foundone = true;
retval = true;
foundPortals.Delete(i);
}
}
}
sector_t *sec = P_PointInSector(newx, newy);
sector_t *wsec = sec;
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && actor->Top() > 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.x;
fixed_t dy = newx + disp.y;
out.setBit(othersec->PortalGroup);
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)
{
sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
fixed_t dx = newx + disp.x;
fixed_t dy = newx + disp.y;
out.setBit(othersec->PortalGroup);
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat,
retval = true;
}
return retval;
}
CCMD(dumplinktable)
{
for (int x = 1; x < Displacements.size; x++)
@ -854,3 +951,4 @@ CCMD(dumplinktable)

View file

@ -7,6 +7,7 @@
#include "actor.h"
#include "p_local.h"
#include "m_bbox.h"
#include "a_sharedglobal.h"
struct FDisplacement
{
@ -33,6 +34,40 @@ struct FDisplacementTable
}
};
extern FDisplacementTable Displacements;
struct FPortalGroupTable
{
TArray<DWORD> data;
TArray<int> touchingGroups;
void setSize(int num)
{
data.Resize((num + 31) / 32);
memset(&data[0], 0, data.Size()*sizeof(DWORD));
}
void clear()
{
data.Clear();
touchingGroups.Clear();
}
void setBit(int group)
{
if (!getBit(group))
{
data[group >> 5] |= (1 << (group & 31));
touchingGroups.Push(group);
}
}
int getBit(int group)
{
return data[group >> 5] & (1 << (group & 31));
}
};
enum
{
PORTF_VISIBLE = 1,
@ -60,6 +95,12 @@ enum
PORG_CEILING,
};
enum
{
PCOLL_NOTLINKED = 1,
PCOLL_LINKED = 2
};
struct FLinePortal
{
line_t *mOrigin;
@ -78,6 +119,12 @@ 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, FPortalGroupTable &out);
void P_CollectLinkedPortals();
inline int P_NumPortalGroups()
{
return Displacements.size;
}
/* code ported from prototype */
@ -145,4 +192,22 @@ inline int line_t::getPortalAlignment() const
return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign;
}
inline bool sector_t::PortalBlocksView(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool sector_t::PortalBlocksMovement(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool sector_t::PortalBlocksSound(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
#endif

View file

@ -739,24 +739,9 @@ struct sector_t
Flags &= ~SECF_SPECIALFLAGS;
}
inline bool PortalBlocksView(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool PortalBlocksMovement(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool PortalBlocksSound(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
bool PortalBlocksView(int plane);
bool PortalBlocksMovement(int plane);
bool PortalBlocksSound(int plane);
int GetTerrain(int pos) const;