- moved most functions of portals.cpp into FLevelLocals.

Much of this is used during level init and needs to be independent of the current level.
This commit is contained in:
Christoph Oelckers 2019-01-25 00:30:55 +01:00
parent 2623fbb54b
commit 3cef56249d
21 changed files with 420 additions and 403 deletions

View file

@ -900,74 +900,12 @@ public:
return other->PosRelative(this) - Pos(); return other->PosRelative(this) - Pos();
} }
DVector2 Vec2Offset(double dx, double dy, bool absolute = false) DVector2 Vec2Offset(double dx, double dy, bool absolute = false);
{ DVector3 Vec2OffsetZ(double dx, double dy, double atz, bool absolute = false);
if (absolute) DVector2 AActor::Vec2Angle(double length, DAngle angle, bool absolute = false);
{ DVector3 Vec3Offset(double dx, double dy, double dz, bool absolute = false);
return { X() + dx, Y() + dy }; DVector3 Vec3Offset(const DVector3 &ofs, bool absolute = false);
} DVector3 Vec3Angle(double length, DAngle angle, double dz, bool absolute = false);
else
{
return P_GetOffsetPosition(X(), Y(), dx, dy);
}
}
DVector3 Vec2OffsetZ(double dx, double dy, double atz, bool absolute = false)
{
if (absolute)
{
return{ X() + dx, Y() + dy, atz };
}
else
{
DVector2 v = P_GetOffsetPosition(X(), Y(), dx, dy);
return DVector3(v, atz);
}
}
DVector2 Vec2Angle(double length, DAngle angle, bool absolute = false)
{
if (absolute)
{
return{ X() + length * angle.Cos(), Y() + length * angle.Sin() };
}
else
{
return P_GetOffsetPosition(X(), Y(), length*angle.Cos(), length*angle.Sin());
}
}
DVector3 Vec3Offset(double dx, double dy, double dz, bool absolute = false)
{
if (absolute)
{
return { X() + dx, Y() + dy, Z() + dz };
}
else
{
DVector2 v = P_GetOffsetPosition(X(), Y(), dx, dy);
return DVector3(v, Z() + dz);
}
}
DVector3 Vec3Offset(const DVector3 &ofs, bool absolute = false)
{
return Vec3Offset(ofs.X, ofs.Y, ofs.Z, absolute);
}
DVector3 Vec3Angle(double length, DAngle angle, double dz, bool absolute = false)
{
if (absolute)
{
return{ X() + length * angle.Cos(), Y() + length * angle.Sin(), Z() + dz };
}
else
{
DVector2 v = P_GetOffsetPosition(X(), Y(), length*angle.Cos(), length*angle.Sin());
return DVector3(v, Z() + dz);
}
}
void ClearInterpolation(); void ClearInterpolation();

View file

@ -94,3 +94,71 @@ inline double AActor::AttackOffset(double offset)
} }
inline DVector2 AActor::Vec2Offset(double dx, double dy, bool absolute)
{
if (absolute)
{
return { X() + dx, Y() + dy };
}
else
{
return level.GetPortalOffsetPosition(X(), Y(), dx, dy);
}
}
inline DVector3 AActor::Vec2OffsetZ(double dx, double dy, double atz, bool absolute)
{
if (absolute)
{
return{ X() + dx, Y() + dy, atz };
}
else
{
DVector2 v = level.GetPortalOffsetPosition(X(), Y(), dx, dy);
return DVector3(v, atz);
}
}
inline DVector2 AActor::Vec2Angle(double length, DAngle angle, bool absolute)
{
if (absolute)
{
return{ X() + length * angle.Cos(), Y() + length * angle.Sin() };
}
else
{
return level.GetPortalOffsetPosition(X(), Y(), length*angle.Cos(), length*angle.Sin());
}
}
inline DVector3 AActor::Vec3Offset(double dx, double dy, double dz, bool absolute)
{
if (absolute)
{
return { X() + dx, Y() + dy, Z() + dz };
}
else
{
DVector2 v = level.GetPortalOffsetPosition(X(), Y(), dx, dy);
return DVector3(v, Z() + dz);
}
}
inline DVector3 AActor::Vec3Offset(const DVector3 &ofs, bool absolute)
{
return Vec3Offset(ofs.X, ofs.Y, ofs.Z, absolute);
}
inline DVector3 AActor::Vec3Angle(double length, DAngle angle, double dz, bool absolute)
{
if (absolute)
{
return{ X() + length * angle.Cos(), Y() + length * angle.Sin(), Z() + dz };
}
else
{
DVector2 v = level.GetPortalOffsetPosition(X(), Y(), length*angle.Cos(), length*angle.Sin());
return DVector3(v, Z() + dz);
}
}

View file

