From e71e4b6dc8dc18365cb914b3595756f045d61633 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 30 Sep 2017 23:58:11 +0200 Subject: [PATCH] - Improved transfer heights support in softpoly --- src/polyrenderer/scene/poly_plane.cpp | 188 ++++--------------- src/polyrenderer/scene/poly_plane.h | 24 +-- src/polyrenderer/scene/poly_playersprite.cpp | 10 +- src/polyrenderer/scene/poly_scene.cpp | 162 +++++++++++++++- src/polyrenderer/scene/poly_scene.h | 22 +++ src/polyrenderer/scene/poly_wall.cpp | 11 +- src/polyrenderer/scene/poly_wall.h | 1 + 7 files changed, 235 insertions(+), 183 deletions(-) diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp index b642057c3..f5485d096 100644 --- a/src/polyrenderer/scene/poly_plane.cpp +++ b/src/polyrenderer/scene/poly_plane.cpp @@ -36,46 +36,46 @@ EXTERN_CVAR(Int, r_3dfloors) -void RenderPolyPlane::RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals) +void RenderPolyPlane::RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals) { - if (sub->sector->CenterFloor() == sub->sector->CenterCeiling()) + if (fakeflat.FrontSector->CenterFloor() == fakeflat.FrontSector->CenterCeiling()) return; RenderPolyPlane plane; - plane.Render(thread, worldToClip, clipPlane, sub, stencilValue, true, skyCeilingHeight, sectorPortals); - plane.Render(thread, worldToClip, clipPlane, sub, stencilValue, false, skyFloorHeight, sectorPortals); + plane.Render(thread, worldToClip, clipPlane, fakeflat, stencilValue, true, skyCeilingHeight, sectorPortals); + plane.Render(thread, worldToClip, clipPlane, fakeflat, stencilValue, false, skyFloorHeight, sectorPortals); } -void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals) +void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals) { - FSectorPortal *portal = sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor); + FSectorPortal *portal = fakeflat.FrontSector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor); if (!portal || (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into { - RenderNormal(thread, worldToClip, clipPlane, sub, stencilValue, ceiling, skyHeight); + RenderNormal(thread, worldToClip, clipPlane, fakeflat, stencilValue, ceiling, skyHeight); } else { - RenderPortal(thread, worldToClip, clipPlane, sub, stencilValue, ceiling, skyHeight, portal, sectorPortals); + RenderPortal(thread, worldToClip, clipPlane, fakeflat, stencilValue, ceiling, skyHeight, portal, sectorPortals); } } -void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight) +void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight) { const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; - - FTextureID picnum = GetPlaneTexture(sub, ceiling); + + FTextureID picnum = fakeflat.FrontSector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor); if (picnum != skyflatnum) { FTexture *tex = TexMan(picnum); if (!tex || tex->UseType == FTexture::TEX_Null) return; - PolyPlaneUVTransform transform = GetPlaneTransform(sub, ceiling, tex); - TriVertex *vertices = CreatePlaneVertices(thread, sub, transform, GetSecPlane(sub, ceiling)); + PolyPlaneUVTransform transform = PolyPlaneUVTransform(ceiling ? fakeflat.FrontSector->planes[sector_t::ceiling].xform : fakeflat.FrontSector->planes[sector_t::floor].xform, tex); + TriVertex *vertices = CreatePlaneVertices(thread, fakeflat.Subsector, transform, ceiling ? fakeflat.FrontSector->ceilingplane : fakeflat.FrontSector->floorplane); PolyDrawArgs args; - SetLightLevel(thread, args, sub, ceiling); - SetDynLights(thread, args, sub, ceiling); + SetLightLevel(thread, args, fakeflat, ceiling); + SetDynLights(thread, args, fakeflat.Subsector, ceiling); args.SetTransform(&worldToClip); args.SetFaceCullCCW(true); args.SetStencilTestValue(stencilValue); @@ -83,11 +83,11 @@ void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const TriMatrix &wo args.SetClipPlane(0, clipPlane); args.SetTexture(tex); args.SetStyle(TriBlendMode::TextureOpaque); - args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan); + args.DrawArray(thread, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan); } else { - TriVertex *vertices = CreateSkyPlaneVertices(thread, sub, skyHeight); + TriVertex *vertices = CreateSkyPlaneVertices(thread, fakeflat.Subsector, skyHeight); PolyDrawArgs args; args.SetTransform(&worldToClip); @@ -98,24 +98,22 @@ void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const TriMatrix &wo args.SetWriteStencil(true, 255); args.SetWriteColor(false); args.SetWriteDepth(false); - args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan); + args.DrawArray(thread, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan); - RenderSkyWalls(thread, args, sub, nullptr, ceiling, skyHeight); + RenderSkyWalls(thread, args, fakeflat.Subsector, nullptr, ceiling, skyHeight); } } -void RenderPolyPlane::RenderPortal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector> §orPortals) +void RenderPolyPlane::RenderPortal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector> §orPortals) { const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; PolyDrawSectorPortal *polyportal = nullptr; std::vector portalSegments; - sector_t *frontsector = sub->sector; - // Skip portals not facing the camera - if ((ceiling && frontsector->ceilingplane.PointOnSide(viewpoint.Pos) < 0) || - (!ceiling && frontsector->floorplane.PointOnSide(viewpoint.Pos) < 0)) + if ((ceiling && fakeflat.FrontSector->ceilingplane.PointOnSide(viewpoint.Pos) < 0) || + (!ceiling && fakeflat.FrontSector->floorplane.PointOnSide(viewpoint.Pos) < 0)) { return; } @@ -159,7 +157,7 @@ void RenderPolyPlane::RenderPortal(PolyRenderThread *thread, const TriMatrix &wo } #endif - TriVertex *vertices = CreateSkyPlaneVertices(thread, sub, skyHeight); + TriVertex *vertices = CreateSkyPlaneVertices(thread, fakeflat.Subsector, skyHeight); PolyDrawArgs args; args.SetTransform(&worldToClip); @@ -170,11 +168,11 @@ void RenderPolyPlane::RenderPortal(PolyRenderThread *thread, const TriMatrix &wo args.SetWriteStencil(true, polyportal->StencilValue); args.SetWriteColor(false); args.SetWriteDepth(false); - args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan); + args.DrawArray(thread, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan); - RenderSkyWalls(thread, args, sub, polyportal, ceiling, skyHeight); + RenderSkyWalls(thread, args, fakeflat.Subsector, polyportal, ceiling, skyHeight); - polyportal->Shape.push_back({ vertices, (int)sub->numlines, true }); + polyportal->Shape.push_back({ vertices, (int)fakeflat.Subsector->numlines, true }); } void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight) @@ -257,139 +255,21 @@ void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &arg } } -sector_t *RenderPolyPlane::GetHeightSec(subsector_t *sub, bool ceiling) +void RenderPolyPlane::SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, const PolyTransferHeights &fakeflat, bool ceiling) { - sector_t *controlsector = sub->sector->GetHeightSec(); - if (!controlsector || controlsector == sub->sector || (ceiling && !!(controlsector->MoreFlags & SECF_FAKEFLOORONLY))) - return nullptr; - else - return controlsector; -} + bool foggy = level.fadeto || fakeflat.FrontSector->Colormap.FadeColor || (level.flags & LEVEL_HASFADETABLE); -HeightSecLocation RenderPolyPlane::GetHeightSecLocation(sector_t *controlsector) -{ - const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; - if (viewpoint.Pos.Z > controlsector->ceilingplane.ZatPoint(viewpoint.Pos.XY())) // Above control sector ceiling (A) - return HeightSecLocation::Above; - else if (viewpoint.Pos.Z > controlsector->floorplane.ZatPoint(viewpoint.Pos.XY())) // Between control sector ceiling and floor (B) - return HeightSecLocation::Between; - else - return HeightSecLocation::Below; -} - -FTextureID RenderPolyPlane::GetPlaneTexture(subsector_t *sub, bool ceiling) -{ - sector_t *controlsector = GetHeightSec(sub, ceiling); - if (!controlsector) - return sub->sector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor); - - bool diffTex = !!(controlsector->MoreFlags & SECF_CLIPFAKEPLANES); - - switch (GetHeightSecLocation(controlsector)) - { - default: - case HeightSecLocation::Above: - if (diffTex && ceiling) - return sub->sector->GetTexture(sector_t::ceiling); - else - return controlsector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor); - - case HeightSecLocation::Between: - return sub->sector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor); - - case HeightSecLocation::Below: - if (diffTex && !ceiling) - return sub->sector->GetTexture(sector_t::floor); - else - return controlsector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor); - } -} - -PolyPlaneUVTransform RenderPolyPlane::GetPlaneTransform(subsector_t *sub, bool ceiling, FTexture *tex) -{ - sector_t *controlsector = GetHeightSec(sub, ceiling); - if (!controlsector) - return PolyPlaneUVTransform(ceiling ? sub->sector->planes[sector_t::ceiling].xform : sub->sector->planes[sector_t::floor].xform, tex); - - bool diffTex = !!(controlsector->MoreFlags & SECF_CLIPFAKEPLANES); - - switch (GetHeightSecLocation(controlsector)) - { - default: - case HeightSecLocation::Above: - if (diffTex && ceiling) - return PolyPlaneUVTransform(sub->sector->planes[sector_t::ceiling].xform, tex); - else - return PolyPlaneUVTransform(ceiling ? controlsector->planes[sector_t::ceiling].xform : controlsector->planes[sector_t::floor].xform, tex); - - case HeightSecLocation::Between: - return PolyPlaneUVTransform(ceiling ? sub->sector->planes[sector_t::ceiling].xform : sub->sector->planes[sector_t::floor].xform, tex); - - case HeightSecLocation::Below: - if (diffTex && !ceiling) - return PolyPlaneUVTransform(sub->sector->planes[sector_t::floor].xform, tex); - else - return PolyPlaneUVTransform(ceiling ? controlsector->planes[sector_t::ceiling].xform : controlsector->planes[sector_t::floor].xform, tex); - } -} - -const secplane_t &RenderPolyPlane::GetSecPlane(subsector_t *sub, bool ceiling) -{ - sector_t *controlsector = GetHeightSec(sub, ceiling); - if (!controlsector) - return ceiling ? sub->sector->ceilingplane : sub->sector->floorplane; - - switch (GetHeightSecLocation(controlsector)) - { - default: - case HeightSecLocation::Above: - return ceiling ? sub->sector->ceilingplane : controlsector->ceilingplane; - case HeightSecLocation::Between: - return ceiling ? controlsector->ceilingplane : controlsector->floorplane; - case HeightSecLocation::Below: - return ceiling ? controlsector->floorplane : sub->sector->floorplane; - } -} - -void RenderPolyPlane::SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling) -{ - sector_t *lightSector = sub->sector; - sector_t *controlsector = GetHeightSec(sub, ceiling); - if (controlsector) - { - bool diffTex = !!(controlsector->MoreFlags & SECF_CLIPFAKEPLANES); - bool noFakeLight = !!(controlsector->MoreFlags & SECF_NOFAKELIGHT); - - switch (GetHeightSecLocation(controlsector)) - { - default: - case HeightSecLocation::Above: - // todo: upper texture as colormap - lightSector = controlsector; - break; - case HeightSecLocation::Between: - // normal texture as colormap - break; - case HeightSecLocation::Below: - // todo: lower texture as colormap - lightSector = controlsector; - break; - } - } - - bool foggy = level.fadeto || lightSector->Colormap.FadeColor || (level.flags & LEVEL_HASFADETABLE); - - int lightlevel = ceiling ? lightSector->GetCeilingLight() : lightSector->GetFloorLight(); + int lightlevel = ceiling ? fakeflat.CeilingLightLevel : fakeflat.FloorLightLevel; int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4; lightlevel = clamp(lightlevel + actualextralight, 0, 255); PolyCameraLight *cameraLight = PolyCameraLight::Instance(); - FDynamicColormap *basecolormap = GetColorTable(lightSector->Colormap, lightSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]); - if (cameraLight->FixedLightLevel() < 0 && lightSector->e && lightSector->e->XFloor.lightlist.Size()) + FDynamicColormap *basecolormap = GetColorTable(fakeflat.FrontSector->Colormap, fakeflat.FrontSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]); + if (cameraLight->FixedLightLevel() < 0 && fakeflat.FrontSector->e && fakeflat.FrontSector->e->XFloor.lightlist.Size()) { - lightlist_t *light = P_GetPlaneLight(lightSector, ceiling ? &lightSector->ceilingplane : &lightSector->floorplane, false); - basecolormap = GetColorTable(light->extra_colormap, lightSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]); - if (light->p_lightlevel != &lightSector->lightlevel) // If this is the real ceiling, don't discard plane lighting R_FakeFlat() accounted for. + lightlist_t *light = P_GetPlaneLight(fakeflat.FrontSector, ceiling ? &fakeflat.FrontSector->ceilingplane : &fakeflat.FrontSector->floorplane, false); + basecolormap = GetColorTable(light->extra_colormap, fakeflat.FrontSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]); + if (light->p_lightlevel != &fakeflat.FrontSector->lightlevel) // If this is the real ceiling, don't discard plane lighting R_FakeFlat() accounted for. { lightlevel = *light->p_lightlevel; } diff --git a/src/polyrenderer/scene/poly_plane.h b/src/polyrenderer/scene/poly_plane.h index 30d374e62..c4af370c7 100644 --- a/src/polyrenderer/scene/poly_plane.h +++ b/src/polyrenderer/scene/poly_plane.h @@ -54,36 +54,22 @@ private: float xOffs, yOffs; }; -enum class HeightSecLocation -{ - Above, // Above control sector ceiling (A) - Between, // Between control sector ceiling and floor (B) - Below // Below control sector floor (C) -}; - class RenderPolyPlane { public: - static void RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals); + static void RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals); private: - void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals); + void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals); - void RenderPortal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector> §orPortals); - void RenderNormal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight); + void RenderPortal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector> §orPortals); + void RenderNormal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight); void RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight); - void SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling); + void SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, const PolyTransferHeights &fakeflat, bool ceiling); void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling); - FTextureID GetPlaneTexture(subsector_t *sub, bool ceiling); - PolyPlaneUVTransform GetPlaneTransform(subsector_t *sub, bool ceiling, FTexture *texture); - const secplane_t &GetSecPlane(subsector_t *sub, bool ceiling); - - sector_t *GetHeightSec(subsector_t *sub, bool ceiling); - HeightSecLocation GetHeightSecLocation(sector_t *controlsector); - TriVertex *CreatePlaneVertices(PolyRenderThread *thread, subsector_t *sub, const PolyPlaneUVTransform &transform, const secplane_t &plane); TriVertex *CreateSkyPlaneVertices(PolyRenderThread *thread, subsector_t *sub, double skyHeight); diff --git a/src/polyrenderer/scene/poly_playersprite.cpp b/src/polyrenderer/scene/poly_playersprite.cpp index 57fc52c5b..8d467ef0a 100644 --- a/src/polyrenderer/scene/poly_playersprite.cpp +++ b/src/polyrenderer/scene/poly_playersprite.cpp @@ -57,6 +57,8 @@ void RenderPolyPlayerSprites::Render(PolyRenderThread *thread) (r_deathcamera && viewpoint.camera->health <= 0)) return; + PolyTransferHeights fakeflat(viewpoint.camera->subsector); + FDynamicColormap *basecolormap; PolyCameraLight *cameraLight = PolyCameraLight::Instance(); if (cameraLight->FixedLightLevel() < 0 && viewpoint.sector->e && viewpoint.sector->e->XFloor.lightlist.Size()) @@ -89,10 +91,10 @@ void RenderPolyPlayerSprites::Render(PolyRenderThread *thread) else { // This used to use camera->Sector but due to interpolation that can be incorrect // when the interpolated viewpoint is in a different sector than the camera. - //sec = FakeFlat(viewpoint.sector, &tempsec, &floorlight, &ceilinglight, nullptr, 0, 0, 0, 0); - // Softpoly has no FakeFlat (its FAKE! Everything is FAKE in Doom. Sigh. Might as well call it FooFlat!) - sec = viewpoint.camera->Sector; - floorlight = ceilinglight = sec->lightlevel; + + sec = fakeflat.FrontSector; + floorlight = fakeflat.FloorLightLevel; + ceilinglight = fakeflat.CeilingLightLevel; // [RH] set basecolormap basecolormap = GetColorTable(sec->Colormap, sec->SpecialColors[sector_t::sprites], true); diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp index a9a9cbf40..02ad1842e 100644 --- a/src/polyrenderer/scene/poly_scene.cpp +++ b/src/polyrenderer/scene/poly_scene.cpp @@ -126,15 +126,17 @@ void RenderPolyScene::RenderSubsector(PolyRenderThread *thread, subsector_t *sub } else { + PolyTransferHeights fakeflat(sub); + Render3DFloorPlane::RenderPlanes(thread, WorldToClip, PortalPlane, sub, StencilValue, subsectorDepth, TranslucentObjects[thread->ThreadIndex]); - RenderPolyPlane::RenderPlanes(thread, WorldToClip, PortalPlane, sub, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); + RenderPolyPlane::RenderPlanes(thread, WorldToClip, PortalPlane, fakeflat, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); for (uint32_t i = 0; i < sub->numlines; i++) { if (Cull.IsLineSegVisible(subsectorDepth, i)) { seg_t *line = &sub->firstline[i]; - RenderLine(thread, sub, line, frontsector, subsectorDepth); + RenderLine(thread, sub, line, fakeflat.FrontSector, subsectorDepth); } } } @@ -393,3 +395,159 @@ void RenderPolyScene::RenderTranslucent(int portalDepth) TranslucentObjects[0].clear(); } + +///////////////////////////////////////////////////////////////////////////// + +PolyTransferHeights::PolyTransferHeights(subsector_t *sub) : Subsector(sub) +{ + sector_t *sec = sub->sector; + + // If player's view height is underneath fake floor, lower the + // drawn ceiling to be just under the floor height, and replace + // the drawn floor and ceiling textures, and light level, with + // the control sector's. + // + // Similar for ceiling, only reflected. + + // [RH] allow per-plane lighting + FloorLightLevel = sec->GetFloorLight(); + CeilingLightLevel = sec->GetCeilingLight(); + + FakeSide = PolyWaterFakeSide::Center; + + const sector_t *s = sec->GetHeightSec(); + if (s != nullptr) + { + sector_t *heightsec = PolyRenderer::Instance()->Viewpoint.sector->heightsec; + bool underwater = (heightsec && heightsec->floorplane.PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos) <= 0); + bool doorunderwater = false; + int diffTex = (s->MoreFlags & SECF_CLIPFAKEPLANES); + + // Replace sector being drawn with a copy to be hacked + tempsec = *sec; + + // Replace floor and ceiling height with control sector's heights. + if (diffTex) + { + if (s->floorplane.CopyPlaneIfValid(&tempsec.floorplane, &sec->ceilingplane)) + { + tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false); + } + else if (s->MoreFlags & SECF_FAKEFLOORONLY) + { + if (underwater) + { + tempsec.Colormap = s->Colormap; + if (!(s->MoreFlags & SECF_NOFAKELIGHT)) + { + tempsec.lightlevel = s->lightlevel; + + FloorLightLevel = s->GetFloorLight(); + CeilingLightLevel = s->GetCeilingLight(); + } + FakeSide = PolyWaterFakeSide::BelowFloor; + FrontSector = &tempsec; + return; + } + FrontSector = sec; + return; + } + } + else + { + tempsec.floorplane = s->floorplane; + } + + if (!(s->MoreFlags & SECF_FAKEFLOORONLY)) + { + if (diffTex) + { + if (s->ceilingplane.CopyPlaneIfValid(&tempsec.ceilingplane, &sec->floorplane)) + { + tempsec.SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false); + } + } + else + { + tempsec.ceilingplane = s->ceilingplane; + } + } + + double refceilz = s->ceilingplane.ZatPoint(PolyRenderer::Instance()->Viewpoint.Pos); + double orgceilz = sec->ceilingplane.ZatPoint(PolyRenderer::Instance()->Viewpoint.Pos); + + if (underwater || doorunderwater) + { + tempsec.floorplane = sec->floorplane; + tempsec.ceilingplane = s->floorplane; + tempsec.ceilingplane.FlipVert(); + tempsec.ceilingplane.ChangeHeight(-1 / 65536.); + tempsec.Colormap = s->Colormap; + } + + // killough 11/98: prevent sudden light changes from non-water sectors: + if (underwater || doorunderwater) + { + // head-below-floor hack + tempsec.SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false); + tempsec.planes[sector_t::floor].xform = s->planes[sector_t::floor].xform; + + tempsec.ceilingplane = s->floorplane; + tempsec.ceilingplane.FlipVert(); + tempsec.ceilingplane.ChangeHeight(-1 / 65536.); + if (s->GetTexture(sector_t::ceiling) == skyflatnum) + { + tempsec.floorplane = tempsec.ceilingplane; + tempsec.floorplane.FlipVert(); + tempsec.floorplane.ChangeHeight(+1 / 65536.); + tempsec.SetTexture(sector_t::ceiling, tempsec.GetTexture(sector_t::floor), false); + tempsec.planes[sector_t::ceiling].xform = tempsec.planes[sector_t::floor].xform; + } + else + { + tempsec.SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false); + tempsec.planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform; + } + + if (!(s->MoreFlags & SECF_NOFAKELIGHT)) + { + tempsec.lightlevel = s->lightlevel; + + FloorLightLevel = s->GetFloorLight(); + CeilingLightLevel = s->GetCeilingLight(); + } + FakeSide = PolyWaterFakeSide::BelowFloor; + } + else if (heightsec && heightsec->ceilingplane.PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos) <= 0 && orgceilz > refceilz && !(s->MoreFlags & SECF_FAKEFLOORONLY)) + { + // Above-ceiling hack + tempsec.ceilingplane = s->ceilingplane; + tempsec.floorplane = s->ceilingplane; + tempsec.floorplane.FlipVert(); + tempsec.floorplane.ChangeHeight(+1 / 65536.); + tempsec.Colormap = s->Colormap; + + tempsec.SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false); + tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false); + tempsec.planes[sector_t::ceiling].xform = tempsec.planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform; + + if (s->GetTexture(sector_t::floor) != skyflatnum) + { + tempsec.ceilingplane = sec->ceilingplane; + tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false); + tempsec.planes[sector_t::floor].xform = s->planes[sector_t::floor].xform; + } + + if (!(s->MoreFlags & SECF_NOFAKELIGHT)) + { + tempsec.lightlevel = s->lightlevel; + + FloorLightLevel = s->GetFloorLight(); + CeilingLightLevel = s->GetCeilingLight(); + } + FakeSide = PolyWaterFakeSide::AboveCeiling; + } + sec = &tempsec; + } + FrontSector = sec; +} diff --git a/src/polyrenderer/scene/poly_scene.h b/src/polyrenderer/scene/poly_scene.h index bf2d1b21d..db9394eb6 100644 --- a/src/polyrenderer/scene/poly_scene.h +++ b/src/polyrenderer/scene/poly_scene.h @@ -89,3 +89,25 @@ private: std::vector> SectorPortals; std::vector> LinePortals; }; + +enum class PolyWaterFakeSide +{ + Center, + BelowFloor, + AboveCeiling +}; + +class PolyTransferHeights +{ +public: + PolyTransferHeights(subsector_t *sub); + + subsector_t *Subsector = nullptr; + sector_t *FrontSector = nullptr; + PolyWaterFakeSide FakeSide = PolyWaterFakeSide::Center; + int FloorLightLevel = 0; + int CeilingLightLevel = 0; + +private: + sector_t tempsec; +}; diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index aba99a85a..20b9a1ade 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -96,6 +96,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, const TriMatrix &world wall.Masked = false; wall.SubsectorDepth = subsectorDepth; wall.StencilValue = stencilValue; + wall.SectorLightLevel = frontsector->lightlevel; if (line->backsector == nullptr) { @@ -111,9 +112,10 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, const TriMatrix &world return true; } } - else + else if (line->PartnerSeg) { - sector_t *backsector = line->backsector; + PolyTransferHeights fakeback(line->PartnerSeg->Subsector); + sector_t *backsector = fakeback.FrontSector; double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1); double backfloorz1 = backsector->floorplane.ZatPoint(line->v1); @@ -215,6 +217,7 @@ void RenderPolyWall::Render3DFloorLine(PolyRenderThread *thread, const TriMatrix wall.Line = fakeFloor->master; wall.Side = fakeFloor->master->sidedef[0]; wall.Colormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]); + wall.SectorLightLevel = frontsector->lightlevel; wall.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS); if (!wall.Additive && fakeFloor->alpha == 255) { @@ -318,7 +321,7 @@ void RenderPolyWall::Render(PolyRenderThread *thread, const TriMatrix &worldToCl } PolyDrawArgs args; - args.SetLight(GetColorTable(Line->frontsector->Colormap, Line->frontsector->SpecialColors[sector_t::walltop]), GetLightLevel(), PolyRenderer::Instance()->Light.WallGlobVis(foggy), false); + args.SetLight(Colormap, GetLightLevel(), PolyRenderer::Instance()->Light.WallGlobVis(foggy), false); args.SetTransform(&worldToClip); args.SetFaceCullCCW(true); args.SetStencilTestValue(StencilValue); @@ -553,7 +556,7 @@ int RenderPolyWall::GetLightLevel() { bool foggy = false; int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4; - return clamp(Side->GetLightLevel(foggy, LineSeg->frontsector->lightlevel) + actualextralight, 0, 255); + return clamp(Side->GetLightLevel(foggy, SectorLightLevel) + actualextralight, 0, 255); } } diff --git a/src/polyrenderer/scene/poly_wall.h b/src/polyrenderer/scene/poly_wall.h index 6cb7aae2f..5b2385db6 100644 --- a/src/polyrenderer/scene/poly_wall.h +++ b/src/polyrenderer/scene/poly_wall.h @@ -55,6 +55,7 @@ public: double UnpeggedCeil1 = 0.0; double UnpeggedCeil2 = 0.0; FSWColormap *Colormap = nullptr; + int SectorLightLevel = 0; bool Masked = false; bool Additive = false; double Alpha = 1.0;