Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

CSG.CPP File Reference

#include "stdafx.h"
#include "qe3.h"
#include "winding.h"

Include dependency graph for CSG.CPP:

Include dependency graph

Go to the source code of this file.

Functions

brush_tBrush_Merge (brush_t *brush1, brush_t *brush2, int onlyshape)
brush_tBrush_MergeList (brush_t *brushlist, int onlyshape)
brush_tBrush_MergeListPairs (brush_t *brushlist, int onlyshape)
void Brush_Scale (brush_t *b)
brush_tBrush_Subtract (brush_t *a, brush_t *b)
void CSG_MakeHollow (void)
void CSG_Merge (void)
void CSG_Subtract (void)


Function Documentation

brush_t* Brush_Merge brush_t brush1,
brush_t brush2,
int  onlyshape
 

Definition at line 91 of file CSG.CPP.

References Brush_Alloc(), Brush_BuildWindings(), brush_s::brush_faces, brush_t, plane_t::dist, Entity_LinkBrush(), f, Face_Alloc(), face_t, face_s::face_winding, i, brush_s::maxs, brush_s::mins, texdef_t::name, face_s::next, plane_t::normal, ON_EPSILON, brush_s::owner, face_s::plane, Plane_Equal(), face_s::planepts, face_s::texdef, VectorCopy, and Winding_PlanesConcave().

Referenced by Brush_MergeListPairs().

00092 {
00093     int i, shared;
00094     brush_t *newbrush;
00095     face_t *face1, *face2, *newface, *f;
00096 
00097     // check for bounding box overlapp
00098     for (i = 0; i < 3; i++)
00099     {
00100         if (brush1->mins[i] > brush2->maxs[i] + ON_EPSILON
00101                 || brush1->maxs[i] < brush2->mins[i] - ON_EPSILON)
00102         {
00103             // never merge if the brushes overlap
00104             return NULL;
00105         }
00106     }
00107     //
00108     shared = 0;
00109     // check if the new brush would be convex... flipped planes make a brush non-convex
00110     for (face1 = brush1->brush_faces; face1; face1 = face1->next)
00111     {
00112         // don't check the faces of brush 1 and 2 touching each other
00113         for (face2 = brush2->brush_faces; face2; face2 = face2->next)
00114         {
00115             if (Plane_Equal(&face1->plane, &face2->plane, true))
00116             {
00117                 shared++;
00118                 // there may only be ONE shared side
00119                 if (shared > 1)
00120                     return NULL;
00121                 break;
00122             }
00123         }
00124         // if this face plane is shared
00125         if (face2) continue;
00126         //
00127         for (face2 = brush2->brush_faces; face2; face2 = face2->next)
00128         {
00129             // don't check the faces of brush 1 and 2 touching each other
00130             for (f = brush1->brush_faces; f; f = f->next)
00131             {
00132                 if (Plane_Equal(&face2->plane, &f->plane, true)) break;
00133             }
00134             if (f)
00135                 continue;
00136             //
00137             if (Plane_Equal(&face1->plane, &face2->plane, false))
00138             {
00139                 //if the texture/shader references should be the same but are not
00140                 if (!onlyshape && stricmp(face1->texdef.name, face2->texdef.name) != 0) return NULL;
00141                 continue;
00142             }
00143             //
00144             if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
00145                                     face1->plane.normal, face2->plane.normal,
00146                                     face1->plane.dist, face2->plane.dist))
00147             {
00148                 return NULL;
00149             } //end if
00150         } //end for
00151     } //end for
00152     //
00153     newbrush = Brush_Alloc();
00154     //
00155     for (face1 = brush1->brush_faces; face1; face1 = face1->next)
00156     {
00157         // don't add the faces of brush 1 and 2 touching each other
00158         for (face2 = brush2->brush_faces; face2; face2 = face2->next)
00159         {
00160             if (Plane_Equal(&face1->plane, &face2->plane, true))
00161                 break;
00162         }
00163         if (face2)
00164             continue;
00165         // don't add faces with the same plane twice
00166         for (f = newbrush->brush_faces; f; f = f->next)
00167         {
00168             if (Plane_Equal(&face1->plane, &f->plane, false))
00169                 break;
00170             if (Plane_Equal(&face1->plane, &f->plane, true))
00171                 break;
00172         }
00173         if (f)
00174             continue;
00175         //
00176         newface = Face_Alloc();
00177         newface->texdef = face1->texdef;
00178         VectorCopy(face1->planepts[0], newface->planepts[0]);
00179         VectorCopy(face1->planepts[1], newface->planepts[1]);
00180         VectorCopy(face1->planepts[2], newface->planepts[2]);
00181         newface->plane = face1->plane;
00182         newface->next = newbrush->brush_faces;
00183         newbrush->brush_faces = newface;
00184     }
00185     //
00186     for (face2 = brush2->brush_faces; face2; face2 = face2->next)
00187     {
00188         // don't add the faces of brush 1 and 2 touching each other
00189         for (face1 = brush1->brush_faces; face1; face1 = face1->next)
00190         {
00191             if (Plane_Equal(&face2->plane, &face1->plane, true))
00192                 break;
00193         }
00194         if (face1)
00195             continue;
00196         // don't add faces with the same plane twice
00197         for (f = newbrush->brush_faces; f; f = f->next)
00198         {
00199             if (Plane_Equal(&face2->plane, &f->plane, false))
00200                 break;
00201             if (Plane_Equal(&face2->plane, &f->plane, true))
00202                 break;
00203         }
00204         if (f)
00205             continue;
00206         //
00207         newface = Face_Alloc();
00208         newface->texdef = face2->texdef;
00209         VectorCopy(face2->planepts[0], newface->planepts[0]);
00210         VectorCopy(face2->planepts[1], newface->planepts[1]);
00211         VectorCopy(face2->planepts[2], newface->planepts[2]);
00212         newface->plane = face2->plane;
00213         newface->next = newbrush->brush_faces;
00214         newbrush->brush_faces = newface;
00215     }
00216     // link the new brush to an entity
00217     Entity_LinkBrush (brush1->owner, newbrush);
00218     // build windings for the faces
00219     Brush_BuildWindings( newbrush, false);
00220     return newbrush;
00221 }