@ -73,7 +73,7 @@ bool DBot::Reachable (AActor *rtarget)
double estimated_dist = player->mo->Distance2D(rtarget); double estimated_dist = player->mo->Distance2D(rtarget);
bool reachable = true; bool reachable = true;
FPathTraverse it(player->mo->X()+player->mo->Vel.X, player->mo->Y()+player->mo->Vel.Y, rtarget->X(), rtarget->Y(), PT_ADDLINES|PT_ADDTHINGS); FPathTraverse it(&level, player->mo->X()+player->mo->Vel.X, player->mo->Y()+player->mo->Vel.Y, rtarget->X(), rtarget->Y(), PT_ADDLINES|PT_ADDTHINGS);
intercept_t *in; intercept_t *in;
while ((in = it.Next())) while ((in = it.Next()))
{ {

View file

@ -50,6 +50,38 @@
#include "r_data/r_sections.h" #include "r_data/r_sections.h"
#include "r_data/r_canvastexture.h" #include "r_data/r_canvastexture.h"
//============================================================================
//
// This is used to mark processed portals for some collection functions.
//
//============================================================================
struct FPortalBits
{
TArray<uint32_t> data;
void setSize(int num)
{
data.Resize((num + 31) / 32);
clear();
}
void clear()
{
memset(&data[0], 0, data.Size() * sizeof(uint32_t));
}
void setBit(int group)
{
data[group >> 5] |= (1 << (group & 31));
}
int getBit(int group)
{
return data[group >> 5] & (1 << (group & 31));
}
};
class DACSThinker; class DACSThinker;
class DFraggleThinker; class DFraggleThinker;
class DSpotState; class DSpotState;
@ -120,6 +152,8 @@ struct FLevelData
struct FLevelLocals : public FLevelData struct FLevelLocals : public FLevelData
{ {
friend class MapLoader;
void Tick(); void Tick();
void Mark(); void Mark();
void AddScroller(int secnum); void AddScroller(int secnum);
@ -138,6 +172,33 @@ struct FLevelLocals : public FLevelData
void SetConversation(int convid, PClassActor *Class, int dlgindex); void SetConversation(int convid, PClassActor *Class, int dlgindex);
int FindNode (const FStrifeDialogueNode *node); int FindNode (const FStrifeDialogueNode *node);
private:
line_t *FindPortalDestination(line_t *src, int tag);
void BuildPortalBlockmap();
void UpdatePortal(FLinePortal *port);
void CollectLinkedPortals();
void CreateLinkedPortals();
bool ChangePortalLine(line_t *line, int destid);
void AddDisplacementForPortal(FSectorPortal *portal);
void AddDisplacementForPortal(FLinePortal *portal);
bool ConnectPortalGroups();
public:
void FinalizePortals();
bool ChangePortal(line_t *ln, int thisid, int destid);
unsigned GetSkyboxPortal(AActor *actor);
unsigned GetPortal(int type, int plane, sector_t *orgsec, sector_t *destsec, const DVector2 &displacement);
unsigned GetStackPortal(AActor *point, int plane);
DVector2 GetPortalOffsetPosition(double x, double y, double dx, double dy);
bool CollectConnectedGroups(int startgroup, const DVector3 &position, double upperz, double checkradius, FPortalGroupArray &out);
private:
// Work data for CollectConnectedGroups.
FPortalBits processMask;
TArray<FLinePortal*> foundPortals;
TArray<int> groupsToCheck;
public:
FSectorTagIterator GetSectorTagIterator(int tag) FSectorTagIterator GetSectorTagIterator(int tag)
{ {
return FSectorTagIterator(tagManager, tag); return FSectorTagIterator(tagManager, tag);

View file

@ -3290,5 +3290,5 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
if (reloop) LoopSidedefs(false); if (reloop) LoopSidedefs(false);
PO_Init(); // Initialize the polyobjs PO_Init(); // Initialize the polyobjs
if (!Level->IsReentering()) if (!Level->IsReentering())
P_FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them. Level->FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them.
} }

View file

@ -185,6 +185,7 @@ private:
void SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int linked); void SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int linked);
void CopyPortal(int sectortag, int plane, unsigned pnum, double alpha, bool tolines); void CopyPortal(int sectortag, int plane, unsigned pnum, double alpha, bool tolines);
void SetPortal(sector_t *sector, int plane, unsigned pnum, double alpha); void SetPortal(sector_t *sector, int plane, unsigned pnum, double alpha);
void SpawnLinePortal(line_t* line);
void SetupPortals(); void SetupPortals();
void SpawnSkybox(AActor *origin); void SpawnSkybox(AActor *origin);
void SetupFloorPortal (AActor *point); void SetupFloorPortal (AActor *point);

View file

@ -109,7 +109,87 @@ EXTERN_CVAR(Bool, forcewater)
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//--------------------------------------------------------------------------- //============================================================================
//
// Spawns a single line portal
//
//============================================================================
void MapLoader::SpawnLinePortal(line_t* line)
{
// portal destination is special argument #0
line_t* dst = nullptr;
if (line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED)
{
dst = Level->FindPortalDestination(line, line->args[0]);
line->portalindex = Level->linePortals.Reserve(1);
FLinePortal *port = &Level->linePortals.Last();
memset(port, 0, sizeof(FLinePortal));
port->mOrigin = line;
port->mDestination = dst;
port->mType = uint8_t(line->args[2]); // range check is done above.
if (port->mType == PORTT_LINKED)
{
// Linked portals have no z-offset ever.
port->mAlign = PORG_ABSOLUTE;
}
else
{
port->mAlign = uint8_t(line->args[3] >= PORG_ABSOLUTE && line->args[3] <= PORG_CEILING ? line->args[3] : PORG_ABSOLUTE);
if (port->mType == PORTT_INTERACTIVE && port->mAlign != PORG_ABSOLUTE)
{
// Due to the way z is often handled, these pose a major issue for parts of the code that needs to transparently handle interactive portals.
Printf(TEXTCOLOR_RED "Warning: z-offsetting not allowed for interactive portals. Changing line %d to teleport-portal!\n", line->Index());
port->mType = PORTT_TELEPORT;
}
}
port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE :
port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT :
PORTF_TYPEINTERACTIVE;
}
else if (line->args[2] == PORTT_LINKEDEE && line->args[0] == 0)
{
// EE-style portals require that the first line ID is identical and the first arg of the two linked linedefs are 0 and 1 respectively.
int mytag = Level->GetFirstLineId(line);
for (auto &ln : Level->lines)
{
if (Level->GetFirstLineId(&ln) == mytag && ln.args[0] == 1 && ln.special == Line_SetPortal)
{
line->portalindex = Level->linePortals.Reserve(1);
FLinePortal *port = &Level->linePortals.Last();
memset(port, 0, sizeof(FLinePortal));
port->mOrigin = line;
port->mDestination = &ln;
port->mType = PORTT_LINKED;
port->mAlign = PORG_ABSOLUTE;
port->mDefFlags = PORTF_TYPEINTERACTIVE;
// we need to create the backlink here, too.
ln.portalindex = Level->linePortals.Reserve(1);
port = &Level->linePortals.Last();
memset(port, 0, sizeof(FLinePortal));
port->mOrigin = &ln;
port->mDestination = line;
port->mType = PORTT_LINKED;
port->mAlign = PORG_ABSOLUTE;
port->mDefFlags = PORTF_TYPEINTERACTIVE;
}
}
}
else
{
// undefined type
return;
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
@ -128,7 +208,7 @@ void MapLoader::SetupFloorPortal (AActor *point)
if (Sector->GetAlpha(sector_t::floor) == 1.) if (Sector->GetAlpha(sector_t::floor) == 1.)
Sector->SetAlpha(sector_t::floor, clamp(point->args[0], 0, 255) / 255.); Sector->SetAlpha(sector_t::floor, clamp(point->args[0], 0, 255) / 255.);
Sector->Portals[sector_t::floor] = P_GetStackPortal(skyv, sector_t::floor); Sector->Portals[sector_t::floor] = Level->GetStackPortal(skyv, sector_t::floor);
} }
} }
@ -149,7 +229,7 @@ void MapLoader::SetupCeilingPortal (AActor *point)
if (Sector->GetAlpha(sector_t::ceiling) == 1.) if (Sector->GetAlpha(sector_t::ceiling) == 1.)
Sector->SetAlpha(sector_t::ceiling, clamp(point->args[0], 0, 255) / 255.); Sector->SetAlpha(sector_t::ceiling, clamp(point->args[0], 0, 255) / 255.);
Sector->Portals[sector_t::ceiling] = P_GetStackPortal(skyv, sector_t::ceiling); Sector->Portals[sector_t::ceiling] = Level->GetStackPortal(skyv, sector_t::ceiling);
} }
} }
@ -319,7 +399,7 @@ void MapLoader::SpawnPortal(line_t *line, int sectortag, int plane, int bytealph
// beware of overflows. // beware of overflows.
DVector2 pos1 = line->v1->fPos() + line->Delta() / 2; DVector2 pos1 = line->v1->fPos() + line->Delta() / 2;
DVector2 pos2 = oline.v1->fPos() + oline.Delta() / 2; DVector2 pos2 = oline.v1->fPos() + oline.Delta() / 2;
unsigned pnum = P_GetPortal(linked ? PORTS_LINKEDPORTAL : PORTS_PORTAL, plane, line->frontsector, oline.frontsector, pos2 - pos1); unsigned pnum = Level->GetPortal(linked ? PORTS_LINKEDPORTAL : PORTS_PORTAL, plane, line->frontsector, oline.frontsector, pos2 - pos1);
CopyPortal(sectortag, plane, pnum, bytealpha / 255., false); CopyPortal(sectortag, plane, pnum, bytealpha / 255., false);
return; return;
} }
@ -348,7 +428,7 @@ void MapLoader::SpawnSkybox(AActor *origin)
if (refline->special == Sector_SetPortal && refline->args[1] == 2) if (refline->special == Sector_SetPortal && refline->args[1] == 2)
{ {
// We found the setup linedef for this skybox, so let's use it for our init. // We found the setup linedef for this skybox, so let's use it for our init.
unsigned pnum = P_GetSkyboxPortal(origin); unsigned pnum = Level->GetSkyboxPortal(origin);
CopyPortal(refline->args[0], refline->args[2], pnum, 0, true); CopyPortal(refline->args[0], refline->args[2], pnum, 0, true);
return; return;
} }
@ -669,13 +749,13 @@ void MapLoader::SpawnSpecials ()
} }
else if (line.args[1] == 3 || line.args[1] == 4) else if (line.args[1] == 3 || line.args[1] == 4)
{ {
unsigned pnum = P_GetPortal(line.args[1] == 3 ? PORTS_PLANE : PORTS_HORIZON, line.args[2], line.frontsector, NULL, { 0,0 }); unsigned pnum = Level->GetPortal(line.args[1] == 3 ? PORTS_PLANE : PORTS_HORIZON, line.args[2], line.frontsector, NULL, { 0,0 });
CopyPortal(line.args[0], line.args[2], pnum, 0, true); CopyPortal(line.args[0], line.args[2], pnum, 0, true);
} }
break; break;
case Line_SetPortal: case Line_SetPortal:
P_SpawnLinePortal(&line); SpawnLinePortal(&line);
break; break;
// [RH] ZDoom Static_Init settings // [RH] ZDoom Static_Init settings

View file

@ -264,7 +264,7 @@ void P_ThinkParticles ()
} }
// Handle crossing a line portal // Handle crossing a line portal
DVector2 newxy = P_GetOffsetPosition(particle->Pos.X, particle->Pos.Y, particle->Vel.X, particle->Vel.Y); DVector2 newxy = level.GetPortalOffsetPosition(particle->Pos.X, particle->Pos.Y, particle->Vel.X, particle->Vel.Y);
particle->Pos.X = newxy.X; particle->Pos.X = newxy.X;
particle->Pos.Y = newxy.Y; particle->Pos.Y = newxy.Y;
particle->Pos.Z += particle->Vel.Z; particle->Pos.Z += particle->Vel.Z;

View file

@ -3402,7 +3402,7 @@ FUNC(LS_Thing_SetConversation)
FUNC(LS_Line_SetPortalTarget) FUNC(LS_Line_SetPortalTarget)
// Line_SetPortalTarget(thisid, destid) // Line_SetPortalTarget(thisid, destid)
{ {
return P_ChangePortal(ln, arg0, arg1); return Level->ChangePortal(ln, arg0, arg1);
} }
FUNC(LS_Sector_SetPlaneReflection) FUNC(LS_Sector_SetPlaneReflection)

View file

