- 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();
}
DVector2 Vec2Offset(double dx, double dy, bool absolute = false)
{
if (absolute)
{
return { X() + dx, Y() + dy };
}
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);
}
}
DVector2 Vec2Offset(double dx, double dy, bool absolute = false);
DVector3 Vec2OffsetZ(double dx, double dy, double atz, bool absolute = false);
DVector2 AActor::Vec2Angle(double length, DAngle angle, bool absolute = false);
DVector3 Vec3Offset(double dx, double dy, double dz, bool absolute = false);
DVector3 Vec3Offset(const DVector3 &ofs, bool absolute = false);
DVector3 Vec3Angle(double length, DAngle angle, double dz, bool absolute = false);
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);
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;
while ((in = it.Next()))
{

View file

@ -50,6 +50,38 @@
#include "r_data/r_sections.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 DFraggleThinker;
class DSpotState;
@ -120,6 +152,8 @@ struct FLevelData
struct FLevelLocals : public FLevelData
{
friend class MapLoader;
void Tick();
void Mark();
void AddScroller(int secnum);
@ -138,6 +172,33 @@ struct FLevelLocals : public FLevelData
void SetConversation(int convid, PClassActor *Class, int dlgindex);
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)
{
return FSectorTagIterator(tagManager, tag);

View file

@ -3290,5 +3290,5 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
if (reloop) LoopSidedefs(false);
PO_Init(); // Initialize the polyobjs
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 CopyPortal(int sectortag, int plane, unsigned pnum, double alpha, bool tolines);
void SetPortal(sector_t *sector, int plane, unsigned pnum, double alpha);
void SpawnLinePortal(line_t* line);
void SetupPortals();
void SpawnSkybox(AActor *origin);
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.)
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.)
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.
DVector2 pos1 = line->v1->fPos() + line->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);
return;
}
@ -348,7 +428,7 @@ void MapLoader::SpawnSkybox(AActor *origin)
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.
unsigned pnum = P_GetSkyboxPortal(origin);
unsigned pnum = Level->GetSkyboxPortal(origin);
CopyPortal(refline->args[0], refline->args[2], pnum, 0, true);
return;
}
@ -669,13 +749,13 @@ void MapLoader::SpawnSpecials ()
}
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);
}
break;
case Line_SetPortal:
P_SpawnLinePortal(&line);
SpawnLinePortal(&line);
break;
// [RH] ZDoom Static_Init settings

View file

@ -264,7 +264,7 @@ void P_ThinkParticles ()
}
// 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.Y = newxy.Y;
particle->Pos.Z += particle->Vel.Z;

View file

@ -3402,7 +3402,7 @@ FUNC(LS_Thing_SetConversation)
FUNC(LS_Line_SetPortalTarget)
// Line_SetPortalTarget(thisid, destid)
{
return P_ChangePortal(ln, arg0, arg1);
return Level->ChangePortal(ln, arg0, arg1);
}
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)
{
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;
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)
{
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;
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 (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;
if (aimdebug)
@ -4539,7 +4539,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
// position a bit closer for puffs
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,
trace.SrcAngleFromTarget - 90, 0, puffFlags);
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.
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.Y = ofs.Y;
bleedpos.Z -= -10 * trace.HitVector.Z;
@ -5101,7 +5101,7 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
newhit.HitAngle = res.SrcAngleFromTarget;
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.Y = ofs.Y;
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)
{
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;
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)
{
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;
while ((in = it.Next()))
@ -5596,7 +5596,7 @@ int P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType)
start = PuzzleItemUser->GetPortalTransition(PuzzleItemUser->Height / 2);
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;
while ((in = it.Next()))

View file

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

View file

@ -358,6 +358,7 @@ class FPathTraverse
protected:
static TArray<intercept_t> intercepts;
FLevelLocals *Level;
divline_t trace;
double Startfrac;
unsigned int intercept_index;
@ -366,13 +367,17 @@ protected:
virtual void AddLineIntercepts(int bx, int by);
virtual void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible);
FPathTraverse() {}
FPathTraverse(FLevelLocals *l)
{
Level = l;
}
public:
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);
}
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
//