Here is the call graph for this function:

brush_t* Brush_MergeList brush_t brushlist,
int  onlyshape
 

Definition at line 304 of file CSG.CPP.

References Brush_Alloc(), Brush_BuildWindings(), brush_s::brush_faces, brush_t, plane_t::dist, Entity_LinkBrush(), f, Face_Alloc(), face_t, face_s::face_winding, texdef_t::name, face_s::next, brush_s::next, plane_t::normal, brush_s::owner, face_s::plane, Plane_Equal(), face_s::planepts, face_s::texdef, VectorCopy, and Winding_PlanesConcave().

Referenced by CSG_Merge().

00305 {
00306     brush_t *brush1, *brush2, *brush3, *newbrush;
00307     face_t *face1, *face2, *face3, *newface, *f;
00308 
00309     if (!brushlist) return NULL;
00310     for (brush1 = brushlist; brush1; brush1 = brush1->next)
00311     {
00312         // check if the new brush would be convex... flipped planes make a brush concave
00313         for (face1 = brush1->brush_faces; face1; face1 = face1->next)
00314         {
00315             // don't check face1 if it touches another brush
00316             for (brush2 = brushlist; brush2; brush2 = brush2->next)
00317             {
00318                 if (brush2 == brush1) continue;
00319                 for (face2 = brush2->brush_faces; face2; face2 = face2->next)
00320                 {
00321                     if (Plane_Equal(&face1->plane, &face2->plane, true))
00322                     {
00323                         break;
00324                     }
00325                 }
00326                 if (face2) break;
00327             }
00328             // if face1 touches another brush
00329             if (brush2) continue;
00330             //
00331             for (brush2 = brush1->next; brush2; brush2 = brush2->next)
00332             {
00333                 // don't check the faces of brush 2 touching another brush
00334                 for (face2 = brush2->brush_faces; face2; face2 = face2->next)
00335                 {
00336                     for (brush3 = brushlist; brush3; brush3 = brush3->next)
00337                     {
00338                         if (brush3 == brush2) continue;
00339                         for (face3 = brush3->brush_faces; face3; face3 = face3->next)
00340                         {
00341                             if (Plane_Equal(&face2->plane, &face3->plane, true)) break;
00342                         }
00343                         if (face3) break;
00344                     }
00345                     // if face2 touches another brush
00346                     if (brush3) continue;
00347                     //
00348                     if (Plane_Equal(&face1->plane, &face2->plane, false))
00349                     {
00350                         //if the texture/shader references should be the same but are not
00351                         if (!onlyshape && stricmp(face1->texdef.name, face2->texdef.name) != 0) return NULL;
00352                         continue;
00353                     }
00354                     //
00355                     if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
00356                                             face1->plane.normal, face2->plane.normal,
00357                                             face1->plane.dist, face2->plane.dist))
00358                     {
00359                         return NULL;
00360                     }
00361                 }
00362             }
00363         }
00364     }
00365     //
00366     newbrush = Brush_Alloc();
00367     //
00368     for (brush1 = brushlist; brush1; brush1 = brush1->next)
00369     {
00370         for (face1 = brush1->brush_faces; face1; face1 = face1->next)
00371         {
00372             // don't add face1 to the new brush if it touches another brush
00373             for (brush2 = brushlist; brush2; brush2 = brush2->next)
00374             {
00375                 if (brush2 == brush1) continue;
00376                 for (face2 = brush2->brush_faces; face2; face2 = face2->next)
00377                 {
00378                     if (Plane_Equal(&face1->plane, &face2->plane, true))
00379                     {
00380                         break;
00381                     }
00382                 }
00383                 if (face2) break;
00384             }
00385             if (brush2) continue;
00386             // don't add faces with the same plane twice
00387             for (f = newbrush->brush_faces; f; f = f->next)
00388             {
00389                 if (Plane_Equal(&face1->plane, &f->plane, false))
00390                     break;
00391                 if (Plane_Equal(&face1->plane, &f->plane, true))
00392                     break;
00393             }
00394             if (f)
00395                 continue;
00396             //
00397             newface = Face_Alloc();
00398             newface->texdef = face1->texdef;
00399             VectorCopy(face1->planepts[0], newface->planepts[0]);
00400             VectorCopy(face1->planepts[1], newface->planepts[1]);
00401             VectorCopy(face1->planepts[2], newface->planepts[2]);
00402             newface->plane = face1->plane;
00403             newface->next = newbrush->brush_faces;
00404             newbrush->brush_faces = newface;
00405         }
00406     }
00407     // link the new brush to an entity
00408     Entity_LinkBrush (brushlist->owner, newbrush);
00409     // build windings for the faces
00410     Brush_BuildWindings( newbrush, false);
00411     return newbrush;
00412 }

