- refactored sector portal data so that it does not rely on actors.

This is necessary because otherwise the level data cannot be serialized before the actors.
This commit is contained in:
Christoph Oelckers 2016-04-20 19:20:11 +02:00
parent 3532dd9ea1
commit 082042818b
23 changed files with 410 additions and 284 deletions

View file

@ -384,6 +384,15 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld)
changed += players[i].FixPointers (old, notOld);
}
for (auto &s : sectorPortals)
{
if (s.mSkybox == old)
{
s.mSkybox = static_cast<ASkyViewpoint*>(notOld);
changed++;
}
}
// Go through sectors.
if (sectors != NULL)
{
@ -392,8 +401,6 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld)
#define SECTOR_CHECK(f,t) \
if (sectors[i].f.p == static_cast<t *>(old)) { sectors[i].f = static_cast<t *>(notOld); changed++; }
SECTOR_CHECK( SoundTarget, AActor );
SECTOR_CHECK( SkyBoxes[sector_t::ceiling], ASkyViewpoint );
SECTOR_CHECK( SkyBoxes[sector_t::floor], ASkyViewpoint );
SECTOR_CHECK( SecActTarget, ASectorAction );
SECTOR_CHECK( floordata, DSectorEffect );
SECTOR_CHECK( ceilingdata, DSectorEffect );

View file

@ -327,7 +327,10 @@ static void MarkRoot()
DThinker::MarkRoots();
FCanvasTextureInfo::Mark();
Mark(DACSThinker::ActiveThinker);
Mark(level.DefaultSkybox);
for (auto &s : sectorPortals)
{
Mark(s.mSkybox);
}
// Mark dead bodies.
for (i = 0; i < BODYQUESIZE; ++i)
{
@ -680,8 +683,6 @@ size_t DSectorMarker::PropagateMark()
{
sector_t *sec = &sectors[SecNum + i];
GC::Mark(sec->SoundTarget);
GC::Mark(sec->SkyBoxes[sector_t::ceiling]);
GC::Mark(sec->SkyBoxes[sector_t::floor]);
GC::Mark(sec->SecActTarget);
GC::Mark(sec->floordata);
GC::Mark(sec->ceilingdata);

View file

@ -298,6 +298,7 @@ template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node);
template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw);
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da);
FArchive &operator<< (FArchive &arc, FLinePortal &da);
FArchive &operator<< (FArchive &arc, FSectorPortal &da);

View file

@ -1386,7 +1386,6 @@ void G_InitLevelLocals ()
NormalLight.ChangeFade (level.fadeto);
level.DefaultEnvironment = info->DefaultEnvironment;
level.DefaultSkybox = NULL;
}
//==========================================================================
@ -1538,7 +1537,7 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
P_SerializeSubsectors(arc);
StatusBar->Serialize (arc);
arc << level.DefaultSkybox << level.total_monsters << level.total_items << level.total_secrets;
arc << level.total_monsters << level.total_items << level.total_secrets;
// Does this level have custom translations?
FRemapTable *trans;

View file

@ -435,8 +435,6 @@ struct FLevelLocals
int airsupply;
int DefaultEnvironment; // Default sound environment.
TObjPtr<class ASkyViewpoint> DefaultSkybox;
FSectorScrollValues *Scrolls; // NULL if no DScrollers in this level
SBYTE WallVertLight; // Light diffs for vert/horiz walls

View file

@ -91,14 +91,9 @@ public:
class ASkyViewpoint : public AActor
{
DECLARE_CLASS (ASkyViewpoint, AActor)
HAS_OBJECT_POINTERS
public:
void Serialize (FArchive &arc);
void BeginPlay ();
void Destroy ();
bool bInSkybox;
bool bAlways;
TObjPtr<ASkyViewpoint> Mate;
};
// For an EE compatible linedef based definition.

View file

@ -38,49 +38,42 @@
#include "p_lnspec.h"
#include "farchive.h"
#include "r_sky.h"
#include "portal.h"
// arg0 = Visibility*4 for this skybox
IMPLEMENT_POINTY_CLASS (ASkyViewpoint)
DECLARE_POINTER(Mate)
END_POINTERS
IMPLEMENT_CLASS (ASkyViewpoint)
// If this actor has no TID, make it the default sky box
void ASkyViewpoint::BeginPlay ()
{
Super::BeginPlay ();
if (tid == 0 && level.DefaultSkybox == NULL)
if (tid == 0 && sectorPortals[0].mSkybox == nullptr)
{
level.DefaultSkybox = this;
sectorPortals[0].mSkybox = this;
sectorPortals[0].mDestination = Sector;
}
special1 = SKYBOX_SKYVIEWPOINT;
}
void ASkyViewpoint::Serialize (FArchive &arc)
{
Super::Serialize (arc);
arc << bInSkybox << bAlways << Mate;
}
void ASkyViewpoint::Destroy ()
{
// remove all sector references to ourselves.
for (int i = 0; i <numsectors; i++)
for (int i = 0; i < numsectors; i++)
{
if (sectors[i].SkyBoxes[sector_t::floor] == this)
{
sectors[i].SkyBoxes[sector_t::floor] = NULL;
}
if (sectors[i].SkyBoxes[sector_t::ceiling] == this)
{
sectors[i].SkyBoxes[sector_t::ceiling] = NULL;
}
if (sectors[i].GetPortal(sector_t::floor)->mSkybox == this)
sectors[i].ClearPortal(sector_t::floor);
if (sectors[i].GetPortal(sector_t::ceiling)->mSkybox == this)
sectors[i].ClearPortal(sector_t::ceiling);
}
if (level.DefaultSkybox == this)
for (auto &s : sectorPortals)
{
level.DefaultSkybox = NULL;
if (s.mSkybox == this) s.mSkybox = 0;
// This is necessary to entirely disable EE-style skyboxes
// if their viewpoint gets deleted.
s.mFlags |= PORTSF_SKYFLATONLY;
}
Super::Destroy();
}
@ -90,10 +83,8 @@ void ASkyCamCompat::BeginPlay()
{
// Do not call the SkyViewpoint's super method because it would trash our setup
AActor::BeginPlay();
special1 = SKYBOX_SKYVIEWPOINT;
}
//---------------------------------------------------------------------------
// arg0 = tid of matching SkyViewpoint
@ -130,20 +121,18 @@ void ASkyPicker::PostBeginPlay ()
if (box == NULL && args[0] != 0)
{
Printf ("Can't find SkyViewpoint %d for sector %td\n",
args[0], Sector - sectors);
Printf ("Can't find SkyViewpoint %d for sector %td\n", args[0], Sector - sectors);
}
else
{
int boxindex = P_GetSkyboxPortal(box);
if (0 == (args[1] & 2))
{
Sector->SkyBoxes[sector_t::ceiling] = box;
if (box == NULL) Sector->MoreFlags |= SECF_NOCEILINGSKYBOX; // sector should ignore the level's default skybox
Sector->Portals[sector_t::ceiling] = boxindex;
}
if (0 == (args[1] & 1))
{
Sector->SkyBoxes[sector_t::floor] = box;
if (box == NULL) Sector->MoreFlags |= SECF_NOFLOORSKYBOX; // sector should ignore the level's default skybox
Sector->Portals[sector_t::floor] = boxindex;
}
}
Destroy ();
@ -160,9 +149,6 @@ void AStackPoint::BeginPlay ()
{
// Skip SkyViewpoint's initialization
AActor::BeginPlay ();
bAlways = true;
special1 = SKYBOX_STACKEDSECTORTHING;
}
//---------------------------------------------------------------------------

