From 0ee021a97248dbec97713342519ea7ff15fea913 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 29 Sep 2017 05:23:17 +0200 Subject: [PATCH] - Improve transfer heights support in softpoly --- src/polyrenderer/scene/poly_plane.cpp | 655 +++++++++++++++----------- src/polyrenderer/scene/poly_plane.h | 27 +- 2 files changed, 399 insertions(+), 283 deletions(-) diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp index 2ec86327e..b642057c3 100644 --- a/src/polyrenderer/scene/poly_plane.cpp +++ b/src/polyrenderer/scene/poly_plane.cpp @@ -47,238 +47,357 @@ void RenderPolyPlane::RenderPlanes(PolyRenderThread *thread, const TriMatrix &wo } void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals) +{ + FSectorPortal *portal = sub->sector->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); + } + else + { + RenderPortal(thread, worldToClip, clipPlane, sub, 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) { const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; - sector_t *fakesector = sub->sector->heightsec; - if (fakesector && (fakesector == sub->sector || (fakesector->MoreFlags & SECF_IGNOREHEIGHTSEC) == SECF_IGNOREHEIGHTSEC)) - fakesector = nullptr; - - bool fakeflooronly = fakesector && (fakesector->MoreFlags & SECF_FAKEFLOORONLY) == SECF_FAKEFLOORONLY; - - FTextureID picnum; - bool ccw; - sector_t *frontsector; - if (fakesector) + FTextureID picnum = GetPlaneTexture(sub, ceiling); + if (picnum != skyflatnum) { - // Floor and ceiling texture needs to be swapped sometimes? Why?? :( - - if (viewpoint.Pos.Z < fakesector->floorplane.Zat0()) // In water - { - if (ceiling) - { - picnum = fakesector->GetTexture(sector_t::ceiling); - ceiling = false; - frontsector = fakesector; - ccw = false; - } - else - { - picnum = fakesector->GetTexture(sector_t::floor); - frontsector = sub->sector; - ccw = true; - } - } - else if (viewpoint.Pos.Z >= fakesector->ceilingplane.Zat0() && !fakeflooronly) // In ceiling water - { - if (ceiling) - { - picnum = fakesector->GetTexture(sector_t::ceiling); - frontsector = sub->sector; - ccw = true; - } - else - { - picnum = fakesector->GetTexture(sector_t::floor); - frontsector = fakesector; - ccw = false; - ceiling = true; - } - } - else if (!ceiling) // Water surface - { - picnum = fakesector->GetTexture(sector_t::ceiling); - frontsector = fakesector; - ccw = true; - } - else if (!fakeflooronly) // Ceiling water surface - { - picnum = fakesector->GetTexture(sector_t::floor); - frontsector = fakesector; - ccw = true; - } - else // Upper ceiling - { - picnum = sub->sector->GetTexture(sector_t::ceiling); - ccw = true; - frontsector = sub->sector; - } - } - else - { - picnum = sub->sector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor); - ccw = true; - frontsector = sub->sector; - } - - FTexture *tex = TexMan(picnum); - if (tex->UseType == FTexture::TEX_Null) - return; - - std::vector portalSegments; - FSectorPortal *portal = sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor); - PolyDrawSectorPortal *polyportal = nullptr; - if (portal && (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into - portal = nullptr; - - bool isSky = portal || picnum == skyflatnum; - - if (portal) - { - // Skip portals not facing the camera - if ((ceiling && frontsector->ceilingplane.PointOnSide(viewpoint.Pos) < 0) || - (!ceiling && frontsector->floorplane.PointOnSide(viewpoint.Pos) < 0)) - { + FTexture *tex = TexMan(picnum); + if (!tex || tex->UseType == FTexture::TEX_Null) return; - } - for (auto &p : sectorPortals) - { - if (p->Portal == portal) // To do: what other criteria do we need to check for? - { - polyportal = p.get(); - break; - } - } - if (!polyportal) - { - sectorPortals.push_back(std::unique_ptr(new PolyDrawSectorPortal(portal, ceiling))); - polyportal = sectorPortals.back().get(); - } + PolyPlaneUVTransform transform = GetPlaneTransform(sub, ceiling, tex); + TriVertex *vertices = CreatePlaneVertices(thread, sub, transform, GetSecPlane(sub, ceiling)); -#if 0 - // Calculate portal clipping - portalSegments.reserve(sub->numlines); - for (uint32_t i = 0; i < sub->numlines; i++) - { - seg_t *line = &sub->firstline[i]; - - DVector2 pt1 = line->v1->fPos() - viewpoint.Pos; - DVector2 pt2 = line->v2->fPos() - viewpoint.Pos; - bool backside = pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0; - if (!backside) - { - angle_t angle1, angle2; - if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2)) - portalSegments.push_back({ angle1, angle2 }); - } - else - { - angle_t angle1, angle2; - if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2)) - portalSegments.push_back({ angle1, angle2 }); - } - } -#endif - } - - PolyPlaneUVTransform transform(ceiling ? frontsector->planes[sector_t::ceiling].xform : frontsector->planes[sector_t::floor].xform, tex); - - TriVertex *vertices = thread->FrameMemory->AllocMemory(sub->numlines); - - if (ceiling) - { - if (!isSky) - { - for (uint32_t i = 0; i < sub->numlines; i++) - { - seg_t *line = &sub->firstline[i]; - vertices[sub->numlines - 1 - i] = transform.GetVertex(line->v1, frontsector->ceilingplane.ZatPoint(line->v1)); - } - } - else - { - for (uint32_t i = 0; i < sub->numlines; i++) - { - seg_t *line = &sub->firstline[i]; - vertices[sub->numlines - 1 - i] = transform.GetVertex(line->v1, skyHeight); - } - } - } - else - { - if (!isSky) - { - for (uint32_t i = 0; i < sub->numlines; i++) - { - seg_t *line = &sub->firstline[i]; - vertices[i] = transform.GetVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1)); - } - } - else - { - for (uint32_t i = 0; i < sub->numlines; i++) - { - seg_t *line = &sub->firstline[i]; - vertices[i] = transform.GetVertex(line->v1, skyHeight); - } - } - } - - bool foggy = level.fadeto || frontsector->Colormap.FadeColor || (level.flags & LEVEL_HASFADETABLE); - - int lightlevel = ceiling ? frontsector->GetCeilingLight() : frontsector->GetFloorLight(); - int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4; - lightlevel = clamp(lightlevel + actualextralight, 0, 255); - - PolyCameraLight *cameraLight = PolyCameraLight::Instance(); - FDynamicColormap *basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]); - if (cameraLight->FixedLightLevel() < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size()) - { - lightlist_t *light = P_GetPlaneLight(frontsector, ceiling ? &frontsector->ceilingplane : &frontsector->floorplane, false); - basecolormap = GetColorTable(light->extra_colormap, frontsector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]); - if (light->p_lightlevel != &frontsector->lightlevel) // If this is the real ceiling, don't discard plane lighting R_FakeFlat() accounted for. - { - lightlevel = *light->p_lightlevel; - } - } - - PolyDrawArgs args; - args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false); - //args.SetSubsectorDepth(isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth); - args.SetTransform(&worldToClip); - args.SetFaceCullCCW(ccw); - args.SetStencilTestValue(stencilValue); - args.SetWriteStencil(true, stencilValue + 1); - args.SetClipPlane(0, clipPlane); - - if (!isSky) - { + PolyDrawArgs args; + SetLightLevel(thread, args, sub, ceiling); SetDynLights(thread, args, sub, ceiling); + args.SetTransform(&worldToClip); + args.SetFaceCullCCW(true); + args.SetStencilTestValue(stencilValue); + args.SetWriteStencil(true, stencilValue + 1); + args.SetClipPlane(0, clipPlane); args.SetTexture(tex); args.SetStyle(TriBlendMode::TextureOpaque); args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan); } else { - if (portal) - { - args.SetWriteStencil(true, polyportal->StencilValue); - polyportal->Shape.push_back({ vertices, (int)sub->numlines, ccw }); - } - else - { - args.SetWriteStencil(true, 255); - } + TriVertex *vertices = CreateSkyPlaneVertices(thread, sub, skyHeight); + PolyDrawArgs args; + args.SetTransform(&worldToClip); + args.SetFaceCullCCW(true); + args.SetStencilTestValue(stencilValue); + args.SetWriteStencil(true, stencilValue + 1); + args.SetClipPlane(0, clipPlane); + args.SetWriteStencil(true, 255); args.SetWriteColor(false); args.SetWriteDepth(false); args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan); - RenderSkyWalls(thread, args, sub, frontsector, portal, polyportal, ceiling, skyHeight, transform); + RenderSkyWalls(thread, args, sub, 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) +{ + 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)) + { + return; + } + + for (auto &p : sectorPortals) + { + if (p->Portal == portal) // To do: what other criteria do we need to check for? + { + polyportal = p.get(); + break; + } + } + if (!polyportal) + { + sectorPortals.push_back(std::unique_ptr(new PolyDrawSectorPortal(portal, ceiling))); + polyportal = sectorPortals.back().get(); + } + +#if 0 + // Calculate portal clipping + portalSegments.reserve(sub->numlines); + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + + DVector2 pt1 = line->v1->fPos() - viewpoint.Pos; + DVector2 pt2 = line->v2->fPos() - viewpoint.Pos; + bool backside = pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0; + if (!backside) + { + angle_t angle1, angle2; + if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2)) + portalSegments.push_back({ angle1, angle2 }); + } + else + { + angle_t angle1, angle2; + if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2)) + portalSegments.push_back({ angle1, angle2 }); + } + } +#endif + + TriVertex *vertices = CreateSkyPlaneVertices(thread, sub, skyHeight); + + PolyDrawArgs args; + args.SetTransform(&worldToClip); + args.SetFaceCullCCW(true); + args.SetStencilTestValue(stencilValue); + args.SetWriteStencil(true, stencilValue + 1); + args.SetClipPlane(0, clipPlane); + args.SetWriteStencil(true, polyportal->StencilValue); + args.SetWriteColor(false); + args.SetWriteDepth(false); + args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan); + + RenderSkyWalls(thread, args, sub, polyportal, ceiling, skyHeight); + + polyportal->Shape.push_back({ vertices, (int)sub->numlines, true }); +} + +void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight) +{ + sector_t *frontsector = sub->sector; + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + + double skyBottomz1 = frontsector->ceilingplane.ZatPoint(line->v1); + double skyBottomz2 = frontsector->ceilingplane.ZatPoint(line->v2); + if (line->backsector) + { + sector_t *backsector = line->backsector; + + double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1); + double backfloorz1 = backsector->floorplane.ZatPoint(line->v1); + double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2); + double backfloorz2 = backsector->floorplane.ZatPoint(line->v2); + + bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum; + + bool closedSector = backceilz1 == backfloorz1 && backceilz2 == backfloorz2; + if (ceiling && bothSkyCeiling && closedSector) + { + double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1); + double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1); + double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2); + double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2); + + double topceilz1 = frontceilz1; + double topceilz2 = frontceilz2; + double topfloorz1 = MIN(backceilz1, frontceilz1); + double topfloorz2 = MIN(backceilz2, frontceilz2); + double bottomceilz1 = MAX(frontfloorz1, backfloorz1); + double bottomceilz2 = MAX(frontfloorz2, backfloorz2); + double middleceilz1 = topfloorz1; + double middleceilz2 = topfloorz2; + double middlefloorz1 = MIN(bottomceilz1, middleceilz1); + double middlefloorz2 = MIN(bottomceilz2, middleceilz2); + + skyBottomz1 = middlefloorz1; + skyBottomz2 = middlefloorz2; + } + else if (bothSkyCeiling) + { + continue; + } + } + else if (polyportal && line->linedef && line->linedef->special == Line_Horizon) + { + // Not entirely correct as this closes the line horizon rather than allowing the floor to continue to infinity + skyBottomz1 = frontsector->floorplane.ZatPoint(line->v1); + skyBottomz2 = frontsector->floorplane.ZatPoint(line->v2); + } + + TriVertex *wallvert = thread->FrameMemory->AllocMemory(4); + + if (ceiling) + { + wallvert[0] = GetSkyVertex(line->v1, skyHeight); + wallvert[1] = GetSkyVertex(line->v2, skyHeight); + wallvert[2] = GetSkyVertex(line->v2, skyBottomz2); + wallvert[3] = GetSkyVertex(line->v1, skyBottomz1); + } + else + { + wallvert[0] = GetSkyVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1)); + wallvert[1] = GetSkyVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2)); + wallvert[2] = GetSkyVertex(line->v2, skyHeight); + wallvert[3] = GetSkyVertex(line->v1, skyHeight); + } + + args.DrawArray(thread, wallvert, 4, PolyDrawMode::TriangleFan); + + if (polyportal) + { + polyportal->Shape.push_back({ wallvert, 4, args.FaceCullCCW() }); + } + } +} + +sector_t *RenderPolyPlane::GetHeightSec(subsector_t *sub, bool ceiling) +{ + sector_t *controlsector = sub->sector->GetHeightSec(); + if (!controlsector || controlsector == sub->sector || (ceiling && !!(controlsector->MoreFlags & SECF_FAKEFLOORONLY))) + return nullptr; + else + return controlsector; +} + +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 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()) + { + 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. + { + lightlevel = *light->p_lightlevel; + } + } + + args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false); +} + void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling) { FLightNode *light_list = sub->lighthead; @@ -342,83 +461,55 @@ void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, args.SetNormal({ (float)normal.X, (float)normal.Y, (float)normal.Z }); } -void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform) +TriVertex *RenderPolyPlane::CreatePlaneVertices(PolyRenderThread *thread, subsector_t *sub, const PolyPlaneUVTransform &transform, const secplane_t &plane) { - for (uint32_t i = 0; i < sub->numlines; i++) + TriVertex *vertices = thread->FrameMemory->AllocMemory(sub->numlines); + + const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; + double planeZ = plane.ZatPoint(viewpoint.Pos.XY()); + if (viewpoint.Pos.Z < planeZ) { - seg_t *line = &sub->firstline[i]; - - double skyBottomz1 = frontsector->ceilingplane.ZatPoint(line->v1); - double skyBottomz2 = frontsector->ceilingplane.ZatPoint(line->v2); - if (line->backsector) + for (uint32_t i = 0; i < sub->numlines; i++) { - sector_t *backsector = line->backsector; - - double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1); - double backfloorz1 = backsector->floorplane.ZatPoint(line->v1); - double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2); - double backfloorz2 = backsector->floorplane.ZatPoint(line->v2); - - bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum; - - bool closedSector = backceilz1 == backfloorz1 && backceilz2 == backfloorz2; - if (ceiling && bothSkyCeiling && closedSector) - { - double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1); - double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1); - double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2); - double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2); - - double topceilz1 = frontceilz1; - double topceilz2 = frontceilz2; - double topfloorz1 = MIN(backceilz1, frontceilz1); - double topfloorz2 = MIN(backceilz2, frontceilz2); - double bottomceilz1 = MAX(frontfloorz1, backfloorz1); - double bottomceilz2 = MAX(frontfloorz2, backfloorz2); - double middleceilz1 = topfloorz1; - double middleceilz2 = topfloorz2; - double middlefloorz1 = MIN(bottomceilz1, middleceilz1); - double middlefloorz2 = MIN(bottomceilz2, middleceilz2); - - skyBottomz1 = middlefloorz1; - skyBottomz2 = middlefloorz2; - } - else if (bothSkyCeiling) - { - continue; - } - } - else if (portal && line->linedef && line->linedef->special == Line_Horizon) - { - // Not entirely correct as this closes the line horizon rather than allowing the floor to continue to infinity - skyBottomz1 = frontsector->floorplane.ZatPoint(line->v1); - skyBottomz2 = frontsector->floorplane.ZatPoint(line->v2); - } - - TriVertex *wallvert = thread->FrameMemory->AllocMemory(4); - - if (ceiling) - { - wallvert[0] = transform.GetVertex(line->v1, skyHeight); - wallvert[1] = transform.GetVertex(line->v2, skyHeight); - wallvert[2] = transform.GetVertex(line->v2, skyBottomz2); - wallvert[3] = transform.GetVertex(line->v1, skyBottomz1); - } - else - { - wallvert[0] = transform.GetVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1)); - wallvert[1] = transform.GetVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2)); - wallvert[2] = transform.GetVertex(line->v2, skyHeight); - wallvert[3] = transform.GetVertex(line->v1, skyHeight); - } - - args.DrawArray(thread, wallvert, 4, PolyDrawMode::TriangleFan); - - if (portal) - { - polyportal->Shape.push_back({ wallvert, 4, args.FaceCullCCW() }); + seg_t *line = &sub->firstline[sub->numlines - 1 - i]; + vertices[i] = transform.GetVertex(line->v1, plane.ZatPoint(line->v1)); } } + else + { + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + vertices[i] = transform.GetVertex(line->v1, plane.ZatPoint(line->v1)); + } + } + + return vertices; +} + +TriVertex *RenderPolyPlane::CreateSkyPlaneVertices(PolyRenderThread *thread, subsector_t *sub, double skyHeight) +{ + TriVertex *vertices = thread->FrameMemory->AllocMemory(sub->numlines); + + const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; + if (viewpoint.Pos.Z < skyHeight) + { + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[sub->numlines - 1 - i]; + vertices[i] = GetSkyVertex(line->v1, skyHeight); + } + } + else + { + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + vertices[i] = GetSkyVertex(line->v1, skyHeight); + } + } + + return vertices; } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/polyrenderer/scene/poly_plane.h b/src/polyrenderer/scene/poly_plane.h index 74db247e6..30d374e62 100644 --- a/src/polyrenderer/scene/poly_plane.h +++ b/src/polyrenderer/scene/poly_plane.h @@ -54,6 +54,13 @@ 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: @@ -61,8 +68,26 @@ public: 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 RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform); + + 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 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 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); + + static TriVertex GetSkyVertex(vertex_t *v, double height) { return { (float)v->fX(), (float)v->fY(), (float)height, 1.0f, 0.0f, 0.0f }; } }; class Render3DFloorPlane