// Compute a list of faces that are visible on the detail brush sides face_t *ComputeVisibleBrushSides( bspbrush_t *list ) { face_t *pTotalFaces = NULL; CUtlVector<bspbrush_t *> cutBrushes; // Go through the whole brush list for ( bspbrush_t *pbrush = list; pbrush; pbrush = pbrush->next ) { face_t *pFaces = NULL; mapbrush_t *mb = pbrush->original; if ( !(mb->contents & ALL_VISIBLE_CONTENTS) ) continue; // Make a face for each brush side, then clip it by the other // details to see if any fragments are visible for ( int i = 0; i < pbrush->numsides; i++ ) { winding_t *winding = pbrush->sides[i].winding; if ( !winding ) continue; if (! (pbrush->sides[i].contents & ALL_VISIBLE_CONTENTS) ) continue; side_t *side = FindOriginalSide( mb, pbrush->sides + i ); face_t *f = MakeBrushFace( side, winding ); // link to head of face list f->next = pFaces; pFaces = f; } // Make a list of brushes that can cut the face list for this brush cutBrushes.RemoveAll(); if ( GetListOfCutBrushes( cutBrushes, pbrush, list ) ) { // now cut each face to find visible fragments for ( face_t *f = pFaces; f; f = f->next ) { // this will be a new list of faces that this face cuts into face_t *pClip = NULL; ClipFaceToBrushList( f, cutBrushes, &pClip ); if ( pClip ) { int outCount = CountFaceList(pClip); // it cut into more faces (or it was completely cut away) if ( outCount <= 1 ) { // was removed or cut down, mark as split f->split[0] = f; // insert face fragments at head of list (UNDONE: reverses order, do we care?) while ( pClip ) { face_t *next = pClip->next; pClip->next = pFaces; pFaces = pClip; pClip = next; } } else { // it cut into more than one visible fragment // Don't fragment details // UNDONE: Build 2d convex hull of this list and swap face winding // with that polygon? That would fix the remaining issues. FreeFaceList( pClip ); pClip = NULL; } } } } // move visible fragments to global face list while ( pFaces ) { face_t *next = pFaces->next; if ( pFaces->split[0] ) { FreeFace( pFaces ); } else { pFaces->next = pTotalFaces; pTotalFaces = pFaces; } pFaces = next; } } return pTotalFaces; }
/* ================ BuildFaceTree_r ================ */ void BuildFaceTree_r(node_t * node, bspFace_t * list) { bspFace_t *split; bspFace_t *next; int side; plane_t *plane; bspFace_t *newFace; bspFace_t *childLists[2]; winding_t *frontWinding, *backWinding; int i; int splitPlaneNum; int hintSplit; i = CountFaceList(list); SelectSplitPlaneNum(node, list, &splitPlaneNum, &hintSplit); // if we don't have any more faces, this is a node if(splitPlaneNum == -1) { node->planenum = PLANENUM_LEAF; c_faceLeafs++; return; } // partition the list node->planenum = splitPlaneNum; node->hint = hintSplit; plane = &mapPlanes[splitPlaneNum]; childLists[0] = NULL; childLists[1] = NULL; for(split = list; split; split = next) { next = split->next; if(split->planenum == node->planenum) { FreeBspFace(split); continue; } side = WindingOnPlaneSide(split->w, plane->normal, plane->dist); if(side == SIDE_CROSS) { ClipWindingEpsilon(split->w, plane->normal, plane->dist, CLIP_EPSILON * 2, &frontWinding, &backWinding); if(frontWinding) { newFace = AllocBspFace(); newFace->w = frontWinding; newFace->next = childLists[0]; newFace->planenum = split->planenum; newFace->priority = split->priority; newFace->hint = split->hint; childLists[0] = newFace; } if(backWinding) { newFace = AllocBspFace(); newFace->w = backWinding; newFace->next = childLists[1]; newFace->planenum = split->planenum; newFace->priority = split->priority; newFace->hint = split->hint; childLists[1] = newFace; } FreeBspFace(split); } else if(side == SIDE_FRONT) { split->next = childLists[0]; childLists[0] = split; } else if(side == SIDE_BACK) { split->next = childLists[1]; childLists[1] = split; } } // recursively process children for(i = 0; i < 2; i++) { node->children[i] = AllocNode(); node->children[i]->parent = node; VectorCopy(node->mins, node->children[i]->mins); VectorCopy(node->maxs, node->children[i]->maxs); } for(i = 0; i < 3; i++) { if(plane->normal[i] == 1) { node->children[0]->mins[i] = plane->dist; node->children[1]->maxs[i] = plane->dist; break; } } for(i = 0; i < 2; i++) { BuildFaceTree_r(node->children[i], childLists[i]); } }
void BuildFaceTree_r( node_t *node, face_t *list ){ face_t *split; face_t *next; int side; plane_t *plane; face_t *newFace; face_t *childLists[2]; winding_t *frontWinding, *backWinding; int i; int splitPlaneNum, compileFlags; /* count faces left */ i = CountFaceList( list ); /* select the best split plane */ SelectSplitPlaneNum( node, list, &splitPlaneNum, &compileFlags ); /* if we don't have any more faces, this is a node */ if ( splitPlaneNum == -1 ) { node->planenum = PLANENUM_LEAF; c_faceLeafs++; return; } /* partition the list */ node->planenum = splitPlaneNum; node->compileFlags = compileFlags; plane = &mapplanes[ splitPlaneNum ]; childLists[0] = NULL; childLists[1] = NULL; for ( split = list; split; split = next ) { /* set next */ next = split->next; /* don't split by identical plane */ if ( split->planenum == node->planenum ) { FreeBspFace( split ); continue; } /* determine which side the face falls on */ side = WindingOnPlaneSide( split->w, plane->normal, plane->dist ); /* switch on side */ if ( side == SIDE_CROSS ) { ClipWindingEpsilon( split->w, plane->normal, plane->dist, CLIP_EPSILON * 2, &frontWinding, &backWinding ); if ( frontWinding ) { newFace = AllocBspFace(); newFace->w = frontWinding; newFace->next = childLists[0]; newFace->planenum = split->planenum; newFace->priority = split->priority; newFace->compileFlags = split->compileFlags; childLists[0] = newFace; } if ( backWinding ) { newFace = AllocBspFace(); newFace->w = backWinding; newFace->next = childLists[1]; newFace->planenum = split->planenum; newFace->priority = split->priority; newFace->compileFlags = split->compileFlags; childLists[1] = newFace; } FreeBspFace( split ); } else if ( side == SIDE_FRONT ) { split->next = childLists[0]; childLists[0] = split; } else if ( side == SIDE_BACK ) { split->next = childLists[1]; childLists[1] = split; } } // recursively process children for ( i = 0 ; i < 2 ; i++ ) { node->children[i] = AllocNode(); node->children[i]->parent = node; VectorCopy( node->mins, node->children[i]->mins ); VectorCopy( node->maxs, node->children[i]->maxs ); } for ( i = 0 ; i < 3 ; i++ ) { if ( plane->normal[i] == 1 ) { node->children[0]->mins[i] = plane->dist; node->children[1]->maxs[i] = plane->dist; break; } } for ( i = 0 ; i < 2 ; i++ ) { BuildFaceTree_r( node->children[i], childLists[i] ); } }
void BuildFaceTree_r(node_t * node, face_t * list) { face_t *split; face_t *next; int side; plane_t *plane; face_t *newFace; face_t *childLists[2]; winding_t *frontWinding, *backWinding; int i; int splitPlaneNum, compileFlags; qboolean isstruct = qfalse; int splits, front, back; /* count faces left */ i = CountFaceList(list); #if defined(DEBUG_SPLITS) Sys_FPrintf(SYS_VRB, "faces left = %d\n", i); #endif /* select the best split plane */ SelectSplitPlaneNum(node, list, &splitPlaneNum, &compileFlags); /* if we don't have any more faces, this is a leaf */ if(splitPlaneNum == -1) { node->planenum = PLANENUM_LEAF; node->has_structural_children = qfalse; c_faceLeafs++; return; } /* partition the list */ node->planenum = splitPlaneNum; node->compileFlags = compileFlags; node->has_structural_children = !(compileFlags & C_DETAIL) && !node->opaque; plane = &mapplanes[splitPlaneNum]; childLists[0] = NULL; childLists[1] = NULL; splits = front = back = 0; for(split = list; split; split = next) { /* set next */ next = split->next; /* don't split by identical plane */ if(split->planenum == node->planenum) { FreeBspFace(split); continue; } if(!(split->compileFlags & C_DETAIL)) isstruct = 1; /* determine which side the face falls on */ side = WindingOnPlaneSide(split->w, plane->normal, plane->dist); /* switch on side */ if(side == SIDE_CROSS) { splits++; ClipWindingEpsilon(split->w, plane->normal, plane->dist, CLIP_EPSILON * 2, &frontWinding, &backWinding); if(frontWinding) { newFace = AllocBspFace(); newFace->w = frontWinding; newFace->next = childLists[0]; newFace->planenum = split->planenum; newFace->priority = split->priority; newFace->compileFlags = split->compileFlags; childLists[0] = newFace; front++; } if(backWinding) { newFace = AllocBspFace(); newFace->w = backWinding; newFace->next = childLists[1]; newFace->planenum = split->planenum; newFace->priority = split->priority; newFace->compileFlags = split->compileFlags; childLists[1] = newFace; back++; } FreeBspFace(split); } else if(side == SIDE_FRONT) { split->next = childLists[0]; childLists[0] = split; front++; } else if(side == SIDE_BACK) { split->next = childLists[1]; childLists[1] = split; back++; } } // recursively process children for(i = 0; i < 2; i++) { node->children[i] = AllocNode(); node->children[i]->parent = node; VectorCopy(node->mins, node->children[i]->mins); VectorCopy(node->maxs, node->children[i]->maxs); c_faceNodes++; } for(i = 0; i < 3; i++) { if(plane->normal[i] == 1) { node->children[0]->mins[i] = plane->dist; node->children[1]->maxs[i] = plane->dist; break; } } #if 1 if(drawBSP && drawTree) { drawChildLists[0] = childLists[0]; drawChildLists[1] = childLists[1]; drawSplitNode = node; Draw_Scene(DrawAll); } #endif #if defined(DEBUG_SPLITS) if((node->compileFlags & C_DETAIL) && isstruct) Sys_FPrintf(SYS_ERR, "I am detail, my child is structural, this is a wtf1\n", node->has_structural_children); #endif for(i = 0; i < 2; i++) { BuildFaceTree_r(node->children[i], childLists[i]); node->has_structural_children |= node->children[i]->has_structural_children; } #if defined(DEBUG_SPLITS) if((node->compileFlags & C_DETAIL) && !(node->children[0]->compileFlags & C_DETAIL) && node->children[0]->planenum != PLANENUM_LEAF) Sys_FPrintf(SYS_ERR, "I am detail, my child is structural\n", node->has_structural_children); if((node->compileFlags & C_DETAIL) && isstruct) Sys_FPrintf(SYS_ERR, "I am detail, my child is structural, this is a wtf2\n", node->has_structural_children); #endif }