From 7d3b5a9c3f56c4f2e5f9bde549dfc84ccf485609 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Fri, 17 Jun 2022 22:34:36 -0600 Subject: [PATCH] qbsp: import SplitNodePortals from qbsp3 --- qbsp/portals.cc | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/qbsp/portals.cc b/qbsp/portals.cc index ab9b241f..dbbf49ea 100644 --- a/qbsp/portals.cc +++ b/qbsp/portals.cc @@ -27,6 +27,8 @@ #include #include +#include + /* ============= AddPortalToNodes @@ -258,6 +260,99 @@ std::optional BaseWindingForNode(node_t *node) return w; } +struct portalstats_t { + std::atomic c_tinyportals; +}; + +/* +============== +SplitNodePortals + +Move or split the portals that bound node so that the node's +children have portals instead of node. +============== +*/ +void SplitNodePortals(node_t *node, portalstats_t &stats) +{ + const auto plane = map.planes.at(node->planenum); + node_t *f = node->children[0]; + node_t *b = node->children[1]; + + portal_t *next_portal = nullptr; + for (portal_t *p = node->portals; p ; p = next_portal) + { + side_t side; + if (p->nodes[SIDE_FRONT] == node) + side = SIDE_FRONT; + else if (p->nodes[SIDE_BACK] == node) + side = SIDE_BACK; + else + FError("CutNodePortals_r: mislinked portal"); + next_portal = p->next[side]; + + node_t *other_node = p->nodes[!side]; + RemovePortalFromNode(p, p->nodes[0]); + RemovePortalFromNode(p, p->nodes[1]); + + // + // cut the portal into two portals, one on each side of the cut plane + // + auto [frontwinding, backwinding] = p->winding->clip(plane, SPLIT_WINDING_EPSILON, true); + + if (frontwinding && WindingIsTiny(*frontwinding)) + { + frontwinding = {}; + stats.c_tinyportals++; + } + + if (backwinding && WindingIsTiny(*backwinding)) + { + backwinding = {}; + stats.c_tinyportals++; + } + + if (!frontwinding && !backwinding) + { // tiny windings on both sides + continue; + } + + if (!frontwinding) + { + if (side == SIDE_FRONT) + AddPortalToNodes(p, b, other_node); + else + AddPortalToNodes(p, other_node, b); + continue; + } + if (!backwinding) + { + if (side == SIDE_FRONT) + AddPortalToNodes(p, f, other_node); + else + AddPortalToNodes(p, other_node, f); + continue; + } + + // the winding is split + auto *new_portal = new portal_t{*p}; + new_portal->winding = backwinding; + p->winding = frontwinding; + + if (side == SIDE_FRONT) + { + AddPortalToNodes(p, f, other_node); + AddPortalToNodes(new_portal, b, other_node); + } + else + { + AddPortalToNodes(p, other_node, f); + AddPortalToNodes(new_portal, other_node, b); + } + } + + node->portals = nullptr; +} + /* ================ CutNodePortals_r