View file

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

View file

@ -186,7 +186,7 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags)
if (!predicting)
{
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);
}

View file

@ -777,7 +777,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
// Do a 3D floor check in the starting sector
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;
int lastsplashsector = -1;

View file

@ -64,72 +64,40 @@ DEFINE_FIELD(FSectorPortal, mDisplacement);
DEFINE_FIELD(FSectorPortal, mPlaneZ);
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
//
//============================================================================
static void BuildBlockmap()
void FLevelLocals::BuildPortalBlockmap()
{
auto bmapwidth = level.blockmap.bmapwidth;
auto bmapheight = level.blockmap.bmapheight;
auto bmapwidth = blockmap.bmapwidth;
auto bmapheight = blockmap.bmapheight;
level.PortalBlockmap.Clear();
level.PortalBlockmap.Create(bmapwidth, bmapheight);
PortalBlockmap.Clear();
PortalBlockmap.Create(bmapwidth, bmapheight);
for (int y = 0; y < bmapheight; y++)
{
for (int x = 0; x < bmapwidth; x++)
{
int *list = level.blockmap.GetLines(x, y);
FPortalBlock &block = level.PortalBlockmap(x, y);
int *list = blockmap.GetLines(x, y);
FPortalBlock &block = PortalBlockmap(x, y);
while (*list != -1)
{
line_t *ld = &level.lines[*list++];
line_t *ld = &lines[*list++];
FLinePortal *port = ld->getPortal();
if (port && port->mType != PORTT_VISUAL)
{
level.PortalBlockmap.containsLines = true;
PortalBlockmap.containsLines = true;
block.portallines.Push(ld);
block.neighborContainsLines = true;
if (ld->getPortal()->mType == PORTT_LINKED) block.containsLinkedPortals = true;
if (x > 0) level.PortalBlockmap(x - 1, y).neighborContainsLines = true;
if (y > 0) level.PortalBlockmap(x, y - 1).neighborContainsLines = true;
if (x < level.PortalBlockmap.dx - 1) level.PortalBlockmap(x + 1, y).neighborContainsLines = true;
if (y < level.PortalBlockmap.dy - 1) level.PortalBlockmap(x, y + 1).neighborContainsLines = true;
if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true;
if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true;
if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true;
if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).neighborContainsLines = true;
}
else
{
@ -140,7 +108,7 @@ static void BuildBlockmap()
yes |= ld->backsector->PortalIsLinked(sector_t::ceiling) || ld->backsector->PortalIsLinked(sector_t::floor);
}
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.
@ -158,9 +143,9 @@ static void BuildBlockmap()
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++)
{
@ -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)
{
int lineno = -1;
auto it = level.GetLineIdIterator(tag);
auto it = GetLineIdIterator(tag);
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)
{
@ -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
//
//============================================================================
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))
{
@ -378,7 +281,7 @@ void P_UpdatePortal(FLinePortal *port)
port->mFlags = port->mDefFlags;
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.
}
@ -390,7 +293,7 @@ void P_UpdatePortal(FLinePortal *port)
}
// 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();
for (unsigned i = 0; i < level.linePortals.Size(); i++)
linkedPortals.Clear();
for (unsigned i = 0; i < linePortals.Size(); i++)
{
FLinePortal * port = &level.linePortals[i];
FLinePortal * port = &linePortals[i];
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];
P_UpdatePortal(port);
FLinePortal * port = &linePortals[i];
UpdatePortal(port);
}
P_CollectLinkedPortals();
BuildBlockmap();
P_CreateLinkedPortals();
CollectLinkedPortals();
BuildPortalBlockmap();
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;
FLinePortal *port = &level.linePortals[line->portalindex];
if (line->portalindex >= linePortals.Size()) return false;
FLinePortal *port = &linePortals[line->portalindex];
if (port->mType == PORTT_LINKED) return false; // linked portals cannot be changed.
if (destid == 0) port->mDestination = nullptr;
port->mDestination = FindDestination(line, destid);
port->mDestination = FindPortalDestination(line, destid);
if (port->mDestination == nullptr)
{
port->mFlags = 0;
}
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)
{
// this is a 2-way interactive portal
@ -461,13 +364,13 @@ static bool ChangePortalLine(line_t *line, int destid)
{
port->mFlags = port->mDefFlags;
}
SetRotation(portd);
SetPortalRotation(portd);
}
else
{
port->mFlags = port->mDefFlags;
}
SetRotation(port);
SetPortalRotation(port);
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;
if (thisid == 0) return ChangePortalLine(ln, destid);
auto it = level.GetLineIdIterator(thisid);
auto it = GetLineIdIterator(thisid);
bool res = false;
while ((lineno = it.Next()) >= 0)
{
res |= ChangePortalLine(&level.lines[lineno], destid);
res |= ChangePortalLine(&lines[lineno], destid);
}
return res;
}
@ -553,7 +456,7 @@ void P_TranslatePortalXY(line_t* src, double& x, double& y)
if (!src) return;
FLinePortal *port = src->getPortal();
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
double nposx = x - src->v1->fX();
@ -581,7 +484,7 @@ void P_TranslatePortalVXVY(line_t* src, double &velx, double &vely)
if (!src) return;
FLinePortal *port = src->getPortal();
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_vely = vely;
@ -600,7 +503,7 @@ void P_TranslatePortalAngle(line_t* src, DAngle& angle)
if (!src) return;
FLinePortal *port = src->getPortal();
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();
}
@ -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.
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);
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i]));
level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT;
level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY;
level.sectorPortals[i].mSkybox = actor;
level.sectorPortals[i].mDestination = actor->Sector;
unsigned i = sectorPortals.Reserve(1);
memset(&sectorPortals[i], 0, sizeof(sectorPortals[i]));
sectorPortals[i].mType = PORTS_SKYVIEWPOINT;
sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY;
sectorPortals[i].mSkybox = actor;
sectorPortals[i].mDestination = actor->Sector;
return i;
}
DEFINE_ACTION_FUNCTION(FSectorPortal, GetSkyboxPortal)
DEFINE_ACTION_FUNCTION(FLevelLocals, GetSkyboxPortal)
{
PARAM_PROLOGUE;
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
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);
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i]));
level.sectorPortals[i].mType = type;
level.sectorPortals[i].mPlane = plane;
level.sectorPortals[i].mOrigin = from;
level.sectorPortals[i].mDestination = to;
level.sectorPortals[i].mDisplacement = displacement;
level.sectorPortals[i].mPlaneZ = type == PORTS_LINKEDPORTAL? from->GetPlaneTexZ(plane) : FLT_MAX;
unsigned i = sectorPortals.Reserve(1);
memset(&sectorPortals[i], 0, sizeof(sectorPortals[i]));
sectorPortals[i].mType = type;
sectorPortals[i].mPlane = plane;
sectorPortals[i].mOrigin = from;
sectorPortals[i].mDestination = to;
sectorPortals[i].mDisplacement = displacement;
sectorPortals[i].mPlaneZ = type == PORTS_LINKEDPORTAL? from->GetPlaneTexZ(plane) : FLT_MAX;
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);
memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i]));
level.sectorPortals[i].mType = PORTS_STACKEDSECTORTHING;
level.sectorPortals[i].mPlane = plane;
level.sectorPortals[i].mOrigin = point->target->Sector;
level.sectorPortals[i].mDestination = point->Sector;
level.sectorPortals[i].mPlaneZ = FLT_MAX;
level.sectorPortals[i].mSkybox = point;
unsigned i = sectorPortals.Reserve(1);
memset(&sectorPortals[i], 0, sizeof(sectorPortals[i]));
sectorPortals[i].mType = PORTS_STACKEDSECTORTHING;
sectorPortals[i].mPlane = plane;
sectorPortals[i].mOrigin = point->target->Sector;
sectorPortals[i].mDestination = point->Sector;
sectorPortals[i].mPlaneZ = FLT_MAX;
sectorPortals[i].mSkybox = point;
return i;
}
//============================================================================
//
// P_GetOffsetPosition
// level.GetPortalOffsetPosition
//
// Offsets a given coordinate if the trace from the origin crosses an
// 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);
if (level.PortalBlockmap.containsLines)
if (PortalBlockmap.containsLines)
{
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.
if (dx < 128 && dy < 128)
{
int blockx = level.blockmap.GetBlockX(actx);
int blocky = level.blockmap.GetBlockY(acty);
if (blockx < 0 || blocky < 0 || blockx >= level.PortalBlockmap.dx || blocky >= level.PortalBlockmap.dy || !level.PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
int blockx = blockmap.GetBlockX(actx);
int blocky = blockmap.GetBlockY(acty);
if (blockx < 0 || blocky < 0 || blockx >= PortalBlockmap.dx || blocky >= PortalBlockmap.dy || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
}
bool repeat;
do
{
FLinePortalTraverse it;
FLinePortalTraverse it(this);
it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA);
intercept_t *in;
@ -777,11 +680,6 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy)
return dest;
}
static void GetOffsetPosition(double x, double y, double dx, double dy, DVector2 *result)
{
*result = P_GetOffsetPosition(x, y, dx, dy);
}
//============================================================================
//
// 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 othergroup = portal->mDestination->PortalGroup;
@ -839,14 +737,14 @@ static void AddDisplacementForPortal(FSectorPortal *portal)
portal->mType = PORTS_PORTAL;
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);
portal->mType = PORTS_PORTAL;
return;
}
FDisplacement & disp = level.Displacements(thisgroup, othergroup);
FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet)
{
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 othergroup = portal->mDestination->frontsector->PortalGroup;
if (thisgroup == othergroup)
{
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;
}
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());
portal->mType = level.linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
portal->mType = linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
return;
}
FDisplacement & disp = level.Displacements(thisgroup, othergroup);
FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet)
{
disp.pos = portal->mDisplacement;
@ -892,7 +790,7 @@ static void AddDisplacementForPortal(FLinePortal *portal)
if (disp.pos != portal->mDisplacement)
{
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;
}
}
@ -906,7 +804,7 @@ static void AddDisplacementForPortal(FLinePortal *portal)
//
//============================================================================
static bool ConnectGroups()
bool FLevelLocals::ConnectPortalGroups()
{
// Now
uint8_t indirect = 1;
@ -915,19 +813,19 @@ static bool ConnectGroups()
do
{
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)
{
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)
{
FDisplacement &dispxz = level.Displacements(x, z);
FDisplacement &dispxz = Displacements(x, z);
if (dispxz.isSet)
{
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;
int id = 1;
bool bogus = false;
for(auto &s : level.sectorPortals)
for(auto &s : sectorPortals)
{
if (s.mType == PORTS_LINKEDPORTAL)
{
@ -982,7 +880,7 @@ void P_CreateLinkedPortals()
id = 1;
if (orgs.Size() != 0)
{
for (auto &sec : level.sectors)
for (auto &sec : sectors)
{
for (int j = 0; j < 2; j++)
{
@ -1006,27 +904,27 @@ void P_CreateLinkedPortals()
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());
level.linePortals[i].mOrigin->portalindex = UINT_MAX;
level.linePortals[i].mType = PORTT_VISUAL;
Printf("Linked portal on line %d is unconnected and will be disabled\n", linePortals[i].mOrigin->Index());
linePortals[i].mOrigin->portalindex = UINT_MAX;
linePortals[i].mType = PORTT_VISUAL;
}
else
{
if (CollectSectors(id, level.linePortals[i].mOrigin->frontsector)) id++;
if (CollectSectors(id, level.linePortals[i].mDestination->frontsector)) id++;
if (CollectSectors(id, linePortals[i].mOrigin->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
for (auto &sec : level.sectors)
for (auto &sec : sectors)
{
for (int j = 0; j < 2; j++)
{
@ -1041,34 +939,34 @@ void P_CreateLinkedPortals()
{
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 &dispyx = level.Displacements(y, x);
FDisplacement &dispxy = Displacements(x, y);
FDisplacement &dispyx = Displacements(y, x);
if (dispxy.isSet && dispyx.isSet &&
(dispxy.pos.X != -dispyx.pos.X || dispxy.pos.Y != -dispyx.pos.Y))
{
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 (sec2 == -1 && level.sectors[i].PortalGroup == y) sec2 = i;
if (sec1 == -1 && sectors[i].PortalGroup == x) sec1 = i;
if (sec2 == -1 && sectors[i].PortalGroup == y) sec2 = i;
}
Printf("Link offset mismatch between sectors %d and %d\n", sec1, sec2);
bogus = true;
}
// 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)
{
@ -1076,7 +974,7 @@ void P_CreateLinkedPortals()
}
}
// 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)
{
@ -1086,19 +984,19 @@ void P_CreateLinkedPortals()
}
}
}
bogus |= ConnectGroups();
bogus |= ConnectPortalGroups();
if (bogus)
{
// todo: disable all portals whose offsets do not match the associated groups
}
// 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.
for (auto &sec : level.sectors)
for (auto &sec : sectors)
{
sec.CheckPortalPlane(sector_t::floor);
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::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
TThinkerIterator<AActor> it;
@ -1144,7 +1042,7 @@ void P_CreateLinkedPortals()
if (!(actor->flags & MF_NOBLOCKMAP))
{
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)
{
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;
out.inited = true;
processMask.setSize(level.Displacements.size);
if (level.Displacements.size == 1)
processMask.setSize(Displacements.size);
if (Displacements.size == 1)
{
processMask.setBit(startgroup);
return false;
}
if (level.linkedPortals.Size() != 0)
if (linkedPortals.Size() != 0)
{
processMask.clear();
foundPortals.Clear();
@ -1191,17 +1083,17 @@ bool P_CollectConnectedGroups(int startgroup, const DVector3 &position, double u
processMask.setBit(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;
FDisplacement &disp = level.Displacements(thisgroup, othergroup);
FDisplacement &disp = Displacements(thisgroup, othergroup);
if (!disp.isSet) continue; // no connection.
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
foundPortals.Push(level.linkedPortals[i]);
if (!box.inRange(ld) || box.BoxOnLineSide(linkedPortals[i]->mOrigin) != -1) continue; // not touched
foundPortals.Push(linkedPortals[i]);
}
bool foundone = true;
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))
{
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;
processMask.setBit(othergroup);
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))
{
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;
processMask.setBit(othergroup);
out.Add(othergroup | FPortalGroupArray::LOWER);
wsec = P_PointInSector(pos); // get lower sector at the exact spot we want to check and repeat
retval = true;
}
if (out.method == FPortalGroupArray::PGA_Full3d && level.PortalBlockmap.hasLinkedSectorPortals)
if (out.method == FPortalGroupArray::PGA_Full3d && PortalBlockmap.hasLinkedSectorPortals)
{
groupsToCheck.Clear();
groupsToCheck.Push(startgroup);
int thisgroup = startgroup;
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);
FBlockLinesIterator it(box);
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 */
@ -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_TranslatePortalAngle(line_t* src, DAngle& angle);
void P_TranslatePortalZ(line_t* src, double& vz);
DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy);
struct FLevelLocals;
void InitPortalGroups(FLevelLocals *Level);

View file

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

View file

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

View file

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

View file

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