@ -2928,7 +2928,7 @@ void FSlide::HitSlideLine(line_t* ld)
void FSlide::SlideTraverse(const DVector2 &start, const DVector2 &end) void FSlide::SlideTraverse(const DVector2 &start, const DVector2 &end)
{ {
FLineOpening open; FLineOpening open;
FPathTraverse it(start.X, start.Y, end.X, end.Y, PT_ADDLINES); FPathTraverse it(&level, start.X, start.Y, end.X, end.Y, PT_ADDLINES);
intercept_t *in; intercept_t *in;
while ((in = it.Next())) while ((in = it.Next()))
@ -3285,7 +3285,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, DVector2 &move)
bool FSlide::BounceTraverse(const DVector2 &start, const DVector2 &end) bool FSlide::BounceTraverse(const DVector2 &start, const DVector2 &end)
{ {
FLineOpening open; FLineOpening open;
FPathTraverse it(start.X, start.Y, end.X, end.Y, PT_ADDLINES); FPathTraverse it(&level, start.X, start.Y, end.X, end.Y, PT_ADDLINES);
intercept_t *in; intercept_t *in;
while ((in = it.Next())) while ((in = it.Next()))
@ -3977,7 +3977,7 @@ struct aim_t
if (ceilingportalstate) EnterSectorPortal(sector_t::ceiling, 0, lastsector, toppitch, MIN<DAngle>(0., bottompitch)); if (ceilingportalstate) EnterSectorPortal(sector_t::ceiling, 0, lastsector, toppitch, MIN<DAngle>(0., bottompitch));
if (floorportalstate) EnterSectorPortal(sector_t::floor, 0, lastsector, MAX<DAngle>(0., toppitch), bottompitch); if (floorportalstate) EnterSectorPortal(sector_t::floor, 0, lastsector, MAX<DAngle>(0., toppitch), bottompitch);
FPathTraverse it(startpos.X, startpos.Y, aimtrace.X, aimtrace.Y, PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE | PT_DELTA, startfrac); FPathTraverse it(&level, startpos.X, startpos.Y, aimtrace.X, aimtrace.Y, PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE | PT_DELTA, startfrac);
intercept_t *in; intercept_t *in;
if (aimdebug) if (aimdebug)
@ -4539,7 +4539,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
// position a bit closer for puffs // position a bit closer for puffs
if (nointeract || trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky)) if (nointeract || trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky))
{ {
DVector2 pos = P_GetOffsetPosition(trace.HitPos.X, trace.HitPos.Y, -trace.HitVector.X * 4, -trace.HitVector.Y * 4); DVector2 pos = level.GetPortalOffsetPosition(trace.HitPos.X, trace.HitPos.Y, -trace.HitVector.X * 4, -trace.HitVector.Y * 4);
puff = P_SpawnPuff(t1, pufftype, DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4), trace.SrcAngleFromTarget, puff = P_SpawnPuff(t1, pufftype, DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4), trace.SrcAngleFromTarget,
trace.SrcAngleFromTarget - 90, 0, puffFlags); trace.SrcAngleFromTarget - 90, 0, puffFlags);
puff->radius = 1/65536.; puff->radius = 1/65536.;
@ -4590,7 +4590,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
// position a bit closer for puffs/blood if using compatibility mode. // position a bit closer for puffs/blood if using compatibility mode.
if (i_compatflags & COMPATF_HITSCAN) if (i_compatflags & COMPATF_HITSCAN)
{ {
DVector2 ofs = P_GetOffsetPosition(bleedpos.X, bleedpos.Y, -10 * trace.HitVector.X, -10 * trace.HitVector.Y); DVector2 ofs = level.GetPortalOffsetPosition(bleedpos.X, bleedpos.Y, -10 * trace.HitVector.X, -10 * trace.HitVector.Y);
bleedpos.X = ofs.X; bleedpos.X = ofs.X;
bleedpos.Y = ofs.Y; bleedpos.Y = ofs.Y;
bleedpos.Z -= -10 * trace.HitVector.Z; bleedpos.Z -= -10 * trace.HitVector.Z;
@ -5101,7 +5101,7 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
newhit.HitAngle = res.SrcAngleFromTarget; newhit.HitAngle = res.SrcAngleFromTarget;
if (i_compatflags & COMPATF_HITSCAN) if (i_compatflags & COMPATF_HITSCAN)
{ {
DVector2 ofs = P_GetOffsetPosition(newhit.HitPos.X, newhit.HitPos.Y, -10 * res.HitVector.X, -10 * res.HitVector.Y); DVector2 ofs = level.GetPortalOffsetPosition(newhit.HitPos.X, newhit.HitPos.Y, -10 * res.HitVector.X, -10 * res.HitVector.Y);
newhit.HitPos.X = ofs.X; newhit.HitPos.X = ofs.X;
newhit.HitPos.Y = ofs.Y; newhit.HitPos.Y = ofs.Y;
newhit.HitPos.Z -= -10 * res.HitVector.Z; newhit.HitPos.Z -= -10 * res.HitVector.Z;
@ -5376,7 +5376,7 @@ bool P_TalkFacing(AActor *player)
bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end, bool &foundline) bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end, bool &foundline)
{ {
FPathTraverse it(start.X, start.Y, end.X, end.Y, PT_ADDLINES | PT_ADDTHINGS); FPathTraverse it(&level, start.X, start.Y, end.X, end.Y, PT_ADDLINES | PT_ADDTHINGS);
intercept_t *in; intercept_t *in;
DVector3 xpos = { start.X, start.Y, usething->Z() }; DVector3 xpos = { start.X, start.Y, usething->Z() };
@ -5519,7 +5519,7 @@ bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end,
bool P_NoWayTraverse(AActor *usething, const DVector2 &start, const DVector2 &end) bool P_NoWayTraverse(AActor *usething, const DVector2 &start, const DVector2 &end)
{ {
FPathTraverse it(start.X, start.Y, end.X, end.Y, PT_ADDLINES); FPathTraverse it(&level, start.X, start.Y, end.X, end.Y, PT_ADDLINES);
intercept_t *in; intercept_t *in;
while ((in = it.Next())) while ((in = it.Next()))
@ -5596,7 +5596,7 @@ int P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType)
start = PuzzleItemUser->GetPortalTransition(PuzzleItemUser->Height / 2); start = PuzzleItemUser->GetPortalTransition(PuzzleItemUser->Height / 2);
end = PuzzleItemUser->Angles.Yaw.ToVector(usedist); end = PuzzleItemUser->Angles.Yaw.ToVector(usedist);
FPathTraverse it(start.X, start.Y, end.X, end.Y, PT_DELTA | PT_ADDLINES | PT_ADDTHINGS); FPathTraverse it(&level, start.X, start.Y, end.X, end.Y, PT_DELTA | PT_ADDLINES | PT_ADDTHINGS);
intercept_t *in; intercept_t *in;
while ((in = it.Next())) while ((in = it.Next()))

View file

@ -504,7 +504,7 @@ void AActor::LinkToWorld(FLinkContext *ctx, bool spawningmapthing, sector_t *sec
{ {
FPortalGroupArray check; FPortalGroupArray check;
P_CollectConnectedGroups(Sector->PortalGroup, Pos(), Top(), radius, check); level.CollectConnectedGroups(Sector->PortalGroup, Pos(), Top(), radius, check);
BlockNode = NULL; BlockNode = NULL;
FBlockNode **alink = &this->BlockNode; FBlockNode **alink = &this->BlockNode;
@ -714,7 +714,7 @@ FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AAc
: checklist(check) : checklist(check)
{ {
checkpoint = origin->Pos(); checkpoint = origin->Pos();
if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); if (!check.inited) level.CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist);
checkpoint.Z = checkradius == -1? origin->radius : checkradius; checkpoint.Z = checkradius == -1? origin->radius : checkradius;
basegroup = origin->Sector->PortalGroup; basegroup = origin->Sector->PortalGroup;
startsector = origin->Sector; startsector = origin->Sector;
@ -728,7 +728,7 @@ FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, dou
if (newsec == NULL) newsec = P_PointInSector(checkx, checky); if (newsec == NULL) newsec = P_PointInSector(checkx, checky);
startsector = newsec; startsector = newsec;
basegroup = newsec->PortalGroup; basegroup = newsec->PortalGroup;
if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist); if (!check.inited) level.CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist);
checkpoint.Z = checkradius; checkpoint.Z = checkradius;
Reset(); Reset();
} }
@ -1056,7 +1056,7 @@ FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, A
: checklist(check) : checklist(check)
{ {
checkpoint = origin->Pos(); checkpoint = origin->Pos();
if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); if (!check.inited) level.CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist);
checkpoint.Z = checkradius == -1? origin->radius : checkradius; checkpoint.Z = checkradius == -1? origin->radius : checkradius;
basegroup = origin->Sector->PortalGroup; basegroup = origin->Sector->PortalGroup;
Reset(); Reset();
@ -1070,7 +1070,7 @@ FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, d
checkpoint.Z = checkz; checkpoint.Z = checkz;
if (newsec == NULL) newsec = P_PointInSector(checkx, checky); if (newsec == NULL) newsec = P_PointInSector(checkx, checky);
basegroup = newsec->PortalGroup; basegroup = newsec->PortalGroup;
if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist); if (!check.inited) level.CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist);
checkpoint.Z = checkradius; checkpoint.Z = checkradius;
Reset(); Reset();
} }

View file

@ -358,6 +358,7 @@ class FPathTraverse
protected: protected:
static TArray<intercept_t> intercepts; static TArray<intercept_t> intercepts;
FLevelLocals *Level;
divline_t trace; divline_t trace;
double Startfrac; double Startfrac;
unsigned int intercept_index; unsigned int intercept_index;
@ -366,13 +367,17 @@ protected:
virtual void AddLineIntercepts(int bx, int by); virtual void AddLineIntercepts(int bx, int by);
virtual void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible); virtual void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible);
FPathTraverse() {} FPathTraverse(FLevelLocals *l)
{
Level = l;
}
public: public:
intercept_t *Next(); intercept_t *Next();
FPathTraverse(double x1, double y1, double x2, double y2, int flags, double startfrac = 0) FPathTraverse(FLevelLocals *l, double x1, double y1, double x2, double y2, int flags, double startfrac = 0)
{ {
Level = l;
init(x1, y1, x2, y2, flags, startfrac); init(x1, y1, x2, y2, flags, startfrac);
} }
void init(double x1, double y1, double x2, double y2, int flags, double startfrac = 0); void init(double x1, double y1, double x2, double y2, int flags, double startfrac = 0);
@ -392,23 +397,6 @@ public:
}; };
//============================================================================
//
// A traverser that uses the portal blockmap
// This should be in portal.h but that'd create circular dependencies.
//
//============================================================================
class FLinePortalTraverse : public FPathTraverse
{
void AddLineIntercepts(int bx, int by);
public:
FLinePortalTraverse()
{
}
};
// //
// P_MAPUTL // P_MAPUTL
// //

View file

