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

CSG.CPP

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 #include "stdafx.h"
00024 #include "qe3.h"
00025 #include "winding.h"
00026 
00027 
00028 /*
00029 =============
00030 CSG_MakeHollow
00031 =============
00032 */
00033 
00034 void Brush_Scale(brush_t* b)
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 }
00044 
00045 void CSG_MakeHollow (void)
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 }
00077 
00078 /*
00079 =============
00080 Brush_Merge
00081 
00082  Returns a new brush that is created by merging brush1 and brush2.
00083  May return NULL if brush1 and brush2 do not create a convex brush when merged.
00084  The input brushes brush1 and brush2 stay intact.
00085 
00086  if onlyshape is true then the merge is allowed based on the shape only
00087  otherwise the texture/shader references of faces in the same plane have to
00088  be the same as well.
00089 =============
00090 */
00091 brush_t *Brush_Merge(brush_t *brush1, brush_t *brush2, int onlyshape)
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 }
00222 
00223 /*
00224 =============
00225 Brush_MergeListPairs
00226 
00227   Returns a list with merged brushes.
00228   Tries to merge brushes pair wise.
00229   The input list is destroyed.
00230   Input and output should be a single linked list using .next
00231 =============
00232 */
00233 brush_t *Brush_MergeListPairs(brush_t *brushlist, int onlyshape)
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 }
00288 
00289 /*
00290 =============
00291 Brush_MergeList
00292 
00293  Tries to merge all brushes in the list into one new brush.
00294  The input brush list stays intact.
00295  Returns NULL if no merged brush can be created.
00296  To create a new brush the brushes in the list may not overlap and
00297  the outer faces of the brushes together should make a new convex brush.
00298 
00299  if onlyshape is true then the merge is allowed based on the shape only
00300  otherwise the texture/shader references of faces in the same plane have to
00301  be the same as well.
00302 =============
00303 */
00304 brush_t *Brush_MergeList(brush_t *brushlist, int onlyshape)
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 }
00413 
00414 /*
00415 =============
00416 Brush_Subtract
00417 
00418  Returns a list of brushes that remain after B is subtracted from A.
00419  May by empty if A is contained inside B.
00420  The originals are undisturbed.
00421 =============
00422 */
00423 brush_t *Brush_Subtract(brush_t *a, brush_t *b)
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 }
00460 
00461 /*
00462 =============
00463 CSG_Subtract
00464 =============
00465 */
00466 void CSG_Subtract (void)
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 }
00585 
00586 /*
00587 =============
00588 CSG_Merge
00589 =============
00590 */
00591 void CSG_Merge(void)
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 }

Generated on Thu Aug 25 12:38:27 2005 for Quake III Arena by  doxygen 1.3.9.1