# Conflicts:
#	src/p_spec.cpp
#	src/r_bsp.cpp
#	src/r_defs.h
This commit is contained in:
Christoph Oelckers 2016-04-20 19:56:07 +02:00
commit 9c6e7753d8
29 changed files with 435 additions and 316 deletions

View file

@ -576,7 +576,6 @@ public:
~AActor (); ~AActor ();
void Serialize (FArchive &arc); void Serialize (FArchive &arc);
void PostSerialize();
static AActor *StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false); static AActor *StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false);

View file

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

View file

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

View file

@ -69,7 +69,6 @@ public:
virtual ~DThinker (); virtual ~DThinker ();
virtual void Tick (); virtual void Tick ();
virtual void PostBeginPlay (); // Called just before the first tick virtual void PostBeginPlay (); // Called just before the first tick
virtual void PostSerialize() {}
size_t PropagateMark(); size_t PropagateMark();
void ChangeStatNum (int statnum); void ChangeStatNum (int statnum);

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, FSwitchDef* &sw);
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da); template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da);
FArchive &operator<< (FArchive &arc, FLinePortal &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); NormalLight.ChangeFade (level.fadeto);
level.DefaultEnvironment = info->DefaultEnvironment; level.DefaultEnvironment = info->DefaultEnvironment;
level.DefaultSkybox = NULL;
} }
//========================================================================== //==========================================================================
@ -1534,13 +1533,14 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
FBehavior::StaticSerializeModuleStates (arc); FBehavior::StaticSerializeModuleStates (arc);
if (arc.IsLoading()) interpolator.ClearInterpolations(); if (arc.IsLoading()) interpolator.ClearInterpolations();
P_SerializeWorld(arc);
P_SerializeThinkers (arc, hubLoad); P_SerializeThinkers (arc, hubLoad);
P_SerializeWorld (arc); P_SerializeWorldActors(arc); // serializing actor pointers in the world data must be done after SerializeWorld has restored the entire sector state, otherwise LinkToWorld may fail.
P_SerializePolyobjs (arc); P_SerializePolyobjs (arc);
P_SerializeSubsectors(arc); P_SerializeSubsectors(arc);
StatusBar->Serialize (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? // Does this level have custom translations?
FRemapTable *trans; FRemapTable *trans;
@ -1582,13 +1582,6 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
P_SerializeSounds (arc); P_SerializeSounds (arc);
if (arc.IsLoading()) if (arc.IsLoading())
{ {
FThinkerIterator it(RUNTIME_CLASS(DThinker));
DThinker *th;
while ((th = it.Next()))
{
th->PostSerialize();
}
for (i = 0; i < numsectors; i++) for (i = 0; i < numsectors; i++)
{ {
P_Recalculate3DFloors(&sectors[i]); P_Recalculate3DFloors(&sectors[i]);

View file

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

View file

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

View file

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

View file

@ -358,7 +358,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player)
// Checks whether the player's feet touch a solid 3D floor in the sector // Checks whether the player's feet touch a solid 3D floor in the sector
// //
//========================================================================== //==========================================================================
bool P_CheckFor3DFloorHit(AActor * mo) bool P_CheckFor3DFloorHit(AActor * mo, double z)
{ {
if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false; if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false;
@ -368,7 +368,7 @@ bool P_CheckFor3DFloorHit(AActor * mo)
if(rover->flags & FF_SOLID && rover->model->SecActTarget) if(rover->flags & FF_SOLID && rover->model->SecActTarget)
{ {
if(mo->Z() == rover->top.plane->ZatPoint(mo)) if (fabs(z - rover->top.plane->ZatPoint(mo)) < EQUAL_EPSILON)
{ {
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor); rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor);
return true; return true;
@ -384,7 +384,7 @@ bool P_CheckFor3DFloorHit(AActor * mo)
// Checks whether the player's head touches a solid 3D floor in the sector // Checks whether the player's head touches a solid 3D floor in the sector
// //
//========================================================================== //==========================================================================
bool P_CheckFor3DCeilingHit(AActor * mo) bool P_CheckFor3DCeilingHit(AActor * mo, double z)
{ {
if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false; if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false;
@ -394,7 +394,7 @@ bool P_CheckFor3DCeilingHit(AActor * mo)
if(rover->flags & FF_SOLID && rover->model->SecActTarget) if(rover->flags & FF_SOLID && rover->model->SecActTarget)
{ {
if(mo->Top() == rover->bottom.plane->ZatPoint(mo)) if(fabs(z - rover->bottom.plane->ZatPoint(mo)) < EQUAL_EPSILON)
{ {
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling); rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling);
return true; return true;

View file

@ -122,8 +122,8 @@ struct lightlist_t
class player_s; class player_s;
void P_PlayerOnSpecial3DFloor(player_t* player); void P_PlayerOnSpecial3DFloor(player_t* player);
bool P_CheckFor3DFloorHit(AActor * mo); bool P_CheckFor3DFloorHit(AActor * mo, double z);
bool P_CheckFor3DCeilingHit(AActor * mo); bool P_CheckFor3DCeilingHit(AActor * mo, double z);
void P_Recalculate3DFloors(sector_t *); void P_Recalculate3DFloors(sector_t *);
void P_RecalculateAttached3DFloors(sector_t * sec); void P_RecalculateAttached3DFloors(sector_t * sec);
void P_RecalculateLights(sector_t *sector); void P_RecalculateLights(sector_t *sector);

View file

@ -587,7 +587,7 @@ bool P_Move (AActor *actor)
{ {
actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor);
} }
P_CheckFor3DFloorHit(actor); P_CheckFor3DFloorHit(actor, actor->Z());
} }
} }
} }

View file

@ -1629,10 +1629,10 @@ int FPathTraverse::PortalRelocate(intercept_t *in, int flags, DVector3 *optpos)
return saved->getPortal()->mType == PORTT_LINKED? 1:-1; 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 hitx = trace.x + displacement.X;
double hity = trace.y + portalthing->Scale.Y; double hity = trace.y + displacement.Y;
double endx = hitx + trace.dx; double endx = hitx + trace.dx;
double endy = hity + trace.dy; double endy = hity + trace.dy;
intercepts.Resize(intercept_index); 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); 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); 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(); virtual ~FPathTraverse();
const divline_t &Trace() const { return trace; } const divline_t &Trace() const { return trace; }

View file

@ -397,6 +397,9 @@ void AActor::Serialize(FArchive &arc)
if (arc.IsLoading ()) if (arc.IsLoading ())
{ {
touching_sectorlist = NULL;
LinkToWorld(false, Sector);
AddToHash (); AddToHash ();
SetShade (fillcolor); SetShade (fillcolor);
if (player) if (player)
@ -413,17 +416,11 @@ void AActor::Serialize(FArchive &arc)
Speed = GetDefault()->Speed; Speed = GetDefault()->Speed;
} }
} }
ClearInterpolation();
UpdateWaterLevel(false);
} }
} }
void AActor::PostSerialize()
{
touching_sectorlist = NULL;
LinkToWorld(false, Sector);
ClearInterpolation();
UpdateWaterLevel(false);
}
AActor::AActor () throw() AActor::AActor () throw()
{ {
} }
@ -2399,7 +2396,7 @@ void P_ZMovement (AActor *mo, double oldfloorz)
{ // [RH] Let the sector do something to the actor { // [RH] Let the sector do something to the actor
mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor); mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor);
} }
P_CheckFor3DFloorHit(mo); P_CheckFor3DFloorHit(mo, mo->floorz);
// [RH] Need to recheck this because the sector action might have // [RH] Need to recheck this because the sector action might have
// teleported the actor so it is no longer below the floor. // teleported the actor so it is no longer below the floor.
if (mo->Z() <= mo->floorz) if (mo->Z() <= mo->floorz)
@ -2499,7 +2496,7 @@ void P_ZMovement (AActor *mo, double oldfloorz)
{ // [RH] Let the sector do something to the actor { // [RH] Let the sector do something to the actor
mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling); mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling);
} }
P_CheckFor3DCeilingHit(mo); P_CheckFor3DCeilingHit(mo, mo->ceilingz);
// [RH] Need to recheck this because the sector action might have // [RH] Need to recheck this because the sector action might have
// teleported the actor so it is no longer above the ceiling. // teleported the actor so it is no longer above the ceiling.
if (mo->Top() > mo->ceilingz) if (mo->Top() > mo->ceilingz)
@ -3861,11 +3858,11 @@ void AActor::CheckSectorTransition(sector_t *oldsec)
} }
if (Z() == floorz) if (Z() == floorz)
{ {
P_CheckFor3DFloorHit(this); P_CheckFor3DFloorHit(this, Z());
} }
if (Top() == ceilingz) if (Top() == ceilingz)
{ {
P_CheckFor3DCeilingHit(this); P_CheckFor3DCeilingHit(this, Top());
} }
} }
} }