Here is the call graph for this function:

brush_t* Brush_MergeListPairs brush_t brushlist,
int  onlyshape
 

Definition at line 233 of file CSG.CPP.

References Brush_Free(), Brush_Merge(), brush_t, brush_s::next, and brush_s::prev.

Referenced by CSG_Subtract().

00234 {
00235     int nummerges, merged;
00236     brush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
00237     brush_t *lastb2;
00238 
00239     if (!brushlist) return NULL;
00240 
00241     nummerges = 0;
00242     do
00243     {
00244         for (tail = brushlist; tail; tail = tail->next)
00245         {
00246             if (!tail->next) break;
00247         }
00248         merged = 0;
00249         newbrushlist = NULL;
00250         for (b1 = brushlist; b1; b1 = brushlist)
00251         {
00252             lastb2 = b1;
00253             for (b2 = b1->next; b2; b2 = b2->next)
00254             {
00255                 newbrush = Brush_Merge(b1, b2, onlyshape);
00256                 if (newbrush)
00257                 {
00258                     tail->next = newbrush;
00259                     lastb2->next = b2->next;
00260                     brushlist = brushlist->next;
00261                     b1->next = b1->prev = NULL;
00262                     b2->next = b2->prev = NULL;
00263                     Brush_Free(b1);
00264                     Brush_Free(b2);
00265                     for (tail = brushlist; tail; tail = tail->next)
00266                     {
00267                         if (!tail->next) break;
00268                     } //end for
00269                     merged++;
00270                     nummerges++;
00271                     break;
00272                 }
00273                 lastb2 = b2;
00274             }
00275             //if b1 can't be merged with any of the other brushes
00276             if (!b2)
00277             {
00278                 brushlist = brushlist->next;
00279                 //keep b1
00280                 b1->next = newbrushlist;
00281                 newbrushlist = b1;
00282             }
00283         }
00284         brushlist = newbrushlist;
00285     } while(merged);
00286     return newbrushlist;
00287 }

Here is the call graph for this function:

