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

csg.c

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 "qbsp.h"
00024 
00025 /*
00026 
00027 tag all brushes with original contents
00028 brushes may contain multiple contents
00029 there will be no brush overlap after csg phase
00030 
00031 */
00032 
00033 int minplanenums[3];
00034 int maxplanenums[3];
00035 
00036 //===========================================================================
00037 //
00038 // Parameter:               -
00039 // Returns:                 -
00040 // Changes Globals:     -
00041 //===========================================================================
00042 void CheckBSPBrush(bspbrush_t *brush)
00043 {
00044     int i, j;
00045     plane_t *plane1, *plane2;
00046 
00047     //check if the brush is convex... flipped planes make a brush non-convex
00048     for (i = 0; i < brush->numsides; i++)
00049     {
00050         for (j = 0; j < brush->numsides; j++)
00051         {
00052             if (i == j) continue;
00053             plane1 = &mapplanes[brush->sides[i].planenum];
00054             plane2 = &mapplanes[brush->sides[j].planenum];
00055             //
00056             if (WindingsNonConvex(brush->sides[i].winding,
00057                                     brush->sides[j].winding,
00058                                     plane1->normal, plane2->normal,
00059                                     plane1->dist, plane2->dist))
00060             {
00061                 Log_Print("non convex brush");
00062                 break;
00063             } //end if
00064         } //end for
00065     } //end for
00066     BoundBrush(brush);
00067     //check for out of bound brushes
00068     for (i = 0; i < 3; i++)
00069     {
00070         if (brush->mins[i] < -MAX_MAP_BOUNDS || brush->maxs[i] > MAX_MAP_BOUNDS)
00071         {
00072             Log_Print("brush: bounds out of range\n");
00073             Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]);
00074             break;
00075         } //end if
00076         if (brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS)
00077         {
00078             Log_Print("brush: no visible sides on brush\n");
00079             Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]);
00080             break;
00081         } //end if
00082     } //end for
00083 } //end of the function CheckBSPBrush
00084 //===========================================================================
00085 //
00086 // Parameter:               -
00087 // Returns:                 -
00088 // Changes Globals:     -
00089 //===========================================================================
00090 void BSPBrushWindings(bspbrush_t *brush)
00091 {
00092     int i, j;
00093     winding_t *w;
00094     plane_t *plane;
00095 
00096     for (i = 0; i < brush->numsides; i++)
00097     {
00098         plane = &mapplanes[brush->sides[i].planenum];
00099         w = BaseWindingForPlane(plane->normal, plane->dist);
00100         for (j = 0; j < brush->numsides && w; j++)
00101         {
00102             if (i == j) continue;
00103             plane = &mapplanes[brush->sides[j].planenum^1];
00104             ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
00105         } //end for
00106         brush->sides[i].winding = w;
00107     } //end for
00108 } //end of the function BSPBrushWindings
00109 //===========================================================================
00110 // NOTE: can't keep brush->original intact
00111 //
00112 // Parameter:               -
00113 // Returns:                 -
00114 // Changes Globals:     -
00115 //===========================================================================
00116 bspbrush_t *TryMergeBrushes(bspbrush_t *brush1, bspbrush_t *brush2)
00117 {
00118     int i, j, k, n, shared;
00119     side_t *side1, *side2, *cs;
00120     plane_t *plane1, *plane2;
00121     bspbrush_t *newbrush;
00122 
00123     //check for bounding box overlapp
00124     for (i = 0; i < 3; i++)
00125     {
00126         if (brush1->mins[i] > brush2->maxs[i] + 2
00127                 || brush1->maxs[i] < brush2->mins[i] - 2)
00128         {
00129             return NULL;
00130         } //end if
00131     } //end for
00132     //
00133     shared = 0;
00134     //check if the brush is convex... flipped planes make a brush non-convex
00135     for (i = 0; i < brush1->numsides; i++)
00136     {
00137         side1 = &brush1->sides[i];
00138         //don't check the "shared" sides
00139         for (k = 0; k < brush2->numsides; k++)
00140         {
00141             side2 = &brush2->sides[k];
00142             if (side1->planenum == (side2->planenum^1))
00143             {
00144                 shared++;
00145                 //there may only be ONE shared side
00146                 if (shared > 1) return NULL;
00147                 break;
00148             } //end if
00149         } //end for
00150         if (k < brush2->numsides) continue;
00151         //
00152         for (j = 0; j < brush2->numsides; j++)
00153         {
00154             side2 = &brush2->sides[j];
00155             //don't check the "shared" sides
00156             for (n = 0; n < brush1->numsides; n++)
00157             {
00158                 side1 = &brush1->sides[n];
00159                 if (side1->planenum == (side2->planenum^1)) break;
00160             } //end for
00161             if (n < brush1->numsides) continue;
00162             //
00163             side1 = &brush1->sides[i];
00164             //if the side is in the same plane
00165             //*
00166             if (side1->planenum == side2->planenum)
00167             {
00168                 if (side1->texinfo != TEXINFO_NODE &&
00169                     side2->texinfo != TEXINFO_NODE &&
00170                     side1->texinfo != side2->texinfo) return NULL;
00171                 continue;
00172             } //end if
00173             //
00174             plane1 = &mapplanes[side1->planenum];
00175             plane2 = &mapplanes[side2->planenum];
00176             //
00177             if (WindingsNonConvex(side1->winding, side2->winding,
00178                                     plane1->normal, plane2->normal,
00179                                     plane1->dist, plane2->dist))
00180             {
00181                 return NULL;
00182             } //end if
00183         } //end for
00184     } //end for
00185     newbrush = AllocBrush(brush1->numsides + brush2->numsides);
00186     newbrush->original = brush1->original;
00187     newbrush->numsides = 0;
00188     //newbrush->side = brush1->side;    //brush contents
00189     //fix texinfos for sides lying in the same plane
00190     for (i = 0; i < brush1->numsides; i++)
00191     {
00192         side1 = &brush1->sides[i];
00193         //
00194         for (n = 0; n < brush2->numsides; n++)
00195         {
00196             side2 = &brush2->sides[n];
00197             //if both sides are in the same plane get the texinfo right
00198             if (side1->planenum == side2->planenum)
00199             {
00200                 if (side1->texinfo == TEXINFO_NODE) side1->texinfo = side2->texinfo;
00201                 if (side2->texinfo == TEXINFO_NODE) side2->texinfo = side1->texinfo;
00202             } //end if
00203         } //end for
00204     } //end for
00205     //
00206     for (i = 0; i < brush1->numsides; i++)
00207     {
00208         side1 = &brush1->sides[i];
00209         //don't add the "shared" sides
00210         for (n = 0; n < brush2->numsides; n++)
00211         {
00212             side2 = &brush2->sides[n];
00213             if (side1->planenum == (side2->planenum ^ 1)) break;
00214         } //end for
00215         if (n < brush2->numsides) continue;
00216         //
00217         for (n = 0; n < newbrush->numsides; n++)
00218         {
00219             cs = &newbrush->sides[n];
00220             if (cs->planenum == side1->planenum)
00221             {
00222                 Log_Print("brush duplicate plane\n");
00223                 break;
00224             } //end if
00225         } //end if
00226         if (n < newbrush->numsides) continue;
00227         //add this side
00228         cs = &newbrush->sides[newbrush->numsides];
00229         newbrush->numsides++;
00230         *cs = *side1;
00231     } //end for
00232     for (j = 0; j < brush2->numsides; j++)
00233     {
00234         side2 = &brush2->sides[j];
00235         for (n = 0; n < brush1->numsides; n++)
00236         {
00237             side1 = &brush1->sides[n];
00238             //if the side is in the same plane
00239             if (side2->planenum == side1->planenum) break;
00240             //don't add the "shared" sides
00241             if (side2->planenum == (side1->planenum ^ 1)) break;
00242         } //end for
00243         if (n < brush1->numsides) continue;
00244         //
00245         for (n = 0; n < newbrush->numsides; n++)
00246         {
00247             cs = &newbrush->sides[n];
00248             if (cs->planenum == side2->planenum)
00249             {
00250                 Log_Print("brush duplicate plane\n");
00251                 break;
00252             } //end if
00253         } //end if
00254         if (n < newbrush->numsides) continue;
00255         //add this side
00256         cs = &newbrush->sides[newbrush->numsides];
00257         newbrush->numsides++;
00258         *cs = *side2;
00259     } //end for
00260     BSPBrushWindings(newbrush);
00261     BoundBrush(newbrush);
00262     CheckBSPBrush(newbrush);
00263     return newbrush;
00264 } //end of the function TryMergeBrushes
00265 //===========================================================================
00266 //
00267 // Parameter:               -
00268 // Returns:                 -
00269 // Changes Globals:     -
00270 //===========================================================================
00271 bspbrush_t *MergeBrushes(bspbrush_t *brushlist)
00272 {
00273     int nummerges, merged;
00274     bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
00275     bspbrush_t *lastb2;
00276 
00277     if (!brushlist) return NULL;
00278 
00279     qprintf("%5d brushes merged", nummerges = 0);
00280     do
00281     {
00282         for (tail = brushlist; tail; tail = tail->next)
00283         {
00284             if (!tail->next) break;
00285         } //end for
00286         merged = 0;
00287         newbrushlist = NULL;
00288         for (b1 = brushlist; b1; b1 = brushlist)
00289         {
00290             lastb2 = b1;
00291             for (b2 = b1->next; b2; b2 = b2->next)
00292             {
00293                 //if the brushes don't have the same contents
00294                 if (b1->original->contents != b2->original->contents ||
00295                     b1->original->expansionbbox != b2->original->expansionbbox) newbrush = NULL;
00296                 else newbrush = TryMergeBrushes(b1, b2);
00297                 if (newbrush)
00298                 {
00299                     tail->next = newbrush;
00300                     lastb2->next = b2->next;
00301                     brushlist = brushlist->next;
00302                     FreeBrush(b1);
00303                     FreeBrush(b2);
00304                     for (tail = brushlist; tail; tail = tail->next)
00305                     {
00306                         if (!tail->next) break;
00307                     } //end for
00308                     merged++;
00309                     qprintf("\r%5d", nummerges++);
00310                     break;
00311                 } //end if
00312                 lastb2 = b2;
00313             } //end for
00314             //if b1 can't be merged with any of the other brushes
00315             if (!b2)
00316             {
00317                 brushlist = brushlist->next;
00318                 //keep b1
00319                 b1->next = newbrushlist;
00320                 newbrushlist = b1;
00321             } //end else
00322         } //end for
00323         brushlist = newbrushlist;
00324     } while(merged);
00325     qprintf("\n");
00326     return newbrushlist;
00327 } //end of the function MergeBrushes
00328 //===========================================================================
00329 //
00330 // Parameter:               -
00331 // Returns:                 -
00332 // Changes Globals:     -
00333 //===========================================================================
00334 void SplitBrush2 (bspbrush_t *brush, int planenum,
00335     bspbrush_t **front, bspbrush_t **back)
00336 {
00337     SplitBrush (brush, planenum, front, back);
00338 #if 0
00339     if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1)
00340         (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1
00341     if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1)
00342         (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo;    // not -1
00343 #endif
00344 } //end of the function SplitBrush2
00345 //===========================================================================
00346 // Returns a list of brushes that remain after B is subtracted from A.
00347 // May by empty if A is contained inside B.
00348 // The originals are undisturbed.
00349 //
00350 // Parameter:               -
00351 // Returns:                 -
00352 // Changes Globals:     -
00353 //===========================================================================
00354 bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b)
00355 {   // a - b = out (list)
00356     int     i;
00357     bspbrush_t  *front, *back;
00358     bspbrush_t  *out, *in;
00359 
00360     in = a;
00361     out = NULL;
00362     for (i = 0; i < b->numsides && in; i++)
00363     {
00364         SplitBrush2(in, b->sides[i].planenum, &front, &back);
00365         if (in != a) FreeBrush(in);
00366         if (front)
00367         {   // add to list
00368             front->next = out;
00369             out = front;
00370         } //end if
00371         in = back;
00372     } //end for
00373     if (in)
00374     {
00375         FreeBrush (in);
00376     } //end if
00377     else
00378     {   // didn't really intersect
00379         FreeBrushList (out);
00380         return a;
00381     } //end else
00382     return out;
00383 } //end of the function SubtractBrush
00384 //===========================================================================
00385 // Returns a single brush made up by the intersection of the
00386 // two provided brushes, or NULL if they are disjoint.
00387 //
00388 // The originals are undisturbed.
00389 //
00390 // Parameter:               -
00391 // Returns:                 -
00392 // Changes Globals:     -
00393 //===========================================================================
00394 bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b)
00395 {
00396     int     i;
00397     bspbrush_t  *front, *back;
00398     bspbrush_t  *in;
00399 
00400     in = a;
00401     for (i=0 ; i<b->numsides && in ; i++)
00402     {
00403         SplitBrush2(in, b->sides[i].planenum, &front, &back);
00404         if (in != a) FreeBrush(in);
00405         if (front) FreeBrush(front);
00406         in = back;
00407     } //end for
00408 
00409     if (in == a) return NULL;
00410 
00411     in->next = NULL;
00412     return in;
00413 } //end of the function IntersectBrush
00414 //===========================================================================
00415 // Returns true if the two brushes definately do not intersect.
00416 // There will be false negatives for some non-axial combinations.
00417 //
00418 // Parameter:               -
00419 // Returns:                 -
00420 // Changes Globals:     -
00421 //===========================================================================
00422 qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b)
00423 {
00424     int     i, j;
00425 
00426     // check bounding boxes
00427     for (i=0 ; i<3 ; i++)
00428         if (a->mins[i] >= b->maxs[i]
00429         || a->maxs[i] <= b->mins[i])
00430             return true;    // bounding boxes don't overlap
00431 
00432     // check for opposing planes
00433     for (i=0 ; i<a->numsides ; i++)
00434     {
00435         for (j=0 ; j<b->numsides ; j++)
00436         {
00437             if (a->sides[i].planenum ==
00438             (b->sides[j].planenum^1) )
00439                 return true;    // opposite planes, so not touching
00440         }
00441     }
00442 
00443     return false;   // might intersect
00444 } //end of the function BrushesDisjoint
00445 //===========================================================================
00446 // Returns a content word for the intersection of two brushes.
00447 // Some combinations will generate a combination (water + clip),
00448 // but most will be the stronger of the two contents.
00449 //
00450 // Parameter:               -
00451 // Returns:                 -
00452 // Changes Globals:     -
00453 //===========================================================================
00454 int IntersectionContents (int c1, int c2)
00455 {
00456     int out;
00457 
00458     out = c1 | c2;
00459 
00460     if (out & CONTENTS_SOLID) out = CONTENTS_SOLID;
00461 
00462     return out;
00463 } //end of the function IntersectionContents
00464 //===========================================================================
00465 // Any planes shared with the box edge will be set to no texinfo
00466 //
00467 // Parameter:               -
00468 // Returns:                 -
00469 // Changes Globals:     -
00470 //===========================================================================
00471 bspbrush_t *ClipBrushToBox(bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs)
00472 {
00473     int     i, j;
00474     bspbrush_t  *front, *back;
00475     int     p;
00476 
00477     for (j=0 ; j<2 ; j++)
00478     {
00479         if (brush->maxs[j] > clipmaxs[j])
00480         {
00481             SplitBrush (brush, maxplanenums[j], &front, &back);
00482             if (front)
00483                 FreeBrush (front);
00484             brush = back;
00485             if (!brush)
00486                 return NULL;
00487         }
00488         if (brush->mins[j] < clipmins[j])
00489         {
00490             SplitBrush (brush, minplanenums[j], &front, &back);
00491             if (back)
00492                 FreeBrush (back);
00493             brush = front;
00494             if (!brush)
00495                 return NULL;
00496         }
00497     }
00498 
00499     // remove any colinear faces
00500 
00501     for (i=0 ; i<brush->numsides ; i++)
00502     {
00503         p = brush->sides[i].planenum & ~1;
00504         if (p == maxplanenums[0] || p == maxplanenums[1] 
00505             || p == minplanenums[0] || p == minplanenums[1])
00506         {
00507             brush->sides[i].texinfo = TEXINFO_NODE;
00508             brush->sides[i].flags &= ~SFL_VISIBLE;
00509         }
00510     }
00511     return brush;
00512 } //end of the function ClipBrushToBox
00513 //===========================================================================
00514 //
00515 // Parameter:               -
00516 // Returns:                 -
00517 // Changes Globals:     -
00518 //===========================================================================
00519 bspbrush_t *MakeBspBrushList(int startbrush, int endbrush,
00520                                             vec3_t clipmins, vec3_t clipmaxs)
00521 {
00522     mapbrush_t  *mb;
00523     bspbrush_t  *brushlist, *newbrush;
00524     int         i, j;
00525     int         c_faces;
00526     int         c_brushes;
00527     int         numsides;
00528     int         vis;
00529     vec3_t      normal;
00530     float       dist;
00531 
00532     for (i=0 ; i<2 ; i++)
00533     {
00534         VectorClear (normal);
00535         normal[i] = 1;
00536         dist = clipmaxs[i];
00537         maxplanenums[i] = FindFloatPlane(normal, dist);
00538         dist = clipmins[i];
00539         minplanenums[i] = FindFloatPlane(normal, dist);
00540     }
00541 
00542     brushlist = NULL;
00543     c_faces = 0;
00544     c_brushes = 0;
00545 
00546     for (i=startbrush ; i<endbrush ; i++)
00547     {
00548         mb = &mapbrushes[i];
00549 
00550         numsides = mb->numsides;
00551         if (!numsides)
00552             continue;
00553 
00554         // make sure the brush has at least one face showing
00555         vis = 0;
00556         for (j=0 ; j<numsides ; j++)
00557             if ((mb->original_sides[j].flags & SFL_VISIBLE) && mb->original_sides[j].winding)
00558                 vis++;
00559 #if 0
00560         if (!vis)
00561             continue;   // no faces at all
00562 #endif
00563         // if the brush is outside the clip area, skip it
00564         for (j=0 ; j<3 ; j++)
00565             if (mb->mins[j] >= clipmaxs[j]
00566             || mb->maxs[j] <= clipmins[j])
00567             break;
00568         if (j != 3)
00569             continue;
00570 
00571         //
00572         // make a copy of the brush
00573         //
00574         newbrush = AllocBrush (mb->numsides);
00575         newbrush->original = mb;
00576         newbrush->numsides = mb->numsides;
00577         memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t));
00578         for (j=0 ; j<numsides ; j++)
00579         {
00580             if (newbrush->sides[j].winding)
00581                 newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding);
00582             if (newbrush->sides[j].surf & SURF_HINT)
00583                 newbrush->sides[j].flags |= SFL_VISIBLE;    // hints are always visible
00584         }
00585         VectorCopy (mb->mins, newbrush->mins);
00586         VectorCopy (mb->maxs, newbrush->maxs);
00587 
00588         //
00589         // carve off anything outside the clip box
00590         //
00591         newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs);
00592         if (!newbrush)
00593             continue;
00594 
00595         c_faces += vis;
00596         c_brushes++;
00597 
00598         newbrush->next = brushlist;
00599         brushlist = newbrush;
00600     }
00601 
00602     return brushlist;
00603 } //end of the function MakeBspBrushList
00604 //===========================================================================
00605 //
00606 // Parameter:               -
00607 // Returns:                 -
00608 // Changes Globals:     -
00609 //===========================================================================
00610 bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail)
00611 {
00612     bspbrush_t  *walk, *next;
00613 
00614     for (walk=list ; walk ; walk=next)
00615     {   // add to end of list
00616         next = walk->next;
00617         walk->next = NULL;
00618         tail->next = walk;
00619         tail = walk;
00620     } //end for
00621     return tail;
00622 } //end of the function AddBrushListToTail
00623 //===========================================================================
00624 // Builds a new list that doesn't hold the given brush
00625 //
00626 // Parameter:               -
00627 // Returns:                 -
00628 // Changes Globals:     -
00629 //===========================================================================
00630 bspbrush_t *CullList(bspbrush_t *list, bspbrush_t *skip1)
00631 {
00632     bspbrush_t  *newlist;
00633     bspbrush_t  *next;
00634 
00635     newlist = NULL;
00636 
00637     for ( ; list ; list = next)
00638     {
00639         next = list->next;
00640         if (list == skip1)
00641         {
00642             FreeBrush (list);
00643             continue;
00644         }
00645         list->next = newlist;
00646         newlist = list;
00647     }
00648     return newlist;
00649 } //end of the function CullList
00650 //===========================================================================
00651 //
00652 // Parameter:               -
00653 // Returns:                 -
00654 // Changes Globals:     -
00655 //===========================================================================
00656 /*
00657 void WriteBrushMap(char *name, bspbrush_t *list)
00658 {
00659     FILE    *f;
00660     side_t  *s;
00661     int     i;
00662     winding_t   *w;
00663 
00664     Log_Print("writing %s\n", name);
00665     f = fopen (name, "wb");
00666     if (!f)
00667         Error ("Can't write %s\b", name);
00668 
00669     fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
00670 
00671     for ( ; list ; list=list->next )
00672     {
00673         fprintf (f, "{\n");
00674         for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
00675         {
00676             w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
00677 
00678             fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
00679             fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
00680             fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
00681 
00682             fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
00683             FreeWinding (w);
00684         }
00685         fprintf (f, "}\n");
00686     }
00687     fprintf (f, "}\n");
00688 
00689     fclose (f);
00690 } //end of the function WriteBrushMap
00691 */
00692 //===========================================================================
00693 // Returns true if b1 is allowed to bite b2
00694 //
00695 // Parameter:               -
00696 // Returns:                 -
00697 // Changes Globals:     -
00698 //===========================================================================
00699 qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
00700 {
00701 #ifdef ME
00702     if (create_aas)
00703     {
00704         if (b1->original->expansionbbox != b2->original->expansionbbox)
00705         {
00706             return false;
00707         } //end if
00708         //never have something else bite a ladder brush
00709         //never have a ladder brush bite something else
00710         if ( (b1->original->contents & CONTENTS_LADDER)
00711             && !(b2->original->contents & CONTENTS_LADDER))
00712         { 
00713             return false;
00714         } //end if
00715     } //end if
00716 #endif //ME
00717     // detail brushes never bite structural brushes
00718     if ( (b1->original->contents & CONTENTS_DETAIL) 
00719         && !(b2->original->contents & CONTENTS_DETAIL) )
00720     {
00721         return false;
00722     } //end if
00723     if (b1->original->contents & CONTENTS_SOLID)
00724     {
00725         return true;
00726     } //end if
00727     return false;
00728 } //end of the function BrushGE
00729 //===========================================================================
00730 // Carves any intersecting solid brushes into the minimum number
00731 // of non-intersecting brushes.
00732 //
00733 // Parameter:               -
00734 // Returns:                 -
00735 // Changes Globals:     -
00736 //===========================================================================
00737 bspbrush_t *ChopBrushes (bspbrush_t *head)
00738 {
00739     bspbrush_t  *b1, *b2, *next;
00740     bspbrush_t  *tail;
00741     bspbrush_t  *keep;
00742     bspbrush_t  *sub, *sub2;
00743     int         c1, c2;
00744     int num_csg_iterations;
00745 
00746     Log_Print("-------- Brush CSG ---------\n");
00747     Log_Print("%6d original brushes\n", CountBrushList (head));
00748 
00749     num_csg_iterations = 0;
00750     qprintf("%6d output brushes", num_csg_iterations);
00751 
00752 #if 0
00753     if (startbrush == 0)
00754         WriteBrushList ("before.gl", head, false);
00755 #endif
00756     keep = NULL;
00757 
00758 newlist:
00759     // find tail
00760     if (!head) return NULL;
00761 
00762     for (tail = head; tail->next; tail = tail->next)
00763         ;
00764 
00765     for (b1=head ; b1 ; b1=next)
00766     {
00767         next = b1->next;
00768 
00769         //if the conversion is cancelled
00770         if (cancelconversion)
00771         {
00772             b1->next = keep;
00773             keep = b1;
00774             continue;
00775         } //end if
00776         
00777         for (b2 = b1->next; b2; b2 = b2->next)
00778         {
00779             if (BrushesDisjoint (b1, b2))
00780                 continue;
00781 
00782             sub = NULL;
00783             sub2 = NULL;
00784             c1 = 999999;
00785             c2 = 999999;
00786 
00787             if (BrushGE (b2, b1))
00788             {
00789                 sub = SubtractBrush (b1, b2);
00790                 if (sub == b1)
00791                 {
00792                     continue;       // didn't really intersect
00793                 } //end if
00794                 if (!sub)
00795                 {   // b1 is swallowed by b2
00796                     head = CullList (b1, b1);
00797                     goto newlist;
00798                 }
00799                 c1 = CountBrushList (sub);
00800             }
00801 
00802             if ( BrushGE (b1, b2) )
00803             {
00804                 sub2 = SubtractBrush (b2, b1);
00805                 if (sub2 == b2)
00806                     continue;       // didn't really intersect
00807                 if (!sub2)
00808                 {   // b2 is swallowed by b1
00809                     FreeBrushList (sub);
00810                     head = CullList (b1, b2);
00811                     goto newlist;
00812                 }
00813                 c2 = CountBrushList (sub2);
00814             }
00815 
00816             if (!sub && !sub2)
00817                 continue;       // neither one can bite
00818 
00819             // only accept if it didn't fragment
00820             // (commenting this out allows full fragmentation)
00821             if (c1 > 1 && c2 > 1)
00822             {
00823                 if (sub2)
00824                     FreeBrushList (sub2);
00825                 if (sub)
00826                     FreeBrushList (sub);
00827                 continue;
00828             }
00829 
00830             if (c1 < c2)
00831             {
00832                 if (sub2) FreeBrushList (sub2);
00833                 tail = AddBrushListToTail (sub, tail);
00834                 head = CullList (b1, b1);
00835                 goto newlist;
00836             } //end if
00837             else
00838             {
00839                 if (sub) FreeBrushList (sub);
00840                 tail = AddBrushListToTail (sub2, tail);
00841                 head = CullList (b1, b2);
00842                 goto newlist;
00843             } //end else
00844         } //end for
00845 
00846         if (!b2)
00847         {   // b1 is no longer intersecting anything, so keep it
00848             b1->next = keep;
00849             keep = b1;
00850         } //end if
00851         num_csg_iterations++;
00852         qprintf("\r%6d", num_csg_iterations);
00853     } //end for
00854 
00855     if (cancelconversion) return keep;
00856     //
00857     qprintf("\n");
00858     Log_Write("%6d output brushes\r\n", num_csg_iterations);
00859 
00860 #if 0
00861     {
00862         WriteBrushList ("after.gl", keep, false);
00863         WriteBrushMap ("after.map", keep);
00864     }
00865 #endif
00866 
00867     return keep;
00868 } //end of the function ChopBrushes
00869 //===========================================================================
00870 //
00871 // Parameter:               -
00872 // Returns:                 -
00873 // Changes Globals:     -
00874 //===========================================================================
00875 bspbrush_t *InitialBrushList (bspbrush_t *list)
00876 {
00877     bspbrush_t *b;
00878     bspbrush_t  *out, *newb;
00879     int         i;
00880 
00881     // only return brushes that have visible faces
00882     out = NULL;
00883     for (b=list ; b ; b=b->next)
00884     {
00885 #if 0
00886         for (i=0 ; i<b->numsides ; i++)
00887             if (b->sides[i].flags & SFL_VISIBLE)
00888                 break;
00889         if (i == b->numsides)
00890             continue;
00891 #endif
00892         newb = CopyBrush (b);
00893         newb->next = out;
00894         out = newb;
00895 
00896         // clear visible, so it must be set by MarkVisibleFaces_r
00897         // to be used in the optimized list
00898         for (i=0 ; i<b->numsides ; i++)
00899         {
00900             newb->sides[i].original = &b->sides[i];
00901 //          newb->sides[i].visible = true;
00902             b->sides[i].flags &= ~SFL_VISIBLE;
00903         }
00904     }
00905 
00906     return out;
00907 } //end of the function InitialBrushList
00908 //===========================================================================
00909 //
00910 // Parameter:               -
00911 // Returns:                 -
00912 // Changes Globals:     -
00913 //===========================================================================
00914 bspbrush_t *OptimizedBrushList (bspbrush_t *list)
00915 {
00916     bspbrush_t *b;
00917     bspbrush_t  *out, *newb;
00918     int         i;
00919 
00920     // only return brushes that have visible faces
00921     out = NULL;
00922     for (b=list ; b ; b=b->next)
00923     {
00924         for (i=0 ; i<b->numsides ; i++)
00925             if (b->sides[i].flags & SFL_VISIBLE)
00926                 break;
00927         if (i == b->numsides)
00928             continue;
00929         newb = CopyBrush (b);
00930         newb->next = out;
00931         out = newb;
00932     } //end for
00933 
00934 //  WriteBrushList ("vis.gl", out, true);
00935     return out;
00936 } //end of the function OptimizeBrushList
00937 //===========================================================================
00938 //
00939 // Parameter:               -
00940 // Returns:                 -
00941 // Changes Globals:     -
00942 //===========================================================================
00943 tree_t *ProcessWorldBrushes(int brush_start, int brush_end)
00944 {
00945     bspbrush_t *brushes;
00946     tree_t *tree;
00947     node_t *node;
00948     vec3_t mins, maxs;
00949 
00950     //take the whole world
00951     mins[0] = map_mins[0] - 8;
00952     mins[1] = map_mins[1] - 8;
00953     mins[2] = map_mins[2] - 8;
00954 
00955     maxs[0] = map_maxs[0] + 8;
00956     maxs[1] = map_maxs[1] + 8;
00957     maxs[2] = map_maxs[2] + 8;
00958 
00959     //reset the brush bsp
00960     ResetBrushBSP();
00961 
00962     // the makelist and chopbrushes could be cached between the passes...
00963 
00964     //create a list with brushes that are within the given mins/maxs
00965     //some brushes will be cut and only the part that falls within the
00966     //mins/maxs will be in the bush list
00967     brushes = MakeBspBrushList(brush_start, brush_end, mins, maxs);
00968     //
00969 
00970     if (!brushes)
00971     {
00972         node = AllocNode ();
00973         node->planenum = PLANENUM_LEAF;
00974         node->contents = CONTENTS_SOLID;
00975 
00976         tree = Tree_Alloc();
00977         tree->headnode = node;
00978         VectorCopy(mins, tree->mins);
00979         VectorCopy(maxs, tree->maxs);
00980     } //end if
00981     else
00982     {
00983         //Carves any intersecting solid brushes into the minimum number
00984         //of non-intersecting brushes. 
00985         if (!nocsg)
00986         {
00987             brushes = ChopBrushes(brushes);
00988             /*
00989             if (create_aas)
00990             {
00991                 brushes = MergeBrushes(brushes);
00992             } //end if*/
00993         } //end if
00994         //if the conversion is cancelled
00995         if (cancelconversion)
00996         {
00997             FreeBrushList(brushes);
00998             return NULL;
00999         } //end if
01000         //create the actual bsp tree
01001         tree = BrushBSP(brushes, mins, maxs);
01002     } //end else
01003     //return the tree
01004     return tree;
01005 } //end of the function ProcessWorldBrushes

Generated on Thu Aug 25 12:37:15 2005 for Quake III Arena by  doxygen 1.3.9.1