/* ============== 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) { portal_t *p, *next_portal, *new_portal; node_t *f, *b, *other_node; int side; dplane_t *plane; winding_t *frontwinding, *backwinding; plane = &dplanes[node->planenum]; f = node->children[0]; b = node->children[1]; for (p = node->portals ; p ; p = next_portal) { if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) side = 1; else Error ("CutNodePortals_r: mislinked portal"); next_portal = p->next[side]; 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 // DivideWinding (p->winding, plane, &frontwinding, &backwinding); if (!frontwinding) { if (side == 0) AddPortalToNodes (p, b, other_node); else AddPortalToNodes (p, other_node, b); continue; } if (!backwinding) { if (side == 0) AddPortalToNodes (p, f, other_node); else AddPortalToNodes (p, other_node, f); continue; } // the winding is split new_portal = AllocPortal (); *new_portal = *p; new_portal->winding = backwinding; FreeWinding (p->winding); p->winding = frontwinding; if (side == 0) { 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 = NULL; }
/* ================ CutNodePortals_r ================ */ static void CutNodePortals_r(node_t *node) { plane_t *plane, clipplane; node_t *f, *b, *other_node; portal_t *p, *new_portal, *next_portal; winding_t *w, *frontwinding, *backwinding; int side; #ifdef PARANOID CheckLeafPortalConsistancy (node); #endif // separate the portals on node into it's children if (node->contents) return; // at a leaf, no more dividing plane = &pPlanes[node->planenum]; f = node->children[0]; b = node->children[1]; // create the new portal by taking the full plane winding for the cutting plane // and clipping it by all of the planes from the other portals new_portal = AllocMem(PORTAL, 1, true); new_portal->planenum = node->planenum; w = BaseWindingForPlane(&pPlanes[node->planenum]); side = 0; // shut up compiler warning for (p = node->portals; p; p = p->next[side]) { clipplane = pPlanes[p->planenum]; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorSubtract(vec3_origin, clipplane.normal, clipplane.normal); side = 1; } else Message(msgError, errMislinkedPortal); w = ClipWinding(w, &clipplane, true); if (!w) { Message(msgWarning, warnPortalClippedAway); break; } } if (w) { // if the plane was not clipped on all sides, there was an error new_portal->winding = w; AddPortalToNodes(new_portal, f, b); } // partition the portals for (p = node->portals; p; p = next_portal) { if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) side = 1; else Message(msgError, errMislinkedPortal); next_portal = p->next[side]; 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 DivideWinding(p->winding, plane, &frontwinding, &backwinding); if (!frontwinding) { if (side == 0) AddPortalToNodes(p, b, other_node); else AddPortalToNodes(p, other_node, b); continue; } if (!backwinding) { if (side == 0) AddPortalToNodes(p, f, other_node); else AddPortalToNodes(p, other_node, f); continue; } // the winding is split new_portal = AllocMem(PORTAL, 1, true); *new_portal = *p; new_portal->winding = backwinding; FreeMem(p->winding, WINDING, 1); p->winding = frontwinding; if (side == 0) { AddPortalToNodes(p, f, other_node); AddPortalToNodes(new_portal, b, other_node); } else { AddPortalToNodes(p, other_node, f); AddPortalToNodes(new_portal, other_node, b); } } // Display progress iNodesDone++; Message(msgPercent, iNodesDone, splitnodes); CutNodePortals_r(f); CutNodePortals_r(b); }
static clipleaf_t * carve_leaf (hull_t *hull, nodeleaf_t *nodeleafs, clipleaf_t *leaf, int num) { mclipnode_t *node; plane_t *plane; winding_t *winding, *fw, *bw; clipport_t *portal; clipport_t *new_portal; clipport_t *next_portal; clipleaf_t *other_leaf; clipleaf_t *new_leaf; plane_t clipplane; int side; if (num < 0) { // we've hit a leaf. all done leaf->contents = num; return leaf; } node = hull->clipnodes + num; plane = hull->planes + node->planenum; winding = BaseWindingForPlane (plane); for (portal = leaf->portals; portal; portal = portal->next[side]) { clipplane = hull->planes[portal->planenum]; side = (portal->leafs[1] == leaf); if (side) PlaneFlip (&clipplane, &clipplane); winding = ClipWinding (winding, &clipplane, true); } new_leaf = alloc_leaf (); portal = leaf->portals; leaf->portals = 0; for (; portal; portal = next_portal) { side = (portal->leafs[1] == leaf); next_portal = portal->next[side]; other_leaf = portal->leafs[!side]; remove_portal (portal, other_leaf); DivideWinding (portal->winding, plane, &fw, &bw); if (!fw) { if (side) add_portal (portal, other_leaf, new_leaf); else add_portal (portal, new_leaf, other_leaf); continue; } if (!bw) { if (side) add_portal (portal, other_leaf, leaf); else add_portal (portal, leaf, other_leaf); continue; } new_portal = alloc_portal (); new_portal->planenum = portal->planenum; new_portal->winding = bw; FreeWinding (portal->winding); portal->winding = fw; if (side) { add_portal (portal, other_leaf, leaf); add_portal (new_portal, other_leaf, new_leaf); } else { add_portal (portal, leaf, other_leaf); add_portal (new_portal, new_leaf, other_leaf); } } new_portal = alloc_portal (); new_portal->planenum = node->planenum; new_portal->winding = winding; add_portal (new_portal, leaf, new_leaf); nodeleafs[num].leafs[0] = carve_leaf (hull, nodeleafs, leaf, node->children[0]); nodeleafs[num].leafs[1] = carve_leaf (hull, nodeleafs, new_leaf, node->children[1]); return 0; }
/* ================ CutNodePortals_r ================ */ void CutNodePortals_r (node_t *node) { plane_t *plane, clipplane; node_t *f, *b, *other_node; portal_t *p, *new_portal, *next_portal; winding_t *w, *frontwinding, *backwinding; int side; // CheckLeafPortalConsistancy (node); // // seperate the portals on node into it's children // if (node->contents) { return; // at a leaf, no more dividing } plane = &planes[node->planenum]; f = node->children[0]; b = node->children[1]; // // create the new portal by taking the full plane winding for the cutting plane // and clipping it by all of the planes from the other portals // new_portal = AllocPortal (); new_portal->planenum = node->planenum; w = BaseWindingForPlane (&planes[node->planenum]); side = 0; // shut up compiler warning for (p = node->portals ; p ; p = p->next[side]) { clipplane = planes[p->planenum]; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorSubtract (vec3_origin, clipplane.normal, clipplane.normal); side = 1; } else Error ("CutNodePortals_r: mislinked portal"); w = ClipWinding (w, &clipplane, true); if (!w) { printf ("WARNING: CutNodePortals_r:new portal was clipped away\n"); break; } } if (w) { // if the plane was not clipped on all sides, there was an error new_portal->winding = w; AddPortalToNodes (new_portal, f, b); } // // partition the portals // for (p = node->portals ; p ; p = next_portal) { if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) side = 1; else Error ("CutNodePortals_r: mislinked portal"); next_portal = p->next[side]; 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 // DivideWinding (p->winding, plane, &frontwinding, &backwinding); if (!frontwinding) { if (side == 0) AddPortalToNodes (p, b, other_node); else AddPortalToNodes (p, other_node, b); continue; } if (!backwinding) { if (side == 0) AddPortalToNodes (p, f, other_node); else AddPortalToNodes (p, other_node, f); continue; } // the winding is split new_portal = AllocPortal (); *new_portal = *p; new_portal->winding = backwinding; FreeWinding (p->winding); p->winding = frontwinding; if (side == 0) { AddPortalToNodes (p, f, other_node); AddPortalToNodes (new_portal, b, other_node); } else { AddPortalToNodes (p, other_node, f); AddPortalToNodes (new_portal, other_node, b); } } DrawLeaf (f,1); DrawLeaf (b,2); CutNodePortals_r (f); CutNodePortals_r (b); }