diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 22f3f1b8d..604e99736 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -426,6 +426,7 @@ enum ActorFlag8 MF8_DONTFOLLOWPLAYERS = 0x04000000, // [inkoalawetrust] Friendly monster will not follow players. MF8_SEEFRIENDLYMONSTERS = 0X08000000, // [inkoalawetrust] Hostile monster can see friendly monsters. MF8_CROSSLINECHECK = 0x10000000, // [MC]Enables CanCrossLine virtual + MF8_MASTERNOSEE = 0x20000000, // Don't show object in first person if their master is the current camera. }; // --- mobj.renderflags --- diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 25d87b0aa..cc83abe88 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -729,17 +729,25 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t DVector3 thingpos = thing->InterpolatedPosition(vp.TicFrac); if (thruportal == 1) thingpos += di->Level->Displacements.getOffset(thing->Sector->PortalGroup, sector->PortalGroup); - // 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 (thing == camera && !vp.showviewer) + AActor *viewmaster = thing; + if ((thing->flags8 & MF8_MASTERNOSEE) && thing->master != nullptr) { - DVector3 thingorigin = thing->Pos(); - if (thruportal == 1) thingorigin += di->Level->Displacements.getOffset(thing->Sector->PortalGroup, sector->PortalGroup); - if (fabs(thingorigin.X - vp.ActorPos.X) < 2 && fabs(thingorigin.Y - vp.ActorPos.Y) < 2) return; + viewmaster = thing->master; + } + + // 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) + { + 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; } // Thing is invisible if close to the camera. - if (thing->renderflags & RF_MAYBEINVISIBLE) + if (viewmaster->renderflags & RF_MAYBEINVISIBLE) { - if (fabs(thingpos.X - vp.Pos.X) < 32 && fabs(thingpos.Y - vp.Pos.Y) < 32) return; + DVector3 viewpos = viewmaster->InterpolatedPosition(vp.TicFrac); + if (thruportal == 1) viewpos += di->Level->Displacements.getOffset(viewmaster->Sector->PortalGroup, sector->PortalGroup); + if (fabs(viewpos.X - vp.Pos.X) < 32 && fabs(viewpos.Y - vp.Pos.Y) < 32) return; } // Too close to the camera. This doesn't look good if it is a sprite. @@ -1376,11 +1384,33 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area) DVector3 newpos = savedpos; sector_t fakesector; - if (!vp.showviewer && th == vp.camera) + if (!vp.showviewer) { - if (fabs(savedpos.X - vp.ActorPos.X) < 2 && fabs(savedpos.Y - vp.ActorPos.Y) < 2) + AActor *viewmaster = th; + if ((th->flags8 & MF8_MASTERNOSEE) && th->master != nullptr) { - continue; + viewmaster = th->master; + } + + if (viewmaster == vp.camera) + { + DVector3 vieworigin = viewmaster->Pos(); + + if (fabs(vieworigin.X - vp.ActorPos.X) < 2 && fabs(vieworigin.Y - vp.ActorPos.Y) < 2) + { + // Same as the original position + continue; + } + + P_TranslatePortalXY(line, vieworigin.X, vieworigin.Y); + P_TranslatePortalZ(line, vieworigin.Z); + + if (fabs(vieworigin.X - vp.ActorPos.X) < 2 && fabs(vieworigin.Y - vp.ActorPos.Y) < 2) + { + // Same as the translated position + // (This is required for MASTERNOSEE actors with 3D models) + continue; + } } } diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.cpp b/src/rendering/swrenderer/scene/r_opaque_pass.cpp index b045f05f3..8fe768335 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.cpp +++ b/src/rendering/swrenderer/scene/r_opaque_pass.cpp @@ -998,6 +998,7 @@ namespace swrenderer // Don't waste time projecting sprites that are definitely not visible. if (thing == nullptr || (thing->renderflags & RF_INVISIBLE) || + (thing->renderflags & RF_MAYBEINVISIBLE) || !thing->RenderStyle.IsVisible(thing->Alpha) || !thing->IsVisibleToPlayer() || !thing->IsInsideVisibleAngles()) @@ -1005,6 +1006,16 @@ namespace swrenderer return false; } + if ((thing->flags8 & MF8_MASTERNOSEE) && thing->master != nullptr) + { + // Make MASTERNOSEE actors invisible if their master + // is invisible due to viewpoint shenanigans. + if (thing->master->renderflags & RF_MAYBEINVISIBLE) + { + return false; + } + } + // check renderrequired vs ~r_rendercaps, if anything matches we don't support that feature, // check renderhidden vs r_rendercaps, if anything matches we do support that feature and should hide it. if ((!r_debug_disable_vis_filter && !!(thing->RenderRequired & ~r_renderercaps)) || diff --git a/src/rendering/swrenderer/scene/r_portal.cpp b/src/rendering/swrenderer/scene/r_portal.cpp index f56c702a6..17f962b90 100644 --- a/src/rendering/swrenderer/scene/r_portal.cpp +++ b/src/rendering/swrenderer/scene/r_portal.cpp @@ -389,7 +389,7 @@ namespace swrenderer if (dist1 + dist2 < distp + 1) { - viewpoint.camera->renderflags |= RF_INVISIBLE; + viewpoint.camera->renderflags |= RF_MAYBEINVISIBLE; } } } diff --git a/src/rendering/swrenderer/scene/r_scene.cpp b/src/rendering/swrenderer/scene/r_scene.cpp index 7bc3bec2f..cd334d5b6 100644 --- a/src/rendering/swrenderer/scene/r_scene.cpp +++ b/src/rendering/swrenderer/scene/r_scene.cpp @@ -171,7 +171,7 @@ namespace swrenderer // Never draw the player unless in chasecam mode if (!MainThread()->Viewport->viewpoint.showviewer) { - MainThread()->Viewport->viewpoint.camera->renderflags |= RF_INVISIBLE; + MainThread()->Viewport->viewpoint.camera->renderflags |= RF_MAYBEINVISIBLE; } RenderThreadSlices(); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 42a3f145f..3f5a84e3b 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -341,6 +341,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF8, DONTFOLLOWPLAYERS, AActor, flags8), DEFINE_FLAG(MF8, SEEFRIENDLYMONSTERS, AActor, flags8), DEFINE_FLAG(MF8, CROSSLINECHECK, AActor, flags8), + DEFINE_FLAG(MF8, MASTERNOSEE, AActor, flags8), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),