void Brush_Scale brush_t b  ) 
 

Definition at line 34 of file CSG.CPP.

References b, brush_s::brush_faces, brush_t, QEGlobals_t::d_gridsize, f, face_t, g_qeglobals, i, face_s::next, face_s::planepts, and VectorScale.

00035 {
00036   for (face_t* f = b->brush_faces ; f ; f=f->next)
00037   {
00038       for (int i=0 ; i<3 ; i++)
00039     {
00040       VectorScale (f->planepts[i], g_qeglobals.d_gridsize, f->planepts[i]);
00041     }
00042   }
00043 }

brush_t* Brush_Subtract brush_t a,
brush_t b
 

Definition at line 423 of file CSG.CPP.

References b, brush_s::brush_faces, Brush_Free(), Brush_SplitBrushByFace(), brush_t, f, face_t, in, next, brush_s::next, face_s::next, and brush_s::prev.

Referenced by CSG_Subtract().

00424 {
00425     // a - b = out (list)
00426     brush_t *front, *back;
00427     brush_t *in, *out, *next;
00428     face_t *f;
00429 
00430     in = a;
00431     out = NULL;
00432     for (f = b->brush_faces; f && in; f = f->next)
00433     {
00434         Brush_SplitBrushByFace(in, f, &front, &back);
00435         if (in != a) Brush_Free(in);
00436         if (front)
00437         {   // add to list
00438             front->next = out;
00439             out = front;
00440         }
00441         in = back;
00442     }
00443     //NOTE: in != a just in case brush b has no faces
00444     if (in && in != a)
00445     {
00446         Brush_Free(in);
00447     }
00448     else
00449     {   //didn't really intersect
00450         for (b = out; b; b = next)
00451         {
00452             next = b->next;
00453             b->next = b->prev = NULL;
00454             Brush_Free(b);
00455         }
00456         return a;
00457     }
00458     return out;
00459 }

Here is the call graph for this function:

void CSG_MakeHollow void   ) 
 

Definition at line 45 of file CSG.CPP.

References b, Brush_AddToList(), brush_s::brush_faces, Brush_Free(), Brush_SplitBrushByFace(), brush_t, QEGlobals_t::d_gridsize, entity_s::eclass, f, face_t, eclass_s::fixedsize, g_qeglobals, brush_s::hiddenBrush, i, move(), brush_s::next, next, face_s::next, plane_t::normal, brush_s::owner, brush_s::patchBrush, face_s::plane, face_s::planepts, selected_brushes, Sys_UpdateWindows(), brush_s::terrainBrush, vec3_t, VectorScale, VectorSubtract, and W_ALL.

Referenced by CMainFrame::OnSelectionMakehollow().

00046 {
00047     brush_t     *b, *front, *back, *next;
00048     face_t      *f;
00049     face_t      split;
00050     vec3_t      move;
00051     int         i;
00052 
00053     for (b = selected_brushes.next ; b != &selected_brushes ; b=next)
00054     {
00055         next = b->next;
00056 
00057     if (b->owner->eclass->fixedsize || b->patchBrush || b->terrainBrush || b->hiddenBrush)
00058           continue;
00059 
00060         for (f = b->brush_faces ; f ; f=f->next)
00061         {
00062             split = *f;
00063             VectorScale (f->plane.normal, g_qeglobals.d_gridsize, move);
00064             for (i=0 ; i<3 ; i++)
00065                 VectorSubtract (split.planepts[i], move, split.planepts[i]);
00066 
00067             Brush_SplitBrushByFace (b, &split, &front, &back);
00068             if (back)
00069                 Brush_Free (back);
00070             if (front)
00071                 Brush_AddToList (front, &selected_brushes);
00072         }
00073         Brush_Free (b);
00074     }
00075     Sys_UpdateWindows (W_ALL);
00076 }

Here is the call graph for this function:

void CSG_Merge void   ) 
 

Definition at line 591 of file CSG.CPP.

References b, qtexture_s::bFromShader, Brush_AddToList(), brush_s::brush_faces, Brush_Free(), Brush_MergeList(), Brush_RemoveFromList(), brush_t, face_s::d_texture, entity_s::eclass, eclass_s::fixedsize, brush_s::next, next, qtexture_s::nShaderFlags, brush_s::owner, brush_s::patchBrush, brush_s::prev, selected_brushes, Sys_Printf(), Sys_UpdateWindows(), brush_s::terrainBrush, and W_ALL.

