diff --git a/src/actor.h b/src/actor.h index ece9714dd8..ad3f3b8e7e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -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 diff --git a/src/dobject.cpp b/src/dobject.cpp index 511f3e5f01..82014c133c 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -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(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(old)) { sectors[i].f = static_cast(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 ); diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index ec79b374d8..afdc755083 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -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 = §ors[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); diff --git a/src/dthinker.h b/src/dthinker.h index c08ea9d83e..10a53309d6 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -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); diff --git a/src/farchive.h b/src/farchive.h index 4a17153447..b6722986a3 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -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); diff --git a/src/g_level.cpp b/src/g_level.cpp index 23ff24233a..dc5d408b96 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -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(§ors[i]); diff --git a/src/g_level.h b/src/g_level.h index b12a3aceaa..a5b3006aca 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -435,8 +435,6 @@ struct FLevelLocals int airsupply; int DefaultEnvironment; // Default sound environment. - TObjPtr DefaultSkybox; - FSectorScrollValues *Scrolls; // NULL if no DScrollers in this level SBYTE WallVertLight; // Light diffs for vert/horiz walls diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 6776fa8142..f746375d38 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -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 Mate; }; // For an EE compatible linedef based definition. diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 9a7aacb8e3..4e57c638e7 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -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 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; } //--------------------------------------------------------------------------- diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 42eab532d7..daa70d5b1e 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -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; diff --git a/src/p_3dfloors.h b/src/p_3dfloors.h index 5268da0e29..fc784c55c9 100644 --- a/src/p_3dfloors.h +++ b/src/p_3dfloors.h @@ -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); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 6c3e375acb..56437e1339 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -587,7 +587,7 @@ bool P_Move (AActor *actor) { actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); } - P_CheckFor3DFloorHit(actor); + P_CheckFor3DFloorHit(actor, actor->Z()); } } } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index ae87b258d1..552889c481 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -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); diff --git a/src/p_maputl.h b/src/p_maputl.h index c22984fd4a..e5a8a5f4ff 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -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; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 90c8beef36..46bc320dfc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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()); } } } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 731d2e9a4f..dda47ef666 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -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; diff --git a/src/p_saveg.h b/src/p_saveg.h index 9ae32cc87a..c6c0560041 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -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); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index dbc3991b9a..7db61dc673 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -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(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; + } } //=========================================================================== diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e4138afd81..c4a121507c 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -838,12 +838,13 @@ static void SetupFloorPortal (AStackPoint *point) NActorIterator it (NAME_LowerStackLookOnly, point->tid); sector_t *Sector = point->Sector; ASkyViewpoint *skyv = static_cast(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(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) - §orPortals[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(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(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(§ors[s], plane, origin, alpha); + SetPortal(§ors[s], plane, pnum, alpha); } for (int j=0;j= 0) { - SetPortal(§ors[s], plane, origin, alpha); + SetPortal(§ors[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(pos1, NO_REPLACE); - AStackPoint *reference = Spawn(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(); - 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; diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 61ebd03806..8a3664ac83 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -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; } } diff --git a/src/portal.cpp b/src/portal.cpp index c47b4c21f2..3dfd9a0504 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -64,6 +64,8 @@ FPortalBlockmap PortalBlockmap; TArray linePortals; TArray linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. +TArray 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(§orPortals[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(§orPortals[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;iGetClass()->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(§orPortals[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(§orPortals[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 it; - AStackPoint *mo; - TArray orgs; + TArray 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(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, §ors[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), §ors[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); } } } diff --git a/src/portal.h b/src/portal.h index 0aa9a2ef20..9c05f23b7c 100644 --- a/src/portal.h +++ b/src/portal.h @@ -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 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 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 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 */ diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index de083d7b02..39dd22766c 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -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 diff --git a/src/r_defs.h b/src/r_defs.h index 2260dbf1db..ab42114659 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -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 §orPortals[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 SecActTarget; - // [RH] The sky box to render for this sector. NULL means use a - // regular sky. - TObjPtr SkyBoxes[2]; + // [RH] The portal or skybox to render for this sector. + unsigned Portals[2]; int PortalGroup; int sectornum; // for comparing sector copies diff --git a/src/r_main.cpp b/src/r_main.cpp index 1c15f9f1e7..1344ac4539 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -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 diff --git a/src/r_plane.cpp b/src/r_plane.cpp index d950075db8..a1c429fea6 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -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 interestingStack; static TArray 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(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 diff --git a/src/r_plane.h b/src/r_plane.h index 6bcec657dd..e1030f66d1 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -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); diff --git a/src/r_things.cpp b/src/r_things.cpp index 7404402731..bbecd15590 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -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)) diff --git a/src/version.h b/src/version.h index c5161643ae..1ad04e1681 100644 --- a/src/version.h +++ b/src/version.h @@ -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)