diff --git a/src/r_poly_plane.cpp b/src/r_poly_plane.cpp index 68a56c69bb..57db62600d 100644 --- a/src/r_poly_plane.cpp +++ b/src/r_poly_plane.cpp @@ -32,7 +32,7 @@ EXTERN_CVAR(Int, r_3dfloors) -void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight) +void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals) { RenderPolyPlane plane; @@ -84,8 +84,8 @@ void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, subsector_t *su } } - plane.Render(worldToClip, sub, subsectorDepth, stencilValue, true, skyCeilingHeight); - plane.Render(worldToClip, sub, subsectorDepth, stencilValue, false, skyFloorHeight); + plane.Render(worldToClip, sub, subsectorDepth, stencilValue, true, skyCeilingHeight, sectorPortals); + plane.Render(worldToClip, sub, subsectorDepth, stencilValue, false, skyFloorHeight, sectorPortals); } void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakeFloor) @@ -146,8 +146,14 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, subsector_t *s PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); } -void RenderPolyPlane::Render(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight) +void RenderPolyPlane::Render(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals) { + FSectorPortal *portal = sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor); + if (portal && sectorPortals.empty()) + { + sectorPortals.push_back(std::make_unique(portal, ceiling)); + } + sector_t *fakesector = sub->sector->heightsec; if (fakesector && (fakesector == sub->sector || (fakesector->MoreFlags & SECF_IGNOREHEIGHTSEC) == SECF_IGNOREHEIGHTSEC)) fakesector = nullptr; @@ -237,13 +243,29 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, subsector_t *sub, uin if (!isSky) { - args.SetTexture(tex); - PolyTriangleDrawer::draw(args, TriDrawVariant::DrawNormal, TriBlendMode::Copy); - PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); + if (!portal) + { + args.SetTexture(tex); + PolyTriangleDrawer::draw(args, TriDrawVariant::DrawNormal, TriBlendMode::Copy); + PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); + } + else + { + args.stencilwritevalue = 252; + PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); + } } else { - args.stencilwritevalue = 255; + if (portal) + { + args.stencilwritevalue = 252; + } + else + { + args.stencilwritevalue = 255; + } + PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); for (uint32_t i = 0; i < sub->numlines; i++) diff --git a/src/r_poly_plane.h b/src/r_poly_plane.h index d36bb70dcb..6e418bf502 100644 --- a/src/r_poly_plane.h +++ b/src/r_poly_plane.h @@ -24,13 +24,15 @@ #include "r_poly_triangle.h" +class PolyDrawSectorPortal; + class RenderPolyPlane { public: - static void RenderPlanes(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight); + static void RenderPlanes(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals); private: void Render3DFloor(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakefloor); - void Render(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight); + void Render(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals); TriVertex PlaneVertex(vertex_t *v1, double height); }; diff --git a/src/r_poly_portal.cpp b/src/r_poly_portal.cpp index 6b37d6424b..aad43986bf 100644 --- a/src/r_poly_portal.cpp +++ b/src/r_poly_portal.cpp @@ -29,9 +29,18 @@ #include "gl/data/gl_data.h" CVAR(Bool, r_debug_cull, 0, 0) +EXTERN_CVAR(Int, r_portal_recursions) ///////////////////////////////////////////////////////////////////////////// +RenderPolyPortal::RenderPolyPortal() +{ +} + +RenderPolyPortal::~RenderPolyPortal() +{ +} + void RenderPolyPortal::SetViewpoint(const TriMatrix &worldToClip, uint32_t stencilValue) { WorldToClip = worldToClip; @@ -43,7 +52,9 @@ void RenderPolyPortal::Render() ClearBuffers(); Cull.CullScene(WorldToClip); RenderSectors(); - for (auto &portal : Portals) + for (auto &portal : SectorPortals) + portal->Render(); + for (auto &portal : LinePortals) portal->Render(); } @@ -53,7 +64,8 @@ void RenderPolyPortal::ClearBuffers() SectorSpriteRanges.resize(numsectors); SortedSprites.clear(); TranslucentObjects.clear(); - Portals.clear(); + SectorPortals.clear(); + LinePortals.clear(); NextSubsectorDepth = 0; } @@ -80,10 +92,7 @@ void RenderPolyPortal::RenderSubsector(subsector_t *sub) if (sub->sector->CenterFloor() != sub->sector->CenterCeiling()) { - RenderPolyPlane::RenderPlanes(WorldToClip, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight); - - FSectorPortal *ceilingPortal = frontsector->ValidatePortal(sector_t::ceiling); - FSectorPortal *floorPortal = frontsector->ValidatePortal(sector_t::floor); + RenderPolyPlane::RenderPlanes(WorldToClip, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); } for (uint32_t i = 0; i < sub->numlines; i++) @@ -181,7 +190,10 @@ void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *front void RenderPolyPortal::RenderTranslucent() { - for (auto it = Portals.rbegin(); it != Portals.rend(); ++it) + for (auto it = SectorPortals.rbegin(); it != SectorPortals.rend(); ++it) + (*it)->RenderTranslucent(); + + for (auto it = LinePortals.rbegin(); it != LinePortals.rend(); ++it) (*it)->RenderTranslucent(); for (auto it = TranslucentObjects.rbegin(); it != TranslucentObjects.rend(); ++it) @@ -208,3 +220,94 @@ void RenderPolyPortal::RenderTranslucent() } } } + +///////////////////////////////////////////////////////////////////////////// + +PolyDrawSectorPortal::PolyDrawSectorPortal(FSectorPortal *portal, bool ceiling) : Portal(portal), Ceiling(ceiling) +{ +} + +void PolyDrawSectorPortal::Render() +{ + if (Portal->mType != PORTS_SKYVIEWPOINT) + return; + + static int recursion = 0; + if (recursion >= 1/*r_portal_recursions*/) + return; + recursion++; + + int savedextralight = extralight; + DVector3 savedpos = ViewPos; + DAngle savedangle = ViewAngle; + double savedvisibility = R_GetVisibility(); + AActor *savedcamera = camera; + sector_t *savedsector = viewsector; + + // Don't let gun flashes brighten the sky box + ASkyViewpoint *sky = barrier_cast(Portal->mSkybox); + extralight = 0; + R_SetVisibility(sky->args[0] * 0.25f); + ViewPos = sky->InterpolatedPosition(r_TicFracF); + ViewAngle = savedangle + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * r_TicFracF); + + camera = nullptr; + viewsector = Portal->mDestination; + R_SetViewAngle(); + + // To do: get this information from RenderPolyScene instead of duplicating the code.. + double radPitch = ViewPitch.Normalized180().Radians(); + double angx = cos(radPitch); + double angy = sin(radPitch) * glset.pixelstretch; + double alen = sqrt(angx*angx + angy*angy); + float adjustedPitch = (float)asin(angy / alen); + float adjustedViewAngle = (float)(ViewAngle - 90).Radians(); + float ratio = WidescreenRatio; + float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio; + float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(FieldOfView.Radians() / 2) / fovratio)).Degrees); + TriMatrix worldToView = + TriMatrix::rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) * + TriMatrix::rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) * + TriMatrix::scale(1.0f, glset.pixelstretch, 1.0f) * + TriMatrix::swapYZ() * + TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z); + TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; + + RenderPortal.SetViewpoint(worldToClip, 252); + RenderPortal.Render(); + + camera = savedcamera; + viewsector = savedsector; + ViewPos = savedpos; + R_SetVisibility(savedvisibility); + extralight = savedextralight; + ViewAngle = savedangle; + R_SetViewAngle(); + + recursion--; +} + +void PolyDrawSectorPortal::RenderTranslucent() +{ + /*if (Portal->mType != PORTS_SKYVIEWPOINT) + return; + + RenderPortal.RenderTranslucent();*/ +} + +///////////////////////////////////////////////////////////////////////////// + +PolyDrawLinePortal::PolyDrawLinePortal(line_t *src, line_t *dest, bool mirror) : Src(src), Dest(dest) +{ + // To do: do what R_EnterPortal and PortalDrawseg does +} + +void PolyDrawLinePortal::Render() +{ + RenderPortal.Render(); +} + +void PolyDrawLinePortal::RenderTranslucent() +{ + RenderPortal.RenderTranslucent(); +} diff --git a/src/r_poly_portal.h b/src/r_poly_portal.h index 364f2dcfb4..34e4666f78 100644 --- a/src/r_poly_portal.h +++ b/src/r_poly_portal.h @@ -74,10 +74,15 @@ public: int Count = 0; }; +class PolyDrawSectorPortal; +class PolyDrawLinePortal; + // Renders everything from a specific viewpoint class RenderPolyPortal { public: + RenderPolyPortal(); + ~RenderPolyPortal(); void SetViewpoint(const TriMatrix &worldToClip, uint32_t stencilValue); void Render(); void RenderTranslucent(); @@ -101,5 +106,34 @@ private: std::vector TranslucentObjects; std::vector SubsectorTranslucentWalls; - std::vector> Portals; + std::vector> SectorPortals; + std::vector> LinePortals; +}; + +class PolyDrawSectorPortal +{ +public: + PolyDrawSectorPortal(FSectorPortal *portal, bool ceiling); + + void Render(); + void RenderTranslucent(); + +private: + FSectorPortal *Portal; + bool Ceiling; + RenderPolyPortal RenderPortal; +}; + +class PolyDrawLinePortal +{ +public: + PolyDrawLinePortal(line_t *src, line_t *dest, bool mirror); + + void Render(); + void RenderTranslucent(); + +private: + line_t *Src; + line_t *Dest; + RenderPolyPortal RenderPortal; }; diff --git a/src/r_poly_wall.cpp b/src/r_poly_wall.cpp index f49908965f..a417784d35 100644 --- a/src/r_poly_wall.cpp +++ b/src/r_poly_wall.cpp @@ -39,6 +39,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, seg_t *line, secto wall.Colormap = frontsector->ColorMap; wall.Masked = false; wall.SubsectorDepth = subsectorDepth; + wall.StencilValue = stencilValue; double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1); double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1); @@ -134,6 +135,7 @@ void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, seg_t *line wall.Colormap = frontsector->ColorMap; wall.Masked = false; wall.SubsectorDepth = subsectorDepth; + wall.StencilValue = stencilValue; wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2); wall.TopZ = frontceilz1; wall.BottomZ = frontfloorz1;