# 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,8 +576,7 @@ public:
~AActor ();
void Serialize (FArchive &arc);
void PostSerialize();
static AActor *StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false);
inline AActor *GetDefault () const

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

@ -69,7 +69,6 @@ public:
virtual ~DThinker ();
virtual void Tick ();
virtual void PostBeginPlay (); // Called just before the first tick
virtual void PostSerialize() {}
size_t PropagateMark();
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, 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;
}
//==========================================================================
@ -1534,13 +1533,14 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
FBehavior::StaticSerializeModuleStates (arc);
if (arc.IsLoading()) interpolator.ClearInterpolations();
P_SerializeWorld(arc);
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_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;
@ -1582,13 +1582,6 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
P_SerializeSounds (arc);
if (arc.IsLoading())
{
FThinkerIterator it(RUNTIME_CLASS(DThinker));
DThinker *th;
while ((th = it.Next()))
{
th->PostSerialize();
}
for (i = 0; i < numsectors; i++)
{
P_Recalculate3DFloors(&sectors[i]);

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

@ -358,7 +358,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player)
// 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;
@ -368,7 +368,7 @@ bool P_CheckFor3DFloorHit(AActor * mo)
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);
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
//
//==========================================================================
bool P_CheckFor3DCeilingHit(AActor * mo)
bool P_CheckFor3DCeilingHit(AActor * mo, double z)
{
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(mo->Top() == rover->bottom.plane->ZatPoint(mo))
if(fabs(z - rover->bottom.plane->ZatPoint(mo)) < EQUAL_EPSILON)
{
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling);
return true;

View file

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

View file

@ -587,7 +587,7 @@ bool P_Move (AActor *actor)
{
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;
}
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

@ -397,6 +397,9 @@ void AActor::Serialize(FArchive &arc)
if (arc.IsLoading ())
{
touching_sectorlist = NULL;
LinkToWorld(false, Sector);
AddToHash ();
SetShade (fillcolor);
if (player)
@ -413,17 +416,11 @@ void AActor::Serialize(FArchive &arc)
Speed = GetDefault()->Speed;
}
}
ClearInterpolation();
UpdateWaterLevel(false);
}
}
void AActor::PostSerialize()
{
touching_sectorlist = NULL;
LinkToWorld(false, Sector);
ClearInterpolation();
UpdateWaterLevel(false);
}
AActor::AActor () throw()
{
}
@ -2399,7 +2396,7 @@ void P_ZMovement (AActor *mo, double oldfloorz)
{ // [RH] Let the sector do something to the actor
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
// teleported the actor so it is no longer below the floor.
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
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
// teleported the actor so it is no longer above the ceiling.
if (mo->Top() > mo->ceilingz)
@ -3861,11 +3858,11 @@ void AActor::CheckSectorTransition(sector_t *oldsec)
}
if (Z() == floorz)
{
P_CheckFor3DFloorHit(this);
P_CheckFor3DFloorHit(this, Z());
}
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->damageinterval
<< sec->leakydamage
<< sec->damagetype;
arc << sec->SoundTarget
<< sec->SecActTarget
<< sec->damagetype
<< 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]
@ -454,10 +452,26 @@ void P_SerializeWorld (FArchive &arc)
arc << zn->Environment;
}
arc << linePortals;
arc << linePortals << sectorPortals;
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)
{
arc << FakeFloor.Sectors
@ -570,22 +584,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

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

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,14 +958,14 @@ 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);
}
}
}
@ -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)
{
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)
{
// 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;
}
}
@ -1029,7 +1032,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;
}
}
@ -1355,11 +1359,8 @@ void P_SpawnSpecials (void)
else if (lines[i].args[1] == 3 || lines[i].args[1] == 4)
{
line_t *line = &lines[i];
ASkyViewpoint *origin = Spawn<ASkyViewpoint>();
origin->Sector = line->frontsector;
origin->special1 = line->args[1] == 3? SKYBOX_PLANE:SKYBOX_HORIZON;
CopyPortal(line->args[0], line->args[2], origin, 0, true);
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;

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,25 @@ 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;
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);
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 +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
@ -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 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 +992,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 +1045,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 +1137,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,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/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) ?
@ -1177,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

@ -62,19 +62,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
@ -529,8 +516,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
@ -700,7 +685,7 @@ public:
DInterpolation *SetInterpolation(int position, bool attach);
ASkyViewpoint *GetSkyBox(int which);
FSectorPortal *ValidatePortal(int which);
void CheckPortalPlane(int plane);
enum
@ -963,8 +948,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));
}
@ -985,28 +969,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] == nullptr? -1 : SkyBoxes[plane]->special1;
return sectorPortals[Portals[plane]].mType;
}
int GetOppositePortalGroup(int plane)
{
return SkyBoxes[plane]->Sector->PortalGroup;
return sectorPortals[Portals[plane]].mDestination->PortalGroup;
}
void SetVerticesDirty()
@ -1128,9 +1121,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 4540
// Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got.
#define SAVEVER 4538
#define SAVEVER 4540
#define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)