void FreePortals(node_t* node) { portal_t* p; portal_t* nextp; if (node->planenum != -1) { FreePortals(node->children[0]); FreePortals(node->children[1]); return; } for (p = node->portals; p; p = nextp) { if (p->nodes[0] == node) { nextp = p->next[0]; } else { nextp = p->next[1]; } RemovePortalFromNode(p, p->nodes[0]); RemovePortalFromNode(p, p->nodes[1]); delete p->winding; FreePortal(p); } }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void Tree_FreePortals_r( node_t *node ) { portal_t *p, *nextp; int s; // free children if ( node->planenum != PLANENUM_LEAF ) { Tree_FreePortals_r( node->children[0] ); Tree_FreePortals_r( node->children[1] ); } // free portals for ( p = node->portals; p; p = nextp ) { s = ( p->nodes[1] == node ); nextp = p->next[s]; RemovePortalFromNode( p, p->nodes[!s] ); #ifdef ME if ( p->winding ) { freedtreemem += MemorySize( p->winding ); } freedtreemem += MemorySize( p ); #endif //ME FreePortal( p ); } node->portals = NULL; } //end of the function Tree_FreePortals_r
//===================================================================================== // FreePOrtals_r //===================================================================================== geBoolean FreePortals_r(GBSP_Node *Node) { GBSP_Portal *Portal, *Next; int32 Side; if (!Node) return GE_TRUE; for (Portal = Node->Portals; Portal; Portal = Next) { if (Portal->Nodes[0] == Node) Side = 0; else if (Portal->Nodes[1] == Node) Side = 1; else { GHook.Error("FreePortals_r: Portal does not look at either node.\n"); return GE_FALSE; } Next = Portal->Next[Side]; if (!RemovePortalFromNode(Portal, Portal->Nodes[0])) return GE_FALSE; if (!RemovePortalFromNode(Portal, Portal->Nodes[1])) return GE_FALSE; if (!FreePortal(Portal)) return GE_FALSE; } Node->Portals = NULL; if (Node->PlaneNum == PLANENUM_LEAF) return GE_TRUE; if (!FreePortals_r(Node->Children[0])) return GE_FALSE; if (!FreePortals_r(Node->Children[1])) return GE_FALSE; return GE_TRUE; }
/* ================== FreeNodePortals_r ================== */ static void FreeNodePortals_r (node_t *node) { portal_t *p, *nextp; if (!node->contents) { FreeNodePortals_r (node->children[0]); FreeNodePortals_r (node->children[1]); } for (p=node->portals ; p ; p=nextp) { if (p->nodes[0] == node) nextp = p->next[0]; else nextp = p->next[1]; RemovePortalFromNode (p, p->nodes[0]); RemovePortalFromNode (p, p->nodes[1]); FreeWinding (p->winding); FreePortal (p); } }
/* ================== FreeAllPortals ================== */ void FreeAllPortals(node_t *node) { portal_t *p, *nextp; if (!node->contents) { FreeAllPortals(node->children[0]); FreeAllPortals(node->children[1]); } for (p = node->portals; p; p = nextp) { if (p->nodes[0] == node) nextp = p->next[0]; else nextp = p->next[1]; RemovePortalFromNode(p, p->nodes[0]); RemovePortalFromNode(p, p->nodes[1]); FreeMem(p->winding, WINDING, 1); FreeMem(p, PORTAL, 1); } node->portals = NULL; }
static void FreeTreePortals_r (node_t *node) { portal_t *p, *nextp; /* free children */ if (node->planenum != PLANENUM_LEAF) { FreeTreePortals_r(node->children[0]); FreeTreePortals_r(node->children[1]); } /* free portals */ for (p = node->portals; p; p = nextp) { const int s = (p->nodes[1] == node); nextp = p->next[s]; RemovePortalFromNode(p, p->nodes[!s]); FreePortal(p); } node->portals = nullptr; }
/* ============= FreeTreePortals_r ============= */ void FreeTreePortals_r( node_t *node ){ portal_t *p, *nextp; int s; // free children if ( node->planenum != PLANENUM_LEAF ) { FreeTreePortals_r( node->children[0] ); FreeTreePortals_r( node->children[1] ); } // free portals for ( p = node->portals ; p ; p = nextp ) { s = ( p->nodes[1] == node ); nextp = p->next[s]; RemovePortalFromNode( p, p->nodes[!s] ); FreePortal( p ); } node->portals = NULL; }
//===================================================================================== // PartitionPortals_r //===================================================================================== geBoolean PartitionPortals_r(GBSP_Node *Node) { GBSP_Poly *NewPoly, *FPoly, *BPoly; GBSP_Plane *pPlane, *pPlane2; GBSP_Portal *Portal, *NewPortal, *Next; GBSP_Node *Front, *Back, *OtherNode; int32 Side; CalcNodeBoundsFromPortals(Node); if (Node->PlaneNum == PLANENUM_LEAF) return GE_TRUE; if (VisPortals && Node->Detail) // We can stop at detail seperators for the vis tree return GE_TRUE; //if (!InitializeNodePortal(Node)) // return GE_FALSE; //if (!DistributeNodePortalsToChildren(Node)) // return GE_FALSE; Front = Node->Children[0]; Back = Node->Children[1]; pPlane = &Planes[Node->PlaneNum]; // Create a new portal if (!CreatePolyOnNode (Node, &NewPoly)) { GHook.Error("PartitionPortals_r: CreatePolyOnNode failed.\n"); return GE_FALSE; } // Clip it against all other portals attached to this node for (Portal = Node->Portals; Portal && NewPoly; Portal = Portal->Next[Side]) { if (Portal->Nodes[0] == Node) Side = 0; else if (Portal->Nodes[1] == Node) Side = 1; else { GHook.Error("PartitionPortals_r: Portal does not look at either node.\n"); return GE_FALSE; } pPlane2 = &Planes[Portal->PlaneNum]; if (!ClipPolyEpsilon(NewPoly, 0.001f, pPlane2, Side, &NewPoly)) { GHook.Error("PartitionPortals_r: There was an error clipping the poly.\n"); return GE_FALSE; } if (!NewPoly) { GHook.Printf("PartitionPortals_r: Portal was cut away.\n"); break; } } if (NewPoly && PolyIsTiny (NewPoly)) { FreePoly(NewPoly); NewPoly = NULL; } if (NewPoly) { NewPortal = AllocPortal(); if (!NewPortal) { GHook.Error("PartitionPortals_r: Out of memory for portal.\n"); return GE_FALSE; } NewPortal->Poly = NewPoly; NewPortal->PlaneNum = Node->PlaneNum; NewPortal->OnNode = Node; if (!CheckPortal(NewPortal)) { GHook.Error("PartiionPortals_r: Check Portal failed.\n"); return GE_FALSE; } else AddPortalToNodes(NewPortal, Front, Back); } // Partition all portals by this node for (Portal = Node->Portals; Portal; Portal = Next) { if (Portal->Nodes[0] == Node) Side = 0; else if (Portal->Nodes[1] == Node) Side = 1; else { GHook.Error("PartitionPortals_r: Portal does not look at either node.\n"); return GE_FALSE; } Next = Portal->Next[Side]; // Remember the node on the back side OtherNode = Portal->Nodes[!Side]; RemovePortalFromNode(Portal, Portal->Nodes[0]); RemovePortalFromNode(Portal, Portal->Nodes[1]); if (!SplitPolyEpsilon(Portal->Poly, 0.001f, pPlane, &FPoly, &BPoly, GE_FALSE)) { GHook.Error("PartitionPortals_r: Could not split portal.\n"); return GE_FALSE; } if (FPoly && PolyIsTiny(FPoly)) { FreePoly(FPoly); FPoly = NULL; } if (BPoly && PolyIsTiny(BPoly)) { FreePoly(BPoly); BPoly = NULL; } if (!FPoly && !BPoly) continue; if (!FPoly) { Portal->Poly = BPoly; if (Side) AddPortalToNodes(Portal, OtherNode, Back); else AddPortalToNodes(Portal, Back, OtherNode); continue; } if (!BPoly) { Portal->Poly = FPoly; if (Side) AddPortalToNodes(Portal, OtherNode, Front); else AddPortalToNodes(Portal, Front, OtherNode); continue; } // Portal was split NewPortal = AllocPortal(); if (!NewPortal) { GHook.Error("PartitionPortals_r: Out of memory for portal.\n"); return GE_FALSE; } Portal->Poly = FPoly; *NewPortal = *Portal; NewPortal->Poly = BPoly; if (Side) { AddPortalToNodes(Portal, OtherNode, Front); AddPortalToNodes(NewPortal, OtherNode, Back); } else { AddPortalToNodes(Portal, Front, OtherNode); AddPortalToNodes(NewPortal, Back, OtherNode); } } if (Node->Portals != NULL) { GHook.Printf("*WARNING* PartitionPortals_r: Portals still on node after distribution...\n"); } if (!PartitionPortals_r(Front)) return GE_FALSE; if (!PartitionPortals_r(Back)) return GE_FALSE; return GE_TRUE; }
/* ============== 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; }
void Portal_MakeNodesRecursive( cnode_t *node, int stop_depth ) { hpair_t *pair; // if ( node->plane < 0 ) if ( node->type == NodeType_leaf ) { // it's a leaf pair = NewHPair2( "string", "portalized_leaf", "normal_leaf" ); InsertHPair( node->self, pair ); portalized_num++; return; } #if 0 // hack: contents deep portalization if ( node->contents < stop_depth && node->type == NodeType_node ) { pair = NewHPair2( "string", "portalized_leaf", "deep_stop" ); InsertHPair( node->self, pair ); portalized_num++; return; } #endif if ( !Portal_MakeNodeChildren( node ) ) { printf( " * Portal_MakeNodesRecursive: can't get portal for node '%s'. go up. *\n", node->self->name ); #if 1 // test: // if portalization fail for a sub-tree, ignore it // and remove all portals, to the *node* { portal_t *p, *next; int side; DebugWriteNodePortals( node ); for ( p = node->portals; p ; p=next ) { printf( "." ); { if ( p->nodes[0] == node ) side = 0; else if ( p->nodes[1] == node ) side = 1; else Error( "Portal_SplitNode: can't find node in portal.\n" ); next = p->next[side]; RemovePortalFromNode( p, p->nodes[0] ); RemovePortalFromNode( p, p->nodes[1] ); free( p ); } } } #endif pair = NewHPair2( "string", "portalized_leaf", "node_split_failed" ); InsertHPair( node->self, pair ); portalized_num++; return; } Portal_SplitNode( node ); Portal_MakeNodesRecursive( node->child[0], stop_depth ); Portal_MakeNodesRecursive( node->child[1], stop_depth ); }
/* ==================== Portal_SplitNode ==================== */ void Portal_SplitNode( cnode_t *node ) { cplane_t *pl; portal_t *p, *pnext; int side; cnode_t *othernode; portal_t *frontportal, *backportal; polygon_t *front, *back; pl = node->pl; side = 0; for ( p = node->portals; p ; p=pnext ) { if ( p->nodes[0] == node ) side = 0; else if ( p->nodes[1] == node ) side = 1; else Error( "Portal_SplitNode: can't find node in portal.\n" ); pnext = p->next[side]; othernode = p->nodes[!side]; RemovePortalFromNode( p, p->nodes[0] ); RemovePortalFromNode( p, p->nodes[1] ); SplitPolygon( p->p, pl->norm, pl->dist, &front, &back ); FreePolygon( p->p ); if ( !front && !back ) Error( "Portal_SplitNode: no front and back after split.\n" ); if ( !front ) { // polygon is back p->p = back; if ( side ) // node was back of portal AddPortalToNodes( p, othernode, node->child[1] ); else // node was front AddPortalToNodes( p, node->child[1], othernode ); continue; } if ( !back ) { // polygon is front p->p = front; if ( side ) // node was back of portal AddPortalToNodes( p, othernode, node->child[0] ); else AddPortalToNodes( p, node->child[0], othernode ); continue; } // // portal got split // frontportal = p; frontportal->p = front; backportal = NewPortal(); memcpy( backportal, p, sizeof( portal_t ) ); backportal->p = back; if ( side ) // node was back of portal { AddPortalToNodes( frontportal, othernode, node->child[0] ); AddPortalToNodes( backportal, othernode, node->child[1] ); } else { AddPortalToNodes( frontportal, node->child[0], othernode ); AddPortalToNodes( backportal, node->child[1], othernode ); } } node->portals = NULL; }
/* ============== 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 = 0; plane_t *plane; winding_t *frontwinding, *backwinding; plane = &mapplanes[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 // ClipWindingEpsilon (p->winding, plane->normal, plane->dist, SPLIT_WINDING_EPSILON, &frontwinding, &backwinding); if (frontwinding && WindingIsTiny(frontwinding)) { FreeWinding (frontwinding); frontwinding = NULL; c_tinyportals++; } if (backwinding && WindingIsTiny(backwinding)) { FreeWinding (backwinding); backwinding = NULL; c_tinyportals++; } if (!frontwinding && !backwinding) { // tiny windings on both sides continue; } if (!frontwinding) { FreeWinding (backwinding); if (side == 0) AddPortalToNodes (p, b, other_node); else AddPortalToNodes (p, other_node, b); continue; } if (!backwinding) { FreeWinding (frontwinding); 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; }
//=========================================================================== // Move or split the portals that bound node so that the node's // children have portals instead of node. // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void SplitNodePortals(node_t *node) { portal_t *p, *next_portal, *new_portal; node_t *f, *b, *other_node; int side = 0; // TTimo: init plane_t *plane; winding_t *frontwinding, *backwinding; plane = &mapplanes[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("SplitNodePortals: 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 // ClipWindingEpsilon(p->winding, plane->normal, plane->dist, SPLIT_WINDING_EPSILON, &frontwinding, &backwinding); if(frontwinding && WindingIsTiny(frontwinding)) { FreeWinding(frontwinding); frontwinding = NULL; c_tinyportals++; } //end if if(backwinding && WindingIsTiny(backwinding)) { FreeWinding(backwinding); backwinding = NULL; c_tinyportals++; } //end if #ifdef DEBUG /* //NOTE: don't use this winding ok check // all the invalid windings only have a degenerate edge if (frontwinding && WindingError(frontwinding)) { Log_Print("SplitNodePortals: front %s\n", WindingErrorString()); FreeWinding(frontwinding); frontwinding = NULL; } //end if if (backwinding && WindingError(backwinding)) { Log_Print("SplitNodePortals: back %s\n", WindingErrorString()); FreeWinding(backwinding); backwinding = NULL; } //end if*/ #endif //DEBUG if(!frontwinding && !backwinding) // tiny windings on both sides { continue; } if(!frontwinding) { FreeWinding(backwinding); if(side == 0) { AddPortalToNodes(p, b, other_node); } else { AddPortalToNodes(p, other_node, b); } continue; } if(!backwinding) { FreeWinding(frontwinding); 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); } //end if else { AddPortalToNodes(p, other_node, f); AddPortalToNodes(new_portal, other_node, b); } //end else } node->portals = NULL; } //end of the function SplitNodePortals
/* ============== SplitNodePortals Move or split the portals that bound node so that the node's children have portals instead of node. ============== */ static void SplitNodePortals( node_t *node ) { uPortal_t *p, *next_portal, *new_portal; node_t *f, *b, *other_node; int side; idPlane *plane; idWinding *frontwinding, *backwinding; plane = &dmapGlobals.mapPlanes[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 { common->Error( "SplitNodePortals: mislinked portal" ); side = 0; // quiet a compiler warning } 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 // p->winding->Split( *plane, SPLIT_WINDING_EPSILON, &frontwinding, &backwinding ); if( frontwinding && frontwinding->IsTiny() ) { delete frontwinding; frontwinding = NULL; c_tinyportals++; } if( backwinding && backwinding->IsTiny() ) { delete backwinding; backwinding = NULL; c_tinyportals++; } if( !frontwinding && !backwinding ) { // tiny windings on both sides continue; } if( !frontwinding ) { delete backwinding; if( side == 0 ) { AddPortalToNodes( p, b, other_node ); } else { AddPortalToNodes( p, other_node, b ); } continue; } if( !backwinding ) { delete frontwinding; 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; delete 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; // Vic: properly calculate the bounding box CalcNodeBounds (node); // // separate the portals on node into it's children // if (node->contents) return; // at a leaf, no more dividing plane = &mapplanes[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 // w = BaseWindingForPlane (&mapplanes[node->planenum]); side = 0; // shut up compiler warning for (p = node->portals ; p ; p = p->next[side]) { clipplane = mapplanes[p->planenum]; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorNegate (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 = AllocPortal (); new_portal->planenum = node->planenum; 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 DivideWindingEpsilon( p->winding, plane, &frontwinding, &backwinding, ON_EPSILON ); 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); } } CutNodePortals_r (f); CutNodePortals_r (b); }
/* ================ 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); }