diff --git a/src/polyrenderer/scene/poly_cull.cpp b/src/polyrenderer/scene/poly_cull.cpp index 647dc54a2..623b6e9df 100644 --- a/src/polyrenderer/scene/poly_cull.cpp +++ b/src/polyrenderer/scene/poly_cull.cpp @@ -70,26 +70,6 @@ void PolyCull::CullNode(void *node) void PolyCull::CullSubsector(subsector_t *sub) { - // Mark poly objects first - if (sub->polys) - { - if (sub->BSP == nullptr || sub->BSP->bDirty) - { - sub->BuildPolyBSP(); - } - - if (sub->BSP->Nodes.Size() == 0) - { - CullSubsector(&sub->BSP->Subsectors[0]); - } - else - { - CullNode(&sub->BSP->Nodes.Last()); - } - - return; // Hmm, seems a bit strange the subsector is then ignored. But that's what the sw renderer seems to be doing.. - } - // Update sky heights for the scene if (!FirstSkyHeight) { diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp index a655ca845..21ae23fc8 100644 --- a/src/polyrenderer/scene/poly_scene.cpp +++ b/src/polyrenderer/scene/poly_scene.cpp @@ -111,25 +111,48 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub) uint32_t subsectorDepth = NextSubsectorDepth++; + bool mainBSP = sub->polys == nullptr; + + if (sub->polys) + { + if (sub->BSP == nullptr || sub->BSP->bDirty) + { + sub->BuildPolyBSP(); + + // This is done by the GL renderer, but not the sw renderer. No idea what the purpose is.. + for (unsigned i = 0; i < sub->BSP->Segs.Size(); i++) + { + sub->BSP->Segs[i].Subsector = sub; + sub->BSP->Segs[i].PartnerSeg = nullptr; + } + } + + if (sub->BSP->Nodes.Size() == 0) + { + RenderPolySubsector(&sub->BSP->Subsectors[0], subsectorDepth, frontsector); + } + else + { + RenderPolyNode(&sub->BSP->Nodes.Last(), subsectorDepth, frontsector); + } + } + else + { + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + RenderLine(sub, line, frontsector, subsectorDepth); + } + } + if (sub->sector->CenterFloor() != sub->sector->CenterCeiling()) { RenderPolyPlane::RenderPlanes(WorldToClip, PortalPlane, Cull, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); } - for (uint32_t i = 0; i < sub->numlines; i++) - { - seg_t *line = &sub->firstline[i]; - if (line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ)) - { - RenderLine(sub, line, frontsector, subsectorDepth); - } - } - - RenderMemory &memory = PolyRenderer::Instance()->FrameMemory; - - bool mainBSP = ((unsigned int)(sub->Index()) < level.subsectors.Size()); if (mainBSP) { + RenderMemory &memory = PolyRenderer::Instance()->FrameMemory; int subsectorIndex = sub->Index(); for (int i = ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Particles[i].snext) { @@ -142,6 +165,73 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub) SubsectorDepths[sub] = subsectorDepth; } +void RenderPolyScene::RenderPolyNode(void *node, uint32_t subsectorDepth, sector_t *frontsector) +{ + while (!((size_t)node & 1)) // Keep going until found a subsector + { + node_t *bsp = (node_t *)node; + + // Decide which side the view point is on. + int side = PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos, bsp); + + // Recursively divide front space (toward the viewer). + RenderPolyNode(bsp->children[side], subsectorDepth, frontsector); + + // Possibly divide back space (away from the viewer). + side ^= 1; + + // Don't bother culling on poly objects + //if (!CheckBBox(bsp->bbox[side])) + // return; + + node = bsp->children[side]; + } + + subsector_t *sub = (subsector_t *)((uint8_t *)node - 1); + RenderPolySubsector(sub, subsectorDepth, frontsector); +} + +void RenderPolyScene::RenderPolySubsector(subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector) +{ + const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; + + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + if (line->linedef) + { + // Reject lines not facing viewer + DVector2 pt1 = line->v1->fPos() - viewpoint.Pos; + DVector2 pt2 = line->v2->fPos() - viewpoint.Pos; + if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0) + continue; + + // Cull wall if not visible + angle_t angle1, angle2; + if (!Cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2)) + continue; + + // Tell automap we saw this + if (!PolyRenderer::Instance()->DontMapLines && line->linedef) + { + line->linedef->flags |= ML_MAPPED; + sub->flags |= SSECF_DRAWN; + } + + // Render wall, and update culling info if its an occlusion blocker + if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals)) + { + Cull.MarkSegmentCulled(angle1, angle2); + } + } + } +} + +int RenderPolyScene::PointOnSide(const DVector2 &pos, const node_t *node) +{ + return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0; +} + void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right) { if (level.nodes.Size() == 0) diff --git a/src/polyrenderer/scene/poly_scene.h b/src/polyrenderer/scene/poly_scene.h index 707ee87a3..fc89de7cd 100644 --- a/src/polyrenderer/scene/poly_scene.h +++ b/src/polyrenderer/scene/poly_scene.h @@ -89,6 +89,10 @@ private: void RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right); void RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node); + void RenderPolySubsector(subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector); + void RenderPolyNode(void *node, uint32_t subsectorDepth, sector_t *frontsector); + static int PointOnSide(const DVector2 &pos, const node_t *node); + TriMatrix WorldToClip; PolyClipPlane PortalPlane; uint32_t StencilValue = 0;