Referenced by CMainFrame::OnSelectionCsgmerge().

00592 {
00593     brush_t *b, *next, *newlist, *newbrush;
00594     struct entity_s *owner;
00595 
00596     Sys_Printf ("Merging...\n");
00597 
00598     if (selected_brushes.next == &selected_brushes)
00599     {
00600         Sys_Printf("No brushes selected.\n");
00601         return;
00602     }
00603 
00604     if (selected_brushes.next->next == &selected_brushes)
00605     {
00606         Sys_Printf("At least two brushes have to be selected.\n");
00607         return;
00608     }
00609 
00610     owner = selected_brushes.next->owner;
00611 
00612     for (b = selected_brushes.next; b != &selected_brushes; b = next)
00613     {
00614         next = b->next;
00615 
00616         if (b->owner->eclass->fixedsize)
00617         {
00618             // can't use texture from a fixed entity, so don't subtract
00619             Sys_Printf("Cannot add fixed size entities.\n");
00620             return;
00621         }
00622 
00623         if (b->patchBrush)
00624         {
00625             Sys_Printf("Cannot add patches.\n");
00626             return;
00627         }
00628         if (b->terrainBrush)
00629         {
00630             Sys_Printf("Cannot add terrains.\n");
00631             return;
00632         }
00633 
00634         if (b->brush_faces->d_texture->bFromShader && (b->brush_faces->d_texture->nShaderFlags & QER_NOCARVE))
00635         {
00636             Sys_Printf("Cannot add brushes using shaders that don't allows CSG operations.\n");
00637             return;
00638         }
00639 
00640         if (b->owner != owner)
00641         {
00642             Sys_Printf("Cannot add brushes from different entities.\n");
00643             return;
00644         }
00645 
00646     }
00647 
00648     newlist = NULL;
00649     for (b = selected_brushes.next; b != &selected_brushes; b = next)
00650     {
00651         next = b->next;
00652 
00653         Brush_RemoveFromList(b);
00654         b->next = newlist;
00655         b->prev = NULL;
00656         newlist = b;
00657     }
00658 
00659     newbrush = Brush_MergeList(newlist, true);
00660     // if the new brush would not be convex
00661     if (!newbrush)
00662     {
00663         // add the brushes back into the selection
00664         for (b = newlist; b; b = next)
00665         {
00666             next = b->next;
00667             b->next = NULL;
00668             b->prev = NULL;
00669             Brush_AddToList(b, &selected_brushes);
00670         }
00671         Sys_Printf("Cannot add a set of brushes with a concave hull.\n");
00672         return;
00673     }
00674     // free the original brushes
00675     for (b = newlist; b; b = next)
00676     {
00677         next = b->next;
00678         b->next = NULL;
00679         b->prev = NULL;
00680         Brush_Free(b);
00681     }
00682     Brush_AddToList(newbrush, &selected_brushes);
00683 
00684     Sys_Printf ("done.\n");
00685     Sys_UpdateWindows (W_ALL);
00686 }

Here is the call graph for this function:

void CSG_Subtract void   ) 
 

Definition at line 466 of file CSG.CPP.

References active_brushes, b, qtexture_s::bFromShader, Brush_AddToList(), brush_s::brush_faces, Brush_Free(), Brush_MergeListPairs(), Brush_RemoveFromList(), Brush_Subtract(), brush_t, face_s::d_texture, entity_s::eclass, eclass_s::fixedsize, brush_s::hiddenBrush, i, brush_s::maxs, brush_s::mins, brush_s::next, next, qtexture_s::nShaderFlags, numbrushes, ON_EPSILON, brush_s::owner, brush_s::patchBrush, brush_s::prev, s, selected_brushes, Sys_Printf(), Sys_UpdateWindows(), brush_s::terrainBrush, Undo_AddBrush(), Undo_EndBrush(), and W_ALL.

Referenced by CMainFrame::OnSelectionCsgsubtract(), and Spherize().