View file

@ -363,13 +363,11 @@ void P_SerializeWorld (FArchive &arc)
arc << sec->damageamount; arc << sec->damageamount;
arc << sec->damageinterval arc << sec->damageinterval
<< sec->leakydamage << sec->leakydamage
<< sec->damagetype; << sec->damagetype
arc << sec->SoundTarget
<< sec->SecActTarget
<< sec->sky << sec->sky
<< sec->MoreFlags << sec->MoreFlags
<< sec->Flags << sec->Flags
<< sec->SkyBoxes[sector_t::floor] << sec->SkyBoxes[sector_t::ceiling] << sec->Portals[sector_t::floor] << sec->Portals[sector_t::ceiling]
<< sec->ZoneNumber; << sec->ZoneNumber;
arc << sec->interpolations[0] arc << sec->interpolations[0]
<< sec->interpolations[1] << sec->interpolations[1]
@ -454,10 +452,26 @@ void P_SerializeWorld (FArchive &arc)
arc << zn->Environment; arc << zn->Environment;
} }
arc << linePortals; arc << linePortals << sectorPortals;
P_CollectLinkedPortals(); P_CollectLinkedPortals();
} }
void P_SerializeWorldActors(FArchive &arc)
{
int i, j;
sector_t *sec;
for (i = 0, sec = sectors; i < numsectors; i++, sec++)
{
arc << sec->SoundTarget
<< sec->SecActTarget;
}
for (auto &s : sectorPortals)
{
arc << s.mSkybox;
}
}
void extsector_t::Serialize(FArchive &arc) void extsector_t::Serialize(FArchive &arc)
{ {
arc << FakeFloor.Sectors arc << FakeFloor.Sectors
@ -570,22 +584,8 @@ void P_SerializePolyobjs (FArchive &arc)
I_Error ("UnarchivePolyobjs: Invalid polyobj tag"); I_Error ("UnarchivePolyobjs: Invalid polyobj tag");
} }
arc << angle << delta << po->interpolation; arc << angle << delta << po->interpolation;
if (SaveVersion >= 4537) arc << po->bBlocked;
{ arc << po->bHasPortals;
arc << po->bBlocked;
}
else
{
po->bBlocked = false;
}
if (SaveVersion >= 4538)
{
arc << po->bHasPortals;
}
else
{
po->bHasPortals = 0;
}
po->RotatePolyobj (angle, true); po->RotatePolyobj (angle, true);
delta -= po->StartSpot.pos; delta -= po->StartSpot.pos;