View file

@ -1629,10 +1629,10 @@ int FPathTraverse::PortalRelocate(intercept_t *in, int flags, DVector3 *optpos)
return saved->getPortal()->mType == PORTT_LINKED? 1:-1;
}
void FPathTraverse::PortalRelocate(AActor *portalthing, int flags, double hitfrac)
void FPathTraverse::PortalRelocate(const DVector2 &displacement, int flags, double hitfrac)
{
double hitx = trace.x + portalthing->Scale.X;
double hity = trace.y + portalthing->Scale.Y;
double hitx = trace.x + displacement.X;
double hity = trace.y + displacement.Y;
double endx = hitx + trace.dx;
double endy = hity + trace.dy;
intercepts.Resize(intercept_index);

View file

@ -373,7 +373,7 @@ public:
}
void init(double x1, double y1, double x2, double y2, int flags, double startfrac = 0);
int PortalRelocate(intercept_t *in, int flags, DVector3 *optpos = NULL);
void PortalRelocate(AActor *portalthing, int flags, double hitfrac);
void PortalRelocate(const DVector2 &disp, int flags, double hitfrac);
virtual ~FPathTraverse();
const divline_t &Trace() const { return trace; }

View file

@ -369,7 +369,7 @@ void P_SerializeWorld (FArchive &arc)
<< sec->sky
<< sec->MoreFlags
<< sec->Flags
<< sec->SkyBoxes[sector_t::floor] << sec->SkyBoxes[sector_t::ceiling]
<< sec->Portals[sector_t::floor] << sec->Portals[sector_t::ceiling]
<< sec->ZoneNumber;
arc << sec->interpolations[0]
<< sec->interpolations[1]
@ -449,7 +449,7 @@ void P_SerializeWorld (FArchive &arc)
arc << zn->Environment;
}
arc << linePortals;
arc << linePortals << sectorPortals;
P_CollectLinkedPortals();
}
@ -565,22 +565,8 @@ void P_SerializePolyobjs (FArchive &arc)
I_Error ("UnarchivePolyobjs: Invalid polyobj tag");
}
arc << angle << delta << po->interpolation;
if (SaveVersion >= 4537)
{
arc << po->bBlocked;
}
else
{
po->bBlocked = false;
}
if (SaveVersion >= 4538)
{
arc << po->bHasPortals;
}
else
{
po->bHasPortals = 0;
}
arc << po->bBlocked;
arc << po->bHasPortals;
po->RotatePolyobj (angle, true);
delta -= po->StartSpot.pos;

View file

@ -32,6 +32,7 @@
#include "r_utility.h"
#include "a_sharedglobal.h"
#include "p_local.h"
#include "r_sky.h"
#include "r_data/colormaps.h"
@ -803,11 +804,13 @@ int sector_t::GetCeilingLight () const
}
ASkyViewpoint *sector_t::GetSkyBox(int which)
FSectorPortal *sector_t::ValidatePortal(int which)
{
if (SkyBoxes[which] != NULL) return barrier_cast<ASkyViewpoint*>(SkyBoxes[which]);
if (MoreFlags & (SECF_NOFLOORSKYBOX << which)) return NULL;
return level.DefaultSkybox;
FSectorPortal *port = GetPortal(which);
if (port->mType == PORTS_SKYVIEWPOINT && port->mSkybox == nullptr) return nullptr; // A skybox without a viewpoint is just a regular sky.
if (PortalBlocksView(which)) return nullptr; // disabled or obstructed linked portal.
if ((port->mFlags & PORTSF_SKYFLATONLY) && GetTexture(which) != skyflatnum) return nullptr; // Skybox without skyflat texture
return port;
}
@ -873,13 +876,13 @@ int sector_t::GetTerrain(int pos) const
void sector_t::CheckPortalPlane(int plane)
{
AActor *portal = SkyBoxes[plane];
if (!portal || portal->special1 != SKYBOX_LINKEDPORTAL) return;
double planeh = GetPlaneTexZF(plane);
int obstructed = PLANEF_OBSTRUCTED * (plane == sector_t::floor ?
planeh > portal->specialf1 : planeh < portal->specialf1);
planes[plane].Flags = (planes[plane].Flags & ~PLANEF_OBSTRUCTED) | obstructed;
if (GetPortalType(plane) == PORTS_LINKEDPORTAL)
{
double portalh = GetPortalPlaneZ(plane);
double planeh = GetPlaneTexZF(plane);
int obstructed = PLANEF_OBSTRUCTED * (plane == sector_t::floor ? planeh > portalh : planeh < portalh);
planes[plane].Flags = (planes[plane].Flags & ~PLANEF_OBSTRUCTED) | obstructed;
}
}
//===========================================================================

View file

