/* ================== CSGFaces Returns a list of surfaces containing aall of the faces ================== */ surface_t *CSGFaces (brushset_t *bs) { brush_t *b1, *b2; int i; qboolean overwrite; face_t *f; surface_t *surfhead; qprintf ("---- CSGFaces ----\n"); memset (validfaces, 0, sizeof(validfaces)); csgfaces = brushfaces = csgmergefaces = 0; Draw_ClearWindow (); // // do the solid faces // for (b1 = bs->brushes ; b1 ; b1 = b1->next) { // set outside to a copy of the brush's faces CopyFacesToOutside (b1); overwrite = false; for (b2 = bs->brushes ; b2 ; b2 = b2->next) { // see if b2 needs to clip a chunk out of b1 if (b1 == b2) { overwrite = true; // later brushes now overwrite continue; } // check bounding box first for (i = 0 ; i < 3 ; i++) if (b1->mins[i] > b2->maxs[i] || b1->maxs[i] < b2->mins[i]) break; if (i < 3) continue; // divide faces by the planes of the new brush inside = outside; outside = NULL; for (f = b2->faces ; f ; f = f->next) ClipInside (f->planenum, f->planeside, overwrite); // these faces are continued in another brush, so get rid of them if (b1->contents == CONTENTS_SOLID && b2->contents <= CONTENTS_WATER) FreeInside (b2->contents); else FreeInside (CONTENTS_SOLID); } // all of the faces left in outside are real surface faces if (b1->contents != CONTENTS_SOLID) SaveOutside (true); // mirror faces for inside view else SaveOutside (false); } #if 0 if (!csgfaces) Error ("No faces"); #endif surfhead = BuildSurfaces (); qprintf ("%5i brushfaces\n", brushfaces); qprintf ("%5i csgfaces\n", csgfaces); qprintf ("%5i mergedfaces\n", csgmergefaces); return surfhead; }
/* Builds a list of surfaces containing all of the faces */ void CSGFaces( tree_t *tree ) { int i; bool overwrite; brush_t *b1, *b2; face_t *f; qprintf( "---- CSGFaces ----\n" ); memset( tree->validfaces, 0, sizeof( tree->validfaces ) ); numcsgfaces = numcsgbrushfaces = numcsgmergefaces = 0; // do the solid faces for( b1 = tree->brushes; b1; b1 = b1->next ) { // set outside to a copy of the brush's faces CopyFacesToOutside( b1 ); overwrite = false; for( b2 = tree->brushes; b2; b2 = b2->next ) { // see if b2 needs to clip a chunk out of b1 if( b1 == b2 ) { overwrite = true; // later brushes now overwrite continue; } // check bounding box first for( i = 0; i < 3; i++ ) if( b1->mins[i] > b2->maxs[i] || b1->maxs[i] < b2->mins[i] ) break; if( i < 3 ) continue; // divide faces by the planes of the new brush inside = outside; outside = NULL; for( f = b2->faces; f; f = f->next ) ClipInside( f->planenum, f->planeside, overwrite ); // these faces are continued in another brush, so get rid of them if( b1->contents == BSP_CONTENTS_SOLID && b2->contents <= BSP_CONTENTS_WATER ) FreeInside( b2->contents ); else FreeInside( BSP_CONTENTS_SOLID ); } // all of the faces left in outside are real surface faces if( b1->contents != BSP_CONTENTS_SOLID ) SaveOutside( tree, true ); // mirror faces for inside view else SaveOutside( tree, false ); } BuildSurfaces( tree ); qprintf( "%5i brushfaces\n", numcsgbrushfaces ); qprintf( "%5i csgfaces\n", numcsgfaces ); qprintf( "%5i mergedfaces\n", numcsgmergefaces ); }
/* ================== CSGFaces Returns a list of surfaces containing all of the faces ================== */ surface_t * CSGFaces(void) { brush_t *b1, *b2; int i; bool overwrite; face_t *f; surface_t *surfhead; int iBrushes = 0; Message(msgProgress, "CSGFaces"); if (validfaces == NULL) validfaces = AllocMem(OTHER, sizeof(face_t *) * cPlanes, true); else memset(validfaces, 0, sizeof(face_t *) * cPlanes); csgfaces = brushfaces = csgmergefaces = 0; // do the solid faces for (b1 = pCurEnt->pBrushes; b1; b1 = b1->next) { // set outside to a copy of the brush's faces CopyFacesToOutside(b1); // Why is this necessary? overwrite = false; for (b2 = pCurEnt->pBrushes; b2; b2 = b2->next) { // check bounding box first for (i = 0; i < 3; i++) if (b1->mins[i] > b2->maxs[i] || b1->maxs[i] < b2->mins[i]) break; if (i < 3) continue; // see if b2 needs to clip a chunk out of b1 if (b1 == b2) { overwrite = true; continue; } // divide faces by the planes of the new brush inside = outside; outside = NULL; CheckInside(b2); for (f = b2->faces; f; f = f->next) ClipInside(f->planenum, f->planeside, overwrite); // these faces are continued in another brush, so get rid of them if (b1->contents == CONTENTS_SOLID && b2->contents <= CONTENTS_WATER) FreeInside(b2->contents); else FreeInside(CONTENTS_SOLID); } // all of the faces left in outside are real surface faces if (b1->contents != CONTENTS_SOLID) SaveOutside(true); // mirror faces for inside view else SaveOutside(false); iBrushes++; Message(msgPercent, iBrushes, pCurEnt->cBrushes); } surfhead = BuildSurfaces(); Message(msgStat, "%5i brushfaces", brushfaces); Message(msgStat, "%5i csgfaces", csgfaces); Message(msgStat, "%5i mergedfaces", csgmergefaces); return surfhead; }
/* =========== CSGBrush =========== */ void CSGBrush (int brushnum) { int hull; brush_t *b1, *b2; brushhull_t *bh1, *bh2; int bn; qboolean overwrite; int i; bface_t *f, *f2, *next, *fcopy; bface_t *outside, *oldoutside; entity_t *e; vec_t area; SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL); b1 = &mapbrushes[brushnum]; e = &entities[b1->entitynum]; for (hull = 0 ; hull<NUM_HULLS ; hull++) { bh1 = &b1->hulls[hull]; // set outside to a copy of the brush's faces outside = CopyFacesToOutside (bh1); overwrite = false; for (bn=0 ; bn<e->numbrushes ; bn++) { // see if b2 needs to clip a chunk out of b1 if (bn==brushnum) { overwrite = true; // later brushes now overwrite continue; } b2 = &mapbrushes[e->firstbrush + bn]; bh2 = &b2->hulls[hull]; if (!bh2->faces) continue; // brush isn't in this hull // check brush bounding box first for (i=0 ; i<3 ; i++) if (bh1->mins[i] > bh2->maxs[i] || bh1->maxs[i] < bh2->mins[i]) break; if (i<3) continue; // divide faces by the planes of the b2 to find which // fragments are inside f = outside; outside = NULL; for ( ; f ; f=next) { next = f->next; // check face bounding box first for (i=0 ; i<3 ; i++) if (bh2->mins[i] > f->maxs[i] || bh2->maxs[i] < f->mins[i]) break; if (i<3) { // this face doesn't intersect brush2's bbox f->next = outside; outside = f; continue; } oldoutside = outside; fcopy = CopyFace (f); // save to avoid fake splits // throw pieces on the front sides of the planes // into the outside list, return the remains on the inside for (f2=bh2->faces ; f2 && f ; f2=f2->next) f = ClipFace (b1, f, &outside, f2->planenum, overwrite); area = f ? WindingArea (f->w) : 0; if (f && area < 1.0) { qprintf ("Entity %i, Brush %i: tiny penetration\n" , b1->entitynum, b1->brushnum); c_tiny_clip++; FreeFace (f); f = NULL; } if (f) { // there is one convex fragment of the original // face left inside brush2 FreeFace (fcopy); if (b1->contents > b2->contents) { // inside a water brush f->contents = b2->contents; f->next = outside; outside = f; } else // inside a solid brush FreeFace (f); // throw it away } else { // the entire thing was on the outside, even // though the bounding boxes intersected, // which will never happen with axial planes // free the fragments chopped to the outside while (outside != oldoutside) { f2 = outside->next; FreeFace (outside); outside = f2; } // revert to the original face to avoid // unneeded false cuts fcopy->next = outside; outside = fcopy; } } } // all of the faces left in outside are real surface faces SaveOutside (b1, hull, outside, b1->contents); } }