View file

@ -41,6 +41,7 @@ struct PNGHandle;
// These are the load / save game routines. // These are the load / save game routines.
// Also see farchive.(h|cpp) // Also see farchive.(h|cpp)
void P_SerializePlayers (FArchive &arc, bool fakeload); void P_SerializePlayers (FArchive &arc, bool fakeload);
void P_SerializeWorldActors(FArchive &arc);
void P_SerializeWorld (FArchive &arc); void P_SerializeWorld (FArchive &arc);
void P_SerializeThinkers (FArchive &arc, bool); void P_SerializeThinkers (FArchive &arc, bool);
void P_SerializePolyobjs (FArchive &arc); void P_SerializePolyobjs (FArchive &arc);

View file

@ -32,6 +32,7 @@
#include "r_utility.h" #include "r_utility.h"
#include "a_sharedglobal.h" #include "a_sharedglobal.h"
#include "p_local.h" #include "p_local.h"
#include "r_sky.h"
#include "r_data/colormaps.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]); FSectorPortal *port = GetPortal(which);
if (MoreFlags & (SECF_NOFLOORSKYBOX << which)) return NULL; if (port->mType == PORTS_SKYVIEWPOINT && port->mSkybox == nullptr) return nullptr; // A skybox without a viewpoint is just a regular sky.
return level.DefaultSkybox; 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) void sector_t::CheckPortalPlane(int plane)
{ {
AActor *portal = SkyBoxes[plane]; if (GetPortalType(plane) == PORTS_LINKEDPORTAL)
if (!portal || portal->special1 != SKYBOX_LINKEDPORTAL) return; {
double portalh = GetPortalPlaneZ(plane);
double planeh = GetPlaneTexZF(plane); double planeh = GetPlaneTexZF(plane);
int obstructed = PLANEF_OBSTRUCTED * (plane == sector_t::floor ? int obstructed = PLANEF_OBSTRUCTED * (plane == sector_t::floor ? planeh > portalh : planeh < portalh);
planeh > portal->specialf1 : planeh < portal->specialf1); planes[plane].Flags = (planes[plane].Flags & ~PLANEF_OBSTRUCTED) | obstructed;
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); NActorIterator it (NAME_LowerStackLookOnly, point->tid);
sector_t *Sector = point->Sector; sector_t *Sector = point->Sector;
ASkyViewpoint *skyv = static_cast<ASkyViewpoint*>(it.Next()); ASkyViewpoint *skyv = static_cast<ASkyViewpoint*>(it.Next());
Sector->SkyBoxes[sector_t::floor] = skyv; if (skyv != NULL)
if (skyv != NULL && skyv->bAlways)
{ {
skyv->Mate = point; skyv->target = point;
if (Sector->GetAlphaF(sector_t::floor) == 1.) if (Sector->GetAlphaF(sector_t::floor) == 1.)
Sector->SetAlpha(sector_t::floor, clamp(point->args[0], 0, 255) / 255.); Sector->SetAlpha(sector_t::floor, clamp(point->args[0], 0, 255) / 255.);
Sector->Portals[sector_t::floor] = P_GetStackPortal(skyv, sector_t::floor);
} }
} }
@ -852,12 +853,13 @@ static void SetupCeilingPortal (AStackPoint *point)
NActorIterator it (NAME_UpperStackLookOnly, point->tid); NActorIterator it (NAME_UpperStackLookOnly, point->tid);
sector_t *Sector = point->Sector; sector_t *Sector = point->Sector;
ASkyViewpoint *skyv = static_cast<ASkyViewpoint*>(it.Next()); ASkyViewpoint *skyv = static_cast<ASkyViewpoint*>(it.Next());
Sector->SkyBoxes[sector_t::ceiling] = skyv; if (skyv != NULL)
if (skyv != NULL && skyv->bAlways)
{ {
skyv->Mate = point; skyv->target = point;
if (Sector->GetAlphaF(sector_t::ceiling) == 1.) if (Sector->GetAlphaF(sector_t::ceiling) == 1.)
Sector->SetAlpha(sector_t::ceiling, clamp(point->args[0], 0, 255) / 255.); Sector->SetAlpha(sector_t::ceiling, clamp(point->args[0], 0, 255) / 255.);
Sector->Portals[sector_t::ceiling] = P_GetStackPortal(skyv, sector_t::ceiling);
} }
} }
@ -881,42 +883,68 @@ void P_SetupPortals()
pt->special1 = 0; pt->special1 = 0;
points.Push(pt); 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 // plane: 0=floor, 1=ceiling, 2=both
if (plane > 0) 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.) if (sector->GetAlphaF(sector_t::ceiling) == 1.)
sector->SetAlpha(sector_t::ceiling, alpha); 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 (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.) if (sector->GetAlphaF(sector_t::floor) == 1.)
sector->SetAlpha(sector_t::floor, alpha); 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; int s;
FSectorTagIterator itr(sectortag); FSectorTagIterator itr(sectortag);
while ((s = itr.Next()) >= 0) while ((s = itr.Next()) >= 0)
{ {
SetPortal(&sectors[s], plane, origin, alpha); SetPortal(&sectors[s], plane, pnum, alpha);
} }
for (int j=0;j<numlines;j++) for (int j=0;j<numlines;j++)
@ -930,14 +958,14 @@ static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, double a
{ {
if (lines[j].args[0] == 0) if (lines[j].args[0] == 0)
{ {
SetPortal(lines[j].frontsector, plane, origin, alpha); SetPortal(lines[j].frontsector, plane, pnum, alpha);
} }
else else
{ {
FSectorTagIterator itr(lines[j].args[0]); FSectorTagIterator itr(lines[j].args[0]);
while ((s = itr.Next()) >= 0) while ((s = itr.Next()) >= 0)
{ {
SetPortal(&sectors[s], plane, origin, alpha); SetPortal(&sectors[s], plane, pnum, alpha);
} }
} }
} }
@ -961,6 +989,7 @@ static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, double a
} }
} }
void P_SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int linked) void P_SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int linked)
{ {
if (plane < 0 || plane > 2 || (linked && plane == 2)) return; if (plane < 0 || plane > 2 || (linked && plane == 2)) return;
@ -975,36 +1004,10 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int li
lines[i].args[3] == 1) lines[i].args[3] == 1)
{ {
// beware of overflows. // beware of overflows.
DVector3 pos1((line->v1->fX() + line->v2->fX()) / 2, (line->v1->fY() + line->v2->fY()) / 2, 0); DVector2 pos1 = line->v1->fPos() + line->Delta() / 2;
DVector3 pos2((lines[i].v1->fX() + lines[i].v2->fX()) / 2, (lines[i].v1->fY() + lines[i].v2->fY()) / 2, 0); DVector2 pos2 = lines[i].v1->fPos() + lines[i].Delta() / 2;
double z = linked ? line->frontsector->GetPlaneTexZF(plane) : 0; // the map's sector height defines the portal plane for linked portals unsigned pnum = P_GetPortal(linked ? PORTS_LINKEDPORTAL : PORTS_PORTAL, plane, line->frontsector, lines[i].frontsector, pos2 - pos1);
CopyPortal(sectortag, plane, pnum, bytealpha / 255., false);
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);
return; return;
} }
} }
@ -1029,7 +1032,8 @@ void P_SpawnSkybox(ASkyViewpoint *origin)
if (refline->special == Sector_SetPortal && refline->args[1] == 2) if (refline->special == Sector_SetPortal && refline->args[1] == 2)
{ {
// We found the setup linedef for this skybox, so let's use it for our init. // We found the setup linedef for this skybox, so let's use it for our init.
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; return;
} }
} }
@ -1355,11 +1359,8 @@ void P_SpawnSpecials (void)
else if (lines[i].args[1] == 3 || lines[i].args[1] == 4) else if (lines[i].args[1] == 3 || lines[i].args[1] == 4)
{ {
line_t *line = &lines[i]; line_t *line = &lines[i];
ASkyViewpoint *origin = Spawn<ASkyViewpoint>(); unsigned pnum = P_GetPortal(line->args[1] == 3 ? PORTS_PLANE : PORTS_HORIZON, line->args[2], line->frontsector, NULL, { 0,0 });
origin->Sector = line->frontsector; CopyPortal(line->args[0], line->args[2], pnum, 0, true);
origin->special1 = line->args[1] == 3? SKYBOX_PLANE:SKYBOX_HORIZON;
CopyPortal(line->args[0], line->args[2], origin, 0, true);
} }
break; break;