@ -838,12 +838,13 @@ static void SetupFloorPortal (AStackPoint *point)
NActorIterator it (NAME_LowerStackLookOnly, point->tid);
sector_t *Sector = point->Sector;
ASkyViewpoint *skyv = static_cast<ASkyViewpoint*>(it.Next());
Sector->SkyBoxes[sector_t::floor] = skyv;
if (skyv != NULL && skyv->bAlways)
if (skyv != NULL)
{
skyv->Mate = point;
skyv->target = point;
if (Sector->GetAlphaF(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);
}
}
@ -852,12 +853,13 @@ static void SetupCeilingPortal (AStackPoint *point)
NActorIterator it (NAME_UpperStackLookOnly, point->tid);
sector_t *Sector = point->Sector;
ASkyViewpoint *skyv = static_cast<ASkyViewpoint*>(it.Next());
Sector->SkyBoxes[sector_t::ceiling] = skyv;
if (skyv != NULL && skyv->bAlways)
if (skyv != NULL)
{
skyv->Mate = point;
skyv->target = point;
if (Sector->GetAlphaF(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);
}
}
@ -881,42 +883,68 @@ void P_SetupPortals()
pt->special1 = 0;
points.Push(pt);
}
// the semantics here are incredibly lax so the final setup can only be done once all portals have been created,
// because later stackpoints will happily overwrite info in older ones, if there are multiple links.
for (auto &s : sectorPortals)
{
if (s.mType == PORTS_STACKEDSECTORTHING && s.mSkybox)
{
for (auto &ss : sectorPortals)
{
if (ss.mType == PORTS_STACKEDSECTORTHING && ss.mSkybox == s.mSkybox->target)
{
s.mPartner = (&ss) - &sectorPortals[0];
}
}
}
}
// Now we can finally set the displacement and delete the stackpoint reference.
for (auto &s : sectorPortals)
{
if (s.mType == PORTS_STACKEDSECTORTHING && s.mSkybox)
{
s.mDisplacement = s.mSkybox->Pos() - s.mSkybox->target->Pos();
s.mSkybox = NULL;
}
}
}
static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, double alpha)
static void SetPortal(sector_t *sector, int plane, unsigned pnum, double alpha)
{
// plane: 0=floor, 1=ceiling, 2=both
if (plane > 0)
{
if (sector->SkyBoxes[sector_t::ceiling] == NULL || !barrier_cast<ASkyViewpoint*>(sector->SkyBoxes[sector_t::ceiling])->bAlways)
if (sector->GetPortalType(sector_t::ceiling) == PORTS_SKYVIEWPOINT)
{
sector->SkyBoxes[sector_t::ceiling] = portal;
sector->Portals[sector_t::ceiling] = pnum;
if (sector->GetAlphaF(sector_t::ceiling) == 1.)
sector->SetAlpha(sector_t::ceiling, alpha);
if (!portal->bAlways) sector->SetTexture(sector_t::ceiling, skyflatnum);
if (sectorPortals[pnum].mFlags & PORTSF_SKYFLATONLY)
sector->SetTexture(sector_t::ceiling, skyflatnum);
}
}
if (plane == 2 || plane == 0)
{
if (sector->SkyBoxes[sector_t::floor] == NULL || !barrier_cast<ASkyViewpoint*>(sector->SkyBoxes[sector_t::floor])->bAlways)
if (sector->GetPortalType(sector_t::floor) == PORTS_SKYVIEWPOINT)
{
sector->SkyBoxes[sector_t::floor] = portal;
sector->Portals[sector_t::floor] = pnum;
}
if (sector->GetAlphaF(sector_t::floor) == 1.)
sector->SetAlpha(sector_t::floor, alpha);
if (!portal->bAlways) sector->SetTexture(sector_t::floor, skyflatnum);
if (sectorPortals[pnum].mFlags & PORTSF_SKYFLATONLY)
sector->SetTexture(sector_t::floor, skyflatnum);
}
}
static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, double alpha, bool tolines)
static void CopyPortal(int sectortag, int plane, unsigned pnum, double alpha, bool tolines)
{
int s;
FSectorTagIterator itr(sectortag);
while ((s = itr.Next()) >= 0)
{
SetPortal(&sectors[s], plane, origin, alpha);
SetPortal(&sectors[s], plane, pnum, alpha);
}
for (int j=0;j<numlines;j++)
@ -930,20 +958,21 @@ static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, double a
{
if (lines[j].args[0] == 0)
{
SetPortal(lines[j].frontsector, plane, origin, alpha);
SetPortal(lines[j].frontsector, plane, pnum, alpha);
}
else
{
FSectorTagIterator itr(lines[j].args[0]);
while ((s = itr.Next()) >= 0)
{
SetPortal(&sectors[s], plane, origin, alpha);
SetPortal(&sectors[s], plane, pnum, alpha);
}
}
}
}
}
void P_SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int linked)
{
if (plane < 0 || plane > 2 || (linked && plane == 2)) return;
@ -958,36 +987,10 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int li
lines[i].args[3] == 1)
{
// beware of overflows.
DVector3 pos1((line->v1->fX() + line->v2->fX()) / 2, (line->v1->fY() + line->v2->fY()) / 2, 0);
DVector3 pos2((lines[i].v1->fX() + lines[i].v2->fX()) / 2, (lines[i].v1->fY() + lines[i].v2->fY()) / 2, 0);
double z = linked ? line->frontsector->GetPlaneTexZF(plane) : 0; // the map's sector height defines the portal plane for linked portals
double alpha = bytealpha / 255.;
AStackPoint *anchor = Spawn<AStackPoint>(pos1, NO_REPLACE);
AStackPoint *reference = Spawn<AStackPoint>(pos2, NO_REPLACE);
// In some situations it can happen that the sector here is not the frontsector of the anchor linedef,
// because some colinear node line with opposite direction causes this to be positioned on the wrong side.
// Fortunately these things will never move so it should be sufficient to set the intended sector directly.
anchor->Sector = line->frontsector;
reference->Sector = lines[i].frontsector;
reference->special1 = linked ? SKYBOX_LINKEDPORTAL : SKYBOX_PORTAL;
anchor->special1 = SKYBOX_ANCHOR;
// store the portal displacement in the unused scaleX/Y members of the portal reference actor.
anchor->Scale = -(reference->Scale = pos2 - pos1);
anchor->specialf1 = reference->specialf1 = z;
reference->Mate = anchor;
anchor->Mate = reference;
// This is so that the renderer can distinguish these portals from
// the ones spawned with the '*StackLookOnly' things.
reference->flags |= MF_JUSTATTACKED;
anchor->flags |= MF_JUSTATTACKED;
CopyPortal(sectortag, plane, reference, alpha, false);
DVector2 pos1 = line->v1->fPos() + line->Delta() / 2;
DVector2 pos2 = lines[i].v1->fPos() + lines[i].Delta() / 2;
unsigned pnum = P_GetPortal(linked ? PORTS_LINKEDPORTAL : PORTS_PORTAL, plane, line->frontsector, lines[i].frontsector, pos2 - pos1);
CopyPortal(sectortag, plane, pnum, bytealpha / 255., false);
return;
}
}
@ -1012,7 +1015,8 @@ void P_SpawnSkybox(ASkyViewpoint *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.
CopyPortal(refline->args[0], refline->args[2], origin, 0, true);
unsigned pnum = P_GetSkyboxPortal(origin);
CopyPortal(refline->args[0], refline->args[2], pnum, 0, true);
return;
}
}
@ -1334,6 +1338,12 @@ void P_SpawnSpecials (void)
{
P_SpawnPortal(&lines[i], lines[i].args[0], lines[i].args[2], lines[i].args[4], lines[i].args[1]);
}
else if (lines[i].args[1] == 3 || lines[i].args[1] == 4)
{
line_t *line = &lines[i];
unsigned pnum = P_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:

View file

@ -216,7 +216,7 @@ void FTraceInfo::EnterSectorPortal(FPathTraverse &pt, int position, double frac,
inshootthrough = true;
startfrac = frac;
EnterDist = enterdist;
pt.PortalRelocate(entersec->SkyBoxes[position], ptflags, frac);
pt.PortalRelocate(entersec->GetPortal(position)->mDisplacement, ptflags, frac);
if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
{
@ -321,7 +321,7 @@ void FTraceInfo::Setup3DFloors()
{
CurSector->floorplane = *rover->top.plane;
CurSector->SetTexture(sector_t::floor, *rover->top.texture, false);
CurSector->SkyBoxes[sector_t::floor] = nullptr;
CurSector->ClearPortal(sector_t::floor);
bf = ff_top;
}
}
@ -333,7 +333,7 @@ void FTraceInfo::Setup3DFloors()
CurSector->ceilingplane = *rover->bottom.plane;
CurSector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false);
bc = ff_bottom;
CurSector->SkyBoxes[sector_t::ceiling] = nullptr;
CurSector->ClearPortal(sector_t::ceiling);
}
}
else
@ -343,7 +343,7 @@ void FTraceInfo::Setup3DFloors()
{
CurSector->floorplane = *rover->bottom.plane;
CurSector->SetTexture(sector_t::floor, *rover->bottom.texture, false);
CurSector->SkyBoxes[sector_t::floor] = nullptr;
CurSector->ClearPortal(sector_t::floor);
bf = ff_bottom;
}
@ -351,7 +351,7 @@ void FTraceInfo::Setup3DFloors()
{
CurSector->ceilingplane = *rover->top.plane;
CurSector->SetTexture(sector_t::ceiling, *rover->top.texture, false);
CurSector->SkyBoxes[sector_t::ceiling] = nullptr;
CurSector->ClearPortal(sector_t::ceiling);
bc = ff_top;
}
inshootthrough = false;
@ -499,7 +499,7 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit)
{
entersector->floorplane = *rover->top.plane;
entersector->SetTexture(sector_t::floor, *rover->top.texture, false);
entersector->SkyBoxes[sector_t::floor] = NULL;
entersector->ClearPortal(sector_t::floor);
bf = ff_top;
}
}
@ -510,7 +510,7 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit)
{
entersector->ceilingplane = *rover->bottom.plane;
entersector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false);
entersector->SkyBoxes[sector_t::ceiling] = NULL;
entersector->ClearPortal(sector_t::ceiling);
bc = ff_bottom;
}
}