@ -988,7 +988,7 @@ void G_SerializeLevel(FSerializer &arc, FLevelLocals *Level, bool hubload)
arc("zones", Level->Zones); arc("zones", Level->Zones);
arc("lineportals", Level->linePortals); arc("lineportals", Level->linePortals);
arc("sectorportals", Level->sectorPortals); arc("sectorportals", Level->sectorPortals);
if (arc.isReading()) P_FinalizePortals(); if (arc.isReading()) Level->FinalizePortals();
// [ZZ] serialize health groups // [ZZ] serialize health groups
P_SerializeHealthGroups(arc); P_SerializeHealthGroups(arc);

View file

@ -186,7 +186,7 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags)
if (!predicting) if (!predicting)
{ {
DVector2 vector = angle.ToVector(20); DVector2 vector = angle.ToVector(20);
DVector2 fogpos = P_GetOffsetPosition(pos.X, pos.Y, vector.X, vector.Y); DVector2 fogpos = level.GetPortalOffsetPosition(pos.X, pos.Y, vector.X, vector.Y);
P_SpawnTeleportFog(thing, DVector3(fogpos, thing->Z()), false, true); P_SpawnTeleportFog(thing, DVector3(fogpos, thing->Z()), false, true);
} }

View file

@ -777,7 +777,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
// Do a 3D floor check in the starting sector // Do a 3D floor check in the starting sector
Setup3DFloors(); Setup3DFloors();
FPathTraverse it(Start.X, Start.Y, Vec.X * MaxDist, Vec.Y * MaxDist, ptflags | PT_DELTA, startfrac); FPathTraverse it(&level, Start.X, Start.Y, Vec.X * MaxDist, Vec.Y * MaxDist, ptflags | PT_DELTA, startfrac);
intercept_t *in; intercept_t *in;
int lastsplashsector = -1; int lastsplashsector = -1;

View file

