diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index 5e64c8fdd..3f834fcf6 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -718,6 +718,9 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) bool anglevisible = false; bool pitchvisible = !(Viewpoint.IsAllowedOoB()); // No vertical clipping if viewpoint is not allowed out of bounds bool radarvisible = !(Viewpoint.IsAllowedOoB()) || !r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || ((sub->flags & SSECMF_DRAWN) && !deathmatch); + bool ceilreflect = (mCurrentPortal && strcmp(mCurrentPortal->GetName(), "Planemirror ceiling")); + bool floorreflect = (mCurrentPortal && strcmp(mCurrentPortal->GetName(), "Planemirror floor")); + double planez = (ceilreflect ? sector->ceilingplane.ZatPoint(Viewpoint.Pos) : sector->floorplane.ZatPoint(Viewpoint.Pos)); angle_t pitchtemp; angle_t pitchmin = ANGLE_90; angle_t pitchmax = 0; @@ -741,16 +744,28 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) if (!pitchvisible) { - pitchmin = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->floorplane.ZatPoint(seg->v1)); - pitchmax = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->ceilingplane.ZatPoint(seg->v1)); + pitchmin = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), + (ceilreflect || floorreflect) ? + 2 * planez - sector->floorplane.ZatPoint(seg->v1) : + sector->floorplane.ZatPoint(seg->v1)); + pitchmax = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), + (ceilreflect || floorreflect) ? + 2 * planez - sector->ceilingplane.ZatPoint(seg->v1) : + sector->ceilingplane.ZatPoint(seg->v1)); pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax); } if (pitchvisible && anglevisible && radarvisible) break; if (!pitchvisible) { - pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->floorplane.ZatPoint(seg->v2)); + pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), + (ceilreflect || floorreflect) ? + 2 * planez - sector->floorplane.ZatPoint(seg->v2) : + sector->floorplane.ZatPoint(seg->v2)); if (int(pitchmin) > int(pitchtemp)) pitchmin = pitchtemp; - pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->ceilingplane.ZatPoint(seg->v2)); + pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), + (ceilreflect || floorreflect) ? + 2 * planez - sector->ceilingplane.ZatPoint(seg->v2) : + sector->ceilingplane.ZatPoint(seg->v2)); if (int(pitchmax) < int(pitchtemp)) pitchmax = pitchtemp; pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax); } @@ -819,7 +834,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) SetupSprite.Unclock(); } } - if (r_dithertransparency && Viewpoint.IsAllowedOoB() && (RTnum < MAXDITHERACTORS)) + if (r_dithertransparency && Viewpoint.IsAllowedOoB() && (RTnum < MAXDITHERACTORS) && mCurrentPortal == nullptr) { // [DVR] Not parallelizable due to variables RTnum and RenderedTargets[] for (auto p = sector->touching_renderthings; p != nullptr; p = p->m_snext) diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 0fc7bc896..404203933 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -717,7 +717,7 @@ static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* } break; case TRACE_HitFloor: - if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection]) + if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection] && res.HitVector.dot(res.Sector->floorplane.Normal()) < 0.0) { if (res.HitPos.Z == res.Sector->floorplane.ZatPoint(res.HitPos)) { @@ -743,7 +743,7 @@ static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* } break; case TRACE_HitCeiling: - if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection]) + if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection] && res.HitVector.dot(res.Sector->ceilingplane.Normal()) < 0.0) { if (res.HitPos.Z == res.Sector->ceilingplane.ZatPoint(res.HitPos)) { @@ -779,6 +779,7 @@ static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* void HWDrawInfo::SetDitherTransFlags(AActor* actor) { + // This should really be moved to a shader and have the GPU do some shape-tracing. if (actor && actor->Sector) { FTraceResults results; diff --git a/src/rendering/hwrenderer/scene/hw_flats.cpp b/src/rendering/hwrenderer/scene/hw_flats.cpp index f14757ade..317ba9399 100644 --- a/src/rendering/hwrenderer/scene/hw_flats.cpp +++ b/src/rendering/hwrenderer/scene/hw_flats.cpp @@ -47,6 +47,7 @@ #include "hw_drawstructs.h" #include "hw_renderstate.h" #include "texturemanager.h" +#include "hw_viewpointbuffer.h" #ifdef _DEBUG CVAR(Int, gl_breaksec, -1, 0) @@ -314,6 +315,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) int rel = getExtraLight(); state.SetNormal(plane.plane.Normal().X, plane.plane.Normal().Z, plane.plane.Normal().Y); + double zshift = (plane.plane.Normal().Z > 0.0 ? 0.01f : -0.01f); // The HWPlaneMirrorPortal::DrawPortalStencil() z-fights with flats SetColor(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), Colormap, alpha); SetFog(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), &Colormap, false); @@ -364,7 +366,11 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) else state.AlphaFunc(Alpha_GEqual, 0.f); state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, NO_TRANSLATION, -1); SetPlaneTextureRotation(state, &plane, texture); + di->VPUniforms.mViewMatrix.translate(0.0, zshift, 0.0); + screen->mViewpoints->SetViewpoint(state, &di->VPUniforms); DrawSubsectors(di, state); + di->VPUniforms.mViewMatrix.translate(0.0, -zshift, 0.0); + screen->mViewpoints->SetViewpoint(state, &di->VPUniforms); state.EnableTextureMatrix(false); } state.SetRenderStyle(DefaultRenderStyle()); diff --git a/src/rendering/hwrenderer/scene/hw_portal.cpp b/src/rendering/hwrenderer/scene/hw_portal.cpp index b103f0f81..01ab23b8a 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.cpp +++ b/src/rendering/hwrenderer/scene/hw_portal.cpp @@ -158,13 +158,14 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di if (best) { portals.Delete(bestindex); - if (usestencil) + if (usestencil && ((strcmp(best->GetName(), "Sky") == 0) || (strcmp(best->GetName(), "Skybox") == 0))) { tempmatrix = outer_di->VPUniforms.mProjectionMatrix; // ensure perspective projection matrix for skies outer_di->VPUniforms.mProjectionMatrix = outer_di->ProjectionMatrix2; } RenderPortal(best, state, usestencil, outer_di); - if (usestencil) outer_di->VPUniforms.mProjectionMatrix = tempmatrix; + if (usestencil && ((strcmp(best->GetName(), "Sky") == 0) || (strcmp(best->GetName(), "Skybox") == 0))) + outer_di->VPUniforms.mProjectionMatrix = tempmatrix; delete best; return true; } @@ -332,6 +333,7 @@ void HWPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestenci bool needdepth = NeedDepthBuffer(); // Restore the old view + auto &vp = di->Viewpoint; if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; @@ -870,12 +872,31 @@ bool HWPlaneMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c state->PlaneMirrorFlag++; di->SetClipHeight(planez, state->PlaneMirrorMode < 0 ? -1.f : 1.f); di->SetupView(rstate, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1)); + vp.ViewVector3D.Z = - vp.ViewVector3D.Z; + vp.OffPos.Z = 2 * planez - vp.OffPos.Z; ClearClipper(di, clipper); di->UpdateCurrentMapSection(); return true; } + +void HWPlaneMirrorPortal::DrawPortalStencil(FRenderState &state, int pass) +{ + bool isceiling = planesused & (1 << sector_t::ceiling); + for (unsigned int i = 0; i < lines.Size(); i++) + { + flat.section = lines[i].sub->section; + flat.iboindex = lines[i].sub->sector->iboindex[isceiling ? sector_t::ceiling : sector_t::floor]; + flat.plane.GetFromSector(lines[i].sub->sector, isceiling ? sector_t::ceiling : sector_t::floor); + // if (isceiling) flat.plane.plane.FlipVert(); // Doesn't do anything. Stencil is a screen-space projection + + state.SetNormal(flat.plane.plane.Normal().X, flat.plane.plane.Normal().Z, flat.plane.plane.Normal().Y); + state.DrawIndexed(DT_Triangles, flat.iboindex + flat.section->vertexindex, flat.section->vertexcount, i == 0); + } +} + + void HWPlaneMirrorPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) { auto state = mState; diff --git a/src/rendering/hwrenderer/scene/hw_portal.h b/src/rendering/hwrenderer/scene/hw_portal.h index 760b8c435..ab9fec945 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.h +++ b/src/rendering/hwrenderer/scene/hw_portal.h @@ -59,13 +59,14 @@ class HWPortal TArray mPrimIndices; unsigned int mTopCap = ~0u, mBottomCap = ~0u; - void DrawPortalStencil(FRenderState &state, int pass); + virtual void DrawPortalStencil(FRenderState &state, int pass); public: FPortalSceneState * mState; TArray lines; BoundingRect boundingBox; int planesused = 0; + HWFlat flat; HWPortal(FPortalSceneState *s, bool local = false) : mState(s), boundingBox(false) { @@ -295,6 +296,7 @@ struct HWPlaneMirrorPortal : public HWScenePortalBase protected: bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override; void Shutdown(HWDrawInfo *di, FRenderState &rstate) override; + void DrawPortalStencil(FRenderState &state, int pass) override; virtual void * GetSource() const { return origin; } virtual const char *GetName(); secplane_t * origin; diff --git a/src/rendering/hwrenderer/scene/hw_sky.cpp b/src/rendering/hwrenderer/scene/hw_sky.cpp index 93fc827cc..4610f00da 100644 --- a/src/rendering/hwrenderer/scene/hw_sky.cpp +++ b/src/rendering/hwrenderer/scene/hw_sky.cpp @@ -154,7 +154,7 @@ void HWWall::SkyPlane(HWWallDispatcher *di, sector_t *sector, int plane, bool al case PORTS_PORTAL: case PORTS_LINKEDPORTAL: { - if (di->di && di->di->Viewpoint.IsAllowedOoB()) return; + if (di->di && di->di->Viewpoint.IsAllowedOoB()) return; // Almost works (with planemirrorportal stencil), but no quite auto glport = sector->GetPortalGroup(plane); if (glport != NULL) { diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index 47e651bd4..d5271d05f 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -644,7 +644,8 @@ void HWWall::PutPortal(HWWallDispatcher *di, int ptype, int plane) break; case PORTALTYPE_PLANEMIRROR: - if (portalState.PlaneMirrorMode * planemirror->fC() <= 0) + if (ddi->Viewpoint.IsOrtho() ? (ddi->Viewpoint.ViewVector3D.dot(planemirror->Normal()) < 0) + : (portalState.PlaneMirrorMode * planemirror->fC() <= 0)) { planemirror = portalState.UniquePlaneMirrors.Get(planemirror); portal = ddi->FindPortal(planemirror);