/* ================ SplitBrushList ================ */ void SplitBrushList (bspbrush_t *brushes, node_t *node, bspbrush_t **front, bspbrush_t **back) { bspbrush_t *brush, *newbrush, *newbrush2; side_t *side; int sides; int i; *front = *back = NULL; for (brush = brushes ; brush ; brush=brush->next) { sides = brush->side; if (sides == PSIDE_BOTH) { // split into two brushes SplitBrush (brush, node->planenum, &newbrush, &newbrush2); if (newbrush) { newbrush->next = *front; *front = newbrush; } if (newbrush2) { newbrush2->next = *back; *back = newbrush2; } continue; } newbrush = CopyBrush (brush); // if the planenum is actualy a part of the brush // find the plane and flag it as used so it won't be tried // as a splitter again if (sides & PSIDE_FACING) { for (i=0 ; i<newbrush->numsides ; i++) { side = newbrush->sides + i; if ( (side->planenum& ~1) == node->planenum) side->texinfo = TEXINFO_NODE; } } if (sides & PSIDE_FRONT) { newbrush->next = *front; *front = newbrush; continue; } if (sides & PSIDE_BACK) { newbrush->next = *back; *back = newbrush; continue; } } }
//----------------------------------------------------------------------------- // Purpose: Recursively filter a brush through the tree // Input : *node - // *brush - //----------------------------------------------------------------------------- void MergeBrush_r( node_t *node, bspbrush_t *brush ) { if ( node->planenum == PLANENUM_LEAF ) { if ( node->contents & CONTENTS_SOLID ) { FreeBrush( brush ); } else { AddBrushToLeaf( node, brush ); } return; } bspbrush_t *front, *back; SplitBrush( brush, node->planenum, &front, &back ); FreeBrush( brush ); if ( front ) { MergeBrush_r( node->children[0], front ); } if ( back ) { MergeBrush_r( node->children[1], back ); } }
//=========================================================================== // Returns a single brush made up by the intersection of the // two provided brushes, or NULL if they are disjoint. // // The originals are undisturbed. // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== bspbrush_t *IntersectBrush( bspbrush_t *a, bspbrush_t *b ) { int i; bspbrush_t *front, *back; bspbrush_t *in; in = a; for ( i = 0 ; i < b->numsides && in ; i++ ) { SplitBrush( in, b->sides[i].planenum, &front, &back ); // SplitBrush2(in, b->sides[i].planenum, &front, &back); if ( in != a ) { FreeBrush( in ); } if ( front ) { FreeBrush( front ); } in = back; } //end for if ( in == a ) { return NULL; } in->next = NULL; return in; } //end of the function IntersectBrush
//=========================================================================== // Returns a list of brushes that remain after B is subtracted from A. // May by empty if A is contained inside B. // The originals are undisturbed. // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== bspbrush_t *SubtractBrush( bspbrush_t *a, bspbrush_t *b ) { // a - b = out (list) int i; bspbrush_t *front, *back; bspbrush_t *out, *in; in = a; out = NULL; for ( i = 0; i < b->numsides && in; i++ ) { SplitBrush( in, b->sides[i].planenum, &front, &back ); // SplitBrush2(in, b->sides[i].planenum, &front, &back); if ( in != a ) { FreeBrush( in ); } if ( front ) { // add to list front->next = out; out = front; } //end if in = back; } //end for if ( in ) { FreeBrush( in ); } //end if else { // didn't really intersect FreeBrushList( out ); return a; } //end else return out; } //end of the function SubtractBrush
/* ==================== FilterBrushIntoTree_r ==================== */ int FilterBrushIntoTree_r( uBrush_t *b, node_t *node ) { uBrush_t *front, *back; int c; if( !b ) { return 0; } // add it to the leaf list if( node->planenum == PLANENUM_LEAF ) { b->next = node->brushlist; node->brushlist = b; // classify the leaf by the structural brush if( b->opaque ) { node->opaque = true; } return 1; } // split it by the node plane SplitBrush( b, node->planenum, &front, &back ); FreeBrush( b ); c = 0; c += FilterBrushIntoTree_r( front, node->children[0] ); c += FilterBrushIntoTree_r( back, node->children[1] ); return c; }
void SplitBrushList (bspbrush_t* brushes, uint16_t planenum, bspbrush_t** front, bspbrush_t** back) { bspbrush_t* brush; *front = *back = nullptr; for (brush = brushes; brush; brush = brush->next) { const int sides = brush->side; bspbrush_t* newbrush; if (sides == PSIDE_BOTH) { /* split into two brushes */ bspbrush_t* newbrush2; SplitBrush(brush, planenum, &newbrush, &newbrush2); if (newbrush) { newbrush->next = *front; Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to front list.\n", newbrush->original->brushnum); *front = newbrush; } if (newbrush2) { newbrush2->next = *back; Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to back list.\n", newbrush2->original->brushnum); *back = newbrush2; } continue; } newbrush = CopyBrush(brush); /* if the planenum is actually a part of the brush * find the plane and flag it as used so it won't be tried * as a splitter again */ if (sides & PSIDE_FACING) { int i; for (i = 0; i < newbrush->numsides; i++) { side_t* side = newbrush->sides + i; if ((side->planenum & ~1) == planenum) side->texinfo = TEXINFO_NODE; } } if (sides & PSIDE_FRONT) { newbrush->next = *front; *front = newbrush; Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to front list.\n", newbrush->original->brushnum); continue; } if (sides & PSIDE_BACK) { newbrush->next = *back; Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to back list.\n", newbrush->original->brushnum); *back = newbrush; continue; } Verb_Printf(VERB_DUMP, "SplitBrushList: Brush %i fell off the map.\n", newbrush->original->brushnum); } }
//=========================================================================== // Any planes shared with the box edge will be set to no texinfo // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== bspbrush_t *ClipBrushToBox(bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs) { int i, j; bspbrush_t *front, *back; int p; for (j=0 ; j<2 ; j++) { if (brush->maxs[j] > clipmaxs[j]) { SplitBrush (brush, maxplanenums[j], &front, &back); if (front) FreeBrush (front); brush = back; if (!brush) return NULL; } if (brush->mins[j] < clipmins[j]) { SplitBrush (brush, minplanenums[j], &front, &back); if (back) FreeBrush (back); brush = front; if (!brush) return NULL; } } // remove any colinear faces for (i=0 ; i<brush->numsides ; i++) { p = brush->sides[i].planenum & ~1; if (p == maxplanenums[0] || p == maxplanenums[1] || p == minplanenums[0] || p == minplanenums[1]) { brush->sides[i].texinfo = TEXINFO_NODE; brush->sides[i].flags &= ~SFL_VISIBLE; } } return brush; } //end of the function ClipBrushToBox
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void SplitBrush2 (bspbrush_t *brush, int planenum, bspbrush_t **front, bspbrush_t **back) { SplitBrush (brush, planenum, front, back); #if 0 if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1) (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1 if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1) (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1 #endif } //end of the function SplitBrush2
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean CheckPlaneAgainstVolume (int pnum, node_t *node) { bspbrush_t *front, *back; qboolean good; SplitBrush (node->volume, pnum, &front, &back); good = (front && back); if (front) FreeBrush (front); if (back) FreeBrush (back); return good; } //end of the function CheckPlaneAgaintsVolume
/* ================ BuildTree_r ================ */ node_t *BuildTree_r (node_t *node, bspbrush_t *brushes) { node_t *newnode; side_t *bestside; int i; bspbrush_t *children[2]; if (numthreads == 1) c_nodes++; if (drawflag) DrawBrushList (brushes, node); // find the best plane to use as a splitter bestside = SelectSplitSide (brushes, node); if (!bestside) { // leaf node node->side = NULL; node->planenum = -1; LeafNode (node, brushes); return node; } // this is a splitplane node node->side = bestside; node->planenum = bestside->planenum & ~1; // always use front facing SplitBrushList (brushes, node, &children[0], &children[1]); FreeBrushList (brushes); // allocate children before recursing for (i=0 ; i<2 ; i++) { newnode = AllocNode (); newnode->parent = node; node->children[i] = newnode; } SplitBrush (node->volume, node->planenum, &node->children[0]->volume, &node->children[1]->volume); // recursively process children for (i=0 ; i<2 ; i++) { node->children[i] = BuildTree_r (node->children[i], children[i]); } return node; }
static bool CheckPlaneAgainstVolume (uint16_t pnum, const bspbrush_t* volume) { bspbrush_t* front, *back; bool good; SplitBrush(volume, pnum, &front, &back); good = (front && back); if (front) FreeBrush(front); if (back) FreeBrush(back); return good; }
static node_t *BuildTree_r (node_t *node, bspbrush_t *brushes) { node_t *newnode; side_t *bestside; int i; bspbrush_t *children[2]; if (threadstate.numthreads == 1) c_nodes++; /* find the best plane to use as a splitter */ bestside = SelectSplitSide(brushes, node->volume); if (!bestside) { /* leaf node */ LeafNode(node, brushes); Verb_Printf(VERB_DUMP, "BuildTree_r: Created a leaf node.\n"); return node; } /* make sure the selected plane hasn't been used before. */ CheckPlaneAgainstParents(bestside->planenum, node); Verb_Printf(VERB_DUMP, "BuildTree_r: splitting along plane %i\n", (int)bestside->planenum); /* this is a splitplane node */ node->side = bestside; node->planenum = bestside->planenum & ~1; /* always use front facing */ SplitBrushList(brushes, node->planenum, &children[0], &children[1]); FreeBrushList(brushes); /* allocate children before recursing */ for (i = 0; i < 2; i++) { newnode = AllocNode(); newnode->parent = node; node->children[i] = newnode; } SplitBrush(node->volume, node->planenum, &node->children[0]->volume, &node->children[1]->volume); /* recursively process children */ for (i = 0; i < 2; i++) { node->children[i] = BuildTree_r(node->children[i], children[i]); } return node; }
static _Bool CheckPlaneAgainstVolume(int32_t pnum, node_t *node) { brush_t *front, *back; _Bool good; SplitBrush(node->volume, pnum, &front, &back); good = (front && back); if (front) { FreeBrush(front); } if (back) { FreeBrush(back); } return good; }
/* ==================== FilterBrushIntoTree_r ==================== */ int FilterBrushIntoTree_r(bspBrush_t * b, node_t * node) { bspBrush_t *front, *back; int c; if(!b) { return 0; } // add it to the leaf list if(node->planenum == PLANENUM_LEAF) { b->next = node->brushlist; node->brushlist = b; // classify the leaf by the structural brush if(!b->detail) { if(b->opaque) { node->opaque = qtrue; node->areaportal = qfalse; } else if(b->contents & CONTENTS_AREAPORTAL) { if(!node->opaque) { node->areaportal = qtrue; } } } return 1; } // split it by the node plane SplitBrush(b, node->planenum, &front, &back); FreeBrush(b); c = 0; c += FilterBrushIntoTree_r(front, node->children[0]); c += FilterBrushIntoTree_r(back, node->children[1]); return c; }
int FilterBrushIntoTree_r( brush_t *b, node_t *node ) { brush_t *front, *back; int c; /* dummy check */ if( b == NULL ) return 0; /* add it to the leaf list */ if( node->planenum == PLANENUM_LEAF ) { /* something somewhere is hammering brushlist */ b->next = node->brushlist; node->brushlist = b; /* classify the leaf by the structural brush */ if( !b->detail ) { if( b->opaque ) { node->opaque = qtrue; node->areaportal = qfalse; } else if( b->compileFlags & C_AREAPORTAL ) { if( !node->opaque ) node->areaportal = qtrue; } } return 1; } /* split it by the node plane */ c = b->numsides; SplitBrush( b, node->planenum, &front, &back ); FreeBrush( b ); c = 0; c += FilterBrushIntoTree_r( front, node->children[ 0 ] ); c += FilterBrushIntoTree_r( back, node->children[ 1 ] ); return c; }
node_t *BuildTree_r( node_t *node, bspbrush_t *brushes ) { node_t *newnode; side_t *bestside; int i, totalmem; bspbrush_t *children[2]; qprintf( "\r%6d", numrecurse ); numrecurse++; if ( numthreads == 1 ) { totalmem = WindingMemory() + c_nodememory + c_brushmemory; if ( totalmem > c_peak_totalbspmemory ) { c_peak_totalbspmemory = totalmem; } c_nodes++; } //endif if ( drawflag ) { DrawBrushList( brushes, node ); } // find the best plane to use as a splitter bestside = SelectSplitSide( brushes, node ); if ( !bestside ) { // leaf node node->side = NULL; node->planenum = -1; LeafNode( node, brushes ); if ( node->contents & CONTENTS_SOLID ) { c_solidleafnodes++; } if ( create_aas ) { //free up memory!!! FreeBrushList( node->brushlist ); node->brushlist = NULL; //free the node volume brush if ( node->volume ) { FreeBrush( node->volume ); node->volume = NULL; } //end if } //end if return node; } //end if // this is a splitplane node node->side = bestside; node->planenum = bestside->planenum & ~1; // always use front facing //split the brush list in two for both children SplitBrushList( brushes, node, &children[0], &children[1] ); //free the old brush list FreeBrushList( brushes ); // allocate children before recursing for ( i = 0; i < 2; i++ ) { newnode = AllocNode(); newnode->parent = node; node->children[i] = newnode; } //end for //split the volume brush of the node for the children SplitBrush( node->volume, node->planenum, &node->children[0]->volume, &node->children[1]->volume ); if ( create_aas ) { //free the volume brush if ( node->volume ) { FreeBrush( node->volume ); node->volume = NULL; } //end if } //end if // recursively process children for ( i = 0; i < 2; i++ ) { node->children[i] = BuildTree_r( node->children[i], children[i] ); } //end for return node; } //end of the function BuildTree_r
//thread function, gets nodes from the nodelist and processes them void BuildTreeThread( int threadid ) { node_t *newnode, *node; side_t *bestside; int i, totalmem; bspbrush_t *brushes; for ( node = NextNodeFromList(); node; ) { //if the nodelist isn't empty try to add another thread //if (NodeListSize() > 10) AddThread(BuildTreeThread); //display the number of nodes processed so far if ( numthreads == 1 ) { IncreaseNodeCounter(); } brushes = node->brushlist; if ( numthreads == 1 ) { totalmem = WindingMemory() + c_nodememory + c_brushmemory; if ( totalmem > c_peak_totalbspmemory ) { c_peak_totalbspmemory = totalmem; } //end if c_nodes++; } //endif if ( drawflag ) { DrawBrushList( brushes, node ); } //end if if ( cancelconversion ) { bestside = NULL; } //end if else { // find the best plane to use as a splitter bestside = SelectSplitSide( brushes, node ); } //end else //if there's no split side left if ( !bestside ) { //create a leaf out of the node LeafNode( node, brushes ); if ( node->contents & CONTENTS_SOLID ) { c_solidleafnodes++; } if ( create_aas ) { //free up memory!!! FreeBrushList( node->brushlist ); node->brushlist = NULL; } //end if //free the node volume brush (it is not used anymore) if ( node->volume ) { FreeBrush( node->volume ); node->volume = NULL; } //end if node = NextNodeFromList(); continue; } //end if // this is a splitplane node node->side = bestside; node->planenum = bestside->planenum & ~1; //always use front facing //allocate children for ( i = 0; i < 2; i++ ) { newnode = AllocNode(); newnode->parent = node; node->children[i] = newnode; } //end for //split the brush list in two for both children SplitBrushList( brushes, node, &node->children[0]->brushlist, &node->children[1]->brushlist ); CheckBrushLists( node->children[0]->brushlist, node->children[1]->brushlist ); //free the old brush list FreeBrushList( brushes ); node->brushlist = NULL; //split the volume brush of the node for the children SplitBrush( node->volume, node->planenum, &node->children[0]->volume, &node->children[1]->volume ); if ( !node->children[0]->volume || !node->children[1]->volume ) { Error( "child without volume brush" ); } //end if //free the volume brush if ( node->volume ) { FreeBrush( node->volume ); node->volume = NULL; } //end if //add both children to the node list //AddNodeToList(node->children[0]); AddNodeToList( node->children[1] ); node = node->children[0]; } //end while RemoveThread( threadid ); } //end of the function BuildTreeThread
//=========================================================================== // returns a list with brushes created by splitting the given brush with // planes that go through the face edges and are orthogonal to the face plane // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== bspbrush_t *Q1_SplitBrushWithFace(bspbrush_t *brush, q1_dface_t *face) { int i, edgenum, side, planenum, splits; float dist; q1_dplane_t plane; vec_t *v1, *v2; vec3_t normal, edgevec; bspbrush_t *front, *back, *brushlist; memcpy(&plane, &q1_dplanes[face->planenum], sizeof(q1_dplane_t)); //check on which side of the plane the face is if (face->side) { VectorNegate(plane.normal, plane.normal); plane.dist = -plane.dist; } //end if splits = 0; brushlist = NULL; for (i = 0; i < face->numedges; i++) { //get the first and second vertex of the edge edgenum = q1_dsurfedges[face->firstedge + i]; side = edgenum > 0; //if the face plane is flipped v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point; v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point; //create a plane through the edge vector, orthogonal to the face plane //and with the normal vector pointing out of the face VectorSubtract(v1, v2, edgevec); CrossProduct(edgevec, plane.normal, normal); VectorNormalize(normal); dist = DotProduct(normal, v1); // planenum = FindFloatPlane(normal, dist); //split the current brush SplitBrush(brush, planenum, &front, &back); //if there is a back brush just put it in the list if (back) { //copy the brush contents back->side = brush->side; // back->next = brushlist; brushlist = back; splits++; } //end if if (!front) { Log_Print("Q1_SplitBrushWithFace: no new brush\n"); FreeBrushList(brushlist); return NULL; } //end if //copy the brush contents front->side = brush->side; //continue splitting the front brush brush = front; } //end for if (!splits) { FreeBrush(front); return NULL; } //end if front->next = brushlist; brushlist = front; return brushlist; } //end of the function Q1_SplitBrushWithFace