View file

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

View file

@ -64,6 +64,8 @@ FPortalBlockmap PortalBlockmap;
TArray<FLinePortal> linePortals; TArray<FLinePortal> linePortals;
TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups.
TArray<FSectorPortal> sectorPortals;
//============================================================================ //============================================================================
// //
// This is used to mark processed portals for some collection functions. // This is used to mark processed portals for some collection functions.
@ -213,6 +215,25 @@ FArchive &operator<< (FArchive &arc, FLinePortal &port)
return arc; 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;
return arc;
}
//============================================================================ //============================================================================
// //
@ -487,7 +508,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 +517,17 @@ void P_ClearPortals()
Displacements.Create(1); Displacements.Create(1);
linePortals.Clear(); linePortals.Clear();
linkedPortals.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. // check if this line is between portal and the viewer. clip away if it is.
@ -637,6 +666,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 // P_GetOffsetPosition
@ -756,35 +853,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 thisgroup = portal->mOrigin->PortalGroup;
int othergroup = portal->Sector->PortalGroup; int othergroup = portal->mDestination->PortalGroup;
if (thisgroup == othergroup) 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); 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->special1 = portal->Mate->special1 = SKYBOX_PORTAL; portal->mType = PORTS_PORTAL;
return; return;
} }
if (thisgroup <= 0 || thisgroup >= Displacements.size || othergroup <= 0 || othergroup >= 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->Sector->sectornum, portal->Mate->Sector->sectornum); Printf("Portal between sectors %d and %d has invalid group and will be disabled\n", portal->mOrigin->sectornum, portal->mDestination->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL; portal->mType = PORTS_PORTAL;
return; return;
} }
FDisplacement & disp = Displacements(thisgroup, othergroup); FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet) if (!disp.isSet)
{ {
disp.pos = portal->Scale; disp.pos = portal->mDisplacement;
disp.isSet = true; disp.isSet = true;
} }
else 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); Printf("Portal between sectors %d and %d has displacement mismatch and will be disabled\n", portal->mOrigin->sectornum, portal->mDestination->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL; portal->mType = PORTS_PORTAL;
return; return;
} }
} }
@ -895,55 +992,43 @@ static bool ConnectGroups()
void P_CreateLinkedPortals() void P_CreateLinkedPortals()
{ {
TThinkerIterator<AStackPoint> it; TArray<FSectorPortal *> orgs;
AStackPoint *mo;
TArray<AStackPoint *> orgs;
int id = 1; int id = 1;
bool bogus = false; 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(&s);
{
orgs.Push(mo);
mo->reactiontime = ++id;
}
else
{
// this should never happen, but if it does, the portal needs to be removed
mo->Destroy();
}
} }
} }
id = 1; id = 1;
if (orgs.Size() != 0) if (orgs.Size() != 0)
{ {
for (int i = 0; i < numsectors; i++) for (int i = 0; i < numsectors; i++)
{
for (int j = 0; j < 2; j++)
{ {
AActor *box = sectors[i].SkyBoxes[j]; for (int j = 0; j < 2; j++)
if (box != NULL && box->special1 == SKYBOX_LINKEDPORTAL)
{ {
secplane_t &plane = j == 0 ? sectors[i].floorplane : sectors[i].ceilingplane; if (sectors[i].GetPortalType(j) == PORTS_LINKEDPORTAL)
if (plane.isSlope())
{ {
// The engine cannot deal with portals on a sloped plane. secplane_t &plane = j == 0 ? sectors[i].floorplane : sectors[i].ceilingplane;
sectors[i].SkyBoxes[j] = NULL; if (plane.isSlope())
Printf("Portal on %s of sector %d is sloped and will be disabled\n", j == 0 ? "floor" : "ceiling", i); {
// 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. // Group all sectors, starting at each portal origin.
for (unsigned i = 0; i < orgs.Size(); i++) for (unsigned i = 0; i < orgs.Size(); i++)
{ {
if (CollectSectors(id, orgs[i]->Sector)) id++; if (CollectSectors(id, orgs[i]->mOrigin)) id++;
if (CollectSectors(id, orgs[i]->Mate->Sector)) id++; if (CollectSectors(id, orgs[i]->mDestination)) id++;
} }
} }
for (unsigned i = 0; i < linePortals.Size(); i++) for (unsigned i = 0; i < linePortals.Size(); i++)
{ {
@ -960,17 +1045,9 @@ void P_CreateLinkedPortals()
{ {
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
ASkyViewpoint *box = barrier_cast<ASkyViewpoint*>(sectors[i].SkyBoxes[j]); if (sectors[i].GetPortalType(j) == PORTS_LINKEDPORTAL && sectors[i].PortalGroup == 0)
if (box != NULL)
{ {
if (box->special1 == SKYBOX_LINKEDPORTAL && sectors[i].PortalGroup == 0) CollectSectors(sectors[i].GetOppositePortalGroup(j), &sectors[i]);
{
// 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.
}
} }
} }
} }
@ -1060,11 +1137,11 @@ void P_CreateLinkedPortals()
double fp = sectors[i].floorplane.fD(); double fp = sectors[i].floorplane.fD();
if (cp < fp || fz == fp) if (cp < fp || fz == fp)
{ {
sectors[i].SkyBoxes[sector_t::ceiling] = NULL; sectors[i].ClearPortal(sector_t::ceiling);
} }
else else
{ {
sectors[i].SkyBoxes[sector_t::floor] = NULL; sectors[i].ClearPortal(sector_t::floor);
} }
} }
} }

View file

@ -6,6 +6,7 @@
#include "m_bbox.h" #include "m_bbox.h"
struct FPortalGroupArray; struct FPortalGroupArray;
class ASkyViewpoint;
//============================================================================ //============================================================================
// //
// This table holds the offsets for the different parts of a map // 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) // 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; DAngle mAngleDiff;
double mSinRot; double mSinRot;
double mCosRot; double mCosRot;
void *mRenderData;
}; };
extern TArray<FLinePortal> linePortals; 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_ClearPortals();
void P_SpawnLinePortal(line_t* line); void P_SpawnLinePortal(line_t* line);
void P_FinalizePortals(); void P_FinalizePortals();
@ -205,6 +255,9 @@ inline int P_NumPortalGroups()
{ {
return Displacements.size; 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 */ /* 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) bool R_SkyboxCompare(sector_t *frontsector, sector_t *backsector)
{ {
AActor *frontc = frontsector->SkyBoxes[sector_t::ceiling]; FSectorPortal *frontc = frontsector->GetPortal(sector_t::ceiling);
AActor *frontf = frontsector->SkyBoxes[sector_t::floor]; FSectorPortal *frontf = frontsector->GetPortal(sector_t::floor);
AActor *backc = backsector->SkyBoxes[sector_t::ceiling]; FSectorPortal *backc = backsector->GetPortal(sector_t::ceiling);
AActor *backf = backsector->SkyBoxes[sector_t::floor]; 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. // 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. // 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.) // (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 (!frontc->MergeAllowed()) return (frontc != backc);
if (frontf != NULL && (frontf->special1 == SKYBOX_PORTAL || frontf->special1 == SKYBOX_LINKEDPORTAL)) return (frontf != backf); if (!frontf->MergeAllowed()) return (frontf != backf);
if (backc != NULL && (backc->special1 == SKYBOX_PORTAL || backc->special1 == SKYBOX_LINKEDPORTAL)) return true; if (!backc->MergeAllowed()) return true;
if (backf != NULL && (backf->special1 == SKYBOX_PORTAL || backf->special1 == SKYBOX_LINKEDPORTAL)) return true; if (!backf->MergeAllowed()) return true;
return false; return false;
} }
@ -1046,7 +1046,7 @@ void R_Subsector (subsector_t *sub)
int ceilinglightlevel; // killough 4/11/98 int ceilinglightlevel; // killough 4/11/98
bool outersubsector; bool outersubsector;
int fll, cll, position; int fll, cll, position;
ASkyViewpoint *skybox; FSectorPortal *portal;
// kg3D - fake floor stuff // kg3D - fake floor stuff
visplane_t *backupfp; visplane_t *backupfp;
@ -1114,12 +1114,11 @@ void R_Subsector (subsector_t *sub)
basecolormap = frontsector->ColorMap; basecolormap = frontsector->ColorMap;
} }
skybox = frontsector->GetSkyBox(sector_t::ceiling); portal = frontsector->ValidatePortal(sector_t::ceiling);
if (skybox != NULL && skybox->special1 >= SKYBOX_PLANE) skybox = NULL; // skip unsupported portal types
ceilingplane = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) > 0 || ceilingplane = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) > 0 ||
frontsector->GetTexture(sector_t::ceiling) == skyflatnum || frontsector->GetTexture(sector_t::ceiling) == skyflatnum ||
(skybox != NULL && skybox->bAlways) || portal != NULL ||
(frontsector->heightsec && (frontsector->heightsec &&
!(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) && !(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
frontsector->heightsec->GetTexture(sector_t::floor) == skyflatnum) ? frontsector->heightsec->GetTexture(sector_t::floor) == skyflatnum) ?
@ -1134,7 +1133,7 @@ void R_Subsector (subsector_t *sub)
frontsector->GetYScale(sector_t::ceiling), frontsector->GetYScale(sector_t::ceiling),
frontsector->GetAngle(sector_t::ceiling), frontsector->GetAngle(sector_t::ceiling),
frontsector->sky, frontsector->sky,
skybox portal
) : NULL; ) : NULL;
if (fixedlightlev < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size()) if (fixedlightlev < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
@ -1156,13 +1155,11 @@ void R_Subsector (subsector_t *sub)
// killough 3/7/98: Add (x,y) offsets to flats, add deep water check // killough 3/7/98: Add (x,y) offsets to flats, add deep water check
// killough 3/16/98: add floorlightlevel // killough 3/16/98: add floorlightlevel
// killough 10/98: add support for skies transferred from sidedefs // killough 10/98: add support for skies transferred from sidedefs
portal = frontsector->ValidatePortal(sector_t::floor);
skybox = frontsector->GetSkyBox(sector_t::floor);
if (skybox != NULL && skybox->special1 >= SKYBOX_PLANE) skybox = NULL; // skip unsupported portal types
floorplane = frontsector->floorplane.PointOnSide(viewx, viewy, viewz) > 0 || // killough 3/7/98 floorplane = frontsector->floorplane.PointOnSide(viewx, viewy, viewz) > 0 || // killough 3/7/98
frontsector->GetTexture(sector_t::floor) == skyflatnum || frontsector->GetTexture(sector_t::floor) == skyflatnum ||
(skybox != NULL && skybox->bAlways) || portal != NULL ||
(frontsector->heightsec && (frontsector->heightsec &&
!(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) && !(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
frontsector->heightsec->GetTexture(sector_t::ceiling) == skyflatnum) ? frontsector->heightsec->GetTexture(sector_t::ceiling) == skyflatnum) ?
@ -1177,7 +1174,7 @@ void R_Subsector (subsector_t *sub)
frontsector->GetYScale(sector_t::floor), frontsector->GetYScale(sector_t::floor),
frontsector->GetAngle(sector_t::floor), frontsector->GetAngle(sector_t::floor),
frontsector->sky, frontsector->sky,
skybox portal
) : NULL; ) : NULL;
// kg3D - fake planes rendering // kg3D - fake planes rendering

View file

@ -62,19 +62,6 @@ enum
extern size_t MaxDrawSegs; extern size_t MaxDrawSegs;
struct FDisplacement; 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 // INTERNAL MAP TYPES
// used by play and refresh // used by play and refresh
@ -529,8 +516,6 @@ enum
SECF_UNDERWATERMASK = 32+64, SECF_UNDERWATERMASK = 32+64,
SECF_DRAWN = 128, // sector has been drawn at least once SECF_DRAWN = 128, // sector has been drawn at least once
SECF_HIDDEN = 256, // Do not draw on textured automap 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 enum
@ -700,7 +685,7 @@ public:
DInterpolation *SetInterpolation(int position, bool attach); DInterpolation *SetInterpolation(int position, bool attach);
ASkyViewpoint *GetSkyBox(int which); FSectorPortal *ValidatePortal(int which);
void CheckPortalPlane(int plane); void CheckPortalPlane(int plane);
enum enum
@ -963,8 +948,7 @@ public:
bool PortalBlocksView(int plane) bool PortalBlocksView(int plane)
{ {
if (SkyBoxes[plane] == NULL) return true; if (GetPortalType(plane) != PORTS_LINKEDPORTAL) return false;
if (GetPortalType(plane) != SKYBOX_LINKEDPORTAL) return false;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
} }
@ -985,28 +969,37 @@ public:
bool PortalIsLinked(int plane) 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) double GetPortalPlaneZ(int plane)
{ {
return SkyBoxes[plane]->specialf1; return sectorPortals[Portals[plane]].mPlaneZ;
} }
DVector2 GetPortalDisplacement(int plane) DVector2 GetPortalDisplacement(int plane)
{ {
return SkyBoxes[plane]->Scale; return sectorPortals[Portals[plane]].mDisplacement;
} }
int GetPortalType(int plane) int GetPortalType(int plane)
{ {
return SkyBoxes[plane] == nullptr? -1 : SkyBoxes[plane]->special1; return sectorPortals[Portals[plane]].mType;
} }
int GetOppositePortalGroup(int plane) int GetOppositePortalGroup(int plane)
{ {
return SkyBoxes[plane]->Sector->PortalGroup; return sectorPortals[Portals[plane]].mDestination->PortalGroup;
} }
void SetVerticesDirty() void SetVerticesDirty()
@ -1128,9 +1121,8 @@ public:
// occurs, SecActTarget's TriggerAction method is called. // occurs, SecActTarget's TriggerAction method is called.
TObjPtr<ASectorAction> SecActTarget; TObjPtr<ASectorAction> SecActTarget;
// [RH] The sky box to render for this sector. NULL means use a // [RH] The portal or skybox to render for this sector.
// regular sky. unsigned Portals[2];
TObjPtr<AActor> SkyBoxes[2];
int PortalGroup; int PortalGroup;
int sectornum; // for comparing sector copies 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 starty = viewy;
fixed_t startz = viewz; fixed_t startz = viewz;
DVector3 savedpath[2] = { ViewPath[0], ViewPath[1] }; DVector3 savedpath[2] = { ViewPath[0], ViewPath[1] };
int savedvisibility = camera->renderflags & RF_INVISIBLE; int savedvisibility = camera? camera->renderflags & RF_INVISIBLE : 0;
CurrentPortalUniq++; CurrentPortalUniq++;
@ -746,7 +746,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth)
viewz = FLOAT2FIXED(view.Z); viewz = FLOAT2FIXED(view.Z);
viewangle = va.BAMs(); viewangle = va.BAMs();
if (!r_showviewer) if (!r_showviewer && camera)
{ {
double distp = (ViewPath[0] - ViewPath[1]).Length(); double distp = (ViewPath[0] - ViewPath[1]).Length();
if (distp > EQUAL_EPSILON) if (distp > EQUAL_EPSILON)
@ -802,11 +802,11 @@ void R_EnterPortal (PortalDrawseg* pds, int depth)
InSubsector = NULL; InSubsector = NULL;
R_RenderBSPNode (nodes + numnodes - 1); R_RenderBSPNode (nodes + numnodes - 1);
R_3D_ResetClip(); // reset clips (floor/ceiling) R_3D_ResetClip(); // reset clips (floor/ceiling)
if (!savedvisibility) camera->renderflags &= ~RF_INVISIBLE; if (!savedvisibility && camera) camera->renderflags &= ~RF_INVISIBLE;
PlaneCycles.Clock(); PlaneCycles.Clock();
R_DrawPlanes (); R_DrawPlanes ();
R_DrawSkyBoxes (); R_DrawPortals ();
PlaneCycles.Unclock(); PlaneCycles.Unclock();
fixed_t vzp = viewz; fixed_t vzp = viewz;
@ -961,7 +961,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines)
{ {
PlaneCycles.Clock(); PlaneCycles.Clock();
R_DrawPlanes (); R_DrawPlanes ();
R_DrawSkyBoxes (); R_DrawPortals ();
PlaneCycles.Unclock(); PlaneCycles.Unclock();
// [RH] Walk through mirrors // [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, 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 xoffs, fixed_t yoffs,
fixed_t xscale, fixed_t yscale, angle_t angle, fixed_t xscale, fixed_t yscale, angle_t angle,
int sky, ASkyViewpoint *skybox) int sky, FSectorPortal *portal)
{ {
secplane_t plane; secplane_t plane;
visplane_t *check; 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 column but separated by a wall. If they both try to reside in the
// same visplane, then only the floor sky will be drawn. // same visplane, then only the floor sky will be drawn.
plane.set(0., 0., height.fC(), 0.); 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; plane = height;
isskybox = true; isskybox = true;
@ -622,7 +622,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
// and ->alpha is for stacked sectors // and ->alpha is for stacked sectors
if (fake3D & (FAKE3D_FAKEFLOOR|FAKE3D_FAKECEILING)) sky = 0x80000000 | fakeAlpha; if (fake3D & (FAKE3D_FAKEFLOOR|FAKE3D_FAKECEILING)) sky = 0x80000000 | fakeAlpha;
else sky = 0; // not skyflatnum so it can't be a sky else sky = 0; // not skyflatnum so it can't be a sky
skybox = NULL; portal = NULL;
alpha = OPAQUE; alpha = OPAQUE;
} }
@ -633,9 +633,9 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
{ {
if (isskybox) 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 { // This skybox is really a stacked sector, so we need to
// check even more. // check even more.
if (check->extralight == stacked_extralight && 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 && check->viewz == stacked_viewz &&
( (
// headache inducing logic... :( // headache inducing logic... :(
(!(skybox->flags & MF_JUSTATTACKED)) || (portal->mType != PORTS_STACKEDSECTORTHING) ||
( (
check->Alpha == alpha && check->Alpha == alpha &&
check->Additive == additive && check->Additive == additive &&
@ -710,7 +710,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
check->angle = angle; check->angle = angle;
check->colormap = basecolormap; // [RH] Save colormap check->colormap = basecolormap; // [RH] Save colormap
check->sky = sky; check->sky = sky;
check->skybox = skybox; check->portal = portal;
check->left = viewwidth; // Was SCREENWIDTH -- killough 11/98 check->left = viewwidth; // Was SCREENWIDTH -- killough 11/98
check->right = 0; check->right = 0;
check->extralight = stacked_extralight; check->extralight = stacked_extralight;
@ -781,7 +781,7 @@ visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop)
// make a new visplane // make a new visplane
unsigned hash; 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; hash = MAXVISPLANES;
} }
@ -800,7 +800,7 @@ visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop)
new_pl->yscale = pl->yscale; new_pl->yscale = pl->yscale;
new_pl->angle = pl->angle; new_pl->angle = pl->angle;
new_pl->colormap = pl->colormap; new_pl->colormap = pl->colormap;
new_pl->skybox = pl->skybox; new_pl->portal = pl->portal;
new_pl->extralight = pl->extralight; new_pl->extralight = pl->extralight;
new_pl->visibility = pl->visibility; new_pl->visibility = pl->visibility;
new_pl->viewx = pl->viewx; 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. // 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) CVAR (Bool, r_skyboxes, true, 0)
static int numskyboxes; static int numskyboxes;
void R_DrawSkyBoxes () void R_DrawPortals ()
{ {
static TArray<size_t> interestingStack; static TArray<size_t> interestingStack;
static TArray<ptrdiff_t> drawsegStack; static TArray<ptrdiff_t> drawsegStack;
@ -1221,7 +1221,7 @@ void R_DrawSkyBoxes ()
visplanes[MAXVISPLANES] = pl->next; visplanes[MAXVISPLANES] = pl->next;
pl->next = NULL; 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); R_DrawSinglePlane (pl, OPAQUE, false, false);
*freehead = pl; *freehead = pl;
@ -1231,14 +1231,15 @@ void R_DrawSkyBoxes ()
numskyboxes++; numskyboxes++;
ASkyViewpoint *sky = pl->skybox; FSectorPortal *port = pl->portal;
ASkyViewpoint *mate = sky->Mate; switch (port->mType)
{
if (mate == NULL) case PORTS_SKYVIEWPOINT:
{ {
// Don't let gun flashes brighten the sky box // Don't let gun flashes brighten the sky box
ASkyViewpoint *sky = barrier_cast<ASkyViewpoint*>(port->mSkybox);
extralight = 0; extralight = 0;
R_SetVisibility (sky->args[0] * 0.25f); R_SetVisibility(sky->args[0] * 0.25f);
DVector3 viewpos = sky->InterpolatedPosition(r_TicFracF); DVector3 viewpos = sky->InterpolatedPosition(r_TicFracF);
viewx = FLOAT2FIXED(viewpos.X); 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(); viewangle = savedangle + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * r_TicFracF).BAMs();
R_CopyStackedViewParameters(); R_CopyStackedViewParameters();
break;
} }
else
{ case PORTS_STACKEDSECTORTHING:
case PORTS_PORTAL:
case PORTS_LINKEDPORTAL:
extralight = pl->extralight; extralight = pl->extralight;
R_SetVisibility (pl->visibility); R_SetVisibility (pl->visibility);
viewx = pl->viewx + FLOAT2FIXED(-sky->Mate->X() + sky->X()); viewx = pl->viewx + FLOAT2FIXED(port->mDisplacement.X);
viewy = pl->viewy + FLOAT2FIXED(-sky->Mate->Y() + sky->Y()); viewy = pl->viewy + FLOAT2FIXED(port->mDisplacement.Y);
viewz = pl->viewz; viewz = pl->viewz;
viewangle = pl->viewangle; 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); ViewAngle = AngleToFloat(viewangle);
ViewPos = { FIXED2DBL(viewx), FIXED2DBL(viewy), FIXED2DBL(viewz) }; ViewPos = { FIXED2DBL(viewx), FIXED2DBL(viewy), FIXED2DBL(viewz) };
sky->bInSkybox = true; port->mFlags |= PORTSF_INSKYBOX;
if (mate != NULL) mate->bInSkybox = true; if (port->mPartner > 0) sectorPortals[port->mPartner].mFlags |= PORTSF_INSKYBOX;
camera = sky; camera = NULL;
viewsector = sky->Sector; viewsector = port->mDestination;
assert(viewsector != NULL);
R_SetViewAngle (); R_SetViewAngle ();
validcount++; // Make sure we see all sprites validcount++; // Make sure we see all sprites
@ -1324,8 +1342,8 @@ void R_DrawSkyBoxes ()
R_3D_ResetClip(); // reset clips (floor/ceiling) R_3D_ResetClip(); // reset clips (floor/ceiling)
R_DrawPlanes (); R_DrawPlanes ();
sky->bInSkybox = false; port->mFlags &= ~PORTSF_INSKYBOX;
if (mate != NULL) mate->bInSkybox = false; if (port->mPartner > 0) sectorPortals[port->mPartner].mFlags &= ~PORTSF_INSKYBOX;
} }
// Draw all the masked textures in a second pass, in the reverse order they // 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 fixed_t xscale, yscale; // [RH] Support flat scaling
angle_t angle; // [RH] Support flat rotation angle_t angle; // [RH] Support flat rotation
int sky; 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 // [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 // 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); void R_ClearPlanes (bool fullclear);
int R_DrawPlanes (); int R_DrawPlanes ();
void R_DrawSkyBoxes (); void R_DrawPortals ();
void R_DrawSkyPlane (visplane_t *pl); void R_DrawSkyPlane (visplane_t *pl);
void R_DrawNormalPlane (visplane_t *pl, fixed_t alpha, bool additive, bool masked); 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); void R_DrawTiltedPlane (visplane_t *pl, fixed_t alpha, bool additive, bool masked);
@ -106,7 +106,7 @@ visplane_t *R_FindPlane
fixed_t yscale, fixed_t yscale,
angle_t angle, angle_t angle,
int sky, int sky,
ASkyViewpoint *skybox); FSectorPortal *portal);
visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop); visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop);

View file

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

View file

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