@ -64,72 +64,40 @@ DEFINE_FIELD(FSectorPortal, mDisplacement);
DEFINE_FIELD(FSectorPortal, mPlaneZ); DEFINE_FIELD(FSectorPortal, mPlaneZ);
DEFINE_FIELD(FSectorPortal, mSkybox); DEFINE_FIELD(FSectorPortal, mSkybox);
//============================================================================
//
// This is used to mark processed portals for some collection functions.
//
//============================================================================
struct FPortalBits
{
TArray<uint32_t> data;
void setSize(int num)
{
data.Resize((num + 31) / 32);
clear();
}
void clear()
{
memset(&data[0], 0, data.Size()*sizeof(uint32_t));
}
void setBit(int group)
{
data[group >> 5] |= (1 << (group & 31));
}
int getBit(int group)
{
return data[group >> 5] & (1 << (group & 31));
}
};
//============================================================================ //============================================================================
// //
// BuildBlockmap // BuildBlockmap
// //
//============================================================================ //============================================================================
static void BuildBlockmap() void FLevelLocals::BuildPortalBlockmap()
{ {
auto bmapwidth = level.blockmap.bmapwidth; auto bmapwidth = blockmap.bmapwidth;
auto bmapheight = level.blockmap.bmapheight; auto bmapheight = blockmap.bmapheight;
level.PortalBlockmap.Clear(); PortalBlockmap.Clear();
level.PortalBlockmap.Create(bmapwidth, bmapheight); PortalBlockmap.Create(bmapwidth, bmapheight);
for (int y = 0; y < bmapheight; y++) for (int y = 0; y < bmapheight; y++)
{ {
for (int x = 0; x < bmapwidth; x++) for (int x = 0; x < bmapwidth; x++)
{ {
int *list = level.blockmap.GetLines(x, y); int *list = blockmap.GetLines(x, y);
FPortalBlock &block = level.PortalBlockmap(x, y); FPortalBlock &block = PortalBlockmap(x, y);
while (*list != -1) while (*list != -1)
{ {
line_t *ld = &level.lines[*list++]; line_t *ld = &lines[*list++];
FLinePortal *port = ld->getPortal(); FLinePortal *port = ld->getPortal();
if (port && port->mType != PORTT_VISUAL) if (port && port->mType != PORTT_VISUAL)
{ {
level.PortalBlockmap.containsLines = true; PortalBlockmap.containsLines = true;
block.portallines.Push(ld); block.portallines.Push(ld);
block.neighborContainsLines = true; block.neighborContainsLines = true;
if (ld->getPortal()->mType == PORTT_LINKED) block.containsLinkedPortals = true; if (ld->getPortal()->mType == PORTT_LINKED) block.containsLinkedPortals = true;
if (x > 0) level.PortalBlockmap(x - 1, y).neighborContainsLines = true; if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true;
if (y > 0) level.PortalBlockmap(x, y - 1).neighborContainsLines = true; if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true;
if (x < level.PortalBlockmap.dx - 1) level.PortalBlockmap(x + 1, y).neighborContainsLines = true; if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true;
if (y < level.PortalBlockmap.dy - 1) level.PortalBlockmap(x, y + 1).neighborContainsLines = true; if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).neighborContainsLines = true;
} }
else else
{ {
@ -140,7 +108,7 @@ static void BuildBlockmap()
yes |= ld->backsector->PortalIsLinked(sector_t::ceiling) || ld->backsector->PortalIsLinked(sector_t::floor); yes |= ld->backsector->PortalIsLinked(sector_t::ceiling) || ld->backsector->PortalIsLinked(sector_t::floor);
} }
block.containsLinkedPortals |= yes; block.containsLinkedPortals |= yes;
level.PortalBlockmap.hasLinkedSectorPortals |= yes; PortalBlockmap.hasLinkedSectorPortals |= yes;
} }
} }
@ -148,6 +116,23 @@ static void BuildBlockmap()
} }
} }
//============================================================================
//
// A traverser that uses the portal blockmap
//
//============================================================================
class FLinePortalTraverse : public FPathTraverse
{
void AddLineIntercepts(int bx, int by);
public:
FLinePortalTraverse(FLevelLocals *l) : FPathTraverse(l)
{
}
};
//=========================================================================== //===========================================================================
// //
// FLinePortalTraverse :: AddLineIntercepts. // FLinePortalTraverse :: AddLineIntercepts.
@ -158,9 +143,9 @@ static void BuildBlockmap()
void FLinePortalTraverse::AddLineIntercepts(int bx, int by) void FLinePortalTraverse::AddLineIntercepts(int bx, int by)
{ {
if (by < 0 || by >= level.PortalBlockmap.dy || bx < 0 || bx >= level.PortalBlockmap.dx) return; if (by < 0 || by >= Level->PortalBlockmap.dy || bx < 0 || bx >= Level->PortalBlockmap.dx) return;
FPortalBlock &block = level.PortalBlockmap(bx, by); FPortalBlock &block = Level->PortalBlockmap(bx, by);
for (unsigned i = 0; i<block.portallines.Size(); i++) for (unsigned i = 0; i<block.portallines.Size(); i++)
{ {
@ -203,18 +188,18 @@ void FLinePortalTraverse::AddLineIntercepts(int bx, int by)
// //
//============================================================================ //============================================================================
static line_t *FindDestination(line_t *src, int tag) line_t *FLevelLocals::FindPortalDestination(line_t *src, int tag)
{ {
if (tag) if (tag)
{ {
int lineno = -1; int lineno = -1;
auto it = level.GetLineIdIterator(tag); auto it = GetLineIdIterator(tag);
while ((lineno = it.Next()) >= 0) while ((lineno = it.Next()) >= 0)
{ {
if (&level.lines[lineno] != src) if (&lines[lineno] != src)
{ {
return &level.lines[lineno]; return &lines[lineno];
} }
} }
} }
@ -228,7 +213,7 @@ static line_t *FindDestination(line_t *src, int tag)
// //
//============================================================================ //============================================================================
static void SetRotation(FLinePortal *port) static void SetPortalRotation(FLinePortal *port)
{ {
if (port != nullptr && port->mDestination != nullptr) if (port != nullptr && port->mDestination != nullptr)
{ {
@ -259,95 +244,13 @@ static void SetRotation(FLinePortal *port)
} }
} }
//============================================================================
//
// Spawns a single line portal
//
//============================================================================
void P_SpawnLinePortal(line_t* line)
{
// portal destination is special argument #0
line_t* dst = nullptr;
if (line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED)
{
dst = FindDestination(line, line->args[0]);
line->portalindex = level.linePortals.Reserve(1);
FLinePortal *port = &level.linePortals.Last();
memset(port, 0, sizeof(FLinePortal));
port->mOrigin = line;
port->mDestination = dst;
port->mType = uint8_t(line->args[2]); // range check is done above.
if (port->mType == PORTT_LINKED)
{
// Linked portals have no z-offset ever.
port->mAlign = PORG_ABSOLUTE;
}
else
{
port->mAlign = uint8_t(line->args[3] >= PORG_ABSOLUTE && line->args[3] <= PORG_CEILING ? line->args[3] : PORG_ABSOLUTE);
if (port->mType == PORTT_INTERACTIVE && port->mAlign != PORG_ABSOLUTE)
{
// Due to the way z is often handled, these pose a major issue for parts of the code that needs to transparently handle interactive portals.
Printf(TEXTCOLOR_RED "Warning: z-offsetting not allowed for interactive portals. Changing line %d to teleport-portal!\n", line->Index());
port->mType = PORTT_TELEPORT;
}
}
port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE :
port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT :
PORTF_TYPEINTERACTIVE;
}
else if (line->args[2] == PORTT_LINKEDEE && line->args[0] == 0)
{
// EE-style portals require that the first line ID is identical and the first arg of the two linked linedefs are 0 and 1 respectively.
int mytag = level.GetFirstLineId(line);
for (auto &ln : level.lines)
{
if (level.GetFirstLineId(&ln) == mytag && ln.args[0] == 1 && ln.special == Line_SetPortal)
{
line->portalindex = level.linePortals.Reserve(1);
FLinePortal *port = &level.linePortals.Last();
memset(port, 0, sizeof(FLinePortal));
port->mOrigin = line;
port->mDestination = &ln;
port->mType = PORTT_LINKED;
port->mAlign = PORG_ABSOLUTE;
port->mDefFlags = PORTF_TYPEINTERACTIVE;
// we need to create the backlink here, too.
ln.portalindex = level.linePortals.Reserve(1);
port = &level.linePortals.Last();
memset(port, 0, sizeof(FLinePortal));
port->mOrigin = &ln;
port->mDestination = line;
port->mType = PORTT_LINKED;
port->mAlign = PORG_ABSOLUTE;
port->mDefFlags = PORTF_TYPEINTERACTIVE;
}
}
}
else
{
// undefined type
return;
}
}
//============================================================================ //============================================================================
// //
// Update a line portal's state after all have been spawned // Update a line portal's state after all have been spawned
// //
//============================================================================ //============================================================================
void P_UpdatePortal(FLinePortal *port) void FLevelLocals::UpdatePortal(FLinePortal *port)
{ {
if (port->mType != PORTT_VISUAL && port->mOrigin->backsector == nullptr && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ)) if (port->mType != PORTT_VISUAL && port->mOrigin->backsector == nullptr && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ))
{ {
@ -378,7 +281,7 @@ void P_UpdatePortal(FLinePortal *port)
port->mFlags = port->mDefFlags; port->mFlags = port->mDefFlags;
if (port->mType == PORTT_LINKED) if (port->mType == PORTT_LINKED)
{ {
if (level.linePortals[port->mDestination->portalindex].mType != PORTT_LINKED) if (linePortals[port->mDestination->portalindex].mType != PORTT_LINKED)
{ {
port->mType = PORTT_INTERACTIVE; // linked portals must be two-way. port->mType = PORTT_INTERACTIVE; // linked portals must be two-way.
} }
@ -390,7 +293,7 @@ void P_UpdatePortal(FLinePortal *port)
} }
// Cache the angle between the two linedefs, for rotating. // Cache the angle between the two linedefs, for rotating.
SetRotation(port); SetPortalRotation(port);
} }
//============================================================================ //============================================================================
@ -400,15 +303,15 @@ void P_UpdatePortal(FLinePortal *port)
// //
//============================================================================ //============================================================================
void P_CollectLinkedPortals() void FLevelLocals::CollectLinkedPortals()
{ {
level.linkedPortals.Clear(); linkedPortals.Clear();
for (unsigned i = 0; i < level.linePortals.Size(); i++) for (unsigned i = 0; i < linePortals.Size(); i++)
{ {
FLinePortal * port = &level.linePortals[i]; FLinePortal * port = &linePortals[i];
if (port->mType == PORTT_LINKED) if (port->mType == PORTT_LINKED)
{ {
level.linkedPortals.Push(port); linkedPortals.Push(port);
} }
} }
} }
@ -419,16 +322,16 @@ void P_CollectLinkedPortals()
// //
//============================================================================ //============================================================================
void P_FinalizePortals() void FLevelLocals::FinalizePortals()
{ {
for (unsigned i = 0; i < level.linePortals.Size(); i++) for (unsigned i = 0; i < linePortals.Size(); i++)
{ {
FLinePortal * port = &level.linePortals[i]; FLinePortal * port = &linePortals[i];
P_UpdatePortal(port); UpdatePortal(port);
} }
P_CollectLinkedPortals(); CollectLinkedPortals();
BuildBlockmap(); BuildPortalBlockmap();
P_CreateLinkedPortals(); CreateLinkedPortals();
} }
//============================================================================ //============================================================================
@ -437,20 +340,20 @@ void P_FinalizePortals()
// //
//============================================================================ //============================================================================
static bool ChangePortalLine(line_t *line, int destid) bool FLevelLocals::ChangePortalLine(line_t *line, int destid)
{ {
if (line->portalindex >= level.linePortals.Size()) return false; if (line->portalindex >= linePortals.Size()) return false;
FLinePortal *port = &level.linePortals[line->portalindex]; FLinePortal *port = &linePortals[line->portalindex];
if (port->mType == PORTT_LINKED) return false; // linked portals cannot be changed. if (port->mType == PORTT_LINKED) return false; // linked portals cannot be changed.
if (destid == 0) port->mDestination = nullptr; if (destid == 0) port->mDestination = nullptr;
port->mDestination = FindDestination(line, destid); port->mDestination = FindPortalDestination(line, destid);
if (port->mDestination == nullptr) if (port->mDestination == nullptr)
{ {
port->mFlags = 0; port->mFlags = 0;
} }
else if (port->mType == PORTT_INTERACTIVE) else if (port->mType == PORTT_INTERACTIVE)
{ {
FLinePortal *portd = port->mDestination->portalindex < level.linePortals.Size()? &level.linePortals[port->mDestination->portalindex] : nullptr; FLinePortal *portd = port->mDestination->portalindex < linePortals.Size()? &linePortals[port->mDestination->portalindex] : nullptr;
if (portd != nullptr && portd->mType == PORTT_INTERACTIVE && portd->mDestination == line) if (portd != nullptr && portd->mType == PORTT_INTERACTIVE && portd->mDestination == line)
{ {
// this is a 2-way interactive portal // this is a 2-way interactive portal
@ -461,13 +364,13 @@ static bool ChangePortalLine(line_t *line, int destid)
{ {
port->mFlags = port->mDefFlags; port->mFlags = port->mDefFlags;
} }
SetRotation(portd); SetPortalRotation(portd);
} }
else else
{ {
port->mFlags = port->mDefFlags; port->mFlags = port->mDefFlags;
} }
SetRotation(port); SetPortalRotation(port);
return true; return true;
} }
@ -478,16 +381,16 @@ static bool ChangePortalLine(line_t *line, int destid)
// //
//============================================================================ //============================================================================
bool P_ChangePortal(line_t *ln, int thisid, int destid) bool FLevelLocals::ChangePortal(line_t *ln, int thisid, int destid)
{ {
int lineno; int lineno;
if (thisid == 0) return ChangePortalLine(ln, destid); if (thisid == 0) return ChangePortalLine(ln, destid);
auto it = level.GetLineIdIterator(thisid); auto it = GetLineIdIterator(thisid);
bool res = false; bool res = false;
while ((lineno = it.Next()) >= 0) while ((lineno = it.Next()) >= 0)
{ {
res |= ChangePortalLine(&level.lines[lineno], destid); res |= ChangePortalLine(&lines[lineno], destid);
} }
return res; return res;
} }
@ -553,7 +456,7 @@ void P_TranslatePortalXY(line_t* src, double& x, double& y)
if (!src) return; if (!src) return;
FLinePortal *port = src->getPortal(); FLinePortal *port = src->getPortal();
if (!port) return; if (!port) return;
if (port->mFlags & PORTF_POLYOBJ) SetRotation(port); // update the angle for polyportals. if (port->mFlags & PORTF_POLYOBJ) SetPortalRotation(port); // update the angle for polyportals.
// offsets from line // offsets from line
double nposx = x - src->v1->fX(); double nposx = x - src->v1->fX();
@ -581,7 +484,7 @@ void P_TranslatePortalVXVY(line_t* src, double &velx, double &vely)
if (!src) return; if (!src) return;
FLinePortal *port = src->getPortal(); FLinePortal *port = src->getPortal();
if (!port) return; if (!port) return;
if (port->mFlags & PORTF_POLYOBJ) SetRotation(port); // update the angle for polyportals. if (port->mFlags & PORTF_POLYOBJ) SetPortalRotation(port); // update the angle for polyportals.
double orig_velx = velx; double orig_velx = velx;
double orig_vely = vely; double orig_vely = vely;
@ -600,7 +503,7 @@ void P_TranslatePortalAngle(line_t* src, DAngle& angle)
if (!src) return; if (!src) return;
FLinePortal *port = src->getPortal(); FLinePortal *port = src->getPortal();
if (!port) return; if (!port) return;
if (port->mFlags & PORTF_POLYOBJ) SetRotation(port); // update the angle for polyportals. if (port->mFlags & PORTF_POLYOBJ) SetPortalRotation(port); // update the angle for polyportals.
angle = (angle + port->mAngleDiff).Normalized360(); angle = (angle + port->mAngleDiff).Normalized360();
} }
@ -642,27 +545,27 @@ void P_TranslatePortalZ(line_t* src, double& z)
// //
//============================================================================ //============================================================================
unsigned P_GetSkyboxPortal(AActor *actor) unsigned FLevelLocals::GetSkyboxPortal(AActor *actor)
{ {
if (actor == nullptr) return 1; // this means a regular sky. if (actor == nullptr) return 1; // this means a regular sky.
for (unsigned i = 0;i<level.sectorPortals.Size();i++) for (unsigned i = 0;i<sectorPortals.Size();i++)
{ {
if (level.sectorPortals[i].mSkybox == actor) return i; if (sectorPortals[i].mSkybox == actor) return i;
} }
unsigned i = level.sectorPortals.Reserve(1); unsigned i = sectorPortals.Reserve(1);
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); memset(&sectorPortals[i], 0, sizeof(sectorPortals[i]));
level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT; sectorPortals[i].mType = PORTS_SKYVIEWPOINT;
level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY; sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY;
level.sectorPortals[i].mSkybox = actor; sectorPortals[i].mSkybox = actor;
level.sectorPortals[i].mDestination = actor->Sector; sectorPortals[i].mDestination = actor->Sector;
return i; return i;
} }
DEFINE_ACTION_FUNCTION(FSectorPortal, GetSkyboxPortal) DEFINE_ACTION_FUNCTION(FLevelLocals, GetSkyboxPortal)
{ {
PARAM_PROLOGUE; PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_OBJECT(actor, AActor); PARAM_OBJECT(actor, AActor);
ACTION_RETURN_INT(P_GetSkyboxPortal(actor)); ACTION_RETURN_INT(self->GetSkyboxPortal(actor));
} }
//============================================================================ //============================================================================
// //
@ -672,16 +575,16 @@ DEFINE_ACTION_FUNCTION(FSectorPortal, GetSkyboxPortal)
// //
//============================================================================ //============================================================================
unsigned P_GetPortal(int type, int plane, sector_t *from, sector_t *to, const DVector2 &displacement) unsigned FLevelLocals::GetPortal(int type, int plane, sector_t *from, sector_t *to, const DVector2 &displacement)
{ {
unsigned i = level.sectorPortals.Reserve(1); unsigned i = sectorPortals.Reserve(1);
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); memset(&sectorPortals[i], 0, sizeof(sectorPortals[i]));
level.sectorPortals[i].mType = type; sectorPortals[i].mType = type;
level.sectorPortals[i].mPlane = plane; sectorPortals[i].mPlane = plane;
level.sectorPortals[i].mOrigin = from; sectorPortals[i].mOrigin = from;
level.sectorPortals[i].mDestination = to; sectorPortals[i].mDestination = to;
level.sectorPortals[i].mDisplacement = displacement; sectorPortals[i].mDisplacement = displacement;
level.sectorPortals[i].mPlaneZ = type == PORTS_LINKEDPORTAL? from->GetPlaneTexZ(plane) : FLT_MAX; sectorPortals[i].mPlaneZ = type == PORTS_LINKEDPORTAL? from->GetPlaneTexZ(plane) : FLT_MAX;
return i; return i;
} }
@ -693,47 +596,47 @@ unsigned P_GetPortal(int type, int plane, sector_t *from, sector_t *to, const DV
// //
//============================================================================ //============================================================================
unsigned P_GetStackPortal(AActor *point, int plane) unsigned FLevelLocals::GetStackPortal(AActor *point, int plane)
{ {
unsigned i = level.sectorPortals.Reserve(1); unsigned i = sectorPortals.Reserve(1);
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); memset(&sectorPortals[i], 0, sizeof(sectorPortals[i]));
level.sectorPortals[i].mType = PORTS_STACKEDSECTORTHING; sectorPortals[i].mType = PORTS_STACKEDSECTORTHING;
level.sectorPortals[i].mPlane = plane; sectorPortals[i].mPlane = plane;
level.sectorPortals[i].mOrigin = point->target->Sector; sectorPortals[i].mOrigin = point->target->Sector;
level.sectorPortals[i].mDestination = point->Sector; sectorPortals[i].mDestination = point->Sector;
level.sectorPortals[i].mPlaneZ = FLT_MAX; sectorPortals[i].mPlaneZ = FLT_MAX;
level.sectorPortals[i].mSkybox = point; sectorPortals[i].mSkybox = point;
return i; return i;
} }
//============================================================================ //============================================================================
// //
// P_GetOffsetPosition // level.GetPortalOffsetPosition
// //
// Offsets a given coordinate if the trace from the origin crosses an // Offsets a given coordinate if the trace from the origin crosses an
// interactive line-to-line portal. // interactive line-to-line portal.
// //
//============================================================================ //============================================================================
DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy) DVector2 FLevelLocals::GetPortalOffsetPosition(double x, double y, double dx, double dy)
{ {
DVector2 dest(x + dx, y + dy); DVector2 dest(x + dx, y + dy);
if (level.PortalBlockmap.containsLines) if (PortalBlockmap.containsLines)
{ {
double actx = x, acty = y; double actx = x, acty = y;
// Try some easily discoverable early-out first. If we know that the trace cannot possibly find a portal, this saves us from calling the traverser completely for vast parts of the map. // Try some easily discoverable early-out first. If we know that the trace cannot possibly find a portal, this saves us from calling the traverser completely for vast parts of the map.
if (dx < 128 && dy < 128) if (dx < 128 && dy < 128)
{ {
int blockx = level.blockmap.GetBlockX(actx); int blockx = blockmap.GetBlockX(actx);
int blocky = level.blockmap.GetBlockY(acty); int blocky = blockmap.GetBlockY(acty);
if (blockx < 0 || blocky < 0 || blockx >= level.PortalBlockmap.dx || blocky >= level.PortalBlockmap.dy || !level.PortalBlockmap(blockx, blocky).neighborContainsLines) return dest; if (blockx < 0 || blocky < 0 || blockx >= PortalBlockmap.dx || blocky >= PortalBlockmap.dy || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
} }
bool repeat; bool repeat;
do do
{ {
FLinePortalTraverse it; FLinePortalTraverse it(this);
it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA); it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA);
intercept_t *in; intercept_t *in;
@ -777,11 +680,6 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy)
return dest; return dest;
} }
static void GetOffsetPosition(double x, double y, double dx, double dy, DVector2 *result)
{
*result = P_GetOffsetPosition(x, y, dx, dy);
}
//============================================================================ //============================================================================
// //
// CollectSectors // CollectSectors
@ -829,7 +727,7 @@ static bool CollectSectors(int groupid, sector_t *origin)
// //
//============================================================================ //============================================================================
static void AddDisplacementForPortal(FSectorPortal *portal) void FLevelLocals::AddDisplacementForPortal(FSectorPortal *portal)
{ {
int thisgroup = portal->mOrigin->PortalGroup; int thisgroup = portal->mOrigin->PortalGroup;
int othergroup = portal->mDestination->PortalGroup; int othergroup = portal->mDestination->PortalGroup;
@ -839,14 +737,14 @@ static void AddDisplacementForPortal(FSectorPortal *portal)
portal->mType = PORTS_PORTAL; portal->mType = PORTS_PORTAL;
return; return;
} }
if (thisgroup <= 0 || thisgroup >= level.Displacements.size || othergroup <= 0 || othergroup >= level.Displacements.size) if (thisgroup <= 0 || thisgroup >= Displacements.size || othergroup <= 0 || othergroup >= Displacements.size)
{ {
Printf("Portal between sectors %d and %d has invalid group and will be disabled\n", portal->mOrigin->sectornum, portal->mDestination->sectornum); Printf("Portal between sectors %d and %d has invalid group and will be disabled\n", portal->mOrigin->sectornum, portal->mDestination->sectornum);
portal->mType = PORTS_PORTAL; portal->mType = PORTS_PORTAL;
return; return;
} }
FDisplacement & disp = level.Displacements(thisgroup, othergroup); FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet) if (!disp.isSet)
{ {
disp.pos = portal->mDisplacement; disp.pos = portal->mDisplacement;
@ -864,24 +762,24 @@ static void AddDisplacementForPortal(FSectorPortal *portal)
} }
static void AddDisplacementForPortal(FLinePortal *portal) void FLevelLocals::AddDisplacementForPortal(FLinePortal *portal)
{ {
int thisgroup = portal->mOrigin->frontsector->PortalGroup; int thisgroup = portal->mOrigin->frontsector->PortalGroup;
int othergroup = portal->mDestination->frontsector->PortalGroup; int othergroup = portal->mDestination->frontsector->PortalGroup;
if (thisgroup == othergroup) if (thisgroup == othergroup)
{ {
Printf("Portal between lines %d and %d has both sides in same group\n", portal->mOrigin->Index(), portal->mDestination->Index()); Printf("Portal between lines %d and %d has both sides in same group\n", portal->mOrigin->Index(), portal->mDestination->Index());
portal->mType = level.linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT; portal->mType = linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
return; return;
} }
if (thisgroup <= 0 || thisgroup >= level.Displacements.size || othergroup <= 0 || othergroup >= level.Displacements.size) if (thisgroup <= 0 || thisgroup >= Displacements.size || othergroup <= 0 || othergroup >= Displacements.size)
{ {
Printf("Portal between lines %d and %d has invalid group\n", portal->mOrigin->Index(), portal->mDestination->Index()); Printf("Portal between lines %d and %d has invalid group\n", portal->mOrigin->Index(), portal->mDestination->Index());
portal->mType = level.linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT; portal->mType = linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
return; return;
} }
FDisplacement & disp = level.Displacements(thisgroup, othergroup); FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet) if (!disp.isSet)
{ {
disp.pos = portal->mDisplacement; disp.pos = portal->mDisplacement;
@ -892,7 +790,7 @@ static void AddDisplacementForPortal(FLinePortal *portal)
if (disp.pos != portal->mDisplacement) if (disp.pos != portal->mDisplacement)
{ {
Printf("Portal between lines %d and %d has displacement mismatch\n", portal->mOrigin->Index(), portal->mDestination->Index()); Printf("Portal between lines %d and %d has displacement mismatch\n", portal->mOrigin->Index(), portal->mDestination->Index());
portal->mType = level.linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT; portal->mType = linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
return; return;
} }
} }
@ -906,7 +804,7 @@ static void AddDisplacementForPortal(FLinePortal *portal)
// //
//============================================================================ //============================================================================
static bool ConnectGroups() bool FLevelLocals::ConnectPortalGroups()
{ {
// Now // Now
uint8_t indirect = 1; uint8_t indirect = 1;
@ -915,19 +813,19 @@ static bool ConnectGroups()
do do
{ {
changed = false; changed = false;
for (int x = 1; x < level.Displacements.size; x++) for (int x = 1; x < Displacements.size; x++)
{ {
for (int y = 1; y < level.Displacements.size; y++) for (int y = 1; y < Displacements.size; y++)
{ {
FDisplacement &dispxy = level.Displacements(x, y); FDisplacement &dispxy = Displacements(x, y);
if (dispxy.isSet) if (dispxy.isSet)
{ {
for (int z = 1; z < level.Displacements.size; z++) for (int z = 1; z < Displacements.size; z++)
{ {
FDisplacement &dispyz = level.Displacements(y, z); FDisplacement &dispyz = Displacements(y, z);
if (dispyz.isSet) if (dispyz.isSet)
{ {
FDisplacement &dispxz = level.Displacements(x, z); FDisplacement &dispxz = Displacements(x, z);
if (dispxz.isSet) if (dispxz.isSet)
{ {
if (dispxy.pos.X + dispyz.pos.X != dispxz.pos.X || dispxy.pos.Y + dispyz.pos.Y != dispxz.pos.Y) if (dispxy.pos.X + dispyz.pos.X != dispxz.pos.X || dispxy.pos.Y + dispyz.pos.Y != dispxz.pos.Y)
@ -966,13 +864,13 @@ static bool ConnectGroups()
// //
//============================================================================ //============================================================================
void P_CreateLinkedPortals() void FLevelLocals::CreateLinkedPortals()
{ {
TArray<FSectorPortal *> orgs; TArray<FSectorPortal *> orgs;
int id = 1; int id = 1;
bool bogus = false; bool bogus = false;
for(auto &s : level.sectorPortals) for(auto &s : sectorPortals)
{ {
if (s.mType == PORTS_LINKEDPORTAL) if (s.mType == PORTS_LINKEDPORTAL)
{ {
@ -982,7 +880,7 @@ void P_CreateLinkedPortals()
id = 1; id = 1;
if (orgs.Size() != 0) if (orgs.Size() != 0)
{ {
for (auto &sec : level.sectors) for (auto &sec : sectors)
{ {
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
@ -1006,27 +904,27 @@ void P_CreateLinkedPortals()
if (CollectSectors(id, orgs[i]->mDestination)) id++; if (CollectSectors(id, orgs[i]->mDestination)) id++;
} }
} }
for (unsigned i = 0; i < level.linePortals.Size(); i++) for (unsigned i = 0; i < linePortals.Size(); i++)
{ {
if (level.linePortals[i].mType == PORTT_LINKED) if (linePortals[i].mType == PORTT_LINKED)
{ {
if (level.linePortals[i].mDestination == nullptr) if (linePortals[i].mDestination == nullptr)
{ {
Printf("Linked portal on line %d is unconnected and will be disabled\n", level.linePortals[i].mOrigin->Index()); Printf("Linked portal on line %d is unconnected and will be disabled\n", linePortals[i].mOrigin->Index());
level.linePortals[i].mOrigin->portalindex = UINT_MAX; linePortals[i].mOrigin->portalindex = UINT_MAX;
level.linePortals[i].mType = PORTT_VISUAL; linePortals[i].mType = PORTT_VISUAL;
} }
else else
{ {
if (CollectSectors(id, level.linePortals[i].mOrigin->frontsector)) id++; if (CollectSectors(id, linePortals[i].mOrigin->frontsector)) id++;
if (CollectSectors(id, level.linePortals[i].mDestination->frontsector)) id++; if (CollectSectors(id, linePortals[i].mDestination->frontsector)) id++;
} }
} }
} }
level.Displacements.Create(id); Displacements.Create(id);
// Check for leftover sectors that connect to a portal // Check for leftover sectors that connect to a portal
for (auto &sec : level.sectors) for (auto &sec : sectors)
{ {
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
@ -1041,34 +939,34 @@ void P_CreateLinkedPortals()
{ {
AddDisplacementForPortal(orgs[i]); AddDisplacementForPortal(orgs[i]);
} }
for (unsigned i = 0; i < level.linePortals.Size(); i++) for (unsigned i = 0; i < linePortals.Size(); i++)
{ {
if (level.linePortals[i].mType == PORTT_LINKED) if (linePortals[i].mType == PORTT_LINKED)
{ {
AddDisplacementForPortal(&level.linePortals[i]); AddDisplacementForPortal(&linePortals[i]);
} }
} }
for (int x = 1; x < level.Displacements.size; x++) for (int x = 1; x < Displacements.size; x++)
{ {
for (int y = x + 1; y < level.Displacements.size; y++) for (int y = x + 1; y < Displacements.size; y++)
{ {
FDisplacement &dispxy = level.Displacements(x, y); FDisplacement &dispxy = Displacements(x, y);
FDisplacement &dispyx = level.Displacements(y, x); FDisplacement &dispyx = Displacements(y, x);
if (dispxy.isSet && dispyx.isSet && if (dispxy.isSet && dispyx.isSet &&
(dispxy.pos.X != -dispyx.pos.X || dispxy.pos.Y != -dispyx.pos.Y)) (dispxy.pos.X != -dispyx.pos.X || dispxy.pos.Y != -dispyx.pos.Y))
{ {
int sec1 = -1, sec2 = -1; int sec1 = -1, sec2 = -1;
for (unsigned i = 0; i < level.sectors.Size() && (sec1 == -1 || sec2 == -1); i++) for (unsigned i = 0; i < sectors.Size() && (sec1 == -1 || sec2 == -1); i++)
{ {
if (sec1 == -1 && level.sectors[i].PortalGroup == x) sec1 = i; if (sec1 == -1 && sectors[i].PortalGroup == x) sec1 = i;
if (sec2 == -1 && level.sectors[i].PortalGroup == y) sec2 = i; if (sec2 == -1 && sectors[i].PortalGroup == y) sec2 = i;
} }
Printf("Link offset mismatch between sectors %d and %d\n", sec1, sec2); Printf("Link offset mismatch between sectors %d and %d\n", sec1, sec2);
bogus = true; bogus = true;
} }
// mark everything that connects to a one-sided line // mark everything that connects to a one-sided line
for (auto &line : level.lines) for (auto &line : lines)
{ {
if (line.backsector == nullptr && line.frontsector->PortalGroup == 0) if (line.backsector == nullptr && line.frontsector->PortalGroup == 0)
{ {
@ -1076,7 +974,7 @@ void P_CreateLinkedPortals()
} }
} }
// and now print a message for everything that still wasn't processed. // and now print a message for everything that still wasn't processed.
for (auto &sec : level.sectors) for (auto &sec : sectors)
{ {
if (sec.PortalGroup == 0) if (sec.PortalGroup == 0)
{ {
@ -1086,19 +984,19 @@ void P_CreateLinkedPortals()
} }
} }
} }
bogus |= ConnectGroups(); bogus |= ConnectPortalGroups();
if (bogus) if (bogus)
{ {
// todo: disable all portals whose offsets do not match the associated groups // todo: disable all portals whose offsets do not match the associated groups
} }
// reject would just get in the way when checking sight through portals. // reject would just get in the way when checking sight through portals.
if (level.Displacements.size > 1) if (Displacements.size > 1)
{ {
level.rejectmatrix.Reset(); rejectmatrix.Reset();
} }
// finally we must flag all planes which are obstructed by the sector's own ceiling or floor. // finally we must flag all planes which are obstructed by the sector's own ceiling or floor.
for (auto &sec : level.sectors) for (auto &sec : sectors)
{ {
sec.CheckPortalPlane(sector_t::floor); sec.CheckPortalPlane(sector_t::floor);
sec.CheckPortalPlane(sector_t::ceiling); sec.CheckPortalPlane(sector_t::ceiling);
@ -1134,7 +1032,7 @@ void P_CreateLinkedPortals()
if (sec.PortalIsLinked(sector_t::floor)) sec.planes[sector_t::floor].Flags |= PLANEF_LINKED; if (sec.PortalIsLinked(sector_t::floor)) sec.planes[sector_t::floor].Flags |= PLANEF_LINKED;
if (sec.PortalIsLinked(sector_t::ceiling)) sec.planes[sector_t::ceiling].Flags |= PLANEF_LINKED; if (sec.PortalIsLinked(sector_t::ceiling)) sec.planes[sector_t::ceiling].Flags |= PLANEF_LINKED;
} }
if (level.linkedPortals.Size() > 0) if (linkedPortals.Size() > 0)
{ {
// We need to relink all actors that may touch a linked line portal // We need to relink all actors that may touch a linked line portal
TThinkerIterator<AActor> it; TThinkerIterator<AActor> it;
@ -1144,7 +1042,7 @@ void P_CreateLinkedPortals()
if (!(actor->flags & MF_NOBLOCKMAP)) if (!(actor->flags & MF_NOBLOCKMAP))
{ {
FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals); FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals);
P_CollectConnectedGroups(actor->Sector->PortalGroup, actor->Pos(), actor->Top(), actor->radius, check); CollectConnectedGroups(actor->Sector->PortalGroup, actor->Pos(), actor->Top(), actor->radius, check);
if (check.Size() > 0) if (check.Size() > 0)
{ {
FLinkContext ctx; FLinkContext ctx;
@ -1164,25 +1062,19 @@ void P_CreateLinkedPortals()
// //
//============================================================================ //============================================================================
bool P_CollectConnectedGroups(int startgroup, const DVector3 &position, double upperz, double checkradius, FPortalGroupArray &out) bool FLevelLocals::CollectConnectedGroups(int startgroup, const DVector3 &position, double upperz, double 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.
static FPortalBits processMask;
static TArray<FLinePortal*> foundPortals;
static TArray<int> groupsToCheck;
bool retval = false; bool retval = false;
out.inited = true; out.inited = true;
processMask.setSize(level.Displacements.size); processMask.setSize(Displacements.size);
if (level.Displacements.size == 1) if (Displacements.size == 1)
{ {
processMask.setBit(startgroup); processMask.setBit(startgroup);
return false; return false;
} }
if (level.linkedPortals.Size() != 0) if (linkedPortals.Size() != 0)
{ {
processMask.clear(); processMask.clear();
foundPortals.Clear(); foundPortals.Clear();
@ -1191,17 +1083,17 @@ bool P_CollectConnectedGroups(int startgroup, const DVector3 &position, double u
processMask.setBit(thisgroup); processMask.setBit(thisgroup);
//out.Add(thisgroup); //out.Add(thisgroup);
for (unsigned i = 0; i < level.linkedPortals.Size(); i++) for (unsigned i = 0; i < linkedPortals.Size(); i++)
{ {
line_t *ld = level.linkedPortals[i]->mOrigin; line_t *ld = linkedPortals[i]->mOrigin;
int othergroup = ld->frontsector->PortalGroup; int othergroup = ld->frontsector->PortalGroup;
FDisplacement &disp = level.Displacements(thisgroup, othergroup); FDisplacement &disp = Displacements(thisgroup, othergroup);
if (!disp.isSet) continue; // no connection. if (!disp.isSet) continue; // no connection.
FBoundingBox box(position.X + disp.pos.X, position.Y + disp.pos.Y, checkradius); FBoundingBox box(position.X + disp.pos.X, position.Y + disp.pos.Y, checkradius);
if (!box.inRange(ld) || box.BoxOnLineSide(level.linkedPortals[i]->mOrigin) != -1) continue; // not touched if (!box.inRange(ld) || box.BoxOnLineSide(linkedPortals[i]->mOrigin) != -1) continue; // not touched
foundPortals.Push(level.linkedPortals[i]); foundPortals.Push(linkedPortals[i]);
} }
bool foundone = true; bool foundone = true;
while (foundone) while (foundone)
@ -1228,7 +1120,7 @@ bool P_CollectConnectedGroups(int startgroup, const DVector3 &position, double u
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->GetPortalPlaneZ(sector_t::ceiling)) while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->GetPortalPlaneZ(sector_t::ceiling))
{ {
int othergroup = wsec->GetOppositePortalGroup(sector_t::ceiling); int othergroup = wsec->GetOppositePortalGroup(sector_t::ceiling);
DVector2 pos = level.Displacements.getOffset(startgroup, othergroup) + position; DVector2 pos = Displacements.getOffset(startgroup, othergroup) + position;
if (processMask.getBit(othergroup)) break; if (processMask.getBit(othergroup)) break;
processMask.setBit(othergroup); processMask.setBit(othergroup);
out.Add(othergroup | FPortalGroupArray::UPPER); out.Add(othergroup | FPortalGroupArray::UPPER);
@ -1239,21 +1131,21 @@ bool P_CollectConnectedGroups(int startgroup, const DVector3 &position, double u
while (!wsec->PortalBlocksMovement(sector_t::floor) && position.Z < wsec->GetPortalPlaneZ(sector_t::floor)) while (!wsec->PortalBlocksMovement(sector_t::floor) && position.Z < wsec->GetPortalPlaneZ(sector_t::floor))
{ {
int othergroup = wsec->GetOppositePortalGroup(sector_t::floor); int othergroup = wsec->GetOppositePortalGroup(sector_t::floor);
DVector2 pos = level.Displacements.getOffset(startgroup, othergroup) + position; DVector2 pos = Displacements.getOffset(startgroup, othergroup) + position;
if (processMask.getBit(othergroup)) break; if (processMask.getBit(othergroup)) break;
processMask.setBit(othergroup); processMask.setBit(othergroup);
out.Add(othergroup | FPortalGroupArray::LOWER); out.Add(othergroup | FPortalGroupArray::LOWER);
wsec = P_PointInSector(pos); // get lower sector at the exact spot we want to check and repeat wsec = P_PointInSector(pos); // get lower sector at the exact spot we want to check and repeat
retval = true; retval = true;
} }
if (out.method == FPortalGroupArray::PGA_Full3d && level.PortalBlockmap.hasLinkedSectorPortals) if (out.method == FPortalGroupArray::PGA_Full3d && PortalBlockmap.hasLinkedSectorPortals)
{ {
groupsToCheck.Clear(); groupsToCheck.Clear();
groupsToCheck.Push(startgroup); groupsToCheck.Push(startgroup);
int thisgroup = startgroup; int thisgroup = startgroup;
for (unsigned i = 0; i < groupsToCheck.Size();i++) for (unsigned i = 0; i < groupsToCheck.Size();i++)
{ {
DVector2 disp = level.Displacements.getOffset(startgroup, thisgroup & ~FPortalGroupArray::FLAT); DVector2 disp = Displacements.getOffset(startgroup, thisgroup & ~FPortalGroupArray::FLAT);
FBoundingBox box(position.X + disp.X, position.Y + disp.Y, checkradius); FBoundingBox box(position.X + disp.X, position.Y + disp.Y, checkradius);
FBlockLinesIterator it(box); FBlockLinesIterator it(box);
line_t *ld; line_t *ld;

View file

@ -263,15 +263,6 @@ struct FSectorPortalGroup
// //
//============================================================================ //============================================================================
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(int startgroup, const DVector3 &position, double upperz, double checkradius, FPortalGroupArray &out);
void P_CollectLinkedPortals();
unsigned P_GetSkyboxPortal(AActor *actor);
unsigned P_GetPortal(int type, int plane, sector_t *orgsec, sector_t *destsec, const DVector2 &displacement);
unsigned P_GetStackPortal(AActor *point, int plane);
/* code ported from prototype */ /* code ported from prototype */
@ -280,7 +271,6 @@ void P_TranslatePortalXY(line_t* src, double& vx, double& vy);
void P_TranslatePortalVXVY(line_t* src, double &velx, double &vely); void P_TranslatePortalVXVY(line_t* src, double &velx, double &vely);
void P_TranslatePortalAngle(line_t* src, DAngle& angle); void P_TranslatePortalAngle(line_t* src, DAngle& angle);
void P_TranslatePortalZ(line_t* src, double& vz); void P_TranslatePortalZ(line_t* src, double& vz);
DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy);
struct FLevelLocals; struct FLevelLocals;
void InitPortalGroups(FLevelLocals *Level); void InitPortalGroups(FLevelLocals *Level);

View file

@ -2585,7 +2585,7 @@ static void Vec2Offset(double x, double y, double dx, double dy, bool absolute,
} }
else else
{ {
*result = P_GetOffsetPosition(x, y, dx, dy); *result = level.GetPortalOffsetPosition(x, y, dx, dy);
} }
} }
@ -2610,7 +2610,7 @@ static void Vec2OffsetZ(double x, double y, double dx, double dy, double atz, bo
} }
else else
{ {
DVector2 v = P_GetOffsetPosition(x, y, dx, dy); DVector2 v = level.GetPortalOffsetPosition(x, y, dx, dy);
*result = (DVector3(v, atz)); *result = (DVector3(v, atz));
} }
} }
@ -2637,7 +2637,7 @@ static void Vec3Offset(double x, double y, double z, double dx, double dy, doubl
} }
else else
{ {
DVector2 v = P_GetOffsetPosition(x, y, dx, dy); DVector2 v = level.GetPortalOffsetPosition(x, y, dx, dy);
*result = (DVector3(v, z + dz)); *result = (DVector3(v, z + dz));
} }
} }

View file

@ -695,6 +695,7 @@ struct LevelLocals native
native void StartIntermission(Name type, int state) const; native void StartIntermission(Name type, int state) const;
native SpotState GetSpotState(bool create = true); native SpotState GetSpotState(bool create = true);
native int FindUniqueTid(int start = 0, int limit = 0); native int FindUniqueTid(int start = 0, int limit = 0);
native uint GetSkyboxPortal(Actor actor);
native static clearscope bool IsPointInMap(vector3 p); native static clearscope bool IsPointInMap(vector3 p);

View file

@ -25,9 +25,7 @@ struct SectorPortal native play
native Sector mDestination; native Sector mDestination;
native Vector2 mDisplacement; native Vector2 mDisplacement;
native double mPlaneZ; native double mPlaneZ;
native Actor mSkybox; native Actor mSkybox;
native static uint GetSkyboxPortal(Actor actor);
}; };

View file

@ -119,7 +119,7 @@ class SkyPicker : Actor
} }
else else
{ {
int boxindex = SectorPortal.GetSkyboxPortal(box); int boxindex = level.GetSkyboxPortal(box);
// Do not override special portal types, only regular skies. // Do not override special portal types, only regular skies.
if (0 == (args[1] & 2)) if (0 == (args[1] & 2))
{ {