From f647545c1d2261ae7c927afea21b634bfd7e9d8a Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Fri, 29 Dec 2023 00:34:03 -0600 Subject: [PATCH] Disabled player sprites when crossing through portals. --- src/playsim/d_player.h | 1 + src/playsim/p_local.h | 3 +- src/playsim/p_map.cpp | 41 +++++++++++++++---- src/playsim/p_mobj.cpp | 3 +- src/rendering/hwrenderer/scene/hw_sprites.cpp | 13 +++++- src/rendering/r_utility.cpp | 3 +- src/rendering/r_utility.h | 2 +- 7 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/playsim/d_player.h b/src/playsim/d_player.h index 5b14793e7..675813873 100644 --- a/src/playsim/d_player.h +++ b/src/playsim/d_player.h @@ -375,6 +375,7 @@ public: int chickenPeck = 0; // chicken peck countdown int jumpTics = 0; // delay the next jump for a moment bool onground = 0; // Identifies if this player is on the ground or other object + bool crossingPortal = 0; // Crossing a portal (disables sprite from showing up) int respawn_time = 0; // [RH] delay respawning until this tic TObjPtr camera = MakeObjPtr(nullptr); // [RH] Whose eyes this player sees through diff --git a/src/playsim/p_local.h b/src/playsim/p_local.h index 45de6c462..468a19d8c 100644 --- a/src/playsim/p_local.h +++ b/src/playsim/p_local.h @@ -51,6 +51,7 @@ struct FCheckPosition; struct FTranslatedLineTarget; struct FLinePortal; class DViewPosition; +struct FRenderViewpoint; #include @@ -396,7 +397,7 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner); void P_AimCamera (AActor *t1, DVector3 &, DAngle &, sector_t *&sec, bool &unlinked); // [MC] Aiming for ViewPos -void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &, sector_t *&sec, bool &unlinked, DViewPosition *VP); +void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &, sector_t *&sec, bool &unlinked, DViewPosition *VP, FRenderViewpoint *view); // [RH] Means of death diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index c51ef2fb4..572ec6cc4 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -2636,13 +2636,15 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, auto p = thing->Level->GetConsolePlayer(); if (p) p->viewz += hit.pos.Z; // needs to be done here because otherwise the renderer will not catch the change. P_TranslatePortalAngle(ld, hit.angle); + if (thing->player && (port->mType == PORTT_INTERACTIVE || port->mType == PORTT_TELEPORT)) + thing->player->crossingPortal = true; } R_AddInterpolationPoint(hit); } if (port->mType == PORTT_LINKED) { continue; - } + } } break; } @@ -5600,24 +5602,47 @@ void P_AimCamera(AActor *t1, DVector3 &campos, DAngle &camangle, sector_t *&Came camangle = trace.SrcAngleFromTarget - DAngle::fromDeg(180.); } +struct ViewPosPortal +{ + int counter; +}; + +static ETraceStatus VPos_CheckPortal(FTraceResults &res, void *userdata) +{ + //[MC] Mirror how third person works. + ViewPosPortal *pc = (ViewPosPortal *)userdata; + + if (res.HitType == TRACE_CrossingPortal) + { + res.HitType = TRACE_HitNone; // Needed to force the trace to continue appropriately. + pc->counter++; + return TRACE_Skip; + } + if (res.HitType == TRACE_HitActor) + { + return TRACE_Skip; + } + return TRACE_Stop; +} + // [MC] Used for ViewPos. Uses code borrowed from P_AimCamera. -void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &campos, sector_t *&CameraSector, bool &unlinked, DViewPosition *VP) +void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &campos, sector_t *&CameraSector, bool &unlinked, DViewPosition *VP, FRenderViewpoint *view) { FTraceResults trace; + ViewPosPortal pc; + pc.counter = 0; const DVector3 vvec = campos - orig; const double distance = vvec.Length(); // Trace handles all of the portal crossing, which is why there is no usage of Vec#Offset(Z). - if (Trace(orig, t1->Sector, vvec.Unit(), distance, 0, 0, t1, trace) && + if (Trace(orig, CameraSector, vvec.Unit(), distance, 0, 0, t1, trace, TRACE_ReportPortals, VPos_CheckPortal, &pc) && trace.Distance > 5) - { - // Position camera slightly in front of hit thing campos = orig + vvec.Unit() * (trace.Distance - 5); - } else - { campos = trace.HitPos - trace.HitVector * 1 / 256.; - } + + + if (pc.counter > 2) view->noviewer = true; CameraSector = trace.Sector; unlinked = trace.unlinked; } diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index ddb5f047a..87c58a071 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -3771,7 +3771,8 @@ void AActor::Tick () } else { - + if (player) + player->crossingPortal = false; if (!player || !(player->cheats & CF_PREDICTING)) { // Handle powerup effects here so that the order is controlled diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 2d6ba1ed7..be8289ef6 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -770,13 +770,23 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t { return; } - // Some added checks if the camera actor is not supposed to be seen. It can happen that some portal setup has this actor in view in which case it may not be skipped here if (viewmaster == camera && !vp.showviewer) { + if (vp.noviewer || (viewmaster->player && viewmaster->player->crossingPortal)) return; DVector3 vieworigin = viewmaster->Pos(); if (thruportal == 1) vieworigin += di->Level->Displacements.getOffset(viewmaster->Sector->PortalGroup, sector->PortalGroup); if (fabs(vieworigin.X - vp.ActorPos.X) < 2 && fabs(vieworigin.Y - vp.ActorPos.Y) < 2) return; + + // Necessary in order to prevent sprite pop-ins with viewpos and models. + auto* sec = viewmaster->Sector; + if (sec && !sec->PortalBlocksMovement(sector_t::ceiling)) + { + double zh = sec->GetPortalPlaneZ(sector_t::ceiling); + double top = (viewmaster->player ? max(viewmaster->player->viewz, viewmaster->Top()) + 1 : viewmaster->Top()); + if (viewmaster->Z() < zh && top >= zh) + return; + } } // Thing is invisible if close to the camera. if (viewmaster->renderflags & RF_MAYBEINVISIBLE) @@ -858,7 +868,6 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t { return; } - if (!modelframe) { bool mirror = false; diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index 70a70ad51..4daf7af7c 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -600,6 +600,7 @@ void R_InterpolateView (FRenderViewpoint &viewpoint, player_t *player, double Fr else break; } } + if (moved) viewpoint.noviewer = true; } //========================================================================== @@ -947,7 +948,7 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor // Interpolation still happens with everything else though and seems to work fine. DefaultDraw = false; viewpoint.NoPortalPath = true; - P_AdjustViewPos(mo, orig, next, viewpoint.sector, unlinked, VP); + P_AdjustViewPos(mo, orig, next, viewpoint.sector, unlinked, VP, &viewpoint); if (viewpoint.sector->PortalGroup != oldsector->PortalGroup || (unlinked && ((iview->New.Pos.XY() - iview->Old.Pos.XY()).LengthSquared()) > 256 * 256)) { diff --git a/src/rendering/r_utility.h b/src/rendering/r_utility.h index 77254ebec..7ba6e738c 100644 --- a/src/rendering/r_utility.h +++ b/src/rendering/r_utility.h @@ -44,7 +44,7 @@ struct FRenderViewpoint int extralight; // extralight to be added to this viewpoint bool showviewer; // show the camera actor? bool NoPortalPath; // Disable portal interpolation path for actor viewpos. - + bool noviewer; // Force camera sprite off for first person. void SetViewAngle(const FViewWindow &viewwindow); };