View file

@ -64,6 +64,8 @@ FPortalBlockmap PortalBlockmap;
TArray<FLinePortal> linePortals;
TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups.
TArray<FSectorPortal> sectorPortals;
//============================================================================
//
// This is used to mark processed portals for some collection functions.
@ -213,6 +215,26 @@ FArchive &operator<< (FArchive &arc, FLinePortal &port)
return arc;
}
//============================================================================
//
// Save a sector portal for savegames.
//
//============================================================================
FArchive &operator<< (FArchive &arc, FSectorPortal &port)
{
arc << port.mType
<< port.mFlags
<< port.mPartner
<< port.mPlane
<< port.mOrigin
<< port.mDestination
<< port.mDisplacement
<< port.mPlaneZ
<< port.mSkybox;
return arc;
}
//============================================================================
//
@ -487,7 +509,7 @@ bool P_ChangePortal(line_t *ln, int thisid, int destid)
//============================================================================
//
// clears all portal dat for a new level start
// clears all portal data for a new level start
//
//============================================================================
@ -496,9 +518,17 @@ void P_ClearPortals()
Displacements.Create(1);
linePortals.Clear();
linkedPortals.Clear();
sectorPortals.Resize(2);
// The first entry must always be the default skybox. This is what every sector gets by default.
memset(&sectorPortals[0], 0, sizeof(sectorPortals[0]));
sectorPortals[0].mType = PORTS_SKYVIEWPOINT;
sectorPortals[0].mFlags = PORTSF_SKYFLATONLY;
// The second entry will be the default sky. This is for forcing a regular sky through the skybox picker
memset(&sectorPortals[1], 0, sizeof(sectorPortals[0]));
sectorPortals[1].mType = PORTS_SKYVIEWPOINT;
sectorPortals[1].mFlags = PORTSF_SKYFLATONLY;
}
//============================================================================
//
// check if this line is between portal and the viewer. clip away if it is.
@ -637,6 +667,74 @@ void P_TranslatePortalZ(line_t* src, double& z)
}
}
//============================================================================
//
// P_GetSkyboxPortal
//
// Gets a portal for a SkyViewpoint
// If none exists yet, it will create a new one.
//
//============================================================================
unsigned P_GetSkyboxPortal(ASkyViewpoint *actor)
{
if (actor == NULL) return 1; // this means a regular sky.
for (unsigned i = 0;i<sectorPortals.Size();i++)
{
if (sectorPortals[i].mSkybox == actor) return i;
}
unsigned i = sectorPortals.Reserve(1);
memset(&sectorPortals[i], 0, sizeof(sectorPortals[i]));
sectorPortals[i].mType = PORTS_SKYVIEWPOINT;
sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf(RUNTIME_CLASS(ASkyCamCompat)) ? 0 : PORTSF_SKYFLATONLY;
sectorPortals[i].mSkybox = actor;
sectorPortals[i].mDestination = actor->Sector;
return i;
}
//============================================================================
//
// P_GetPortal
//
// Creates a portal struct for a linedef-based portal
//
//============================================================================
unsigned P_GetPortal(int type, int plane, sector_t *from, sector_t *to, const DVector2 &displacement)
{
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->GetPlaneTexZF(plane) : FLT_MAX;
return i;
}
//============================================================================
//
// P_GetStackPortal
//
// Creates a portal for a stacked sector thing
//
//============================================================================
unsigned P_GetStackPortal(AActor *point, int plane)
{
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
@ -756,35 +854,35 @@ static bool CollectSectors(int groupid, sector_t *origin)
//
//============================================================================
static void AddDisplacementForPortal(AStackPoint *portal)
static void AddDisplacementForPortal(FSectorPortal *portal)
{
int thisgroup = portal->Mate->Sector->PortalGroup;
int othergroup = portal->Sector->PortalGroup;
int thisgroup = portal->mOrigin->PortalGroup;
int othergroup = portal->mDestination->PortalGroup;
if (thisgroup == othergroup)
{
Printf("Portal between sectors %d and %d has both sides in same group and will be disabled\n", portal->Sector->sectornum, portal->Mate->Sector->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL;
Printf("Portal between sectors %d and %d has both sides in same group and will be disabled\n", portal->mOrigin->sectornum, portal->mDestination->sectornum);
portal->mType = PORTS_PORTAL;
return;
}
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->Sector->sectornum, portal->Mate->Sector->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL;
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 = Displacements(thisgroup, othergroup);
if (!disp.isSet)
{
disp.pos = portal->Scale;
disp.pos = portal->mDisplacement;
disp.isSet = true;
}
else
{
if (disp.pos != portal->Scale)
if (disp.pos != portal->mDisplacement)
{
Printf("Portal between sectors %d and %d has displacement mismatch and will be disabled\n", portal->Sector->sectornum, portal->Mate->Sector->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL;
Printf("Portal between sectors %d and %d has displacement mismatch and will be disabled\n", portal->mOrigin->sectornum, portal->mDestination->sectornum);
portal->mType = PORTS_PORTAL;
return;
}
}
@ -895,55 +993,43 @@ static bool ConnectGroups()
void P_CreateLinkedPortals()
{
TThinkerIterator<AStackPoint> it;
AStackPoint *mo;
TArray<AStackPoint *> orgs;
TArray<FSectorPortal *> orgs;
int id = 1;
bool bogus = false;
while ((mo = it.Next()))
for(auto &s : sectorPortals)
{
if (mo->special1 == SKYBOX_LINKEDPORTAL)
if (s.mType == PORTS_LINKEDPORTAL)
{
if (mo->Mate != NULL)
{
orgs.Push(mo);
mo->reactiontime = ++id;
}
else
{
// this should never happen, but if it does, the portal needs to be removed
mo->Destroy();
}
orgs.Push(&s);
}
}
id = 1;
if (orgs.Size() != 0)
{
for (int i = 0; i < numsectors; i++)
{
for (int j = 0; j < 2; j++)
for (int i = 0; i < numsectors; i++)
{
AActor *box = sectors[i].SkyBoxes[j];
if (box != NULL && box->special1 == SKYBOX_LINKEDPORTAL)
for (int j = 0; j < 2; j++)
{
secplane_t &plane = j == 0 ? sectors[i].floorplane : sectors[i].ceilingplane;
if (plane.isSlope())
if (sectors[i].GetPortalType(j) == PORTS_LINKEDPORTAL)
{
// The engine cannot deal with portals on a sloped plane.
sectors[i].SkyBoxes[j] = NULL;
Printf("Portal on %s of sector %d is sloped and will be disabled\n", j == 0 ? "floor" : "ceiling", i);
secplane_t &plane = j == 0 ? sectors[i].floorplane : sectors[i].ceilingplane;
if (plane.isSlope())
{
// The engine cannot deal with portals on a sloped plane.
sectors[i].ClearPortal(j);
Printf("Portal on %s of sector %d is sloped and will be disabled\n", j == 0 ? "floor" : "ceiling", i);
}
}
}
}
}
// Group all sectors, starting at each portal origin.
for (unsigned i = 0; i < orgs.Size(); i++)
{
if (CollectSectors(id, orgs[i]->Sector)) id++;
if (CollectSectors(id, orgs[i]->Mate->Sector)) id++;
}
// Group all sectors, starting at each portal origin.
for (unsigned i = 0; i < orgs.Size(); i++)
{
if (CollectSectors(id, orgs[i]->mOrigin)) id++;
if (CollectSectors(id, orgs[i]->mDestination)) id++;
}
}
for (unsigned i = 0; i < linePortals.Size(); i++)
{
@ -960,17 +1046,9 @@ void P_CreateLinkedPortals()
{
for (int j = 0; j < 2; j++)
{
ASkyViewpoint *box = barrier_cast<ASkyViewpoint*>(sectors[i].SkyBoxes[j]);
if (box != NULL)
if (sectors[i].GetPortalType(j) == PORTS_LINKEDPORTAL && sectors[i].PortalGroup == 0)
{
if (box->special1 == SKYBOX_LINKEDPORTAL && sectors[i].PortalGroup == 0)
{
// Note: the linked actor will be on the other side of the portal.
// To get this side's group we will have to look at the mate object.
CollectSectors(box->Mate->Sector->PortalGroup, &sectors[i]);
// We cannot process the backlink here because all we can access is the anchor object
// If necessary that will have to be done for the other side's portal.
}
CollectSectors(sectors[i].GetOppositePortalGroup(j), &sectors[i]);
}
}
}
@ -1060,11 +1138,11 @@ void P_CreateLinkedPortals()
double fp = sectors[i].floorplane.fD();
if (cp < fp || fz == fp)
{
sectors[i].SkyBoxes[sector_t::ceiling] = NULL;
sectors[i].ClearPortal(sector_t::ceiling);
}
else
{
sectors[i].SkyBoxes[sector_t::floor] = NULL;
sectors[i].ClearPortal(sector_t::floor);
}
}
}

View file

@ -6,6 +6,7 @@
#include "m_bbox.h"
struct FPortalGroupArray;
class ASkyViewpoint;
//============================================================================
//
// This table holds the offsets for the different parts of a map
@ -173,8 +174,6 @@ enum
//============================================================================
//
// All information about a line-to-line portal (all types)
// There is no structure for sector plane portals because for historic
// reasons those use actors to connect.
//
//============================================================================
@ -190,10 +189,61 @@ struct FLinePortal
DAngle mAngleDiff;
double mSinRot;
double mCosRot;
void *mRenderData;
};
extern TArray<FLinePortal> linePortals;
//============================================================================
//
// All information about a sector plane portal
//
//============================================================================
enum
{
PORTS_SKYVIEWPOINT = 0, // a regular skybox
PORTS_STACKEDSECTORTHING, // stacked sectors with the thing method
PORTS_PORTAL, // stacked sectors with Sector_SetPortal
PORTS_LINKEDPORTAL, // linked portal (interactive)
PORTS_PLANE, // EE-style plane portal (not implemented in SW renderer)
PORTS_HORIZON, // EE-style horizon portal (not implemented in SW renderer)
};
enum
{
PORTSF_SKYFLATONLY = 1, // portal is only active on skyflatnum
PORTSF_INSKYBOX = 2, // to avoid recursion
};
struct FSectorPortal
{
int mType;
int mFlags;
unsigned mPartner;
int mPlane;
sector_t *mOrigin;
sector_t *mDestination;
DVector2 mDisplacement;
double mPlaneZ;
TObjPtr<AActor> mSkybox;
void *mRenderData;
bool MergeAllowed() const
{
// For thing based stack sectors and regular skies the portal has no relevance for merging visplanes.
return (mType == PORTS_STACKEDSECTORTHING || (mType == PORTS_SKYVIEWPOINT && (mFlags & PORTSF_SKYFLATONLY)));
}
};
extern TArray<FSectorPortal> sectorPortals;
//============================================================================
//
// Functions
//
//============================================================================
void P_ClearPortals();
void P_SpawnLinePortal(line_t* line);
void P_FinalizePortals();
@ -205,6 +255,9 @@ inline int P_NumPortalGroups()
{
return Displacements.size;
}
unsigned P_GetSkyboxPortal(ASkyViewpoint *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 */

View file

@ -515,18 +515,18 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec,
bool R_SkyboxCompare(sector_t *frontsector, sector_t *backsector)
{
AActor *frontc = frontsector->SkyBoxes[sector_t::ceiling];
AActor *frontf = frontsector->SkyBoxes[sector_t::floor];
AActor *backc = backsector->SkyBoxes[sector_t::ceiling];
AActor *backf = backsector->SkyBoxes[sector_t::floor];
FSectorPortal *frontc = frontsector->GetPortal(sector_t::ceiling);
FSectorPortal *frontf = frontsector->GetPortal(sector_t::floor);
FSectorPortal *backc = backsector->GetPortal(sector_t::ceiling);
FSectorPortal *backf = backsector->GetPortal(sector_t::floor);
// return true if any of the planes has a linedef-based portal (unless both sides have the same one.
// Ideally this should also check thing based portals but the omission of this check had been abused to hell and back for those.
// (Note: This may require a compatibility option if some maps ran into this for line based portals as well.)
if (frontc != NULL && (frontc->special1 == SKYBOX_PORTAL || frontc->special1 == SKYBOX_LINKEDPORTAL)) return (frontc != backc);
if (frontf != NULL && (frontf->special1 == SKYBOX_PORTAL || frontf->special1 == SKYBOX_LINKEDPORTAL)) return (frontf != backf);
if (backc != NULL && (backc->special1 == SKYBOX_PORTAL || backc->special1 == SKYBOX_LINKEDPORTAL)) return true;
if (backf != NULL && (backf->special1 == SKYBOX_PORTAL || backf->special1 == SKYBOX_LINKEDPORTAL)) return true;
if (!frontc->MergeAllowed()) return (frontc != backc);
if (!frontf->MergeAllowed()) return (frontf != backf);
if (!backc->MergeAllowed()) return true;
if (!backf->MergeAllowed()) return true;
return false;
}
@ -1046,7 +1046,7 @@ void R_Subsector (subsector_t *sub)
int ceilinglightlevel; // killough 4/11/98
bool outersubsector;
int fll, cll, position;
ASkyViewpoint *skybox;
FSectorPortal *portal;
// kg3D - fake floor stuff
visplane_t *backupfp;
@ -1114,12 +1114,11 @@ void R_Subsector (subsector_t *sub)
basecolormap = frontsector->ColorMap;
}
skybox = frontsector->GetSkyBox(sector_t::ceiling);
if (skybox != NULL && skybox->special1 >= SKYBOX_PLANE) skybox = NULL; // skip unsupported portal types
portal = frontsector->ValidatePortal(sector_t::ceiling);
ceilingplane = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) > 0 ||
frontsector->GetTexture(sector_t::ceiling) == skyflatnum ||
(skybox != NULL && skybox->bAlways) ||
portal != NULL ||
(frontsector->heightsec &&
!(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
frontsector->heightsec->GetTexture(sector_t::floor) == skyflatnum) ?
@ -1134,7 +1133,7 @@ void R_Subsector (subsector_t *sub)
frontsector->GetYScale(sector_t::ceiling),
frontsector->GetAngle(sector_t::ceiling),
frontsector->sky,
skybox
portal
) : NULL;
if (fixedlightlev < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
@ -1156,12 +1155,11 @@ void R_Subsector (subsector_t *sub)
// killough 3/7/98: Add (x,y) offsets to flats, add deep water check
// killough 3/16/98: add floorlightlevel
// killough 10/98: add support for skies transferred from sidedefs
skybox = frontsector->GetSkyBox(sector_t::floor);
if (skybox != NULL && skybox->special1 >= SKYBOX_PLANE) skybox = NULL; // skip unsupported portal types
portal = frontsector->ValidatePortal(sector_t::floor);
floorplane = frontsector->floorplane.PointOnSide(viewx, viewy, viewz) > 0 || // killough 3/7/98
frontsector->GetTexture(sector_t::floor) == skyflatnum ||
(skybox != NULL && skybox->bAlways) ||
portal != NULL ||
(frontsector->heightsec &&
!(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
frontsector->heightsec->GetTexture(sector_t::ceiling) == skyflatnum) ?
@ -1176,7 +1174,7 @@ void R_Subsector (subsector_t *sub)
frontsector->GetYScale(sector_t::floor),
frontsector->GetAngle(sector_t::floor),
frontsector->sky,
skybox
portal
) : NULL;
// kg3D - fake planes rendering

View file

@ -58,19 +58,6 @@ enum
extern size_t MaxDrawSegs;
struct FDisplacement;
enum
{
SKYBOX_ANCHOR = -1,
SKYBOX_SKYVIEWPOINT = 0, // a regular skybox
SKYBOX_STACKEDSECTORTHING, // stacked sectors with the thing method
SKYBOX_PORTAL, // stacked sectors with Sector_SetPortal
SKYBOX_LINKEDPORTAL, // linked portal (interactive)
SKYBOX_PLANE, // EE-style plane portal (not implemented in SW renderer)
SKYBOX_HORIZON, // EE-style horizon portal (not implemented in SW renderer)
};
//
// INTERNAL MAP TYPES
// used by play and refresh
@ -499,8 +486,6 @@ enum
SECF_UNDERWATERMASK = 32+64,
SECF_DRAWN = 128, // sector has been drawn at least once
SECF_HIDDEN = 256, // Do not draw on textured automap
SECF_NOFLOORSKYBOX = 512, // force use of regular sky
SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!)
};
enum
@ -668,7 +653,7 @@ public:
DInterpolation *SetInterpolation(int position, bool attach);
ASkyViewpoint *GetSkyBox(int which);
FSectorPortal *ValidatePortal(int which);
void CheckPortalPlane(int plane);
enum
@ -930,8 +915,7 @@ public:
bool PortalBlocksView(int plane)
{
if (SkyBoxes[plane] == NULL) return true;
if (GetPortalType(plane) != SKYBOX_LINKEDPORTAL) return false;
if (GetPortalType(plane) != PORTS_LINKEDPORTAL) return false;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
@ -952,28 +936,37 @@ public:
bool PortalIsLinked(int plane)
{
return (SkyBoxes[plane] != NULL && GetPortalType(plane) == SKYBOX_LINKEDPORTAL);
return (GetPortalType(plane) == PORTS_LINKEDPORTAL);
}
void ClearPortal(int plane)
{
Portals[plane] = 0;
}
FSectorPortal *GetPortal(int plane)
{
return &sectorPortals[Portals[plane]];
}
// These intentionally do not validate the SkyBoxes pointers.
double GetPortalPlaneZ(int plane)
{
return SkyBoxes[plane]->specialf1;
return sectorPortals[Portals[plane]].mPlaneZ;
}
DVector2 GetPortalDisplacement(int plane)
{
return SkyBoxes[plane]->Scale;
return sectorPortals[Portals[plane]].mDisplacement;
}
int GetPortalType(int plane)
{
return SkyBoxes[plane]->special1;
return sectorPortals[Portals[plane]].mType;
}
int GetOppositePortalGroup(int plane)
{
return SkyBoxes[plane]->Sector->PortalGroup;
return sectorPortals[Portals[plane]].mDestination->PortalGroup;
}
int GetTerrain(int pos) const;
@ -1083,9 +1076,8 @@ public:
// occurs, SecActTarget's TriggerAction method is called.
TObjPtr<ASectorAction> SecActTarget;
// [RH] The sky box to render for this sector. NULL means use a
// regular sky.
TObjPtr<AActor> SkyBoxes[2];
// [RH] The portal or skybox to render for this sector.
unsigned Portals[2];
int PortalGroup;
int sectornum; // for comparing sector copies

View file

@ -693,7 +693,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth)
fixed_t starty = viewy;
fixed_t startz = viewz;
DVector3 savedpath[2] = { ViewPath[0], ViewPath[1] };
int savedvisibility = camera->renderflags & RF_INVISIBLE;
int savedvisibility = camera? camera->renderflags & RF_INVISIBLE : 0;
CurrentPortalUniq++;
@ -746,7 +746,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth)
viewz = FLOAT2FIXED(view.Z);
viewangle = va.BAMs();
if (!r_showviewer)
if (!r_showviewer && camera)
{
double distp = (ViewPath[0] - ViewPath[1]).Length();
if (distp > EQUAL_EPSILON)
@ -802,11 +802,11 @@ void R_EnterPortal (PortalDrawseg* pds, int depth)
InSubsector = NULL;
R_RenderBSPNode (nodes + numnodes - 1);
R_3D_ResetClip(); // reset clips (floor/ceiling)
if (!savedvisibility) camera->renderflags &= ~RF_INVISIBLE;
if (!savedvisibility && camera) camera->renderflags &= ~RF_INVISIBLE;
PlaneCycles.Clock();
R_DrawPlanes ();
R_DrawSkyBoxes ();
R_DrawPortals ();
PlaneCycles.Unclock();
fixed_t vzp = viewz;
@ -961,7 +961,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines)
{
PlaneCycles.Clock();
R_DrawPlanes ();
R_DrawSkyBoxes ();
R_DrawPortals ();
PlaneCycles.Unclock();
// [RH] Walk through mirrors

View file

@ -584,7 +584,7 @@ static visplane_t *new_visplane (unsigned hash)
visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightlevel, fixed_t alpha, bool additive,
fixed_t xoffs, fixed_t yoffs,
fixed_t xscale, fixed_t yscale, angle_t angle,
int sky, ASkyViewpoint *skybox)
int sky, FSectorPortal *portal)
{
secplane_t plane;
visplane_t *check;
@ -606,9 +606,9 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
// same column but separated by a wall. If they both try to reside in the
// same visplane, then only the floor sky will be drawn.
plane.set(0., 0., height.fC(), 0.);
isskybox = skybox != NULL && !skybox->bInSkybox;
isskybox = portal != NULL && !(portal->mFlags & PORTSF_INSKYBOX);
}
else if (skybox != NULL && skybox->bAlways && !skybox->bInSkybox)
else if (portal != NULL && !(portal->mFlags & PORTSF_INSKYBOX))
{
plane = height;
isskybox = true;
@ -622,7 +622,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
// and ->alpha is for stacked sectors
if (fake3D & (FAKE3D_FAKEFLOOR|FAKE3D_FAKECEILING)) sky = 0x80000000 | fakeAlpha;
else sky = 0; // not skyflatnum so it can't be a sky
skybox = NULL;
portal = NULL;
alpha = OPAQUE;
}
@ -633,9 +633,9 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
{
if (isskybox)
{
if (skybox == check->skybox && plane == check->height)
if (portal == check->portal && plane == check->height)
{
if (skybox->Mate != NULL)
if (portal->mType != PORTS_SKYVIEWPOINT)
{ // This skybox is really a stacked sector, so we need to
// check even more.
if (check->extralight == stacked_extralight &&
@ -645,7 +645,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
check->viewz == stacked_viewz &&
(
// headache inducing logic... :(
(!(skybox->flags & MF_JUSTATTACKED)) ||
(portal->mType != PORTS_STACKEDSECTORTHING) ||
(
check->Alpha == alpha &&
check->Additive == additive &&
@ -710,7 +710,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
check->angle = angle;
check->colormap = basecolormap; // [RH] Save colormap
check->sky = sky;
check->skybox = skybox;
check->portal = portal;
check->left = viewwidth; // Was SCREENWIDTH -- killough 11/98
check->right = 0;
check->extralight = stacked_extralight;
@ -781,7 +781,7 @@ visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop)
// make a new visplane
unsigned hash;
if (pl->skybox != NULL && !pl->skybox->bInSkybox && (pl->picnum == skyflatnum || pl->skybox->bAlways) && viewactive)
if (pl->portal != NULL && !(pl->portal->mFlags & PORTSF_INSKYBOX) && viewactive)
{
hash = MAXVISPLANES;
}
@ -800,7 +800,7 @@ visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop)
new_pl->yscale = pl->yscale;
new_pl->angle = pl->angle;
new_pl->colormap = pl->colormap;
new_pl->skybox = pl->skybox;
new_pl->portal = pl->portal;
new_pl->extralight = pl->extralight;
new_pl->visibility = pl->visibility;
new_pl->viewx = pl->viewx;
@ -1160,7 +1160,7 @@ void R_DrawSinglePlane (visplane_t *pl, fixed_t alpha, bool additive, bool maske
//==========================================================================
//
// R_DrawSkyBoxes
// R_DrawPortals
//
// Draws any recorded sky boxes and then frees them.
//
@ -1181,7 +1181,7 @@ void R_DrawSinglePlane (visplane_t *pl, fixed_t alpha, bool additive, bool maske
CVAR (Bool, r_skyboxes, true, 0)
static int numskyboxes;
void R_DrawSkyBoxes ()
void R_DrawPortals ()
{
static TArray<size_t> interestingStack;
static TArray<ptrdiff_t> drawsegStack;
@ -1221,7 +1221,7 @@ void R_DrawSkyBoxes ()
visplanes[MAXVISPLANES] = pl->next;
pl->next = NULL;
if (pl->right < pl->left || !r_skyboxes || numskyboxes == MAX_SKYBOX_PLANES)
if (pl->right < pl->left || !r_skyboxes || numskyboxes == MAX_SKYBOX_PLANES || pl->portal == NULL)
{
R_DrawSinglePlane (pl, OPAQUE, false, false);
*freehead = pl;
@ -1231,14 +1231,15 @@ void R_DrawSkyBoxes ()
numskyboxes++;
ASkyViewpoint *sky = pl->skybox;
ASkyViewpoint *mate = sky->Mate;
if (mate == NULL)
FSectorPortal *port = pl->portal;
switch (port->mType)
{
case PORTS_SKYVIEWPOINT:
{
// Don't let gun flashes brighten the sky box
ASkyViewpoint *sky = barrier_cast<ASkyViewpoint*>(port->mSkybox);
extralight = 0;
R_SetVisibility (sky->args[0] * 0.25f);
R_SetVisibility(sky->args[0] * 0.25f);
DVector3 viewpos = sky->InterpolatedPosition(r_TicFracF);
viewx = FLOAT2FIXED(viewpos.X);
@ -1247,23 +1248,40 @@ void R_DrawSkyBoxes ()
viewangle = savedangle + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * r_TicFracF).BAMs();
R_CopyStackedViewParameters();
break;
}
else
{
case PORTS_STACKEDSECTORTHING:
case PORTS_PORTAL:
case PORTS_LINKEDPORTAL:
extralight = pl->extralight;
R_SetVisibility (pl->visibility);
viewx = pl->viewx + FLOAT2FIXED(-sky->Mate->X() + sky->X());
viewy = pl->viewy + FLOAT2FIXED(-sky->Mate->Y() + sky->Y());
viewx = pl->viewx + FLOAT2FIXED(port->mDisplacement.X);
viewy = pl->viewy + FLOAT2FIXED(port->mDisplacement.Y);
viewz = pl->viewz;
viewangle = pl->viewangle;
break;
case PORTS_HORIZON:
case PORTS_PLANE:
// not implemented yet
default:
R_DrawSinglePlane(pl, OPAQUE, false, false);
*freehead = pl;
freehead = &pl->next;
numskyboxes--;
continue;
}
ViewAngle = AngleToFloat(viewangle);
ViewPos = { FIXED2DBL(viewx), FIXED2DBL(viewy), FIXED2DBL(viewz) };
sky->bInSkybox = true;
if (mate != NULL) mate->bInSkybox = true;
camera = sky;
viewsector = sky->Sector;
port->mFlags |= PORTSF_INSKYBOX;
if (port->mPartner > 0) sectorPortals[port->mPartner].mFlags |= PORTSF_INSKYBOX;
camera = NULL;
viewsector = port->mDestination;
assert(viewsector != NULL);
R_SetViewAngle ();
validcount++; // Make sure we see all sprites
@ -1324,8 +1342,8 @@ void R_DrawSkyBoxes ()
R_3D_ResetClip(); // reset clips (floor/ceiling)
R_DrawPlanes ();
sky->bInSkybox = false;
if (mate != NULL) mate->bInSkybox = false;
port->mFlags &= ~PORTSF_INSKYBOX;
if (port->mPartner > 0) sectorPortals[port->mPartner].mFlags &= ~PORTSF_INSKYBOX;
}
// Draw all the masked textures in a second pass, in the reverse order they

View file

@ -43,7 +43,7 @@ struct visplane_s
fixed_t xscale, yscale; // [RH] Support flat scaling
angle_t angle; // [RH] Support flat rotation
int sky;
ASkyViewpoint *skybox; // [RH] Support sky boxes
FSectorPortal *portal; // [RH] Support sky boxes
// [RH] This set of variables copies information from the time when the
// visplane is created. They are only used by stacks so that you can
@ -88,7 +88,7 @@ void R_DeinitPlanes ();
void R_ClearPlanes (bool fullclear);
int R_DrawPlanes ();
void R_DrawSkyBoxes ();
void R_DrawPortals ();
void R_DrawSkyPlane (visplane_t *pl);
void R_DrawNormalPlane (visplane_t *pl, fixed_t alpha, bool additive, bool masked);
void R_DrawTiltedPlane (visplane_t *pl, fixed_t alpha, bool additive, bool masked);
@ -106,7 +106,7 @@ visplane_t *R_FindPlane
fixed_t yscale,
angle_t angle,
int sky,
ASkyViewpoint *skybox);
FSectorPortal *portal);
visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop);

View file

@ -1536,6 +1536,7 @@ void R_DrawPlayerSprites ()
F3DFloor *rover;
if (!r_drawplayersprites ||
!camera ||
!camera->player ||
(players[consoleplayer].cheats & CF_CHASECAM) ||
(r_deathcamera && camera->health <= 0))

View file

@ -72,11 +72,11 @@ const char *GetVersionString();
// SAVESIG should match SAVEVER.
// MINSAVEVER is the minimum level snapshot version that can be loaded.
#define MINSAVEVER 4536
#define MINSAVEVER 4539
// Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got.
#define SAVEVER 4538
#define SAVEVER 4539
#define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)

View file

@ -39,13 +39,13 @@ enum
282 = 0, Sector_Attach3DMidtex(tag, 0, 1) // "3DMidTex_MoveWithCeiling"
// Plane portals are not supported in ZDoom, though they probably wouldn't be too hard to implement.
283 = 0, Unsupported() // "Portal_PlaneCeiling"
284 = 0, Unsupported() // "Portal_PlaneFloor"
285 = 0, Unsupported() // "Portal_PlaneFloorCeiling"
286 = 0, Unsupported() // "Portal_HorizonCeiling"
287 = 0, Unsupported() // "Portal_HorizonFloor"
288 = 0, Unsupported() // "Portal_HorizonFloorCeiling"
289 = 0, Unsupported() // "Portal_LineTransfer"
283 = 0, Sector_SetPortal(tag,3, 1, 0, 0) // "Portal_PlaneCeiling"
284 = 0, Sector_SetPortal(tag,3, 0, 0, 0) // "Portal_PlaneFloor"
285 = 0, Sector_SetPortal(tag,3, 2, 0, 0) // "Portal_PlaneFloorCeiling"
286 = 0, Sector_SetPortal(tag,4, 1, 0, 0) // "Portal_HorizonCeiling"
287 = 0, Sector_SetPortal(tag,4, 0, 0, 0) // "Portal_HorizonFloor"
288 = 0, Sector_SetPortal(tag,4, 2, 0, 0) // "Portal_HorizonFloorCeiling"
289 = 0, Sector_SetPortal(0, 5, 0, tag) // "Portal_LineTransfer"
// Skybox portals
290 = 0, Sector_SetPortal(tag, 2, 1, 1, 0) // "Portal_SkyboxCeiling"