00467 {
00468     brush_t     *b, *s, *fragments, *nextfragment, *frag, *next, *snext;
00469     brush_t     fragmentlist;
00470     int         i, numfragments, numbrushes;
00471 
00472     Sys_Printf ("Subtracting...\n");
00473 
00474     if (selected_brushes.next == &selected_brushes)
00475     {
00476         Sys_Printf("No brushes selected.\n");
00477         return;
00478     }
00479 
00480     fragmentlist.next = &fragmentlist;
00481     fragmentlist.prev = &fragmentlist;
00482 
00483     numfragments = 0;
00484     numbrushes = 0;
00485     for (b = selected_brushes.next ; b != &selected_brushes ; b=next)
00486     {
00487         next = b->next;
00488 
00489         if (b->owner->eclass->fixedsize)
00490             continue;   // can't use texture from a fixed entity, so don't subtract
00491 
00492         // chop all fragments further up
00493         for (s = fragmentlist.next; s != &fragmentlist; s = snext)
00494         {
00495             snext = s->next;
00496 
00497             for (i=0 ; i<3 ; i++)
00498                 if (b->mins[i] >= s->maxs[i] - ON_EPSILON 
00499                 || b->maxs[i] <= s->mins[i] + ON_EPSILON)
00500                     break;
00501             if (i != 3)
00502                 continue;   // definately don't touch
00503             fragments = Brush_Subtract(s, b);
00504             // if the brushes did not really intersect
00505             if (fragments == s)
00506                 continue;
00507             // try to merge fragments
00508             fragments = Brush_MergeListPairs(fragments, true);
00509             // add the fragments to the list
00510             for (frag = fragments; frag; frag = nextfragment)
00511             {
00512                 nextfragment = frag->next;
00513                 frag->next = NULL;
00514                 frag->owner = s->owner;
00515                 Brush_AddToList(frag, &fragmentlist);
00516             }
00517             // free the original brush
00518             Brush_Free(s);
00519         }
00520 
00521         // chop any active brushes up
00522         for (s = active_brushes.next; s != &active_brushes; s = snext)
00523         {
00524             snext = s->next;
00525 
00526             if (s->owner->eclass->fixedsize || s->patchBrush || s->terrainBrush || s->hiddenBrush)
00527                 continue;
00528 
00529             //face_t *pFace = s->brush_faces;
00530             if (s->brush_faces->d_texture->bFromShader && (s->brush_faces->d_texture->nShaderFlags & QER_NOCARVE))
00531             {
00532                 continue;
00533             }
00534 
00535             for (i=0 ; i<3 ; i++)
00536                 if (b->mins[i] >= s->maxs[i] - ON_EPSILON 
00537                 || b->maxs[i] <= s->mins[i] + ON_EPSILON)
00538                     break;
00539             if (i != 3)
00540                 continue;   // definately don't touch
00541 
00542             fragments = Brush_Subtract(s, b);
00543             // if the brushes did not really intersect
00544             if (fragments == s)
00545                 continue;
00546             //
00547             Undo_AddBrush(s);
00548             // one extra brush chopped up
00549             numbrushes++;
00550             // try to merge fragments
00551             fragments = Brush_MergeListPairs(fragments, true);
00552             // add the fragments to the list
00553             for (frag = fragments; frag; frag = nextfragment)
00554             {
00555                 nextfragment = frag->next;
00556                 frag->next = NULL;
00557                 frag->owner = s->owner;
00558                 Brush_AddToList(frag, &fragmentlist);
00559             }
00560             // free the original brush
00561             Brush_Free(s);
00562         }
00563     }
00564 
00565     // move all fragments to the active brush list
00566     for (frag = fragmentlist.next; frag != &fragmentlist; frag = nextfragment)
00567     {
00568         nextfragment = frag->next;
00569         numfragments++;
00570         Brush_RemoveFromList(frag);
00571         Brush_AddToList(frag, &active_brushes);
00572         Undo_EndBrush(frag);
00573     }
00574 
00575     if (numfragments == 0)
00576     {
00577         Sys_Printf("Selected brush%s did not intersect with any other brushes.\n",
00578                     (selected_brushes.next->next == &selected_brushes) ? "":"es");
00579         return;
00580     }
00581     Sys_Printf("done. (created %d fragment%s out of %d brush%s)\n", numfragments, (numfragments == 1)?"":"s",
00582                             numbrushes, (numbrushes == 1)?"":"es");
00583     Sys_UpdateWindows(W_ALL);
00584 }

Here is the call graph for this function:


Generated on Thu Aug 25 17:30:20 2005 for Quake III Arena by  doxygen 1.3.9.1